npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@karaplay/file-coder

v1.4.4

Published

A comprehensive library for encoding/decoding karaoke files (.emk, .kar, MIDI) with Next.js support. Convert EMK to KAR, read/write karaoke files, full browser and server support.

Downloads

1,979

Readme

@karaplay/file-coder

A comprehensive library for encoding/decoding karaoke files (.emk, .kar, MIDI) with Next.js support.

✅ Thai Support: Thai lyrics are fully supported with proper TIS-620 encoding. All Thai characters are preserved and readable throughout the EMK→KAR conversion process.

Features

  • 🎵 Convert NCN format (.mid + .lyr + .cur) to .kar (MIDI karaoke)
  • 🔓 Decode .emk (Extreme Karaoke) files
  • 📖 Read and validate .kar files
  • NEW: Complete EMK → KAR workflow (one-step conversion)
  • 🌐 Full TypeScript support
  • ⚛️ Next.js compatible (both client and server side)
  • 🌐 NEW: Browser-compatible API for client-side processing
  • 🇹🇭 Thai language support (TIS-620 encoding)
  • FIXED v1.3.2: Client-side EMK decoder now works correctly!
  • ✅ 131 tests - 100% pass rate (including integration tests with real files)

Installation

npm install @karaplay/file-coder

Quick Start

Browser/Client-Side (Next.js) 🌐 NEW

For client-side processing in Next.js or browser environments:

'use client';

import { convertEmkFileToKar } from '@karaplay/file-coder/client';

function MyComponent() {
  const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    
    const result = await convertEmkFileToKar(file, { autoDownload: true });
    console.log('Converted:', result.metadata.title);
  };
  
  return <input type="file" accept=".emk" onChange={handleFileUpload} />;
}

📚 Full Browser API Documentation →

Server-Side (Node.js)

Usage

EMK to KAR Workflow (Complete Pipeline) ⭐ NEW

Convert EMK files directly to KAR in one step:

import { convertEmkToKar } from '@karaplay/file-coder';

const result = convertEmkToKar({
  inputEmk: 'songs/song.emk',
  outputKar: 'output/song.kar'
});

console.log(`Title: ${result.metadata.title}`);
console.log(`Artist: ${result.metadata.artist}`);
console.log(`Success: ${result.success}`);
// Thai text is readable! ✅

Batch conversion:

import { convertEmkToKarBatch } from '@karaplay/file-coder';

const results = convertEmkToKarBatch(
  ['song1.emk', 'song2.emk', 'song3.emk'],
  'output/kar'
);

See EMK_TO_KAR_WORKFLOW.md for complete documentation.

NCN to KAR Conversion

import { convertNcnToKar } from 'file-coder';

const result = convertNcnToKar({
  inputMidi: 'path/to/song.mid',
  inputLyr: 'path/to/song.lyr',
  inputCur: 'path/to/song.cur',
  outputKar: 'path/to/output.kar',
  appendTitles: true
});

console.log(`Converted: ${result.metadata.title} by ${result.metadata.artist}`);

EMK Decoding (Server-side)

import { decodeEmkServer, parseSongInfoServer } from 'file-coder';
import * as fs from 'fs';

const fileBuffer = fs.readFileSync('path/to/song.emk');
const decoded = decodeEmkServer(fileBuffer);

// Access decoded parts
const midiData = decoded.midi;
const lyricData = decoded.lyric;
const cursorData = decoded.cursor;

// Parse song information
const songInfo = parseSongInfoServer(decoded.songInfo);
console.log(`Title: ${songInfo.TITLE}`);
console.log(`Artist: ${songInfo.ARTIST}`);

EMK Decoding (Client-side/Next.js)

'use client';

import { decodeEmkClient, parseSongInfoClient } from 'file-coder';

function MyComponent() {
  const handleFileUpload = async (file: File) => {
    const arrayBuffer = await file.arrayBuffer();
    const buffer = Buffer.from(arrayBuffer);
    
    const decoded = decodeEmkClient(buffer);
    const songInfo = parseSongInfoClient(decoded.songInfo);
    
    console.log(`Title: ${songInfo.TITLE}`);
  };
  
  return <input type="file" onChange={(e) => handleFileUpload(e.target.files[0])} />;
}

API Reference

NCN to KAR Functions

  • convertNcnToKar(options) - Main conversion function
  • parseLyricFile(filePath) - Parse .lyr file for metadata
  • buildKaraokeTrack(metadata, cursorBuffer, ticksPerBeat) - Build karaoke track with timing
  • buildMetadataTracks(metadata) - Build metadata tracks
  • CursorReader - Class for reading cursor timing data

EMK to KAR Workflow Functions ⭐ NEW

  • convertEmkToKar(options) - Complete pipeline: EMK → KAR (one step!)
  • convertEmkToKarBatch(emkFiles, outputDir, options?) - Batch convert multiple files
  • validateThaiLyricReadability(lyricBuffer) - Validate Thai text readability

KAR File Reader Functions

  • readKarFile(filePath) - Read and parse .kar file
  • validateKarFile(filePath) - Validate .kar file structure
  • extractLyricsFromKar(filePath) - Extract lyrics from .kar file

EMK Decoder Functions

Server-side

  • decodeEmkServer(fileBuffer) - Decode .emk file (Node.js)
  • parseSongInfoServer(songInfoBuffer) - Parse song metadata
  • xorDecryptServer(data) - XOR decryption utility
  • looksLikeTextServer(buffer) - Text detection utility

Client-side

  • decodeEmkClient(fileBuffer) - Decode .emk file (Browser/Next.js)
  • parseSongInfoClient(songInfoBuffer) - Parse song metadata
  • xorDecryptClient(data) - XOR decryption utility
  • looksLikeTextClient(buffer) - Text detection utility

Development

Install Dependencies

npm install

Build

npm run build

Run Tests

npm test

Test Coverage

npm run test:coverage

Requirements

  • Node.js >= 16
  • TypeScript >= 5.0
  • Next.js >= 13.0 (optional, for client-side features)

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Changelog

v1.3.2 (Latest)

🔧 Critical Fix: Client-Side EMK Decoder

  • Fixed: Client-side EMK decoder was failing with "Invalid EMK structure: expected at least 3 zlib blocks, found 0"
  • Root Cause: Missing ZLIB_SECOND_BYTES validation check in client-decoder (was only checking first byte 0x78)
  • Solution: Added proper zlib header validation (both bytes) and fallback to Node.js zlib when available
  • Added: 12 comprehensive client-side decoder tests
  • Result: Client-side EMK decoding now works in both Node.js (tests/SSR) and browser environments

Test results:

// All EMK files decode successfully on client-side ✅
// 131/131 tests passing (was 119 in v1.3.1) ✅
// Client and server decoders produce identical results ✅

v1.3.1

🔧 Critical Fix: Marker Lines Preservation

  • Fixed: Marker lines (e.g., "...... Intro ......", "....ดนตรี....") were being incorrectly filtered out
  • Improved: Now includes ALL lines that have timing data in cursor file
  • Smart Handling: Stops processing when cursor runs out of timing data
  • Result: Complete preservation of songs with intro/solo/outro markers

What was fixed: v1.3.0 introduced marker filtering that removed lines like "...... Intro ......" even when the cursor file had timing data for them. This caused songs like "Move On แบบใด" to be missing marker lines. v1.3.1 removes the filtering and trusts the cursor file - if timing exists, the line is included.

Test results:

// Z2510001: ✅ Has "....ดนตรี...." + complete lyrics
// Z2510006: ✅ Has "...... Intro ......" + complete lyrics  
// 119/119 tests passing ✅

v1.3.0

🔧 Critical Fix: Beginning Lyrics Preservation

  • Fixed: Beginning lyrics were being cut off during EMK to KAR and NCN to KAR conversion
  • Improved: Smart detection and skipping of instrumental intro markers (e.g., "....ดนตรี....")
  • Added: 6 comprehensive tests to verify beginning lyrics preservation
  • Verified: All 119 tests passing, ensuring complete lyric integrity from EMK decode to KAR output

What was fixed: Previously, the conversion process was double-skipping the first 4 lines of lyrics, causing the actual beginning of songs to be missing from KAR files. This version correctly preserves all lyrics from the beginning while intelligently filtering out non-lyrical markers.

Comparison test:

// EMK decoded lyrics vs KAR output: 100% match
// First lyric: "ท่องเที่ยวมาแล้วแทบทั่วเมืองไทย" ✅
// Last lyric: "กับยุพิน ที่เมืองพระรถ..." ✅

v1.2.0

  • Added Thai encoding tests (6 new tests)
  • Verified TIS-620 encoding preservation
  • Updated README with encoding clarification

v1.1.1

  • Documentation update for Thai encoding in KAR files
  • No code changes

v1.0.0

  • Initial release
  • Full browser and server support
  • EMK decoding and NCN to KAR conversion
  • Thai language support (TIS-620)