Giter Club home page Giter Club logo

subsrt-ts's Introduction

subsrt-ts

npm npm Linting DeepSource

Docs · npm package

Subtitle JavaScript library and command line tool with no dependencies.

This is a rewrite of the original subsrt package in TypeScript and using ESM syntax.

Table of Contents
  1. Getting started
  2. Supported subtitle formats
  3. Command line arguments
  4. Using in JavaScript
  5. Source code
  6. License

Getting started

Install the module

npm install -g subsrt

Command line

subsrt --help
subsrt convert sample.sub sample.srt

Using as Node.js library

import subsrt from "subsrt";

// MicroDVD (.sub) content
const sub = "{14975}{104000}Hi, my name is...";

// Convert to SubRip (.srt) content
const srt = subsrt.convert(sub, { format: "srt", fps: 25 });

(back to top)

Supported subtitle formats

(back to top)

Command line arguments

Usage:
  subsrt [command] [options]

Commands:
  list                   List supported formats
  parse [src] [json]     Parse a subtitle file
  build [json] [dst]     Create a subtitle file from captions
  detect [src]           Detect subtitle file format, if supported
  resync [src] [dst]     Resync FPS or shift time (+/- offset)
  convert [src] [dst]    Converts a subtitle format

Options:
  --help                 Print this message
  --eol [chars]          End of line chars, e.g. \r\n
  --fps [fps]            Frames per second for .sub format
  --offset [time]        Resync time shift offset in ms
  --format [ext]         Subtitle format to convert/build/parse
  --verbose              Enable detailed logging
  --version              Print version number

Examples:
  subsrt parse sample.sbv
  subsrt parse sample.srt output.json
  subsrt parse sample.sub --fps 30
  subsrt build input.json output.vtt
  subsrt build input.json --format sbv
  subsrt detect unknown.txt
  subsrt convert sample.srt sample.vtt
  subsrt convert --offset -250 sample.srt sample.ssa
  subsrt resync --offset +3000 input.srt output.srt
  subsrt resync --fps 25-30 input.sub output.sub

(back to top)

Using in JavaScript

The Node.js library supports converting, parsing and building subtitle file formats. Subtitles can also be resynced by shifting time offset, extending the duration or changing FPS.

List supported formats

import subsrt from "subsrt";

const list = subsrt.list();

console.log(list.join(", "));
// vtt, lrc, smi, ssa, ass, sub, srt, sbv, json

Format name is used in conversion options, e.g. { format: "srt" }

Use subsrt.format.name to access functions directly

import subsrt from "subsrt";
const handler = subsrt.format.srt;
// handler = { name: 'srt', helper: [object], parse: [function], build: [function] }

To implement a new subtitle format handler do the following

import subsrt from "subsrt";
subsrt.format.my = {
    // "my" is the format name
    name: "my",
    parse: (content, options) => {
        const captions = [];
        // ...
        return captions;
    },
    build: (captions, options) => {
        const content = "";
        // ...
        return content;
    },
    detect: (content) => {
        if (content.indexOf("my") > 0) {
            return true; // Recognized
        }
    },
};

(back to top)

Detect

Recognizes format by content

import subsrt from "subsrt";

let content = "";
content += "5" + "\r\n";
content += "00:00:16,700 --> 00:00:21,480" + "\r\n";
content += "Okay, so we have all the ingredients laid out here" + "\r\n";

const format = subsrt.detect(content);
// format = "srt"

(back to top)

Parse

Parse a subtitle file

import { readFileSync } from "fs";

import subsrt from "subsrt";

// Read a .srt file
const content = readFileSync("sample.srt", "utf8");

// Parse the content
const options = { verbose: true };
const captions = subsrt.parse(content, options);

// Output to console
console.log(captions);

Example of output

[
    {
        "type": "caption", // "caption" or "meta"
        "index": 1, // Caption id, usually a sequential number
        "start": 599, // Time to show caption in milliseconds
        "end": 4160, // Time to hide caption in milliseconds
        "duration": 3561, // Calculated caption duration
        "content": ">> ALICE: Hi, my name is Alice Miller and this is John Brown", // Formatted content
        "text": "Hi, my name is Alice Miller and this is John Brown" // Plain text content
    },
    {
        "type": "caption",
        "index": 2,
        "start": 4160,
        "end": 6770,
        "duration": 2610,
        "content": ">> JOHN: and we're the owners of Miller Bakery.",
        "text": "and we're the owners of Miller Bakery."
    }
    // ...
]

List of options

  • format: explicitly select a parser, values: sub, srt, sbv, vtt, lrc, smi, ssa, ass, json, default is undefined to auto detect
  • verbose: set to true for extra messages, console only, default: false
  • eol: end of line character(s), default: \r\n
  • fps: frames per second, sub format only
  • preserveSpaces: keep white space lines, smi format only

(back to top)

Build

Build a subtitle file

import { writeFileSync } from "fs";

import subsrt from "subsrt";

// Sample captions
const captions = [
    {
        start: 599, // Time to show caption in milliseconds
        end: 4160, // Time to hide caption in milliseconds
        text: "Hi, my name is Alice Miller and this is John Brown", // Plain text content
    },
    {
        start: 4160,
        end: 6770,
        text: "and we're the owners of Miller Bakery.",
    },
];

// Build the WebVTT content
const options = { format: "vtt" };
const content = subsrt.build(captions, options);

// Write content to .vtt file
writeFileSync("generated.vtt", content);

