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 🙏

© 2024 – Pkg Stats / Ryan Hefner

paroles

v2.3.0

Published

A library for parsing, making, modifying and playing LRC format lyrics

Downloads

10

Readme

paroles

NPM version NPM Downloads License Minified Size Build Status

paroles is a library for parsing, making, modifying and "playing" LRC format lyrics

  • support typescript
  • support ES module and commonjs
  • fully tested
  • zero dependencies

Install

npm i paroles

Or

pnpm add paroles
yarn add paroles

Usage

Parse lyrics

import { Lyrics } from 'paroles'

const text = `
  [ti:We are the world]
  [ar:USA for africa]
  [00:25.32]There comes a time
  [00:28.57]When we hear a certain call
`
const lyrics = new Lyrics(text)

console.log(lyrics.info.title) // We are the world
console.log(lyrics.lines[0]) // There comes a time
console.log(lyrics.atTime(26)) // There comes a time

Make lyrics

import { Lyrics } from 'paroles'

const lyrics = new Lyrics()
lyrics.insert({ time: 25.32, text: 'There comes a time' })
const piece = new Lyrics(`
[00:28.57]When we hear a certain call
[00:31.82]When the world must come together as onee
[00:38.82]advertisement
`)
const french = new Lyrics(`
[00:25.32]Il arrive un moment où nous avons besoin d'un certain appel
[00:31.82]Quand le monde doit être uni
`)
/** It is able to chain the operation methods (i.e. insert, merge, remove, replace, setInfo) */
lyrics
    .merge(piece)
    .merge(french, {
        resolveConflict: (original, affiliate) => {
            return `${original}\n${affiliate}`
        }
    })
    .remove('advertisement')
    .replace('When the world must come together as onee', 'When the world must come together as one')
    .setInfo({
        artist: 'USA for africa',
        length: '07:00.19',
        title: 'We are the world',
        version: 'v1.0.0',
    })
console.log(lyrics.toString())
// [ar:USA for africa]
// [ti:We are the world]
// [length:07:00.19]
// [ve:v1.0.0]
// [00:25.32]There comes a time
// [00:28.57]When we hear a certain call
// [00:31.82]When the world must come together as one

Play lyrics

import { LyricsPlayer } from 'paroles'

const lyricsPlayer = new LyricsPlayer(lyrics)
// subscribe linechange event
lyricsPlayer.on('linechange', (line) => {
    console.log(line) // There comes a time
})

// update play time with audio element
const audio = ducument.querySelector('audio')
audio.addEventListener('timeupdate', (e) => {
    lyricsPlayer.updateTime(e.target.currentTime)
})

API

Lyrics

  • new Lyrics(lyrics?: string | Lyrics, option?: LyricsOption): creates a Lyrics object

    • option.resolveConflict: used to handle lines with exact same time. can be merge, preserve, overwrite or a custom function, defaults to merge. merge equals to (line1, line2) => line1 + this.eol + line2; preserve equals to (line1, line2) => line1; overwrite equals to (line1, line2) => line2
        interface LyricsOption {
            resolveConflict?:
                | 'merge'
                | 'preserve'
                | 'overwrite'
                | ((line1: string, line2: string) => string)
        }
  • info: information contained in lrc text. The abbreviation is replaced with the full word for better readability. Note that offset, which is in milliseconds in LRC format, is converted to seconds in LyricsInfo for consistency.

    interface LyricsInfo {
        /** al, Album where the song is from */
        album?: string
        /** ar, Lyrics artist */
        artist?: string
        /** au, Creator of the Songtext */
        author?: string
        /** ti, Lyrics (song) title */
        title?: string
        /** by, Creator of the LRC file */
        creator?: string
        /** +/- Overall timestamp adjustment (in seconds), + shifts time up, - shifts down i.e. A positive value let lyrics appear sooner, a negative value delays the lyrics */
        offset?: number
        /** How long the song is (in seconds) */
        length?: string
        /** re, The player or editor that created the LRC file */
        editor?: string
        /** ve, version of program */
        version?: string
    }
  • lines: an array consists of every single lyrics line.

  • eol: end of line symbol detected when initialized.

  • clone(): clone and return a new Lyrics object.

  • toString(): return the raw text of the Lyrics object.

  • at(index: number): return the lyrics line at the index. Similar to Array.prototype.at(), when given negative index, it returns the last nth line.

  • atTime(time: number): return the lyrics line based on the time (in seconds). If the provided time is smaller/bigger than the times of all lyrics, the first/last line will be returned.

  • setOffset(time: number): set time offset (in seconds). A positive value let lyrics appear sooner, a negative value delays the lyrics.

  • setInfo(info: LyricsInfo): set LyricsInfo. New properties will override the original ones.

  • merge(lyrics: string | Lyrics, option?): merge another lyrics. The original lyrics is prior by default if there are conflicts.

    • option.override: if true, lyrics to merge is prior to, and will overwrite the original one for LyricsInfo and lines with the same time.
    • option.resolveInfo(originalInfo, affiliateInfo): manually control how to merge LyricsInfo, should return a LyricsInfo object. option.override for LyricsInfo is neglected when use this option.
    • resolveConflict(originalLine, affiliateLine): manually control how to merge two lines with the same time. option.override for lyrics lines is neglected when use this option.
  • insert(line: LyricsLine | LyricsLine[]): insert a new line or several lines. If there is a line with the same time, the inserted line will replace the original one.

  • remove(line: LyricsLine | string | RegExp): remove a line or lines (if multiple lines match). If no such line, it fails in silent.

  • replace(oldLine: LyricsLine | string | RegExp, newLine: LyricsLine | string): replace a line or lines (if multiple lines match). If a RegExp object is provided, it uses String.prototype.replace under the hood. For example, replace(/(abc)xxx/, '$1') will replace the string with the first capturing group.

LyricsPlayer

  • currentTime: current play time (in seconds).
  • lyrics: the Lyrics object.
  • updateTime(time: number): update the current play time (in seconds), should be synchronized with the song play time. If the current lyrics line changes after the update, linechange is triggered.
  • getCurrentLine(): get the current lyrics line based on the current play time. (use Lyrics.atTime under the hood)
  • getCurrentIndex(): get the current lyrics line index based on the current play time.
  • rewind(lyrics?): reset currentTime. If lyrics is provided, LyricsPlayer.lyrics will be replaced and lyricschange will be triggered.
  • on(event, callback): subscribe the event and the callback will be called when event triggers.
    • linechange event: triggered when current lyrics line changes. Current lyrics line and index is available in callback callback(currentLine: text, index: number).
    • lyricschange event: triggered when rewind(lyrics) called and lyrics changes.
  • off(event?, callback?): remove the event listener. If callback is omited, all listeners belong to that event will be removed. If event and callback are both omited, all of the event listeners will be removed.

Changelog

See CHANGELOG

Migrate from v1

  • the package is renamed to paroles. Uninstall lyrics-player and install paroles
  • rename update event to linechange in LyricsPlayer
  • LyricsPlayer.reset() is removed. Use LyricsPlayer.rewind() and LyricsPlayer.off() together instead

LRC format

There is no definite and strict specification for LRC format. Therefore, descriptions on WikiPedia are used to confine the behaviour in paroles.

Credit

This library is inspired by:

Acknowledgment

If you found it useful somehow, I would be grateful if you could leave a star in the project's GitHub repository.

Thank you.