feat: migration to TypeScript FINAL

Co-authored-by: Su-Yong <simssy2205@gmail.com>
This commit is contained in:
JellyBrick
2023-09-04 02:27:53 +09:00
parent c0d7972da3
commit 53f5bda382
72 changed files with 1290 additions and 693 deletions

View File

@ -1,7 +0,0 @@
const path = require('node:path');
const { injectCSS } = require('../utils');
module.exports = (win) => {
injectCSS(win.webContents, path.join(__dirname, 'empty-player.css'));
};

View File

@ -0,0 +1,9 @@
import path from 'node:path';
import { BrowserWindow } from 'electron';
import { injectCSS } from '../utils';
export default (win: BrowserWindow) => {
injectCSS(win.webContents, path.join(__dirname, 'empty-player.css'));
};

View File

@ -1,19 +1,28 @@
const defaultConfig = require('../../config/defaults');
import { Visualizer } from './visualizers/visualizer';
module.exports = (options) => {
import vudio from './visualizers/vudio';
import wave from './visualizers/wave';
import type { ConfigType } from '../../config/dynamic';
import defaultConfig from '../../config/defaults';
export default (options: ConfigType<'visualizer'>) => {
const optionsWithDefaults = {
...defaultConfig.plugins.visualizer,
...options,
};
const VisualizerType = require(`./visualizers/${optionsWithDefaults.type}`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let visualizerType: { new(...args: any[]): Visualizer<unknown> } = vudio;
if (optionsWithDefaults.type === 'wave') visualizerType = wave;
document.addEventListener(
'audioCanPlay',
(e) => {
const video = document.querySelector('video');
const visualizerContainer = document.querySelector('#player');
const video = document.querySelector('video') as (HTMLVideoElement & { captureStream(): MediaStream; });
const visualizerContainer = document.querySelector('#player') as HTMLElement;
let canvas = document.querySelector('#visualizer');
let canvas = document.querySelector('#visualizer') as HTMLCanvasElement;
if (!canvas) {
canvas = document.createElement('canvas');
canvas.id = 'visualizer';
@ -33,17 +42,17 @@ module.exports = (options) => {
gainNode.gain.value = 1.25;
e.detail.audioSource.connect(gainNode);
const visualizer = new VisualizerType(
const visualizer = new visualizerType(
e.detail.audioContext,
e.detail.audioSource,
visualizerContainer,
canvas,
gainNode,
video.captureStream(),
optionsWithDefaults[optionsWithDefaults.type],
optionsWithDefaults,
);
const resizeVisualizer = (width, height) => {
const resizeVisualizer = (width: number, height: number) => {
resizeCanvas();
visualizer.resize(width, height);
};

View File

@ -1,13 +1,19 @@
const { readdirSync } = require('node:fs');
const path = require('node:path');
import { readdirSync } from 'node:fs';
import path from 'node:path';
const { setMenuOptions } = require('../../config/plugins');
import { BrowserWindow } from 'electron';
import { setMenuOptions } from '../../config/plugins';
import { MenuTemplate } from '../../menu';
import type { ConfigType } from '../../config/dynamic';
const visualizerTypes = readdirSync(path.join(__dirname, 'visualizers')).map(
(filename) => path.parse(filename).name,
);
module.exports = (win, options) => [
export default (win: BrowserWindow, options: ConfigType<'visualizer'>): MenuTemplate => [
{
label: 'Type',
submenu: visualizerTypes.map((visualizerType) => ({

View File

@ -1,47 +0,0 @@
const butterchurn = require('butterchurn');
const butterchurnPresets = require('butterchurn-presets');
const presets = butterchurnPresets.getPresets();
class ButterchurnVisualizer {
constructor(
audioContext,
audioSource,
visualizerContainer,
canvas,
audioNode,
stream,
options,
) {
this.visualizer = butterchurn.default.createVisualizer(
audioContext,
canvas,
{
width: canvas.width,
height: canvas.height,
},
);
const preset = presets[options.preset];
this.visualizer.loadPreset(preset, options.blendTimeInSeconds);
this.visualizer.connectAudio(audioNode);
this.renderingFrequencyInMs = options.renderingFrequencyInMs;
}
resize(width, height) {
this.visualizer.setRendererSize(width, height);
}
render() {
const renderVisualizer = () => {
requestAnimationFrame(() => renderVisualizer());
this.visualizer.render();
};
setTimeout(renderVisualizer(), this.renderingFrequencyInMs);
}
}
module.exports = ButterchurnVisualizer;

View File

@ -0,0 +1,18 @@
import type { ConfigType } from '../../../config/dynamic';
export abstract class Visualizer<T> {
abstract visualizer: T;
protected constructor(
audioContext: AudioContext,
audioSource: MediaElementAudioSourceNode,
visualizerContainer: HTMLElement,
canvas: HTMLCanvasElement,
audioNode: GainNode,
stream: MediaStream,
options: ConfigType<'visualizer'>,
) {}
abstract resize(width: number, height: number): void;
abstract render(): void;
}

View File

@ -1,33 +0,0 @@
const Vudio = require('vudio/umd/vudio');
class VudioVisualizer {
constructor(
audioContext,
audioSource,
visualizerContainer,
canvas,
audioNode,
stream,
options,
) {
this.visualizer = new Vudio(stream, canvas, {
width: canvas.width,
height: canvas.height,
// Visualizer config
...options,
});
}
resize(width, height) {
this.visualizer.setOption({
width,
height,
});
}
render() {
this.visualizer.dance();
}
}
module.exports = VudioVisualizer;

View File

@ -0,0 +1,49 @@
import Vudio from 'vudio';
import { Visualizer } from './visualizer';
import type { ConfigType } from '../../../config/dynamic';
class VudioVisualizer extends Visualizer<Vudio> {
visualizer: Vudio;
constructor(
audioContext: AudioContext,
audioSource: MediaElementAudioSourceNode,
visualizerContainer: HTMLElement,
canvas: HTMLCanvasElement,
audioNode: GainNode,
stream: MediaStream,
options: ConfigType<'visualizer'>,
) {
super(
audioContext,
audioSource,
visualizerContainer,
canvas,
audioNode,
stream,
options,
);
this.visualizer = new Vudio(stream, canvas, {
width: canvas.width,
height: canvas.height,
// Visualizer config
...options,
});
}
resize(width: number, height: number) {
this.visualizer.setOptions({
width,
height,
});
}
render() {
this.visualizer.dance();
}
}
export default VudioVisualizer;

View File

@ -1,34 +0,0 @@
const { Wave } = require('@foobar404/wave');
class WaveVisualizer {
constructor(
audioContext,
audioSource,
visualizerContainer,
canvas,
audioNode,
stream,
options,
) {
this.visualizer = new Wave(
{ context: audioContext, source: audioSource },
canvas,
);
for (const animation of options.animations) {
this.visualizer.addAnimation(
eval(`new this.visualizer.animations.${animation.type}(
${JSON.stringify(animation.config)}
)`),
);
}
}
// eslint-disable-next-line no-unused-vars
resize(width, height) {
}
render() {
}
}
module.exports = WaveVisualizer;

View File

@ -0,0 +1,49 @@
import { Wave } from '@foobar404/wave';
import { Visualizer } from './visualizer';
import type { ConfigType } from '../../../config/dynamic';
class WaveVisualizer extends Visualizer<Wave> {
visualizer: Wave;
constructor(
audioContext: AudioContext,
audioSource: MediaElementAudioSourceNode,
visualizerContainer: HTMLElement,
canvas: HTMLCanvasElement,
audioNode: GainNode,
stream: MediaStream,
options: ConfigType<'visualizer'>,
) {
super(
audioContext,
audioSource,
visualizerContainer,
canvas,
audioNode,
stream,
options,
);
this.visualizer = new Wave(
{ context: audioContext, source: audioSource },
canvas,
);
for (const animation of options.wave.animations) {
const TargetVisualizer = this.visualizer.animations[animation.type as keyof typeof this.visualizer.animations];
this.visualizer.addAnimation(
new TargetVisualizer(animation.config as never), // Magic of Typescript
);
}
}
resize(_: number, __: number) {
}
render() {
}
}
export default WaveVisualizer;

34
plugins/visualizer/vudio.d.ts vendored Normal file
View File

@ -0,0 +1,34 @@
declare module 'vudio' {
interface NoneWaveformOptions {
maxHeight?: number;
minHeight?: number;
spacing?: number;
color?: string | string[];
shadowBlur?: number;
shadowColor?: string;
fadeSide?: boolean;
}
interface WaveformOptions extends NoneWaveformOptions{
horizontalAlign: 'left' | 'center' | 'right';
verticalAlign: 'top' | 'middle' | 'bottom';
}
interface VudioOptions {
effect?: 'waveform' | 'circlewave' | 'circlebar' | 'lighting';
accuracy?: number;
width?: number;
height?: number;
waveform?: WaveformOptions
}
class Vudio {
constructor(audio: HTMLAudioElement | MediaStream, canvas: HTMLCanvasElement, options: VudioOptions = {});
dance(): void;
pause(): void;
setOptions(options: VudioOptions): void;
}
export default Vudio;
}