NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Audio Widget Player // @version 1 // @grant none // @include https://*.fandom.com/* // @require https://unpkg.com/preact // @require https://unpkg.com/htm // @copyright 2022, ptrharmonic (https://openuserjs.org/users/ptrharmonic) // @license MIT // @updateURL https://openuserjs.org/meta/ptrharmonic/Audio_Widget_Player.meta.js // @downloadURL https://openuserjs.org/install/ptrharmonic/Audio_Widget_Player.user.js // ==/UserScript== const { h, Component, render } = preact; // const { htm } = htm; console.log(htm, htm.preact); const html = htm.bind(h); config = { "fandom.com": { "mount": ".main-container" } } class Controls extends Component { state = { "playing": false, "elems": [], "index": 0 } constructor(props) { super(props); this.playButton = this.playButton.bind(this); this.scan = this.scan.bind(this); this.playbackEnded = this.playbackEnded.bind(this); this.play = this.play.bind(this); this.pause = this.pause.bind(this); } componentDidMount() { this.scan(); } componentDidUpdate(prevProps, prevState) { if (prevState.index !== this.state.index && this.state.playing) { this.play(); } } currentElem() { return this.state.elems[this.state.index]; } play() { let elem = this.currentElem(); elem.play(); elem.onended = this.playbackEnded; this.setState({"playing": true}); } pause() { this.currentElem().pause(); this.setState({"playing": false}); } playButton() { if (!this.state.playing) { this.play(); } else { this.pause(); } } playbackEnded() { this.setState({"index": this.state.index + 1}); } scan() { let audioElems = document.querySelectorAll("audio"); console.log(audioElems); this.setState({"elems": audioElems}); } seek(value) { this.currentElem().pause(); this.setState({"index": this.state.index + value}); } render(props, state) { return html` <div style="position: sticky;"> <button onClick=${this.playButton}>${(state.playing ? "Pause" : "Play")}</button> <button onClick=${this.scan}>Scan</button> <p>Found ${state.elems.length} audio elems</p> <button onClick=${() => this.seek(-1)}>Prev</button> <button onClick=${() => this.seek(1)}>Next</button> <span>${state.index}</span> </div> `; } } let parts = window.location.host.split("."); let mountParent = document.body; for (let i=0;i<parts.length;i++) { let url = parts.join("."); console.log(url); if (url in config) { console.log("hiya"); mountParent = document.querySelector(config[url].mount); } parts.splice(0, 1); } const elemMount = document.createElement("div"); elemMount.style.cssText = "position: fixed; min-width:5rem; min-height: 5rem; background-color: white; top:0; right:0; z-index:1000"; mountParent.insertAdjacentElement("beforeend", elemMount); const app = html`<${Controls}/>` render(app, elemMount);