Last active
January 20, 2021 18:34
-
-
Save friendlyanon/efb1023a0ffd1308a740951cb09057f8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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 <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>×</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