Video Speed Controller
A port of the Video Speed Controller browser extension to Trilium. Every HTML5 video gets a small draggable overlay showing its current speed, and a set of keyboard shortcuts to drive it:
| Key | Action |
|---|---|
S |
Slower (by the speed step) |
D |
Faster (by the speed step) |
R |
Reset to 1x — press again to go back to the speed you were at |
G |
Jump to your preferred speed — press again to go back |
Z |
Rewind |
X |
Advance |
M |
Set a marker at the current position |
J |
Jump back to the marker |
V |
Show / hide the controller |
Every binding, the speed step, the seek distances, the preferred speed, the controller's corner and opacity, and a per-site blacklist are all in the addon's settings (video-speed-controller@beatlink in the settings tree).
Where it works
Two surfaces, each switchable in settings:
- Web View notes (Trilium Desktop only). Trilium renders these as a real Electron
<webview>, and the controller is injected into the guest page throughexecuteJavaScript()— the same thing the browser extension does to a tab. Shortcuts are document-wide there, as in the extension. - Trilium's own players: video and audio file notes, and the players embedded in text notes.
Setup
- Install the addon and enable it in TAM.
- Reload Trilium — the script reads its config once at startup, so a settings change needs a reload to take effect.
Settings worth knowing
- Remember Speed (off by default) starts each new video at the last speed you set on that site. Off, a video keeps whatever speed the page itself chose and the controller only reports it.
- Shortcut Scope In Trilium decides when the bare letter keys apply inside Trilium's own
document. The default, only while the player is hovered or focused, keeps
S,Dand friends out of the way of the note tree and the editor; whenever a player is on screen matches the extension's behaviour. Web View pages are always document-wide regardless. - Control Audio Too (off by default) extends the controller to plain
<audio>players. - Blocked Sites takes bare hostnames and matches subdomains too, so
youtube.comalso coversmusic.youtube.com.
How it works
- A
#run=frontendStartupscript reads the config, then runs the controller in Trilium's own document and watches the DOM forwebview.note-detail-web-view-contentelements — Trilium mounts and tears these down as you move between notes. - The controller is a single closed function in
libVideoSpeedController.js. For Trilium's own document it is simply called; for a guest page it is stringified and handed toexecuteJavaScript(), since a<webview>shares no scope with the renderer that embeds it. That is why it references nothing outside its own body. - It tracks every
<video>/<audio>in its document through aMutationObserver, so infinite feeds and single-page navigation are picked up, and follows the largest playing one with the overlay. - The overlay is
position: fixedand repositioned from the player's bounding box rather than wrapped around it, which keeps it clear of the page's own layout. Going fullscreen moves it into the fullscreen element, since nothing outside that subtree renders. - Remembered speeds and the controller's dragged offset live in the page's own
localStorage, which is per-origin — hence "the last speed used on that site".
Known caveats
- Web View support is desktop only. Browser Trilium renders a sandboxed
<iframe>instead of an Electron<webview>, which this can't reach into. Trilium's own players still work there. - Nested iframes are not covered.
executeJavaScriptruns in the guest's main frame only, so a video inside an embedded frame (many news sites) is out of reach. - Key collisions with Trilium's own player. Trilium's video note player binds
Mto mute andFto fullscreen; the defaultMhere sets a marker. Rebind either one in settings if it bothers you. - DRM players ignore it. Sites that play through a protected pipeline (Netflix and similar)
often reset or refuse
playbackRate; blacklist them. - Settings need a reload. The config is read once at startup.
- Backend scripting must be enabled in Options → Security. Reading the config note goes through
api.runOnBackend(), as it does for every settings-driven addon here.