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

@concordance-wiki/plugin-reader-vtt

v1.0.0

Published

Reader for VTT and SRT transcripts: cues, speakers, duration, language, HTML rendering with addressable timecodes.

Readme


Why

The transcript of a meeting is where a decision was actually taken, and nobody replays the recording to find the minute. This plugin reads WebVTT (.vtt) and SubRip (.srt) files in your repositories and makes each of them a page of the wiki: the speakers, the duration and the language as properties, the text cut into one addressable unit per speaker turn, so that a mention of a term in it cites 00:12:05 where a note cites a line. Transcripts stay out of the published site until the configuration says otherwise, pseudonymised or not. It is carried by @concordance-wiki/concordance; install it on its own next to @concordance-wiki/cli. No system dependency.

Quick start

npm install --save-dev @concordance-wiki/plugin-reader-vtt

Then declare it in concordance.yaml:

plugins:
  - "@concordance-wiki/plugin-reader-vtt"

Every .vtt and .srt file of a source becomes a transcript entity. To publish the transcripts, and the names in them, say so:

privacy:
  publish_transcripts: true
  pseudonymize:
    enabled: true
    dictionary: ./pseudonyms.yaml

The transcript as a library, without the build:

import { parseTranscript, renderTranscript, transcriptUnits } from "@concordance-wiki/plugin-reader-vtt";

const transcript = parseTranscript("WEBVTT\n\n00:00:01.000 --> 00:00:04.000\n<v Reviewer>The occurrence scan reads every note.\n", "vtt");
transcript.speakers; // ["Reviewer"]
transcriptUnits(transcript).map((unit) => unit.label); // ["00:00:01"]
renderTranscript(transcript); // one <article> per speaker turn, one <p id="t-1000"> per cue

What you get

  • A page per transcript: speakers, duration and language as properties, the text readable turn by turn.
  • Citations by timecode: every mention of a term in a transcript points at the cue where it was said, with a shareable anchor.
  • Private by default: a transcript is read but never published, pseudonymised or not, until privacy.publish_transcripts lets it into the site and its search index.
  • Pseudonymisation at build: rewriteTranscript writes the file again with every speaker and every text passed through your dictionary, so the file offered for download never carries a real name.
  • Two formats, one parser: parseTranscript reads WebVTT and SubRip into cues, speakers in order of first appearance, duration and the Language: header; writeTranscript writes either back.
  • Static HTML: renderTranscript, one <article> per speaker turn, one paragraph per cue, no script needed.

Documentation

Part of Concordance, MIT licence.

The plugin contributes a reader for .vtt and .srt. parseTranscript(text, format) turns a transcript into its cues (index, start and end in seconds, speaker, text), the unique speakers in order of first appearance, the duration (end of the last cue) and, for VTT, the Language: header. renderTranscript produces static HTML: one <article> per run of consecutive cues of the same speaker, headed by the speaker's name, and one <p id="t-<milliseconds>"> per cue whose timecode links to its own anchor, so that a timecode is shareable as a URL fragment; a second cue starting at the same instant takes its rank as a suffix (t-12000-2), so that every cue stays addressable. transcriptText gives the spoken text, one line per speaker turn, with the character range of every cue, so that a position in the text maps back to a timecode. The reader returns { metadata: { format, language, duration, cues, speakers }, text, units }, where units (transcriptUnits) cuts the text into one addressable unit per speaker turn, { label, text, anchor, speaker? }, labelled by the timecode of its first cue, named after its speaker when the cues name one and anchored like the rendering; the build reads them as the positions of the transcript, so that its text goes through term recognition like any other content and a mention in it cites 00:12:05 where a note cites a line. rewriteTranscript writes the file again with every speaker and every text passed through the substitution the pseudonymisation gives, timecodes kept, so that the file offered for download never carries a real name.

Parsing rules

| Rule | VTT | SRT | |---|---|---| | header | WEBVTT required, optional Key: value lines below it; Language: is kept | none | | cue identifier | optional line before the timing | the cue number | | timing | hh:mm:ss.mmm --> hh:mm:ss.mmm or mm:ss.mmm, cue settings after the end ignored | hh:mm:ss,mmm --> hh:mm:ss,mmm | | speaker | <v Name>text</v> or <v Name>text; without a voice span, a Name: prefix | a Name: prefix: one to four words each starting with a capital or a digit (ALICE, Bob Martin, Speaker 1) | | markup | <b>, <i>, <c.class>, inline timestamps and any other tag stripped; &amp;, &lt;, &gt;, &quot;, &#39;, &nbsp; decoded | same | | comments | NOTE, STYLE and REGION blocks skipped | none | | line endings | LF or CRLF; a leading byte order mark is ignored | same |

A malformed timing line throws an Error naming its line number; a VTT file without WEBVTT header throws line 1: missing WEBVTT header. The lines of a multi-line cue are joined with a space.

Privacy

Speaker names are returned as they appear by the reader: pseudonymisation is a separate step of the build, privacy.pseudonymize, that runs before anything of a transcript is rendered, indexed or offered for download, and privacy.publish_transcripts is what lets a transcript into the published site at all. A passage from which a decision note was extracted will carry a reference to that note; the cue anchors are what such a reference points at.