List of options

  • format: required, output subtitle format, values: sub, srt, sbv, vtt, lrc, smi, ssa, ass, json, default: srt
  • verbose: set to true for extra messages, console only, default: false
  • fps: frames per second, sub format only
  • closeTags: set to true to close tags, smi format only

(back to top)

Convert

Using a single action to convert from one to another subtitle format

import { readFileSync, writeFileSync } from "fs";

import subsrt from "subsrt";

// Read a .srt file
const srt = readFileSync("sample.srt", "utf8");

// Convert .srt to .sbv
const sbv = subsrt.convert(srt, { format: "sbv" });

// Write content to .sbv file
writeFileSync("converted.sbv", sbv);

List of options

  • format: required, output subtitle format, values: sub, srt, sbv, vtt, lrc, smi, ssa, ass, json, default: srt
  • verbose: set to true for extra messages, console only, default: false
  • eol: end of line character(s), default: \r\n
  • fps: frames per second, sub format only
  • resync: resync options, see below

(back to top)

Timeshift (+/- offset)

An example to make an extra 3-second delay

import { readFileSync } from "fs";

import subsrt from "subsrt";

// Read a .srt file
const content = readFileSync("sample.srt", "utf8");
const captions = subsrt.parse(content);

// Returns updated captions
const resynced = subsrt.resync(captions, { offset: 3000 });

Use minus sign to display captions earlier

const resynced = subsrt.resync(captions, { offset: -3000 });

(back to top)

Change FPS

The .sub format has captions saved in frame units. To shift from 25 FPS to 30 FPS do the following

import { readFileSync } from "fs";

import subsrt from "subsrt";

// Read a .sub file
const content = readFileSync("sample.sub", "utf8");
const captions = subsrt.parse(content, { fps: 25 }); // The .sub file content is saved in 25 FPS units

// Convert to 30 FPS, make sure to set 'frame' to true to convert frames instead of time
const resynced = subsrt.resync(content, { ratio: 30 / 25, frame: true });

(back to top)

Advanced resync options

Extend caption duration by 500 ms

// Argument 'a' is an array with two elements: [ start, end ]
// Return shifted [ start, end ] values
const resynced = subsrt.resync(content, (a) => [a[0], a[1] + 500]);

(back to top)

Source code

Download the source code from the GitHub repository.

Install required packages if any

pnpm install

Run the unit tests

pnpm test

(back to top)

License

Distributed under the MIT License. See LICENSE.txt for more information.

(back to top)

subsrt-ts's People

Contributors

deepsource-io[bot] avatar dnjstlr555 avatar frost768 avatar github-actions[bot] avatar mend-bolt-for-github[bot] avatar papnkukn avatar rakuzen25 avatar renovate[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

subsrt-ts's Issues

Multiline subtitles

First of all thanks for this great library and conversion to typescript.
The problem is that the regex in vtt doesn't capture the first line of a multiline subtitle.
For example:

WEBVTT

00:00:00.000 --> 00:00:10.000 position:45%,line-right align:center size:35%
- Hey
- Hi

00:00:11.000 --> 00:00:20.000
- Hey
- Hi

The first caption's output is '-Hey -Hi' but the second one's is just '- Hi'.
I believe it is related to \s?.*\r?\n regex before the text group ([\s\S]*).
It matches with the first line and completely disregards it.
Explanation:
In the first caption;

  • `\s?' matches with the space between the times and style
  • .*\r?\n matches with the style and the new line

In the second caption;

  • `\s?' doesn't match anything because there is no space
  • .*\r?\n matches with - Hey because it takes every character until it comes across with a new line which also happens to be the first line of the caption.

https://github.com/leranjun/subsrt-ts/blob/862a66da48ef883b328ae6ceb5e3b4627fed5f5c/lib/format/vtt.ts#L40-L42

bug(vtt): multiline caption new line removal

As stated in #2 before, currently new lines in multiline captions are replaced with spaces which can cause a problem in the captions that have more than one speaker at the current time of the video. In this situtation, subtitle editors mostly denote each speaker with a hyphen (-), words they say and a new line. Hence resulting in outputs as -Where were you? - At the store.
This may confuse people when reading the caption because of this I suggest keeping the content of the caption as it is.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/deploy-docs.yml
  • actions/checkout v4
  • pnpm/action-setup v2
  • actions/setup-node v4
  • actions/configure-pages v5
  • actions/upload-pages-artifact v3
  • actions/deploy-pages v4
.github/workflows/lint-and-test.yml
  • actions/checkout v4
  • pnpm/action-setup v2
  • actions/setup-node v4
  • wearerequired/lint-action v2
.github/workflows/release-please.yml
  • google-github-actions/release-please-action v3
  • actions/checkout v4
  • pnpm/action-setup v2
  • actions/setup-node v4
npm
package.json
  • @types/jest ^29.5.12
  • @types/node ^20.11.16
  • @typescript-eslint/eslint-plugin ^7.0.0
  • @typescript-eslint/parser ^7.0.0
  • eslint ^8.56.0
  • eslint-config-prettier ^9.1.0
  • eslint-import-resolver-typescript ^3.6.1
  • eslint-plugin-import ^2.29.1
  • eslint-plugin-jest ^28.0.0
  • eslint-plugin-regexp ^2.2.0
  • eslint-plugin-tsdoc ^0.3.0
  • jest ^29.7.0
  • prettier ^3.2.5
  • ts-jest ^29.1.2
  • typedoc ^0.26.0
  • typedoc-plugin-missing-exports ^3.0.0
  • typescript ^5.3.3
  • pnpm 9.7.0

  • Check this box to trigger a request for Renovate to run again on this repository

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.