Skip to content

Instantly share code, notes, and snippets.

@friendlyanon
Last active January 20, 2021 18:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save friendlyanon/efb1023a0ffd1308a740951cb09057f8 to your computer and use it in GitHub Desktop.
Save friendlyanon/efb1023a0ffd1308a740951cb09057f8 to your computer and use it in GitHub Desktop.
/* eslint-disable strict, semi, no-empty, no-cond-assign */
/* globals webm, localforage, VanillaModal */
setTimeout(() => {
"use strict";
const saucenao = "http://saucenao.com/search.php?db=999&url=", document = window.document, rem = function(b) {
clearInterval(webm.timer)
clearInterval(webm.updater)
document.body.removeEventListener("mouseup", webm.mouseup)
if (webm.observer)
webm.observer.disconnect()
if (webm.modal)
webm.modal.destroy()
window.webm = b
try { qS('style.webm_style').remove() }
catch(e) {}
try { qS('div#webm_modal_wrapper').remove() }
catch(e) {}
alert("It is advised to change channels/servers to clear out the residue after updating.\n\
You may review the changelog by right clicking on the settings cog in the bottom left corner and selecting \"About WebM\"")
}, qS = (root = document, sel = "") => {
if (typeof root === "string")
sel = root, root = document
return root.querySelector(sel)
}, qSA = (root = document, sel = "") => {
if (typeof root === "string")
sel = root, root = document
return root.querySelectorAll(sel)
}
if ("object" === typeof window.webm) rem()
window.webm = {
config: {},
twitterPlayer(e) {
const video = webm.getStyle('embedVideo')
let node = e.target
for (;;) {
if (node.classList && node.classList.contains(video)) break
if ((node = node.parentNode) == null) return
}
let { href } = node.dataset, h
if (!href) {
h = node.getElementsByTagName("a")[1].href
href = h
}
if (!new URL(href).host.endsWith("twitter.com")) return
else {
node.dataset.href = h
node.classList.add("fuck-twatter")
setTimeout(() => {
const i = node.lastElementChild
const f = () => i.src = "about:blank"
f()
i.addEventListener("load", f, { once: true })
}, 100)
}
const x = new webm.xhr()
x.open("POST", "http://127.0.0.1:9999")
x.send(href)
},
AuthorFinder: class {
constructor(root) {
this.root = root;
this.set = new Set();
}
isObject(value) {
return value !== null && typeof value === "object";
}
addValue(value) {
if (this.isObject(value)) {
this.set.add(this.enumerate(value));
}
}
*enumerate(object) {
if (Array.isArray(object)) {
for (const value of object) {
this.addValue(value);
}
} else if (this.isObject(object)) {
for (const key of Object.keys(object)) {
if (key === "return") {
continue;
}
const value = object[key];
if (key === "author") {
yield value;
} else {
this.addValue(value);
}
}
}
}
*[Symbol.iterator]() {
const { set } = this;
this.addValue(this.root);
do {
for (const gen of set) {
const { value, done } = gen.next();
if (typeof value !== "undefined") {
yield value;
}
if (done) {
set.delete(gen);
}
}
} while (set.size);
}
},
getStyle: (tag, nth = 0) => {
if (webm.style && webm.style[tag] && webm.style[tag][nth]) {
return webm.style[tag][nth];
}
else {
console.log("CSS tag '%s' not found", tag);
return "";
}
},
r: /(gfycat|imgur|giphy)\.com/,
pr: /^([0-9]{1,9})_p[0-9]{1,3}(?:_\w+)?(?:\.\w+)?$/,
hr: /^\/([gs])\/([0-9a-z]+)\/([0-9a-z]+)-?(\d+)?/i,
wr: /\/(https?)(\/.+)(?:\?.+)?$/i,
wCache: Object.setPrototypeOf({}, null),
eCache: new WeakSet,
lastReq: Date.now() - 2000,
version: 23,
timerUtils: {
audio_sel: ["ogg","oga","mp3","wav","m4a" ,"aac","flac","opus"],
video_sel: ["ogm","ogv","m4v","mp4","webm","mov"],
visible(el) {
let v = function(el) {
var rect1 = el.getBoundingClientRect(), rect2 = qS(`.${webm.getStyle("messages")}`).getBoundingClientRect()
return (rect1.bottom & -1) > (rect2.bottom & -1)
}, timer, fn = () => {
!v(el) ? clearInterval(timer) : el.scrollIntoView(!1)
}
if (v(el)) timer = setInterval(fn, 100)
},
looper(e) {
if (e.button != 2) return
let v = e.target, fn = () => {
let el = qS('.' + webm.getStyle('contextMenu')), child, loop = document.createElement("div")
for(child of el.children)
if (/^\s*Copy Link/.test(child.textContent)) break
loop.setAttribute("class", webm.getStyle('item') + " " + webm.getStyle('itemToggle'))
loop.setAttribute("role", "button")
loop.setAttribute("tabindex", "0")
loop.insertAdjacentHTML("beforeend", `<div class="${webm.getStyle('label')}" style="text-transform:capitalize">Loop ${v.tagName.toLowerCase()}</div><div class="checkbox"><div class="checkbox-inner"><input type="checkbox" value="on"${v.loop ? ' checked' : ''}><span></span></div><span></span></div>`)
loop.onclick = () => qS(loop, 'input').checked = v.loop = !v.loop
child.innerHTML = ''
child.appendChild(loop, child)
}
setTimeout(fn, 10)
},
canplay(e) {
let chat = qS(e.target.ownerDocument, `.${webm.getStyle("messages")}`)
e.target.hidden = false
e.target.previousElementSibling.children[0].style.cursor = "pointer"
if (chat.getBoundingClientRect().bottom < e.target.getBoundingClientRect().bottom) {
let group = e.target, message = group.parentNode
while (!group.classList.contains("message-group")) {
if (group == document.body) break
else group = group.parentNode
}
while (!message.classList.contains("message")) {
if (message == document.body) break
else message = message.parentNode
}
if (qSA(group, ".attachment[webm] + [preload]").length > 1 || message.nextElementSibling) group = e.target
webm.timerUtils.visible(group)
}
},
error({ target }) {
const a = target.previousElementSibling.children[0]
if (!target.dataset.retry)
for (const [k, v] of Object.entries(webm.wCache)) {
if (target.src.startsWith(k)) {
target.dataset.retry = "_"
target.src = v
return
}
}
a.setAttribute("style", "filter: hue-rotate(130deg)")
a.onclick = void 0
target.remove()
},
format(el, { href }) {
const { config } = webm
const { canplay, error, looper } = webm.timerUtils
let tag = el
el = document.createElement(tag)
el.style.maxWidth = "100%"
el.style.marginTop = "8px"
el.style.minHeight = "150px"
el.style.maxHeight = "calc(100vh - 175px)"
el.style.minWidth = "250px"
if (config.defaultLoop !== true) el.loop = true
if (tag !== "video") el.style.backgroundColor = "black"
el.controls = el.hidden = true
el.setAttribute("preload", "metadata")
if (href.indexOf("http:") === 0) el.src = href.replace("http:", "https:")
else el.src = href
el.addEventListener("canplay", canplay, {once: true})
el.addEventListener("error", error)
el.addEventListener("mouseup", looper)
return el
},
player_click(tag, par, el) {
let player = par.nextElementSibling || {tagName:""}
if (new RegExp(tag, "i").test(player.tagName)) player.remove()
else {
player = webm.timerUtils.format(tag, el)
par.children[0].style.cursor = "progress"
if (par == par.parentNode.lastElementChild) par.parentNode.appendChild(player)
else par.parentNode.insertBefore(player, par.nextElementSibling)
}
},
finish(tag, el) {
let icon = el.parentNode.previousElementSibling, par
if (!icon) return
switch(tag) {
case 'audio': icon.src = "https://discordapp.com/assets/5b0da31dc2b00717c1e35fb1f84f9b9b.svg"; break
case 'video': break
}
par = icon.parentNode
icon.style.cursor = "pointer"
icon.style.minWidth = "28px"
icon.onclick = webm.timerUtils.player_click.bind(this, tag, par, el)
el.setAttribute("webm", "true")
let size = el.parentNode.getBoundingClientRect().height
qS(`.${webm.getStyle("messages")}`).scrollTop += 39 < size ? size + 20 : 60
},
embed(e) {
const current = e.currentTarget
const iframe = document.createElement("iframe")
const root = current.parentNode.parentNode.parentNode
root.removeChild(root.firstElementChild)
iframe.src = current.nextElementSibling.href
root.replaceChild(iframe, root.firstElementChild)
iframe.classList.add("image")
iframe.width = 400
iframe.height = 300
iframe.setAttribute("frameborder", "0")
iframe.setAttribute("allowfullscreen", "allowfullscreen")
},
fixHttp(str) {
if (String(str[4]).toLowerCase() === "s")
return str
return str.replace(/^http:/i, "https:")
},
popout(e) {
e.preventDefault();
({currentTarget: {parentNode: e}} = e)
return
},
async nhentai(e) {
const path = e.pathname.split("/")
if (path[1] !== "g") return
const embed = document.createElement("div")
embed.className = webm.getStyle('embed') + " embed " + webm.getStyle('flex')
embed.innerHTML = `<div class="${webm.getStyle('embedPill')}"></div><div class="${webm.getStyle('embedInner')}"><div class="${webm.getStyle('embedContent')} ${webm.getStyle('flex')}">Loading hentai preview ...</div></div></div>`
e.parentNode.parentNode.parentNode.nextElementSibling.insertAdjacentElement("afterbegin", embed)
qS(`.${webm.getStyle("messages")}`).scrollTop += Number(embed.dataset.height = embed.offsetHeight)
let toWait, waitFn, obj
toWait = new Promise(done => waitFn = done)
const x = new webm.xhr()
x.open("GET", "https://nhentai.net/api/gallery/" + path[2])
x.responseType = "json"
x.onload = () => waitFn(x.response)
x.send()
obj = await toWait
const b = "<br /><br />"
let lang, cat, tags = [], i = obj.tags.length, k = -1
while(~--i) {
const tag = obj.tags[i]
switch(tag.type) {
case "language":
lang = tag.name
break
case "category":
cat = tag.name
break
case "tag":
tags[++k] = tag.name
break
}
}
embed.innerHTML = `<div class="${webm.getStyle('embedPill')}" style="background-color: hsl(${webm.timerUtils.cat.Doujinshi.color})"></div><div class="${webm.getStyle('embedInner')}"><div class="${webm.getStyle('embedContent')} ${webm.getStyle('flex')}"><div class="${webm.getStyle('embedContentInner')}"><div class=""><a href="https://${e.host}" class="${webm.getStyle('embedProvider')} ${webm.getStyle('size12')} ${webm.getStyle('weightNormal')}">${e.host}</a></div><div class="${webm.getStyle('embedMargin')} ${webm.getStyle('marginTop4')}"><a target="_blank" rel="noreferrer noopener" class="${webm.getStyle('embedTitleLink')} ${webm.getStyle('embedLink')} ${webm.getStyle('embedTitle')} ${webm.getStyle('size14')} ${webm.getStyle('weightMedium')}" href="https://${e.host}/g/${path[2]}/">${obj.title.english}</a></div><div class="${webm.getStyle('embedDescription')} ${webm.getStyle('embedMargin')} ${webm.getStyle('marginTop4')} markup">Japanese title: ${obj.title.japanese}${b}Language: ${lang}${b}Filecount: ${obj.num_pages} images${b}Favourites: ${obj.num_favorites}${b}Tags: ${tags.join(" | ")}</div></div><a class="${webm.getStyle('imageWrapper')} ${webm.getStyle('embedThumbnail')} ${webm.getStyle('embedImage')}" href="https://${e.host}/g/${path[2]}/" rel="noreferrer noopener" target="_blank"><img /></a></div></div>`
if (embed.nextElementSibling) embed.nextElementSibling.remove()
const oldHeight = Number(embed.dataset.height)
qS(`.${webm.getStyle("messages")}`).scrollTop += Number(embed.dataset.height = embed.offsetHeight) - oldHeight
webm.timerUtils.getThumb(`https://t.nhentai.net/galleries/${obj.media_id}/1t.jpg`, qS(embed, "img"), embed, true)
},
hentai(e) {
if (~e.host.indexOf("nhentai.net")) return webm.timerUtils.nhentai(e)
const gallery = e.pathname.match(webm.hr)
if (!gallery) return
const embed = document.createElement("div")
embed.className = webm.getStyle('embed') + " embed " + webm.getStyle('flex')
embed.innerHTML = `<div class="${webm.getStyle('embedPill')}"></div><div class="${webm.getStyle('embedInner')}"><div class="${webm.getStyle('embedContent')} ${webm.getStyle('flex')}">Loading hentai preview ...</div></div></div>`
e.parentNode.parentNode.parentNode.nextElementSibling.insertAdjacentElement("afterbegin", embed)
qS(`.${webm.getStyle("messages")}`).scrollTop += Number(embed.dataset.height = embed.offsetHeight)
const isG = gallery[1] === "g"
const json = JSON.stringify(isG ? {
method: "gdata",
gidlist: [[Number(gallery[2]), gallery[3]]],
namespace: 1
} : {
method: "gtoken",
pagelist: [[Number(gallery[3]), gallery[2], Number(gallery[4])]],
})
webm.timerUtils.req(webm.timerUtils.getHentai, e, json, embed, webm.timerUtils[isG ? "onHentai" : "getToken"])
},
getToken(x, e, embed) {
if (!embed.parentNode) return
const temp = x.response
if (!temp.tokenlist) return embed.lastElementChild.textContent = "Error!"
const token = temp.tokenlist[0]
const json = JSON.stringify({
method: "gdata",
gidlist: [[token.gid, token.token]],
namespace: 1
})
webm.timerUtils.req(webm.timerUtils.getHentai, e, json, embed, webm.timerUtils.onHentai)
},
thumbCache: Object.setPrototypeOf({}, null),
imgLoad() {
const img = this
const style = { width: img.naturalWidth + "px", height: img.naturalHeight + "px"}
Object.assign(img.style, style)
Object.assign(img.parentNode.style, style)
},
getThumb(url, img, embed, nocookie) {
if (url in webm.timerUtils.thumbCache)
return img.onload = webm.timerUtils.imgLoad, img.src = webm.timerUtils.thumbCache[url]
const x = new webm.xhr()
x.open("GET", url)
x.responseType = "arraybuffer"
if (!nocookie) x.setRequestHeader('Cookie', webm.config.embedHentai)
x.onload = () => {
if (!img.parentNode) return
switch(x.status) {
case 304:
case 200:
break
default:
if (url.endsWith(".png")) return
return webm.timerUtils.getThumb(url.replace(".jpg", ".png"), img, embed, nocookie)
}
img.onload = webm.timerUtils.imgLoad
if (webm.timerUtils.thumbCache[url]) img.src = webm.timerUtils.thumbCache[url]
else {
const blob = new Blob([x.response], {type: "application/octet-binary"})
const reader = new FileReader
reader.onload = () => {
const { result } = reader
img.src = webm.timerUtils.thumbCache[url] = "data:image/png;base64," + result.substr(result.indexOf(',') + 1)
}
reader.readAsDataURL(blob)
return
}
const oldHeight = Number(embed.dataset.height)
qS(`.${webm.getStyle("messages")}`).scrollTop += Number(embed.dataset.height = embed.offsetHeight) - oldHeight
}
x.send()
},
getHentai(e, json, embed, cb) {
const x = new webm.xhr()
x.open("POST", "https://" + e.host + "/api.php")
x.responseType = "json"
x.setRequestHeader('Content-Type', 'application/json; charset=utf-8')
x.setRequestHeader('Cookie', webm.config.embedHentai)
x.onload = cb.bind(null, x, e, embed)
x.send(json)
},
cat: {
"Doujinshi" : "0, 92%, 27%" ,
"Manga" : "20, 100%, 24%",
"Artist CG" : "52, 100%, 24%",
"Game CG" : "82, 42%, 14%" ,
"Western" : "82, 100%, 24%",
"Image Set" : "209, 74%, 22%",
"Non-H" : "185, 44%, 24%",
"Cosplay" : "259, 41%, 27%",
"Asian Porn": "321, 76%, 26%",
"Misc" : "321, 0%, 21%" ,
"Private" : "217, 8%, 34%" ,
},
onHentai(x, e, embed) {
if (!embed.parentNode) return
let obj = x.response
if (!(obj.gmetadata && obj.gmetadata[0])) return embed.lastElementChild.textContent = "Error!"
obj = obj.gmetadata[0]
const b = "<br /><br />"
embed.innerHTML = `<div class="${webm.getStyle('embedPill')}" style="background-color: hsl(${webm.timerUtils.cat[obj.category]})"></div><div class="${webm.getStyle('embedInner')}"><div class="${webm.getStyle('embedContent')} ${webm.getStyle('flex')}"><div class="${webm.getStyle('embedContentInner')}"><div class=""><a href="https://${e.host}" class="${webm.getStyle('embedProvider')} ${webm.getStyle('size12')} ${webm.getStyle('weightNormal')}">${e.host}</a></div><div class="${webm.getStyle('embedMargin')} ${webm.getStyle('marginTop4')}"><a target="_blank" rel="noreferrer noopener" class="${webm.getStyle('embedTitleLink')} ${webm.getStyle('embedLink')} ${webm.getStyle('embedTitle')} ${webm.getStyle('size14')} ${webm.getStyle('weightMedium')}" href="https://${e.host}/g/${obj.gid}/${obj.token}">${obj.title}</a></div><div class="${webm.getStyle('embedDescription')} ${webm.getStyle('embedMargin')} ${webm.getStyle('marginTop4')} markup">Japanese title: ${obj.title_jpn}${b}Category: ${obj.category}${b}Filecount: ${obj.filecount} images${b}Rating: ${obj.rating}${b}Tags: ${obj.tags.join(" | ")}</div></div><a class="${webm.getStyle('imageWrapper')} ${webm.getStyle('embedThumbnail')} ${webm.getStyle('embedImage')}" href="https://${e.host}/g/${obj.gid}/${obj.token}" rel="noreferrer noopener" target="_blank"><img /></a></div></div>`
const oldHeight = Number(embed.dataset.height)
qS(`.${webm.getStyle("messages")}`).scrollTop += Number(embed.dataset.height = embed.offsetHeight) - oldHeight
webm.timerUtils.getThumb(obj.thumb, qS(embed, "img"), embed)
},
req(...args) {
let timer
const now = Date.now()
webm.lastReq += 2000
const dif = now - webm.lastReq
if (dif > 0) webm.lastReq = now
else timer = webm.lastReq - now
setTimeout(args.shift(), timer || 0, ...args)
}
},
nitro() {
if (webm.observer) return
const emoji = /\.(gif|webp)(\?.+)?$/;
(webm.observer = new MutationObserver(
mutations => {
for (const mut of mutations) {
let el = mut.target
if (el.nodeName === "IMG" && el.classList.contains("emoji")) {
switch (el.alt) {
case ":FelyneNya:": case ":FelyneNya2:": continue;
default: if (!emoji.test(el.src)) continue;
}
el.src = el.src.replace(emoji, ".png")
}
}
})).observe(document.body, { subtree : true, attributes : true, attributeOldValue : true, attributeFilter : ["style", "src"] })
},
timer: setInterval(f => { try { f() } catch (e) { console.error(e) } }, 1000, function(a) {
const {audio_sel, video_sel, finish, embed, fixHttp, hentai} = webm.timerUtils
const config = webm.config
if (!config) return
if (webm.updateConf && !config.notFirstLaunch) {
webm.aboutModal()
config.notFirstLaunch = true
webm.updateConf()
}
if (config.killWhitey === null) {
const el = document.querySelector('section[aria-label="Channel header"] + * [role="log"]')
if (el && !el.dataset.twatter) {
el.dataset.twatter = "1"
el.addEventListener("click", webm.twitterPlayer, true)
}
}
for (let el of qSA(`button > div > svg[name="Gift"]:not(.DELETED)`)) {
el.classList.add("DELETED")
el.parentNode.parentNode.classList.add("DELETED")
el.parentNode.parentNode.nextElementSibling.classList.add("DELETED")
}
for (let el of qSA(`.${webm.getStyle('cozyMessage')}:not([data-id])`)) {
const [author] = new webm.AuthorFinder(el.__reactInternalInstance$);
try {
if (webm.observer && author.avatar.startsWith("a_")) {
author.avatar = author.avatar.slice(2)
}
el.dataset.id = author.id;
} catch (e) {}
}/*
for (let el of qSA(`svg.${webm.getStyle('gifPickerIcon')}:not(.DELETED)`)) {
el.parentNode.parentNode.parentNode.classList.add("DELETED")
el.classList.add("DELETED")
}*/
if (!config.autoSpoiler)
s: for (let el of qSA(`.${webm.getStyle('spoilerContainer')}:not([data-lol]), .${webm.getStyle('spoilerText')}:not([data-lol])`)) {
el.dataset.lol = "1";
for (let node = el; (node = node.parentNode) != null; ) {
if ((node.className || "").includes("repliedMessage-")) {
for (const c of el.classList) {
if (c.startsWith("hidden-")) {
el.classList.remove(c);
break;
}
}
el.setAttribute("tabindex", "-1");
el.setAttribute("aria-expanded", "true");
el.setAttribute("role", "presentation");
el.removeAttribute("aria-label");
continue s;
}
}
el.click();
}
if (!config.autoSpoiler)
for (let el of qSA(`.${webm.getStyle('spoilerWarning')}`)) {
const hidden = el.nextElementSibling;
hidden.click();
hidden.parentNode.replaceWith(hidden.firstElementChild);
}
if (!config.autoSpoiler)
for (let el of qSA(`.${webm.getStyle('cozyMessage')} .${webm.getStyle('attachment')} div.${webm.getStyle('filenameLinkWrapper')}`)) {
el.parentNode.replaceChild(el.removeChild(el.firstElementChild), el)
}
if (!config.audioEmbed)
for (let el of qSA("[class*='wrapperAudio-']:not(.DELETED)")) {
const meta = qS(el, "[class*='metadataContent-']")
el.insertAdjacentHTML('afterend', `<div style="margin-top:8px" class="${webm.getStyle('attachment')} ${webm.getStyle('horizontal')} ${webm.getStyle('flex')} ${webm.getStyle('directionRow')} ${webm.getStyle('alignCenter')}"><img class="icon-1kp3fr" src="/assets/985ea67d2edab4424c62009886f12e44.svg" title=""><div class="${webm.getStyle('attachmentInner')}"><a href="${qS(el, 'a').href}" target="_blank" class="${webm.getStyle('filenameLink')}" style="font-size:16px;word-break:break-word" rel="noreferrer">${meta.children[0].textContent}</a><div class="${webm.getStyle('weightLight')} ${webm.getStyle('metadata', 1)} ${webm.getStyle('size12')} ${webm.getStyle('height16')}">${meta.children[1].textContent}</div></div></div>`)
finish("audio", el.nextElementSibling.querySelector("a"))
el.classList.add("DELETED")
}
for (let el of qSA(`.${webm.getStyle('markup')} > a:not([webm]), .${webm.getStyle('cozyMessage')} .${webm.getStyle('attachment')} a:not([webm])`)) {
if (webm.r.test(el.origin)) {
el.setAttribute("webm", "true")
continue
}
let ext = el.pathname.split("."), tag
if (ext.length > 1 && (ext = ext.pop().toLowerCase())) tag = audio_sel.includes(ext) ? "audio" : video_sel.includes(ext) ? "video" : void 0
if (!tag || config[tag + "Embed"]) continue
for (let node = el; node; node = node.parentNode) {
const { dataset } = node;
if (dataset && dataset.id) {
webm.eCache.add(node);
break;
}
}
if (el.parentNode.classList.contains(webm.getStyle('markup'))) {
let attach = document.createElement("div"), _
attach.className = `${webm.getStyle('attachment')} ${webm.getStyle('horizontal')} ${webm.getStyle('flex')} ${webm.getStyle('directionRow')} ${webm.getStyle('alignCenter')}`
attach.setAttribute("style", "margin-top:8px")
const msg = el.parentNode.parentNode
_ = msg
while(_ = _.previousElementSibling) if (_.tagName === "DIV") _.remove()
msg.parentNode.appendChild(attach)
attach.insertAdjacentHTML('afterbegin', `<img class="icon-1kp3fr" src="/assets/985ea67d2edab4424c62009886f12e44.svg" title="unknown"><div class="${webm.getStyle('attachmentInner')}"><a href="${el.href}" target="_blank" class="${webm.getStyle('filenameLink')}" style="font-size:16px;word-break:break-word" rel="noreferrer">${el.pathname.split("/").pop()}</a><div class="${webm.getStyle('weightLight')} ${webm.getStyle('metadata', 1)} ${webm.getStyle('size12')} ${webm.getStyle('height16')}">??? MB</div></div>`)
el.setAttribute("webm", "true")
finish(tag, attach.querySelector("a"))
} else finish(tag, el)
}
if (!config.videoEmbed)
for (let el of qSA(".video-8eMOth:not(.DELETED)")) {
let steps = 0, node = el, nodes = [];
while (++steps, node = node.parentNode) {
nodes.push(node);
if (node.classList.contains(webm.getStyle('cozyMessage'))) break;
}
if (!node) {
el.classList.add("DELETED")
continue;
}
let root, loc, meta, hide, size = "??? MB"
if (steps === 5) {
const url = el.src
const match = url.match(webm.wr)
if (match) {
const { 1: pre, 2: suf } = match
webm.wCache[loc = pre + ":/" + suf] = url
meta = new URL(loc).pathname.split("/").pop()
}
else {
loc = url;
meta = "video";
}
root = nodes[nodes.length - 1]
hide = nodes[nodes.length - 2]
}
else if (steps === 3) {
const prev = el.previousElementSibling;
loc = prev.lastElementChild.href;
[meta, size] = Array.from(prev.firstElementChild.children, x => x.textContent)
hide = root = nodes[nodes.length - 2]
}
if (!root) continue
if (!webm.eCache.has(node.parentNode.parentNode.parentNode)) {
root.insertAdjacentHTML('afterend', `<div style="margin-top:8px" class="${webm.getStyle('attachment')} ${webm.getStyle('horizontal')} ${webm.getStyle('flex')} ${webm.getStyle('directionRow')} ${webm.getStyle('alignCenter')}"><img class="icon-1kp3fr" src="/assets/985ea67d2edab4424c62009886f12e44.svg" title=""><div class="${webm.getStyle('attachmentInner')}"><a data-lol="1" href="${loc}" target="_blank" class="${webm.getStyle('filenameLink')}" style="font-size:16px;word-break:break-word" rel="noreferrer">${meta}</a><div class="${webm.getStyle('weightLight')} ${webm.getStyle('metadata', 1)} ${webm.getStyle('size12')} ${webm.getStyle('height16')}">${size}</div></div></div>`)
finish("video", root.nextElementSibling.querySelector("a"))
}
hide.classList.add("DELETED")
el.classList.add("DELETED")
}
if (!config.sauceOnViewer)
for (let el of qSA('a.'+webm.getStyle('downloadLink')+':not([sauce])')) {
el.setAttribute("sauce", "true")
let sauce = document.createElement("a")
sauce.setAttribute("sauce", "true")
sauce.setAttribute("rel", "noreferrer")
sauce.setAttribute("target", "_blank")
sauce.textContent = "Sauce"
sauce.setAttribute("class", `${webm.getStyle('downloadLink')} ${webm.getStyle('size14')} ${webm.getStyle('weightMedium')}`)
sauce.setAttribute("style", "text-align: right; width: max-content; justify-self: end;")
sauce.setAttribute("href", saucenao + el.href)
el.parentNode.appendChild(sauce)
Object.assign(el.parentNode.style, {
display: "grid",
gridTemplateAreas: `"image image" "open download"`,
})
el.parentNode.firstElementChild.style.gridArea = "image";
sauce.previousElementSibling.style.width = "max-content"
}
if (!config.fileNameHover)
for (let el of qSA(`.${webm.getStyle('cozyMessage')} a.${webm.getStyle('imageWrapper')}:not([data-fname])`))
el.dataset.fname = el.href.split("/").pop()
if (config.killWhitey === null) {
if (!webm.waifu) {
webm.waifu = true
qS('style.webm_style').insertAdjacentHTML("beforeend", `div + div > div[class*='channels-']{position:relative}div + div > div[class*='channels-']>div:first-of-type{background-color:transparent}div + div > div[class*='channels-']::before{
content: "";
display: block;
bottom: -156px;
left: -41.6px;
background: url("https://cdn.discordapp.com/attachments/187205892989648897/359786909066723328/Untitled-1.png") no-repeat right bottom;
background-size: contain;
position: fixed;
height: 728px;
width: 960px;
pointer-events: none;
transform: scaleX(-1)
}`)
}
for (let el of qSA('[data-id="90819638220296192"] span > strong[class*="username"]:not([data-lol])')) {
el.dataset.lol = "ayy lmao"
el.textContent = "sopdragonfucker lolfag"
}
for (let el of qSA('[data-id="450629693809623040"] span > strong[class*="username"]:not([data-lol])')) {
el.dataset.lol = "ayy lmao"
el.textContent = "Suki"
}
for (let el of qSA('[data-id="135534799208185856"] span > strong[class*="username"]:not([data-lol])')) {
el.dataset.lol = "ayy lmao"
el.textContent = "Vaioretto"
}
}
if (!config.preventScaryPopUp)
for (let el of qSA(`.${webm.getStyle('markup')} > a[href^="http"][rel="noreferrer"]:not([data-scary])`)) {
el.dataset.scary = "what a faggot"
el.outerHTML += "";
}/*
if (!config.skipNSFW)
for (let el of qSA(`div[data-focus-guard] + div > form.${webm.getStyle('modal')}.${webm.getStyle('sizeSmall', 1)}`)) {
if (
(el = el.children).length !== 2 ||
(el = el[1]).style.flex !== "0 0 auto" ||
(el = el.children).length !== 3 ||
(el = el[0]).type !== "submit" ||
!el.className.includes("primaryButton-") ||
el.firstElementChild.tagName !== "DIV"
) continue
el.click()
}*/
if (!config.skipScary)
for (let el of qSA(`div[tabindex] + div[class*='inner-'] > form[class*='modal-'] strong`)) {
switch (el.textContent.trim().slice(0, 6)) {
case "ftp://": case "http:/": case "https:": break;
default: continue;
}
try {
const root = el.parentNode.parentNode.parentNode.nextElementSibling
if (!root.firstElementChild.matches("button[type='submit']")) {
continue;
}
root.lastElementChild.click();
} catch (_) {}
}
for (let el of qSA(".guilds-wrapper + .channels-wrap > div:first-of-type > div[class*='scrollerWrap-'] > div[class*='scroller-'] > div[class*='wrapperDefault-'] + div[style*='visibility:']")) // eslint-disable-line
window.dispatchEvent(new Event('resize'))
if (!config.videoEmbed)
for (const el of qSA(".embed-wrapper > div[class^='embed ']")) {
const a = el.children[1]
if (a && a.classList.contains("embed-thumbnail-link")) {
const {href} = a
if (/^https?:\/\/(?:www\.)?(rave\.dj|hooktube\.com)\/\w+/i.test(href)) {
el.setAttribute("class", "embed")
const div = document.createElement("div")
const img = fixHttp(a.children[0].getAttribute("href"))
div.setAttribute("class", "embed-thumbnail embed-thumbnail-video")
div.setAttribute("style", "width:400px;height:300px;margin-top:4px")
div.innerHTML = `<img class="image" src="${img}" href="${img}" width="400" height="300"><div class="embed-video-actions"><div class="embed-video-actions-inner"><button class="embed-video-play" type="button"></button><a class="embed-video-popout" href="${fixHttp(href)}" target="_blank" rel="noreferrer"></a></div></div>`
el.replaceChild(div, a)
qS(div, ".embed-video-play").addEventListener("click", embed, {once: true})
qS(`.${webm.getStyle("messages")}`).scrollTop += 404
}
}
}
if (config.embedHentai && webm.xhr)
for (const el of qSA(`.${webm.getStyle('markup')} a[href*='hentai.']:not([data-hentai])`)) {
el.dataset.hentai = "ayy"
// hentai(el)
}
}),
menuitem(text) {
let cls = ['item', 'labelContainer', 'colorDefault'].map(x => webm.getStyle(x)).join(" ");
let div = document.createElement('div');
div.className = cls;
div.setAttribute('tabindex', '-1')
div.setAttribute('role', 'menuitem')
div.innerHTML = `<div class="${webm.getStyle('label')}">${text}</div>`
return div;
},
mouseup(e) {
const config = webm.config
let v = e.target, pixiv = v => {
let match, page_url
if (typeof v !== "string" && v.tagName == "A" && (match = v.href.split("/").pop().match(webm.pr)))
page_url = "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=" + match[1]
else if (v.tagName == "IMG")
page_url = saucenao + v.getAttribute("href")
else
page_url = saucenao + v
return page_url
}
if ((e.button === 2 || e.button === 1) && (v.nodeName === "A" && (v.classList.contains(webm.getStyle('imageWrapper')) || v.classList.contains(webm.getStyle('embedThumbnail'))) || (v.nodeName === "IMG" && ((v = v.parentNode).nodeName === "A" && v.classList.contains(webm.getStyle('imageWrapper')) && v.classList.contains(webm.getStyle('imageZoom'))) || v.nodeName === "DIV" && v.classList.contains(webm.getStyle('imageWrapper')) && (v = v.nextElementSibling) && v.nodeName === "A" && v.classList.contains(webm.getStyle('downloadLink'))))) {
let fn = () => {
if (config.sauceRightClick) return
let el = qS('.' + webm.getStyle('contextMenu')), sauce = document.createElement("div")
sauce.setAttribute("class", webm.getStyle('itemGroup'))
sauce.appendChild(webm.menuitem(v.href.split("/").pop().match(webm.pr) ? 'Pixiv' : 'Sauce'))
sauce.firstElementChild.onclick = () => window.open(pixiv(v))
try {
el.insertBefore(sauce, el.firstElementChild)
el.parentNode.style.top = parseInt(el.parentNode.style.top) - 33 + "px"
} catch(e) {}
if (v.dataset.fname) {
let fname = webm.menuitem('Copy Filename')
sauce.appendChild(fname)
try { el.parentNode.style.top = parseInt(el.parentNode.style.top) - 33 + "px" } catch(e) {}
fname.onclick = (fname => {
let input = document.createElement("input")
input.style.opacity = 0
input.value = fname
document.body.appendChild(input)
input.select()
document.execCommand("copy")
input.remove()
document.body.dispatchEvent(new Event("mousedown"))
}).bind(v, v.dataset.fname)
}
}
if (e.button === 1) {
e.preventDefault()
let href, m
m = v.hasAttribute("href") ?
(href = v.getAttribute("href"), v) :
v.parentNode.previousElementSibling
href || (href = m.getAttribute("href"))
m.removeAttribute("href")
window.open(pixiv(href))
fn = () => m.setAttribute("href", href)
}
return setTimeout(fn, 10)
}
else if (e.button === 2 && ~e.path.indexOf(qS("button[aria-label='User Settings']"))) {
setTimeout(() => {
const el = qS('#user-settings-cog .' + webm.getStyle('item')).parentNode;
el.appendChild(webm.menuitem('WebM settings')).onclick = () => {
const {config} = webm
document.body.dispatchEvent(new Event("mousedown"))
webm.settingsModal()
for (let i = 0, arr = Object.keys(config), len = arr.length; i < len; ++i) {
const key = arr[i]
const input = qS(webm.modal.dom.modalContent, "input#webm_" + key)
if (input) {
input.checked = !config[key]
}
}
}
el.appendChild(webm.menuitem('About WebM')).onclick = () => {
document.body.dispatchEvent(new Event("mousedown"))
webm.aboutModal()
}
setTimeout(() => {
const root = document.getElementById("user-settings-cog").parentNode;
root.style.top = parseInt(root.style.top) - 64 + "px"
}, 100)
}, 10)
}
},
updater: setInterval(() => {
const x = new webm.xhr()
x.open("GET", "https://gist.githubusercontent.com/friendlyanon/f2c804ac8a16916200e190c39e645c3e/raw/?" + Date.now())
x.onload = () => {
if (webm.busy) return
webm.busy = true
if (webm.version < Number(x.response) && confirm(`Discord WebM has an update.\nCurrent: v${webm.version}\nLatest: v${x.response}\n\nDo you wish to update? Cancelling will cause this popup to appear again in 10 minutes.`)) {
const xhr = new webm.xhr()
xhr.open("GET", "https://gist.githubusercontent.com/friendlyanon/efb1023a0ffd1308a740951cb09057f8/raw/?" + Date.now())
xhr.onload = () => {
rem()
Function(xhr.response)()
}
xhr.send()
}
webm.busy = false
}
x.send()
}, 6E5)
};
if (!window.webm.origXhr) {
const proto = (window.webm.origXhr = window.XMLHttpRequest).prototype;
window.XMLHttpRequest = class XMLHttpRequest extends window.webm.origXhr {
open(...args) {
const url = new URL(args[1], "https://discordapp.com")
if (url.pathname.startsWith("/api/v6/science")) {
args[1] = "http://example.com/";
}
return proto.open.apply(this, args);
}
}
}
(function() {
"use strict";
var InvalidStateError, NetworkError, ProgressEvent, SecurityError, SyntaxError, XMLHttpRequest, XMLHttpRequestEventTarget, XMLHttpRequestUpload, http, https, url, extend;
function f(template) {
var i, accumulator, templateLen, _float, _int, end,
temp = "",
argLimit = arguments.length - 1,
last = -1,
argp = 0;
if (!argLimit) return template;
templateLen = template.length - 1;
for (;;) {
i = template.indexOf("%", ++last);
if (i === -1 || (end = i === templateLen)) {
if (accumulator == null) accumulator = template;
else if (!end) accumulator += template.substr(last);
break;
}
if (last) temp = last === i ? "" : template.slice(last, i);
else accumulator = template.substr(0, i);
switch (template.charCodeAt(++i)) {
case 105: // i
case 100: // d
if (argp >= argLimit) continue;
_int = arguments[++argp];
_int = typeof _int === "bigint" ? _int : Math.floor(Number(_int));
accumulator += temp + _int;
last = i;
continue;
case 79: // O
case 111: // o
case 106: // j
if (argp >= argLimit) continue;
try { accumulator += temp + JSON.stringify(arguments[++argp]); }
catch (_) { accumulator += temp + "[Circular]"; }
last = i;
continue;
case 115: // s
if (argp >= argLimit) continue;
accumulator += temp + String(arguments[++argp]);
last = i;
continue;
case 37: // %
accumulator += temp + "%";
last = i;
continue;
case 102: // f
if (argp >= argLimit) continue;
_float = Number(arguments[++argp]);
if (Number.isInteger(_float)) _float += ".0";
accumulator += temp + _float;
last = i;
continue;
}
}
return accumulator;
}
extend = (function() {
var setProto, extend,
has = Object.prototype.hasOwnProperty,
defineProp = Object.defineProperty || function(obj, key, desc) {
obj[key] = desc.value;
},
property = {
writable: true,
configurable: true
};
extend = function(child, parent, properties) {
var key,
proto = child.prototype;
if (properties) {
for (key in properties) {
property.value = properties[key];
defineProp(proto, key, property);
}
}
if (!parent) return;
for (key in parent) {
if (!has.call(parent, key)) continue;
property.value = parent[key];
defineProp(child, key, property);
}
setProto(proto, parent);
};
if ("__proto__" in Object.prototype) {
setProto = function(proto, parent) {
proto.__proto__ = parent.prototype;
};
return extend;
}
else if (typeof Object.setPrototypeOf === "function") {
setProto = function(proto, parent) {
Object.setPrototypeOf(proto, parent.prototype);
};
return extend;
}
else extend = null;
return function(child, parent, properties) {
var key, proto, ctor;
if (parent) {
ctor = function() { this.constructor = child; };
ctor.prototype = parent.prototype;
proto = child.prototype = new ctor;
for (key in parent) {
if (!has.call(parent, key)) continue;
property.value = parent[key];
defineProp(child, key, property);
}
}
else {
proto = child.prototype;
}
if (!properties) return;
for (key in properties) {
property.value = properties[key];
defineProp(proto, key, property);
}
};
}());
XMLHttpRequestEventTarget = (function() {
extend(XMLHttpRequestEventTarget, null, {
onloadstart: null,
onprogress: null,
onabort: null,
onerror: null,
onload: null,
ontimeout: null,
onloadend: null,
addEventListener: function(eventType, listener) {
var base;
eventType = eventType.toLowerCase();
(base = this._listeners)[eventType] || (base[eventType] = []);
this._listeners[eventType].push(listener);
},
removeEventListener: function(eventType, listener) {
var index;
eventType = eventType.toLowerCase();
if (this._listeners[eventType]) {
index = this._listeners[eventType].indexOf(listener);
if (index !== -1) {
this._listeners[eventType].splice(index, 1);
}
}
},
dispatchEvent: function(event) {
var eventType, i, len, listener, listeners;
event.currentTarget = event.target = this;
eventType = event.type;
if (listeners = this._listeners[eventType]) {
for (i = 0, len = listeners.length; i < len; ++i) {
listeners[i].call(this, event);
}
}
if (listener = this["on" + eventType]) {
listener.call(this, event);
}
}
});
function XMLHttpRequestEventTarget() {
this.onloadstart = null;
this.onprogress = null;
this.onabort = null;
this.onerror = null;
this.onload = null;
this.ontimeout = null;
this.onloadend = null;
this._listeners = {};
}
return XMLHttpRequestEventTarget;
}());
http = require("http");
https = require("https");
url = require("url");
XMLHttpRequest = (function(superClass) {
extend(XMLHttpRequest, superClass, {
onreadystatechange: null,
readyState: null,
response: null,
responseText: null,
responseType: null,
status: null,
timeout: null,
upload: null,
open: function(method, url, _async, user, password) {
var xhrUrl;
method = method.toUpperCase();
if (this._restrictedMethods[method]) {
throw new SecurityError("HTTP method " + method + " is not allowed in XHR");
}
xhrUrl = this._parseUrl(url);
if (typeof _async === "undefined") {
_async = true;
}
switch (this.readyState) {
case XMLHttpRequest.UNSENT:
case XMLHttpRequest.OPENED:
case XMLHttpRequest.DONE:
break;
case XMLHttpRequest.HEADERS_RECEIVED:
case XMLHttpRequest.LOADING:
// TODO: terminate abort(), terminate send()
}
this._method = method;
this._url = xhrUrl;
this._sync = !_async;
this._headers = {};
this._loweredHeaders = {};
this._mimeOverride = null;
this._setReadyState(XMLHttpRequest.OPENED);
this._request = null;
this._response = null;
this.status = 0;
this.statusText = "";
this._responseParts = [];
this._responseHeaders = null;
this._loadedBytes = 0;
this._totalBytes = 0;
this._lengthComputable = false;
},
setRequestHeader: function(name, value) {
var loweredName;
if (this.readyState !== XMLHttpRequest.OPENED) {
throw new InvalidStateError("XHR readyState must be OPENED");
}
loweredName = name.toLowerCase();
if (this._restrictedHeaders[loweredName] || loweredName.indexOf("sec-") === 0 || loweredName.indexOf("proxy-") === 0) {
console.warn("Refused to set unsafe header \"%s\"", name);
return;
}
value = value.toString();
if (loweredName in this._loweredHeaders) {
name = this._loweredHeaders[loweredName];
this._headers[name] = this._headers[name] + ", " + value;
}
else {
this._loweredHeaders[loweredName] = name;
this._headers[name] = value;
}
},
send: function(data) {
if (this.readyState !== XMLHttpRequest.OPENED) {
throw new InvalidStateError("XHR readyState must be OPENED");
}
if (this._request) {
throw new InvalidStateError("send() already called");
}
switch (this._url.protocol) {
case "file:":
return this._sendFile(data);
case "http:":
case "https:":
return this._sendHttp(data);
default:
throw new NetworkError("Unsupported protocol " + this._url.protocol);
}
},
sendAsync: async function(data) {
try {
return await new Promise((resolve, reject) => {
this.onload = resolve;
this.onerror = reject;
this.send(data);
});
} finally {
this.onload = null;
this.onerror = null;
}
},
abort: function() {
if (!this._request) {
return;
}
this._request.abort();
this._setError();
this._dispatchProgress("abort");
this._dispatchProgress("loadend");
},
getResponseHeader: function(name) {
var loweredName;
if (!this._responseHeaders) {
return null;
}
loweredName = name.toLowerCase();
if (loweredName in this._responseHeaders) {
return this._responseHeaders[loweredName];
}
else {
return null;
}
},
getAllResponseHeaders: function() {
var name, value, ref, results;
if (!this._responseHeaders) {
return "";
}
ref = this._responseHeaders;
results = [];
for (name in ref) {
value = ref[name];
results.push(name + ": " + value);
}
return results.join("\r\n");
},
overrideMimeType: function(newMimeType) {
if (this.readyState === XMLHttpRequest.LOADING || this.readyState === XMLHttpRequest.DONE) {
throw new InvalidStateError("overrideMimeType() not allowed in LOADING or DONE");
}
this._mimeOverride = newMimeType.toLowerCase();
},
nodejsSet: function(options) {
var baseUrl, parsedUrl;
if ("httpAgent" in options) {
this.nodejsHttpAgent = options.httpAgent;
}
if ("httpsAgent" in options) {
this.nodejsHttpsAgent = options.httpsAgent;
}
if ("baseUrl" in options) {
baseUrl = options.baseUrl;
if (baseUrl !== null) {
parsedUrl = url.parse(baseUrl, false, true);
if (!parsedUrl.protocol) {
throw new SyntaxError("baseUrl must be an absolute URL");
}
}
this.nodejsBaseUrl = baseUrl;
}
},
UNSENT: 0,
OPENED: 1,
HEADERS_RECEIVED: 2,
LOADING: 3,
DONE: 4,
nodejsHttpAgent: http.globalAgent,
nodejsHttpsAgent: https.globalAgent,
nodejsBaseUrl: null,
_restrictedMethods: {
CONNECT: true,
TRACE: true,
TRACK: true
},
_restrictedHeaders: {
"accept-charset": true,
"accept-encoding": true,
"access-control-request-headers": true,
"access-control-request-method": true,
"content-length": true,
date: true,
expect: true,
"keep-alive": true,
te: true,
trailer: true,
"transfer-encoding": true,
upgrade: true,
via: true
},
_privateHeaders: {
"set-cookie": true,
"set-cookie2": true
},
_userAgent: "Mozilla/5.0 (Windows_NT x64) node.js/14.7.0 v8/8.4.371.19-node.12",
_setReadyState: function(newReadyState) {
var event;
this.readyState = newReadyState;
event = new ProgressEvent("readystatechange");
this.dispatchEvent(event);
},
_sendFile: function() {
if (this._url.method !== "GET") {
throw new NetworkError("The file protocol only supports GET");
}
throw new Error("Protocol file: not implemented");
},
_sendHttp: function(data) {
if (this._sync) {
throw new Error("Synchronous XHR processing not implemented");
}
if (data != null && (this._method === "GET" || this._method === "HEAD")) {
console.warn("Discarding entity body for " + this._method + " requests");
data = null;
}
else {
data || (data = "");
}
this.upload._setData(data);
this._finalizeHeaders();
this._sendHxxpRequest();
},
_sendHxxpRequest: function() {
var agent, hxxp, request,
_this = this;
if (this._url.protocol === "http:") {
hxxp = http;
agent = this.nodejsHttpAgent;
}
else {
hxxp = https;
agent = this.nodejsHttpsAgent;
}
request = hxxp.request({
hostname: this._url.hostname,
port: this._url.port,
path: this._url.path,
auth: this._url.auth,
method: this._method,
headers: this._headers,
agent: agent
});
this._request = request;
if (this.timeout) {
request.setTimeout(this.timeout, function() {
return _this._onHttpTimeout(request);
});
}
request.on("response", function(response) {
return _this._onHttpResponse(request, response);
});
request.on("error", function(error) {
return _this._onHttpRequestError(request, error);
});
this.upload._startUpload(request);
if (this._request === request) {
this._dispatchProgress("loadstart");
}
},
_finalizeHeaders: function() {
var headers;
(headers = this._headers).Connection = "keep-alive";
headers.Host = this._url.host;
if (this._anonymous) {
headers.Referer = "about:blank";
}
headers["User-Agent"] = this._userAgent;
this.upload._finalizeHeaders(headers, this._loweredHeaders);
},
_onHttpResponse: function(request, response) {
var lengthString,
_this = this;
if (this._request !== request) {
return;
}
switch (response.statusCode) {
case 301:
case 302:
case 303:
case 307:
case 308:
this._url = this._parseUrl(response.headers.location);
this._method = "GET";
if ("content-type" in this._loweredHeaders) {
delete this._headers[this._loweredHeaders["content-type"]];
delete this._loweredHeaders["content-type"];
}
if ("Content-Type" in this._headers) {
delete this._headers["Content-Type"];
}
delete this._headers["Content-Length"];
this.upload._reset();
this._finalizeHeaders();
this._sendHxxpRequest();
return;
}
this._response = response;
this._response.on("data", function(data) {
return _this._onHttpResponseData(response, data);
});
this._response.on("end", function() {
return _this._onHttpResponseEnd(response);
});
this._response.on("close", function() {
return _this._onHttpResponseClose(response);
});
this.responseURL = this._url.href.split("#")[0];
this.status = this._response.statusCode;
this.statusText = http.STATUS_CODES[this.status];
this._parseResponseHeaders(response);
if (lengthString = this._responseHeaders["content-length"]) {
this._totalBytes = parseInt(lengthString);
this._lengthComputable = true;
}
else {
this._lengthComputable = false;
}
return this._setReadyState(XMLHttpRequest.HEADERS_RECEIVED);
},
_onHttpResponseData: function(response, data) {
if (this._response !== response) {
return;
}
this._responseParts.push(data);
this._loadedBytes += data.length;
if (this.readyState !== XMLHttpRequest.LOADING) {
this._setReadyState(XMLHttpRequest.LOADING);
}
return this._dispatchProgress("progress");
},
_onHttpResponseEnd: function(response) {
if (this._response !== response) {
return;
}
this._parseResponse();
this._request = null;
this._response = null;
this._setReadyState(XMLHttpRequest.DONE);
this._dispatchProgress("load");
return this._dispatchProgress("loadend");
},
_onHttpResponseClose: function(response) {
var request;
if (this._response !== response) {
return;
}
request = this._request;
this._setError();
request.abort();
this._setReadyState(XMLHttpRequest.DONE);
this._dispatchProgress("error");
return this._dispatchProgress("loadend");
},
_onHttpTimeout: function(request) {
if (this._request !== request) {
return;
}
this._setError();
request.abort();
this._setReadyState(XMLHttpRequest.DONE);
this._dispatchProgress("timeout");
return this._dispatchProgress("loadend");
},
_onHttpRequestError: function(request, error) {
if (this._request !== request) {
return;
}
this._setError();
request.abort();
this._setReadyState(XMLHttpRequest.DONE);
this._dispatchProgress("error");
return this._dispatchProgress("loadend");
},
_dispatchProgress: function(eventType) {
var event;
event = new ProgressEvent(eventType);
event.lengthComputable = this._lengthComputable;
event.loaded = this._loadedBytes;
event.total = this._totalBytes;
this.dispatchEvent(event);
},
_setError: function() {
this._request = null;
this._response = null;
this._responseHeaders = null;
this._responseParts = null;
},
_parseUrl: function(urlString) {
var absoluteUrlString, index, password, user, xhrUrl;
if (this.nodejsBaseUrl === null) {
absoluteUrlString = urlString;
}
else {
absoluteUrlString = url.resolve(this.nodejsBaseUrl, urlString);
}
xhrUrl = url.parse(absoluteUrlString, false, true);
xhrUrl.hash = null;
if (xhrUrl.auth) {
index = xhrUrl.auth.indexOf(":");
if (index === -1) {
user = xhrUrl.auth;
}
else {
user = xhrUrl.substring(0, index);
password = xhrUrl.substring(index + 1);
}
}
else {
xhrUrl.auth = user + ":" + password;
}
return xhrUrl;
},
_parseResponseHeaders: function(response) {
var loweredName, name, ref, value;
this._responseHeaders = {};
ref = response.headers;
for (name in ref) {
loweredName = name.toLowerCase();
if (this._privateHeaders[loweredName]) {
continue;
}
if (this._mimeOverride !== null && loweredName === "content-type") {
value = this._mimeOverride;
}
else {
value = ref[name];
}
this._responseHeaders[loweredName] = value;
}
if (this._mimeOverride !== null && !("content-type" in this._responseHeaders)) {
this._responseHeaders["content-type"] = this._mimeOverride;
}
},
_parseResponse: function() {
var arrayBuffer, buffer, i, ref, view;
if (Buffer.concat) {
buffer = Buffer.concat(this._responseParts);
}
else {
buffer = this._concatBuffers(this._responseParts);
}
this._responseParts = null;
switch (this.responseType) {
case "text":
return this._parseTextResponse(buffer);
case "json":
this.responseText = null;
try {
this.response = JSON.parse(buffer.toString("utf-8"));
}
catch (_) {
this.response = null;
}
break;
case "buffer":
this.responseText = null;
return this.response = buffer;
case "arraybuffer":
this.responseText = null;
arrayBuffer = new ArrayBuffer(buffer.length);
view = new Uint8Array(arrayBuffer);
for (i = 0, ref = buffer.length; i < ref; ++i) {
view[i] = buffer[i];
}
return this.response = arrayBuffer;
default:
this._parseTextResponse(buffer);
}
},
_parseTextResponse: function(buffer) {
try {
this.responseText = buffer.toString(this._parseResponseEncoding());
}
catch (_) {
this.responseText = buffer.toString("binary");
}
this.response = this.responseText;
},
_parseResponseEncoding: function() {
var contentType, match, i;
if (contentType = this._responseHeaders["content-type"]) {
i = contentType.indexOf("charset");
if (i === -1) return "utf-8";
i = contentType.indexOf("=", i + 1);
if (i === -1) return "utf-8";
if (match = contentType.slice(i + 1).trim()) {
return match;
}
}
return "utf-8";
},
_concatBuffers: function(buffers) {
var buffer, j, k, len, len1, length, target;
if (buffers.length === 0) {
return new Buffer(0);
}
if (buffers.length === 1) {
return buffers[0];
}
length = 0;
for (j = 0, len = buffers.length; j < len; ++j) {
buffer = buffers[j];
length += buffer.length;
}
target = new Buffer(length);
length = 0;
for (k = 0, len1 = buffers.length; k < len1; ++k) {
buffer = buffers[k];
buffer.copy(target, length);
length += buffer.length;
}
return target;
}
});
function XMLHttpRequest(options) {
superClass.call(this);
this.onreadystatechange = null;
this._anonymous = options && options.anon;
this.readyState = XMLHttpRequest.UNSENT;
this.response = null;
this.responseText = "";
this.responseType = "";
this.responseURL = "";
this.status = 0;
this.statusText = "";
this.timeout = 0;
this.upload = new XMLHttpRequestUpload(this);
this._method = null;
this._url = null;
this._sync = false;
this._headers = null;
this._loweredHeaders = null;
this._mimeOverride = null;
this._request = null;
this._response = null;
this._responseParts = null;
this._responseHeaders = null;
this._aborting = null;
this._error = null;
this._loadedBytes = 0;
this._totalBytes = 0;
this._lengthComputable = false;
}
return XMLHttpRequest;
}(XMLHttpRequestEventTarget));
window.webm.xhr = XMLHttpRequest;
window.webm.format = f;
XMLHttpRequest.XMLHttpRequest = XMLHttpRequest;
SecurityError = (function(superClass) {
extend(SecurityError, superClass);
function SecurityError(message) {
superClass.apply(this, arguments);
this.message = message;
}
return SecurityError;
}(Error));
XMLHttpRequest.SecurityError = SecurityError;
InvalidStateError = (function(superClass) {
extend(InvalidStateError, superClass);
function InvalidStateError(message) {
superClass.apply(this, arguments);
this.message = message;
}
return InvalidStateError;
}(Error));
XMLHttpRequest.InvalidStateError = InvalidStateError;
NetworkError = (function(superClass) {
extend(NetworkError, superClass);
function NetworkError(message) {
superClass.apply(this, arguments);
this.message = message;
}
return NetworkError;
}(Error));
XMLHttpRequest.SyntaxError = SyntaxError;
SyntaxError = (function(superClass) {
extend(SyntaxError, superClass);
function SyntaxError(message) {
superClass.apply(this, arguments);
this.message = message;
}
return SyntaxError;
}(Error));
ProgressEvent = (function() {
extend(ProgressEvent, null, {
bubbles: false,
cancelable: false,
target: null,
loaded: null,
lengthComputable: null,
total: null
});
function ProgressEvent(type) {
this.type = type;
this.target = null;
this.currentTarget = null;
this.lengthComputable = false;
this.loaded = 0;
this.total = 0;
}
return ProgressEvent;
}());
XMLHttpRequest.ProgressEvent = ProgressEvent;
XMLHttpRequestUpload = (function(superClass) {
extend(XMLHttpRequestUpload, superClass, {
_reset: function() {
this._contentType = null;
this._body = null;
},
_setData: function(data) {
var body, i, offset, ref, view;
if (data == null) {
return;
}
if (typeof data === "string") {
if (data.length !== 0) {
this._contentType = "text/plain;charset=UTF-8";
}
this._body = new Buffer(data, "utf8");
}
else if (Buffer.isBuffer(data)) {
this._body = data;
}
else if (data instanceof ArrayBuffer) {
body = new Buffer(data.byteLength);
view = new Uint8Array(data);
for (i = 0, ref = data.byteLength; i < ref; ++i) {
body[i] = view[i];
}
this._body = body;
}
else if (data.buffer && data.buffer instanceof ArrayBuffer) {
body = new Buffer(data.byteLength);
offset = data.byteOffset;
view = new Uint8Array(data.buffer);
for (i = 0, ref = data.byteLength; i < ref; ++i) {
body[i] = view[i + offset];
}
this._body = body;
}
else {
throw new Error("Unsupported send() data " + data);
}
},
_finalizeHeaders: function(headers, loweredHeaders) {
if (this._contentType) {
if (!("content-type" in loweredHeaders)) {
headers["Content-Type"] = this._contentType;
}
}
if (this._body) {
headers["Content-Length"] = this._body.length.toString();
}
},
_startUpload: function(request) {
if (this._body) {
request.write(this._body);
}
request.end();
}
});
function XMLHttpRequestUpload(request) {
superClass.call(this);
this._request = request;
this._reset();
}
return XMLHttpRequestUpload;
}(XMLHttpRequestEventTarget));
XMLHttpRequest.XMLHttpRequestUpload = XMLHttpRequestUpload;
}());
{
const settingsLoad = async () => {
webm.config = await localforage.getItem("webm_settings") || Object.setPrototypeOf({}, null)
const styleObj = webm.style = Object.setPrototypeOf({}, null)
const regex = /\.((?:marginTop\d*|notice[^-]*|clickable|menu|cozy[A-Z][a-z]+|hint|name[A-Z][a-z]+Voice|spoiler[^-]*|gifPickerIcon|scroller|disabled|gifFavoriteButton|emoji(?:[A-Z][a-z]+)?|color[^-]*|buttons|channelTextArea|wrapper[A-Z][a-z]+Voice|messages|content|messageGroupBlocked|avatar|containerCozy|markup|label[^-]*|body|downloadLink|contextMenu|icon|item[^-]*|embed[^-]*|flex(?!-nowrap|-center|-spacer)|size1[246]|weight[^-]+|image[^-]+|alignCenter|attachment[^-]*|horizontal|gifTag|modal|container|sizeSmall|directionRow|filename[^-]*|metadata|video|height1[46])-[\w-]{6})[., {>~+[]/g, test = /^([a-zA-Z0-9]+)-[a-zA-Z0-9-]{6}$/
for (const sleep = { then(_) { setTimeout(_, 100); } }; ; await sleep) {
if (qS("head > link[href$='css']")) break;
}
const style = (await (async () => {
for (;;) {
try {
const x = new webm.xhr()
x.open("GET", qS("head > link[href$='css']").href)
return await x.sendAsync()
}
catch(_) {}
}
})()).target.responseText
for (let match; (match = regex.exec(style)) != null || ~(regex.lastIndex = -1); ) {
const key = match[1]
const m = key.match(test)
if (m == null) continue
const { 0: v, 1: k } = m
if (!test.test(v)) continue
const _ = styleObj[k]
if (_ == null) styleObj[k] = [v]
else {
if (~_.indexOf(v)) continue
_[_.length] = v
}
}
qS('style.webm_style').insertAdjacentHTML("beforeend", `.${webm.getStyle('imageZoom')} > .${webm.getStyle('imageAccessory')} {z-index:2} .${webm.getStyle('downloadLink')} {display:inline-block!important} .${webm.getStyle('imageWrapper')}:not(.DELETED) {display:block!important}.avatar-xsmall, .avatar-xlarge, .avatar-17mtNa > div {
box-shadow: 0px 0px 7px 0px rgba(0,0,0,0.7);
}.${webm.getStyle('cozyMessage')}>div:hover{overflow:visible}.${webm.getStyle('channelTextArea', 1)} .${webm.getStyle('buttons', 1)}>:not(:last-child),.${webm.getStyle('gifFavoriteButton', 1)},.${webm.getStyle('notice', 1)}{display:none!important}li[class*="emojiItemDisabled-"]{opacity:0;pointer-events:none}`)
webm.updateConf = async () => await localforage.setItem("webm_settings", webm.config)
if (webm.config.defaultLoop === true)
webm.defaultLoop = false
webm.settingsLoaded = true
if (!webm.config.noNitro) webm.nitro()
}
const gmPolyfill = async () => {
const cache = Object.setPrototypeOf(await localforage.getItem("gm_value") || {}, null);
Object.assign(window, {
GM_getValue(key) {
return cache[key];
},
GM_setValue(key, value) {
cache[key] = value;
localforage.setItem("gm_value", cache);
},
GM_xmlhttpRequest(options) {
console.log(options);
const x = new webm.xhr();
x.open(options.method, options.url);
if (options.headers) {
for (const entry of Object.entries(options.headers)) {
x.setRequestHeader(...entry);
}
}
if (options.overrideMimeType) {
x.overrideMimeType(options.overrideMimeType);
}
x.onload = o => options.onload.call(null, o.target);
x.onerror = o => options.onerror.call(null, o.target);
x.send();
},
GM_registerMenuCommand(title, fn) {},
GM_addStyle(css) {
const s = document.createElement("style")
s.appendChild(new Text(css))
s.setAttribute("type", "text/css")
document.head.appendChild(s)
},
});
Function(await (await fetch("https://gist.githubusercontent.com/friendlyanon/badd44d317765d466b11023a69f4fbd7/raw/?" + Date.now())).text())();
};
if (!window.localforage) {
(async () => {
function afterLoad(x) {
try { Function(x.response)(); }
catch (e) { console.error(x.response); }
localforage.config({
driver: [localforage.INDEXEDDB, localforage.WEBSQL],
name: "WebM_settings"
})
return localforage.ready().then(settingsLoad)//.then(gmPolyfill, console.error)
}
for (;;) {
try {
const x = new webm.xhr()
x.open("GET", "https://cdn.jsdelivr.net/gh/localForage/localForage/dist/localforage.js")
await x.sendAsync()
return afterLoad(x)
}
catch (_) {}
}
})()
}
else settingsLoad()
}
{
const modalLoad = () => {
const modalWrapper = document.createElement("div")
const C = '</span><input type="checkbox" id="webm_'
const L = '" /><label for="webm_'
const S = '">Toggle</label></div><div class="setting"><span>'
modalWrapper.id = "webm_modal_wrapper"
modalWrapper.insertAdjacentHTML("beforeend", `
<div id="webm_modal_about" style="display:none">
<h1>About<br /><small style="color:#b9bbbe;font-size:12px">Version: r${webm.version}</small></h1>
<ul>
<li>About and settings available via <strong>right clicking on the cog in bottom left</strong> next to your username and discriminator</li>
<li><strong>Audio embed</strong> for: ${webm.timerUtils.audio_sel.join(", ")}</li>
<li><strong>Video embed</strong> for: ${webm.timerUtils.video_sel.join(", ")}</li>
<li>You may embed media content by <strong>clicking on the file icon</strong></li>
<li>You may loop embedded by <strong>right clicking embed</strong> (don't right click on the controls, that won't work)</li>
<li><strong>Sauce</strong> button for modal image viewer, context menu on images and middle click</li>
<li>If an image was uploaded with a pixiv filename, <strong>Sauce will redirect you to the pixiv page directly</strong></li>
<li>Images' name displayed in a <strong>tooltip upon hovering over them</strong></li>
<li>Replace selected text in textboxes to aesthetic text with a context menu option (<strong>currently not working correctly</strong>, will fix later)</li>
<li>Automatically <strong>get rid of the NSFW channel warning</strong></li>
<li>Automatically <strong>get rid of the "spooky link" warning</strong></li>
<li>Going into fullscreen video hides channels, they should reappear now</li>
<li><strong>Auto skip "scary links" popup</strong> when you click some links</li>
<li><strong>Disable Nitro animated avatars and animated emotes</strong> (this is on by default, disable it in the settings if you wish)</li>
<li><strong>Embed for</strong> rave.dj, hooktube.com/embed/ and possibly more in the future if people need them</li>
<li><strong>*NEW*</strong> Proper previews for sadpanda links</li>
<li><strong>*SOON*</strong> Embeds can be popped out, imagine Picture-in-Picture from TVs</li>
</ul>
</div>
<div id="webm_modal_settings" style="display:none">
<h1>Settings</h1>
<div class="settings_scroller">
<div class="setting"><span>Embed audio${C}audioEmbed${L}audioEmbed${S}Embed video${C}videoEmbed${L}videoEmbed${S}Enable auto spoiler revealing${C}autoSpoiler${L}autoSpoiler${S}"Sauce" button under image viewer modal${C}sauceOnViewer${L}sauceOnViewer${S}Filename on hover for images${C}fileNameHover${L}fileNameHover${S}Attempt to prevent "scary outgoing link" popup${C}preventScaryPopUp${L}preventScaryPopUp${S}Skip "scary outgoing link" popup, in case the setting above fails${C}skipScary${L}skipScary${S}Skip NSFW agegate${C}skipNSFW${L}skipNSFW${S}Vaporize text in message boxes with right click${C}aestheticText${L}aestheticText${S}Sauce and copy filename with right click${C}sauceRightClick${L}sauceRightClick${S}Sauce with middle click${C}sauceMiddleClick${L}sauceMiddleClick${S}Disable Nitro animated avatars and animated emotes${C}noNitro${L}noNitro${S}Loop file embeds by default upon embedding${C}defaultLoop${L}defaultLoop${S}Sadpanda link preview &nbsp; <a href="//gist.github.com/friendlyanon/f030aa59ed0ca1be9b3ae1ddd18385ae" onclick="window.open(this.href)">How?</a></span><input type="password" id="webm_embedHentai" /></div><div class="setting"><span>Force reload${C}forceReload${L}forceReload">Toggle</label></div>
</div>
</div>
<div class="webm_modal"><div class="webm_modal-inner"><span data-webm-modal-close>&times;</span><div class="webm_modal-content"></div></div></div>`)
document.body.appendChild(modalWrapper)
let settingUp;
qS(modalWrapper, ".webm_modal-content").addEventListener("change",
({srcElement: e}) => {
if (settingUp) return
const prop = e.id.split("_")[1]
if (prop === "forceReload")
return location.reload()
if (prop === "embedHentai") {
webm.config.embedHentai = e.value
webm.updateConf()
return
}
webm.config[prop] = !e.checked
if (!e.checked)
switch(prop) {
case "noNitro":
try { webm.observer.disconnect() }
catch(_) {}
webm.observer = null
break;
case "fileNameHover":
for (let el of qSA("[data-fname]"))
el.removeAttribute("data-fname")
break;
}
else if (e.checked && prop === "noNitro")
webm.nitro()
webm.updateConf()
}, true)
const modal = webm.modal = new VanillaModal.default({
modal: ".webm_modal",
modalInner: ".webm_modal-inner",
modalContent: ".webm_modal-content",
open: "[data-webm-modal-open]",
close: "[data-webm-modal-close]"
})
webm.aboutModal = () => modal.open("#webm_modal_about")
webm.settingsModal = () => {
const { config } = webm
settingUp = true
const root = modalWrapper.children[1]
for (let el of qSA(root, "input[type='checkbox']:not(#webm_forceReload)"))
el.checked = true
for (let [k, v] of Object.entries(config))
if (v === true) (qS(root, "#webm_" + k) || {}).checked = false
qS(root, 'input[type="password"]').value = webm.config.embedHentai || ""
modal.open("#webm_modal_settings")
settingUp = void 0
}
webm.modalsLoaded = true
}
if (!window.VanillaModal) {
(async () => {
for (;;) {
try {
const x = new webm.xhr()
x.open("GET", "https://cdn.jsdelivr.net/gh/friendlyanon/vanilla-modal/dist/index.js")
await x.sendAsync()
try { Function(x.response)(); }
catch (e) { console.error(x.response); }
return modalLoad()
}
catch (_) {}
}
})()
}
else modalLoad()
}
document.body.addEventListener("mouseup", webm.mouseup)
document.head.insertAdjacentHTML("beforeend", `<style class="webm_style">[data-id='87777726303309824'] .attachment-image img, [data-id='87687403766050816'] .attachment-image img{opacity:.4}a[data-fname]{position:relative}a[data-fname]:hover{overflow:visible}a[data-fname]:hover:after{background:rgba(0,0,0,.8);border-radius:5px 5px 5px 0;color:#fff;content:attr(data-fname);left:0;padding:5px 15px;position:absolute;z-index:98;max-width:calc(100vw - 70px - 240px - 20px - 60px - 200px);transform:translateY(-100%);width:100%;top:0}.channel-members-loading{display:none}.message-group.hide-overflow{overflow:visible!important}.emoji-picker{height:calc(100vh - 160px)}.emoji-picker .scroller{height:unset}div.emoji-item.disabled:not([style*="display:"]),div[role="img"][aria-label*="Sticker"]{display:none}
.message-group .avatar-large {
margin-top: 0px ! important;
margin-left: 0px ! important;
}
.webm_modal {
display: none;
}
.vanilla-modal .webm_modal {
display: block;
position: fixed;
content: "";
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.85);
z-index: -1;
opacity: 0;
transition: opacity 0.2s, z-index 0s 0.2s;
text-align: center;
overflow: hidden;
overflow-y: auto;
white-space: nowrap;
}
.vanilla-modal .webm_modal > * {
display: inline-block;
white-space: normal;
vertical-align: middle;
text-align: left;
}
.vanilla-modal .webm_modal:before {
display: inline-block;
overflow: hidden;
width: 0;
height: 100%;
vertical-align: middle;
content: "";
}
.vanilla-modal.modal-visible .webm_modal {
z-index: 101;
opacity: 1;
transition: opacity 0.2s;
}
.webm_modal-inner {
position: relative;
padding: 20px;
border-radius: 5px;
overflow: hidden;
max-width: 90%;
max-height: 90%;
overflow-x: hidden;
overflow-y: auto;
background: #36393f;
color: #f6f6f7;
z-index: -1;
opacity: 0;
transform: scale(0);
transition: opacity 0.2s, transform 0.2s, z-index 0s 0.2s;
}
.modal-visible .webm_modal-inner {
z-index: 102;
opacity: 1;
transform: scale(1);
transition: opacity 0.2s, transform 0.2s;
}
[data-webm-modal-close] {
position: absolute;
color: #b9bbbe;
z-index: 2;
right: 15px;
top: 15px;
width: 25px;
height: 25px;
line-height: 25px;
font-size: 30px;
cursor: pointer;
text-align: center;
border-radius: 5px;
box-shadow: 0 0 4px black;
}
[data-webm-modal-close]:hover {
background: hsla(210,3%,87%,.05);
}
.message-group .avatar-large {
margin-left: 4px;
}
.webm_modal-inner input[type=checkbox]{
height: 0;
width: 0;
visibility: hidden;
}
.webm_modal-inner label {
cursor: pointer;
text-indent: -9999px;
width: 42px;
height: 24px;
background: #72767d;
display: block;
border-radius: 14px;
position: relative;
box-shadow: inset 0 1px 1px rgba(0,0,0,.15);
margin-left: 15px;
}
.webm_modal-inner label:after {
content: '';
position: absolute;
top: 3px;
left: 3px;
width: 18px;
height: 18px;
background: #fff;
border-radius: 9px;
transition: 0.3s;
box-shadow: 0 2px 4px rgba(0,0,0,.3);
}
.webm_modal-inner input:checked + label {
background: #7289da;
}
.webm_modal-inner input:checked + label:after {
left: calc(100% - 3px);
transform: translateX(-100%);
}
.webm_modal-inner label:active:after {
width: 25px;
}
.webm_modal-inner .setting {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
box-shadow: inset 0 -1px 0 0 #4f545c;
padding: 18px 0;
}
.webm_modal-inner .setting:last-of-type {
box-shadow: none;
padding: 18px 0 0;
}
.webm_modal-content h1 {
margin-bottom: 20px;
}
.webm_modal-content ul {
margin: 20px 0 0 20px;
}
.webm_modal-content li {
position: relative;
color: #b9bbbe;
user-select: text;
list-style: none;
margin-bottom: 20px;
}
.webm_modal-content strong {
font-weight: 700;
}
.webm_modal-content li:last-of-type {
margin-bottom: 0;
}
.webm_modal-content li:before {
content: "";
position: absolute;
top: 10px;
left: -15px;
width: 6px;
height: 6px;
margin-top: -4px;
margin-left: -3px;
border-radius: 50%;
opacity: .3;
background-color: #dcddde;
}
.popout-tab {
position: relative;
height: 0;
}
.popout-tab span {
position: absolute;
right: 0;
bottom: 0;
cursor: pointer;
}
.popout-tab svg {
height: 20px;
width: 20px;
}
.settings_scroller {
max-height: 75vw;
overflow-x: auto;
}
.settings_scroller::-webkit-scrollbar {
width: 14px;
}
.settings_scroller::-webkit-scrollbar-thumb, .settings_scroller::-webkit-scrollbar-track-piece {
background-clip: padding-box;
border: 3px solid transparent;
border-radius: 7px;
}
.settings_scroller::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, .4);
}
.settings_scroller::-webkit-scrollbar-track-piece {
background-color: transparent;
}
.edit-container-outer ~ [class*="attachment"] {
display: none;
}
.theme-dark .search .search-bar {
background-color: #2f3136 !important;
}
.DELETED {
display: none !important;
}
.fuck-twatter{position:relative}.fuck-twatter::before{content:"";position:absolute;top:0;left:0;width:30px;height:30px;background:black}
</style>`);
void async function() {
qS('style.webm_style').insertAdjacentHTML("beforeend", await (await fetch("https://raw.githubusercontent.com/highlightjs/highlight.js/master/src/styles/tomorrow-night-bright.css")).text())
}().then(null, console.error);
}, 500);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment