Convert KaraFun KFN karaoke files to MP4 with synchronized lyrics
Project description
kfn2mp4
Convert KFN karaoke files (the format used by the KaraFun player) into standalone MP4 videos with synchronized, highlighted lyrics.
It parses the KFN container, reads lyric timing and background from Song.ini, and renders
with ffmpeg — a word-by-word wipe over the song's background and audio. CD+Graphics karaoke
(.cdg + audio) converts too.
Why such tool
.kfn is a widely used file format for creating karaoke versions of songs, but it is only well
supported by one application — KaraFun. The desktop player that plays local KFN files, KaraFun
Player 2, is officially no longer updated, and
the current KaraFun offering is built around its subscription streaming catalogue rather than
local files.
There is no open format for karaoke songs — and more and more creators simply publish videos instead.
So rather than relying on the unknown future of KaraFun's local-file support, it seems better to convert KFN files to plain videos — MP4 — that play anywhere. And even better: to convert a whole library at once.
That's why this is here.
Requirements
- Python 3.9+ (not needed for the standalone Windows
.exe) - ffmpeg/ffprobe with libass, libx264 and AAC — verified up front
(
kfn2mp4 --check); found onPATH, viaKFN2MP4_FFMPEG(a directory or the ffmpeg binary path), or next to the Windows.exe - fluidsynth + a General-MIDI soundfont — optional, only for MIDI-only files
(
KFN2MP4_SOUNDFONToverrides the auto-detected soundfont)
Install
pip install kfn2mp4 # from PyPI
Windows users can instead grab the standalone kfn2mp4.exe from the
releases page (no Python needed;
put ffmpeg.exe on PATH or next to the exe). From a checkout: pip install -e .
External tools on Windows
winget install Gyan.FFmpeg # full build: includes libass, libx264, AAC
or download a build from gyan.dev and drop
ffmpeg.exe + ffprobe.exe next to kfn2mp4.exe. For MIDI-only files, install
FluidSynth and point
KFN2MP4_SOUNDFONT at a General-MIDI .sf2 soundfont. Verify with kfn2mp4 --check.
Usage
kfn2mp4 "song.kfn" -o song.mp4 # convert to a specific file
kfn2mp4 "song.kfn" -O out/ # write "<song name>.mp4" into out/
kfn2mp4 *.kfn -O out/ # convert many; re-runs skip finished files
kfn2mp4 *.kfn -O out/ --overwrite # force re-render
kfn2mp4 "song.kfn" --extract-only out/ # just unpack audio/images/Song.ini
kfn2mp4 "song.kfn" -O out/ --file-colors # use the KFN's own lyric colours
kfn2mp4 "song.kfn" -O out/ --duration 40 -v # quick verbose preview (first 40s)
kfn2mp4 "song.cdg" -o song.mp4 # CD+Graphics: pairs the sibling song.mp3
kfn2mp4 *.cdg -O out/ # convert a folder of .cdg+.mp3 pairs
kfn2mp4 "song.cdg" --audio backing.mp3 -o s.mp4 # override the paired audio track
kfn2mp4 "song.kfn" # NO output given -> report the file
kfn2mp4 *.kfn # ...report many files (like ffprobe)
kfn2mp4 "song.kfn" --json # ...as machine-readable JSON
kfn2mp4 *.kfn -o "{artist} - {title}.mp4" # name outputs from KFN metadata
kfn2mp4 "song.kfn" -O out/ --sung-color "#00FF00" # custom lyric colours
kfn2mp4 "song.kfn" -O out/ --logo brand.png # watermark, bottom-left
kfn2mp4 "song.kfn" -O out/ --slots 3 # 3 on-screen lines (default: auto)
kfn2mp4 --check # verify ffmpeg & features (doctor)
kfn2mp4 "broken.kfn" --report # paste-ready diagnostic for a bug
Encoding is intentionally opinionated: a fixed 1280×720 canvas (background fitted, black
bars as needed), crf 28, 25 fps, medium x264 preset. Lyrics use a brand palette
over a translucent box (colour flags and --no-text-box override), in 2–3 slots
auto-picked from the song's pace; duets get an accent colour for the second voice. The MP4
is tagged with the song's title/artist/album/year and a converted-by marker (comment tag):
ffprobe -v error -show_entries format_tags -of default=nw=1 song.mp4
Skipping already-converted files makes a re-run resume a batch cheaply. A progress bar shows
per-file and batch progress on a terminal. Stopping a run (Ctrl-C or kill) removes the
unfinished output and temp files. Globs like *.kfn work even on Windows shells.
How it works
- Parse the KFN container —
KFNBbinary (AES-128-ECB entries), oldPKZIP, or legacyKFN3(chunked deflate). - Read
Song.iniinto a syllable-level lyric timeline + style + background references. - Generate an
.asssubtitle with karaoke wipe (\kf) highlighting. - Render background + lyrics + audio to MP4 with ffmpeg.
Supported formats
| Signature | Format | Support |
|---|---|---|
KFNB |
New KaraFun binary container (AES-128-ECB) | full |
PK |
Old KaraFun (plain ZIP) | full |
KFN3 |
Legacy KaraFun (chunked deflate) | files with a readable body; see below |
.cdg |
CD+Graphics stream + sibling audio (.mp3/.wav/…) |
full (graphics decoded by ffmpeg) |
| MIDI-only KFN | .mid/.kar track, no MP3 |
synthesized via fluidsynth + GM soundfont |
The KFNB container specification is in docs/kfn-format.md.
KFN3 (legacy container)
Read natively; files with an encrypted first chunk cannot be fully decoded (metadata is still
reported, --extract-only salvages what validates). Details:
docs/kfn3-format.md.
Status
Faithful-ish fidelity: image / video / slideshow background, embedded font, auto 2–3 line slot layout, smooth wipe highlighting, duet second voice, MIDI-only synthesis, CD+Graphics. Not yet: full KaraFun effect layers (trajectories, sprites, Milkdrop transitions) and encrypted-head KFN3 (above) — see the open issues.
Development
pip install -e .[dev]
pytest
The suite is built entirely from synthetic in-memory fixtures — no sample library is required, and
no real (copyrighted) .kfn file is ever needed to run or pass the tests.
Legal & disclaimer
This project is an independent, unofficial tool for format interoperability. It is not affiliated with, endorsed by, or connected to KaraFun or Recisio; "KaraFun" is a trademark of its respective owners.
kfn2mp4 only reads a container format so you can convert files you already have for personal
use. It ships no copyrighted content. The musical recordings, lyrics, and artwork inside a KFN
file remain the property of their rights holders — do not use this tool to redistribute copyrighted
material.
License
Released under the GNU General Public License v3.0 or later — see LICENSE.
Acknowledgements
Reverse-engineering of the KFN formats built on prior open work:
- UlduzSoft blog — the reverse-engineering series
(header, directory,
Song.ini, encryption): the authoritative narrative. - WinslowJosiah —
unlock_kfngist (Python): the cleanest read/decrypt reference (AES-128-ECB with theFLIDkey). - gyunaev/spivak — Spivak (C++/Qt): a production
karaoke player;
lyricsparser_kfn.cppis the reference for the Sync/Text merge + tokenization. - MadLord80/KFN_Viewer — KFN_Viewer (C#): a GUI viewer/extractor with the richest field table and an extended-LRC export.
- mazsibazsi/kfn-rs — kfn-rs (Rust): the
best-modeled
[Eff#]effects/animation layer.
Croonify convinced the author that MP4 is the proper format for karaoke.
This project was written with the help of AI tools — the code, tests, and documentation were developed with Anthropic's Claude (Claude Code).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kfn2mp4-0.1.0.tar.gz.
File metadata
- Download URL: kfn2mp4-0.1.0.tar.gz
- Upload date:
- Size: 98.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3dfdc554bb508637e346b9591e1f47d7593099f58bef1133b14349faa23af5bd
|
|
| MD5 |
6313daa4854f529e2c4dcc5309557c1b
|
|
| BLAKE2b-256 |
f15aff96a78c82ea8fe365a9a5f63c864f7f114e062416669f60681133a18abe
|
Provenance
The following attestation bundles were made for kfn2mp4-0.1.0.tar.gz:
Publisher:
release.yml on lukenowak/kfn2mp4
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kfn2mp4-0.1.0.tar.gz -
Subject digest:
3dfdc554bb508637e346b9591e1f47d7593099f58bef1133b14349faa23af5bd - Sigstore transparency entry: 2256114111
- Sigstore integration time:
-
Permalink:
lukenowak/kfn2mp4@d2b77b268735dcb419d45d1b8a9d6dd9a066fabf -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/lukenowak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d2b77b268735dcb419d45d1b8a9d6dd9a066fabf -
Trigger Event:
push
-
Statement type:
File details
Details for the file kfn2mp4-0.1.0-py3-none-any.whl.
File metadata
- Download URL: kfn2mp4-0.1.0-py3-none-any.whl
- Upload date:
- Size: 65.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4250675beba8b6a3589a35d9d6a39a4dade86f55ca4f891565c374177c3218d
|
|
| MD5 |
c6bbe360d2220df215db94d47a693ac5
|
|
| BLAKE2b-256 |
e70d0b5ac1e88c6a36893ddb4f8c87f356be5bc29445a6983105f58cff8c82d9
|
Provenance
The following attestation bundles were made for kfn2mp4-0.1.0-py3-none-any.whl:
Publisher:
release.yml on lukenowak/kfn2mp4
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kfn2mp4-0.1.0-py3-none-any.whl -
Subject digest:
e4250675beba8b6a3589a35d9d6a39a4dade86f55ca4f891565c374177c3218d - Sigstore transparency entry: 2256114123
- Sigstore integration time:
-
Permalink:
lukenowak/kfn2mp4@d2b77b268735dcb419d45d1b8a9d6dd9a066fabf -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/lukenowak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d2b77b268735dcb419d45d1b8a9d6dd9a066fabf -
Trigger Event:
push
-
Statement type: