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

lomasub

v0.1.3

Published

Lomasub cli is a command-line tool for creating subtitles from local audio or video in Node.js or the terminal, using lomasub.ai cloud service.

Readme

Loma Sub: Node.js SDK and CLI

Create subtitles from a local audio or video file. Requires Node.js 20+ and a Loma Sub API key. No runtime npm dependencies.

Sign in to the editor, open your account dialog, and generate your personal API key. Copy it when shown: it is displayed only once. Each account has one active key; replacing or revoking it immediately invalidates the old key. Your CLI/SDK requests use your account's quota and create jobs in your own history. Inactive accounts cannot use personal keys. The shared deployment secret is reserved for internal scripts and workers.

Install

Run directly with npx:

export LOMA_API_SECRET_KEY="<your-api-key>"
npx lomasub transcribe ./video.mp4 --language th

For a Node.js project, run npm install lomasub. For a persistent CLI, run npm install --global lomasub. From a repository checkout, npm install --global ./cli-sdk also works.

CLI

lomasub transcribe video.mp4 --output video.srt
lomasub transcribe video.mp4 --speaker-diarization --srt-max-chars 48 --srt-cue-words 6
lomasub transcribe video.mp4 --config options.json
lomasub transcribe video.mp4 --no-ffmpeg
lomasub download <job-id> --output video.srt
lomasub --help

The command uploads the file, creates the job, waits, and saves <input-stem>.srt beside the input. --output changes the destination; --overwrite permits replacing an existing file. Progress and the job ID go to stderr; the saved path goes to stdout. If interrupted, the server job continues: resume using download and the printed job ID. Errors exit with code 1; cancellation exits with code 130. Job creation is never automatically retried.

When ffmpeg is on PATH, audio is extracted into a temporary Matroska audio file using -map 0:a:0 -vn -c:a copy. This copies the first audio stream without encoding, resampling, or changing quality. It excludes video to reduce uploads. If ffmpeg is missing or extraction fails (including a codec unsupported by Matroska), the original file is uploaded. --no-ffmpeg disables extraction. Temporary files are removed afterward.

--config reads an object of API transcription settings, without a surrounding config key:

{
  "forcealigner_level": "default",
  "speaker_diarization": true,
  "srt_max_chars": 48,
  "srt_cue_words": 6,
  "min_srt_duration_ms": 1200
}

Supported transcription flags use kebab-case. Use --promodel pro (SDK: config: { promodel: "pro" }) for word correction before alignment. Revision settings (revise_srt, revise_speakername, srt_revision_backend) are not supported by this CLI/SDK, including through --config JSON. Boolean fields support --name and --no-name. Explicit flags override JSON values, including false and 0. Unset settings use server defaults; the API validates settings and reports retired names. Other additional config keys pass through unchanged.

| Settings | CLI flags | | --- | --- | | Alignment | --forcealigner-level (default, llmsplitting, none) | | VAD | --min-vad-duration-seconds, --max-vad-duration-seconds, --vad-threshold | | Subtitle cues | --min-srt-duration-ms, --srt-max-chars, --srt-cue-words | | Diarization | --speaker-diarization, --speaker-local-distance-threshold, --speaker-merge-distance-threshold, --speaker-clustering-drop-dialogue-percentile, --agglomeration-min-appear, --agglomolation-group-size |

--filename, --language, and --duration-seconds are job metadata, outside config. The original local filename is preserved unless overridden. An explicit duration is forwarded to upload preparation and job creation; duration is not automatically measured.

The server defaults omitted, null, or blank language to th; --language en overrides it. The Thai hint permits Thai, English, and mixed transcripts: readable English is not discarded because of its script. This is a model hint, not automatic language detection.

Use --endpoint http://localhost:8080 for another API server. The default is https://api.lomasub.ai. Bearer credentials are sent only to the API, never to storage upload/download URLs.

SDK

import { LomaClient } from 'lomasub';

const client = new LomaClient(); // LOMA_API_SECRET_KEY; or { apiKey, endpoint }
const result = await client.transcribeFile('./video.mp4', {
  output: './video.srt',
  language: 'th',
  config: { speaker_diarization: true, srt_max_chars: 48 },
  onProgress: event => console.error(event),
});
console.log(result.output_path, result.timing);

Results include API job data and whichever artifact URLs the server produced. transcribeFile() also returns timing and, when saved, output_path.

| Method | Behavior | | --- | --- | | submitFile(file, options?) | Extract/upload and return the newly created job | | getStatus(jobId, { signal }?) | Read current status and fresh download URLs | | waitForJob(jobId, options?) | Poll until READY; throw with the failed stage on FAILED | | transcribeFile(file, options?) | Submit, wait, optionally save SRT, and return timing | | downloadSrt(jobId, output, options?) | Wait if needed, download original SRT, return absolute saved path |

Transcription options: config, filename, language, duration_seconds, ffmpeg (default true), signal, onProgress, and pollIntervalMs (default 2000). Waiting/downloading accept signal, onProgress, and pollIntervalMs; downloading also accepts overwrite (default false). Output parent directories must already exist.

transcribeFile() additionally accepts output (SRT path) and overwrite (default false). Existing output files are rejected before uploading unless overwrite is enabled.

After successful CLI transcription, stderr includes a final summary:

Content: 600.00s | Total: 60.00s | Speed: 10.00x realtime

The SDK returns timing: { content_duration_seconds, total_seconds, speed_x }. Total time uses a monotonic clock and includes extraction, upload, queueing, processing, and saving the SRT when output is provided. Without output, timing ends at READY. Speed is content duration divided by total time: 10x means ten seconds of content per second elapsed. SDK numbers retain full precision; CLI values show two decimal places.

Content duration comes from the worker's measured audio_duration_seconds, falling back to your explicit duration_seconds hint. Missing duration/speed is null in the SDK and unknown in the CLI; zero duration is valid. Failures and cancellation produce no success summary. Standalone download does not report whole-run timing because it cannot measure the earlier local steps.

Pass an AbortController's signal to stop local work. A submitted job continues on the server. HTTP errors include status and detail; ordinary network/file errors propagate. There are no automatic retries.

This package covers transcription and original results only. Account/login, job-history management, subtitle editing, and edited-subtitle uploads are outside its scope.

Development

cd cli-sdk
npm test
npm run check
npm pack --dry-run

Tests use local mock HTTP servers. One optional ffmpeg test checks that stream-copy extraction preserves audio packet bytes. No production jobs are submitted.