jadefin/mods/VolumeBoost.js
2024-03-01 21:01:22 +01:00

199 lines
6.8 KiB
JavaScript

//@ts-check
import JadefinIntegrity from '../JadefinIntegrity.js';
import JadefinMod from "../JadefinMod.js";
import JadefinModules from "../JadefinModules.js";
import JadefinUtils from "../JadefinUtils.js";
export default JadefinIntegrity("VolumeBoost", import.meta.url, () => new (class VolumeBoost extends JadefinMod {
audioCtx = new AudioContext();
audioBypass = this.audioCtx.createGain();
audioGain = this.audioCtx.createGain();
audioComp = this.audioCtx.createDynamicsCompressor();
audioCompGain = this.audioCtx.createGain();
_currentGain = 1;
constructor() {
super();
this.audioBypass.gain.value = 1;
this.audioGain.gain.value = 0;
this.audioComp.knee.value = 40;
this.audioComp.ratio.value = 12;
this.audioComp.attack.value = 0;
this.audioComp.release.value = 0.25;
this.audioCompGain.gain.value = 0;
this.audioBypass.connect(this.audioCtx.destination);
this.audioGain.connect(this.audioComp).connect(this.audioCompGain).connect(this.audioCtx.destination);
document.addEventListener("click", e => this.audioCtxResume(), true);
}
get currentGain() {
return this._currentGain;
}
set currentGain(value) {
this.log.i(`Changing gain to ${value}`);
const diff = Math.abs(this._currentGain - value);
const timeNow = this.audioCtx.currentTime;
const time = this.audioCtx.currentTime + Math.min(0.5 * diff, 2);
if (diff != 0) {
this.audioBypass.gain.setValueAtTime(this.audioBypass.gain.value, timeNow);
this.audioGain.gain.setValueAtTime(this.audioGain.gain.value, timeNow);
this.audioCompGain.gain.setValueAtTime(this.audioCompGain.gain.value, timeNow);
this.audioBypass.gain.linearRampToValueAtTime((value <= 1) ? value : 0, time);
this.audioGain.gain.linearRampToValueAtTime((value <= 1) ? 0 : value, time);
this.audioCompGain.gain.linearRampToValueAtTime((value <= 1) ? 0 : 1, time);
}
this._currentGain = value;
this.connect();
}
async init(name, url) {
await super.init(name, url);
this.initHookActionSheetShow();
document.addEventListener("viewshow", () => {
if (JadefinUtils.routePathIsVideo) {
this.log.i("Navigating to video");
this.audioCtxResume();
if (this._connectRepeat) {
clearInterval(this._connectRepeat);
}
clearInterval(this._connectRepeat);
this._connectRepeat = setInterval(() => this.connect(), 100);
}
});
this.log.i("Ready");
}
initHookActionSheetShow() {
const orig = this._actionSheetShowOrig = JadefinModules.actionSheet.show.bind(JadefinModules.actionSheet);
JadefinModules.actionSheet.show = (options) => {
const optionsOrig = Object.assign({}, options, {
items: options.items.slice()
});
this.log.v("actionSheet.show(...)");
this.log.dir(options);
// Options menu during playback
if (options.items.length >= 6 &&
options.items[0].id == "aspectratio" &&
options.items[1].id == "playbackrate" &&
options.items[2].id == "quality" &&
options.items[3].id == "repeatmode" &&
options.items[4].id == "suboffset" &&
options.items[5].id == "stats" &&
true
) {
options.items.splice(4, 0, {id: "custom-volumeboost", name: "Volume Boost", asideText: `${this.currentGain}x`});
return new Promise((resolve, reject) => {
JadefinModules.actionSheet.show({
positionTo: options.positionTo,
items: [
{id: "all", name: "Advanced..."},
{divider: true},
...options.items.slice(4),
]
}).then(id => {
if (id == "all") {
orig(Object.assign({}, options, {
items: [
...options.items.slice(0, 4),
{divider: true},
{id: "back", name: "Back..."},
]
})).then(id => {
if (id == "back") {
JadefinModules.actionSheet.show(optionsOrig).then(resolve).catch(reject);
} else {
resolve(id);
}
}).catch(reject);
return;
}
if (id == "custom-volumeboost") {
reject();
JadefinModules.actionSheet.show({
positionTo: options.positionTo,
items: [
{id: "1", name: "1x", selected: this.currentGain == 1},
{id: "2", name: "2x", selected: this.currentGain == 2},
{id: "3", name: "3x", selected: this.currentGain == 3},
{id: "4", name: "4x", selected: this.currentGain == 4},
]
}).then(id => {
if (!id) {
return;
}
this.currentGain = parseInt(id);
});
return;
}
resolve(id);
}).catch(reject);
});
}
return orig(options);
};
}
connect() {
const video = JadefinUtils.video;
if (!video) {
return;
}
const last = this.video;
const lastSrc = this.videoSrc;
if (video != last) {
lastSrc?.disconnect();
this.videoSrc = null;
}
this.video = video;
if (!this.videoSrc) {
this.log.i("Connected to video element");
this.log.dir(this.video);
this.videoSrc = this.audioCtx.createMediaElementSource(this.video);
this.videoSrc.connect(this.audioBypass);
this.videoSrc.connect(this.audioGain);
}
if (this._connectRepeat) {
clearInterval(this._connectRepeat);
}
}
audioCtxResume() {
if (this.audioCtx.state === "suspended") {
this.audioCtx.resume();
}
}
})());