lrc-karaoke-player
A karaoke-oriented media player. Supports simultaneous playback of a main video/audio file, a secondary audio track, LRC lyrics, and SRV3 (YouTube Timed Text) subtitles.
https://github.com/Patchwork-Archive/Patchwork-Karaoke/assets/21994085/5106bb53-d962-45e9-9a6b-6368dd1c6437
Build
pnpm i
pnpm run dev
Features
- LRC lyrics — scrolling line-by-line lyrics with highlight animation
- SRV3 subtitles — YouTube Timed Text rendered over the video
- Dual audio — mix a main media file with a secondary audio track (e.g. vocals + instrumental)
- Audio/Video balance — slider to blend the two audio sources
- Timing offsets — independently adjust LRC sync and Audio #2 sync in milliseconds
- Drag and drop — drop any supported file directly onto the player
- Resizable panes — drag the divider between the lyrics and video panels
- MoekyunKaraoke codes — shareable codes that load a full session from remote URLs
Supported File Types
| Slot | Accepted formats |
|---|---|
| Media (file1) | mp4, webm, ogg, mp3, wav, flac, and any format the browser supports |
| Audio #2 (file2) | Same as above |
| Lyrics | .lrc |
| Subtitles | .srv3 (YouTube Timed Text) |
The purpose of having Audio #2 is if you want to dynamically change the volume of 2 tracks. As an example, you may want Media to be an insturmental, while Audio #2 to be acapella/vocal-isolated version. This way you can dynamically change the volume of either.
MoekyunKaraoke Code
A MoekyunKaraoke code is a Base64-encoded JSON object that encodes remote URLs and timing settings for a session. Paste one into the input field on the player page, or pass it as a ?code= URL query parameter to share a fully-loaded session as a single link.
Encoding / decoding
// Encode
const code = btoa(JSON.stringify(payload));
// Decode (done internally by the player)
const payload = JSON.parse(atob(code));
Fields
All fields are optional — include only the ones you need.
| Field | Type | Description |
|---|---|---|
lrc |
string (URL) |
URL to an .lrc lyrics file. Fetched by the player at load time. |
srv3 |
string (URL) |
URL to a .srv3 YouTube Timed Text subtitle file. Fetched by the player at load time. |
file1 |
string (URL) |
URL to the main video or audio file. |
file2 |
string (URL) |
URL to the supplemental (secondary) audio file. |
offset |
number (ms) |
LRC timing offset in milliseconds. Negative values shift lyrics earlier; positive values shift them later. |
offset2 |
number (ms) |
Audio #2 timing offset in milliseconds. |
Example payload
{
"lrc": "https://example.com/song.lrc",
"file1": "https://example.com/song.webm",
"offset": -800
}
Full session with every field:
{
"lrc": "https://example.com/song.lrc",
"srv3": "https://example.com/song.srv3",
"file1": "https://example.com/song.webm",
"file2": "https://example.com/instrumental.mp3",
"offset": -800,
"offset2": 120
}
Sharing via URL
https://your-player-domain.com/?code=eyJsciI6Imh0dHBzOi8v...
Notes
lrcandsrv3are fetched client-side and require the hosting server to send permissive CORS headers (Access-Control-Allow-Origin: *).file1andfile2are set as mediasrcattributes directly and are subject to the same CORS restrictions for cross-origin URLs.
See
KARAOKE_CODE.mdfor the full format reference including code generation examples in JavaScript and Python.
