|
// ==UserScript== |
|
// @name Low Hanging Fruit: the Soundgasm Gaylewdst Userscript (autoplay) |
|
// @namespace rip.aapo.userscript |
|
// @version 0.0.2 |
|
// @description sometimes you need more than one 🤔 (it hacks a simple playist into Soundgasm) |
|
// @author @shinmai - shinmai.wtf |
|
// @match https://soundgasm.net/u/*/* |
|
// @updateURL https://gist.github.com/shinmai/487d2de059d8b4ae0b90cfab21e0d75e/raw/LHF-autoplay.user.js |
|
// @downloadURL https://gist.github.com/shinmai/487d2de059d8b4ae0b90cfab21e0d75e/raw/LHF-autoplay.user.js |
|
// @grant none |
|
// ==/UserScript== |
|
|
|
/** |
|
* Changelog: |
|
* 0.0.1 (240108) - initial version |
|
* 0.0.2 (240108) - added data parsing error handling so script doesn't die if malformed playlist is imported |
|
*/ |
|
|
|
(function() { |
|
'use strict'; |
|
|
|
// EDIT HERE FOR NO-INTERACTION AUTOPLAY OF NEXT PLAYLIST ITEM |
|
// *IF* you've updated your browsers autoplay settings to whitelist soundgasm.net, you can change the below to true to automagically play audios in the playlist |
|
// NOTE: Enabling the below WITHOUT updating the autoplay whitelist will remove the "easy" playback prompt from pages WITHOUT autoplaying audio. |
|
const AUTOPLAY_AUDIO = true |
|
|
|
// DON'T LOOK BEYOND HERE, I'M BAD AT COMPUTER-TOUCHING AND EMBARRAS EASILY |
|
|
|
class Entry { constructor(url, text) { this.uuid = crypto.randomUUID(); this.url = url; this.text = text } } |
|
class Playlist { constructor() { this.entries = []; this.current = null; } add(entry){this.entries.push(entry)} find(uuid){ return this.entries.find(e=>e.uuid == uuid)} } |
|
|
|
const sg_audio = document.getElementById("jp_audio_0"), |
|
sg_ns = sg_audio.parentElement, |
|
pl_ui = document.createElement("pre"), |
|
overlay = document.createElement('div'), |
|
elementUUID = e => { return e.parentElement.dataset.playlistID }, |
|
play = a => { localStorage.setItem("rausp_cursor", a.uuid); window.location = a.url.pathname+"#sgplplay" }, |
|
getPLData = () => { |
|
var pl = localStorage.getItem("rausp_pl") |
|
try { |
|
if(pl == null) pl = [] |
|
else pl = JSON.parse(pl) |
|
} catch (err) { pl=[] } |
|
return pl |
|
}, |
|
nextAudio = e => { |
|
var pl = getPLData() |
|
var cursor = localStorage.getItem("rausp_cursor") |
|
const cur = pl.find(e=>e.uuid == cursor) |
|
const next = pl[pl.indexOf(cur)+1] |
|
if(next) play(next) |
|
else if(window.location.hash) if(window.location.hash.substring(1)=="sgplplay") window.location.hash="" |
|
}, |
|
add_btn_handler = e => { |
|
var pl = getPLData() |
|
const titleText = document.querySelector('[aria-label="title"],.jp-title').innerText |
|
const username = document.location.pathname.split("/")[2] |
|
const entry = new Entry(document.location, username + " - " + titleText); |
|
pl.push(entry) |
|
localStorage.setItem("rausp_pl", JSON.stringify(pl)) |
|
renderPlaylist() |
|
e.preventDefault(); return false; |
|
}, |
|
clr_btn_handler = e => { localStorage.setItem("rausp_pl", JSON.stringify([])); renderPlaylist(); e.preventDefault(); return false; }, |
|
exp_btn_handler = e => { |
|
(async () => { |
|
try { |
|
await navigator.clipboard.writeText(localStorage.getItem("rausp_pl")) |
|
} catch (err) { console.error('Failed to copy: ', err) } |
|
})() |
|
e.preventDefault(); return false |
|
}, |
|
imp_btn_handler = e => { |
|
localStorage.setItem("rausp_pl", prompt("Paste playlist JSON here:")) |
|
e.preventDefault(); return false |
|
}, |
|
ply_btn_handler = e => { |
|
var pl = getPLData() |
|
const uuid = elementUUID(e.target) |
|
const next = pl.find(e=>e.uuid == uuid) |
|
if(next) play(next) |
|
e.preventDefault(); return false; |
|
}, |
|
del_btn_handler = e => { |
|
var pl = getPLData() |
|
const uuid = elementUUID(e.target) |
|
const next = pl.find(e=>e.uuid == uuid) |
|
if(next) { |
|
pl.splice(pl.indexOf(next), 1) |
|
} |
|
localStorage.setItem("rausp_pl", JSON.stringify(pl)) |
|
renderPlaylist() |
|
e.preventDefault(); return false; |
|
}, |
|
renderPlaylistItem = (pl_ui, text, plid, current=false) => { |
|
const line = document.createElement(current?"b":"span") |
|
line.appendChild(document.createTextNode("[")) |
|
if(!current) { |
|
const icon = document.createElement("a") |
|
icon.innerText = ">" |
|
icon.href="#" |
|
icon.addEventListener("click", ply_btn_handler) |
|
line.appendChild(icon) |
|
} else { |
|
line.appendChild(document.createTextNode("*")) |
|
} |
|
line.appendChild(document.createTextNode("] " + text)) |
|
const del = document.createElement("a") |
|
del.innerText = "(X)" |
|
del.href="#" |
|
del.addEventListener("click", del_btn_handler) |
|
line.appendChild(del) |
|
line.appendChild(document.createTextNode("\n")) |
|
line.dataset.playlistID = plid |
|
pl_ui.appendChild(line) |
|
}, |
|
renderPlaylist = () => { |
|
var pl = getPLData() |
|
var cursor = localStorage.getItem("rausp_cursor") |
|
pl_ui.innerHTML="<b>Playlist:</b>\n" |
|
|
|
for (let audio of pl) { |
|
renderPlaylistItem(pl_ui, audio.text, audio.uuid, audio.uuid == cursor) |
|
} |
|
|
|
pl_ui.appendChild(document.createElement('hr')) |
|
const controls = document.createElement('span') |
|
controls.innerHTML = "<a href='#' id='add_btn'>[+] Add current audio to playlist</a> | <a href='#' id='clr_btn'>[X] Clear playlist</a> \n<a href='#' id='exp_btn'>[S] Export playlist</a> | <a href='#' id='imp_btn'>[L] Import playlist</a>" |
|
pl_ui.appendChild(controls) |
|
document.getElementById("add_btn").addEventListener("click", add_btn_handler); |
|
document.getElementById("clr_btn").addEventListener("click", clr_btn_handler); |
|
document.getElementById("exp_btn").addEventListener("click", exp_btn_handler); |
|
document.getElementById("imp_btn").addEventListener("click", imp_btn_handler); |
|
} |
|
|
|
const ol_style=document.createElement('style') |
|
ol_style.innerHTML=".autoplay_overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;color:#FFF;font-size:24px}a:visited{color:blue!important;}" |
|
document.head.appendChild(ol_style) |
|
document.body.insertBefore(pl_ui, sg_ns) |
|
|
|
renderPlaylist() |
|
|
|
sg_audio.addEventListener('ended',nextAudio,{once: true}) |
|
|
|
if(window.location.hash) |
|
if(window.location.hash.substring(1)=="sgplplay") |
|
if(AUTOPLAY_AUDIO) { |
|
setTimeout(e=>sg_audio.play(),250) |
|
} else { |
|
overlay.innerHTML = '<div>Click to play audio.<br /><small style="font-size:0.5em">Enable audio autoplay for soundgasm.net and change playback setting in userscript to disable this.</small></div>' |
|
overlay.className = "autoplay_overlay" |
|
document.body.appendChild(overlay) |
|
document.addEventListener("click", function(){document.getElementsByClassName("jp-play")[0].click();overlay.style.display="none"}, {once: true}) |
|
} |
|
|
|
window.addEventListener('focus', e => { renderPlaylist() }) |
|
})(); |