diff --git a/src/plugins/slowed/index.tsx b/src/plugins/slowed/index.tsx new file mode 100644 index 0000000000..b55e4a0eb7 --- /dev/null +++ b/src/plugins/slowed/index.tsx @@ -0,0 +1,140 @@ +import { createSignal, createEffect, onCleanup, Show } from 'solid-js'; +import { render } from 'solid-js/web'; + +import style from './style.css?inline'; +import { createPlugin } from '@/utils'; + +export interface SlowedConfig { + enabled: boolean; + speed: number; + keepPitch: boolean; +} + +const DEFAULT_CONFIG: SlowedConfig = { + enabled: false, + speed: 1.0, + keepPitch: false, +}; + +export default createPlugin({ + name: () => 'Slowed', + authors: ['The-Kryz'], + restartNeeded: false, + config: DEFAULT_CONFIG, + stylesheets: [style], + + renderer: { + cleanup: null as (() => void) | null, + + start({ config, setConfig }) { + const safeConfig = config || DEFAULT_CONFIG; + + const [speed, setSpeed] = createSignal(safeConfig.speed ?? 1.0); + const [keepPitch, setKeepPitch] = createSignal(safeConfig.keepPitch ?? false); + const [collapsed, setCollapsed] = createSignal(false); + + const getVideo = () => document.querySelector('video'); + + document.getElementById('sr-panel')?.remove(); + + const panel = document.createElement('div'); + panel.id = 'sr-panel'; + document.body.appendChild(panel); + + const dispose = render(() => ( +
+
setCollapsed(!collapsed())} style="cursor: pointer;"> + + SLOWED +
+ + +
+
+ + + +
+ +
+
+ Speed + {speed().toFixed(2)}x +
+ setSpeed(parseFloat(e.currentTarget.value))} + style={{ '--fill': `${((speed() - 0.5) / (1.5 - 0.5)) * 100}%` }} + /> +
+ +
+ Keep pitch + +
+
+
+
+ ), panel); + + const interval = setInterval(() => { + const video = getVideo(); + if (!video) return; + + if (Math.abs(video.playbackRate - speed()) > 0.01) { + video.playbackRate = speed(); + } + + if (video.preservesPitch !== keepPitch()) { + video.preservesPitch = keepPitch(); + // @ts-ignore - Prefixos para garantir funcionamento no Electron/Chromium + video.webkitPreservesPitch = keepPitch(); + } + }, 500); + + const doCleanup = () => { + clearInterval(interval); + dispose(); + panel.remove(); + const video = getVideo(); + if (video) { + video.playbackRate = 1.0; + video.preservesPitch = true; + // @ts-ignore + video.webkitPreservesPitch = true; + } + }; + + this.cleanup = doCleanup; + onCleanup(doCleanup); + + createEffect(() => { + const video = getVideo(); + if (video) { + const s = speed(); + const p = keepPitch(); + video.playbackRate = s; + video.preservesPitch = p; + // @ts-ignore + video.webkitPreservesPitch = p; + } + }); + + createEffect(() => { + setConfig({ speed: speed(), keepPitch: keepPitch() }); + }); + }, + + stop() { + if (this.cleanup) { + this.cleanup(); + this.cleanup = null; + } + } + }, +}); \ No newline at end of file diff --git a/src/plugins/slowed/readme.md b/src/plugins/slowed/readme.md new file mode 100644 index 0000000000..e74dde566f --- /dev/null +++ b/src/plugins/slowed/readme.md @@ -0,0 +1,12 @@ +# Slowed & Nightcore Plugin + +Adds an interactive floating panel to easily apply "Slowed" or "Nightcore" effects to tracks. + +## Features +* **Playback Speed Control:** Precision slider from 0.5x to 1.5x. +* **Pitch Preservation:** Toggle to keep the original pitch or let it deepen/raise with the speed (true slowed/nightcore effect). +* **Presets:** Quick buttons for standard Slowed, Nightcore, and Reset. +* **Persistent Settings:** Preserves your chosen speed and pitch settings across track changes seamlessly. + +## Compatibility Note +This plugin operates strictly via the HTML5 `