2024-03-01 21:01:22 +01:00
|
|
|
//@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);
|
|
|
|
|
2024-05-13 21:24:03 +02:00
|
|
|
await JadefinUtils.waitUntil(() => JadefinModules.actionSheet);
|
|
|
|
|
2024-03-01 21:01:22 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})());
|