Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module.exports = {
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'error',

'import/prefer-default-export': 'off',
'import/no-extraneous-dependencies': 'off',
'no-restricted-syntax': 'off',
'no-continue': 'off',
Expand All @@ -36,5 +37,15 @@ module.exports = {
tsx: 'never',
},
],
'prefer-destructuring': [
'error',
{
array: false,
object: true,
},
{
enforceForRenamedProperties: false,
},
],
},
};
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ dist/

# parcel
.cache/
/src/unparse.ts
92 changes: 90 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# clrc [![version](https://img.shields.io/npm/v/clrc)](https://www.npmjs.com/package/clrc) [![license](https://img.shields.io/npm/l/clrc)](https://github.com/mebtte/react-lrc/blob/master/LICENSE) [![](https://img.shields.io/bundlephobia/minzip/clrc)](https://bundlephobia.com/result?p=clrc)

LRC format parser for JavaScript/TypeScript. Here is a [playground](https://mebtte.github.io/clrc).
Parser for LRC and enhanced LRC. Here is a [playground](https://mebtte.github.io/clrc).

[2.x README](https://github.com/mebtte/clrc/blob/5c6efcbbfe08d4021e0a7d6252088c5deca428f7/README.md)

## Features

- Typescript support
- Browser & Node.js support
- Simple format and enhanced format support

## Install & Usage

Expand Down Expand Up @@ -65,13 +66,100 @@ The output is:

parse lrc string to array.

### parseEnhanced(lrcString)

parse enhanced lrc string to array. here is a example:

```txt
[ti: Somebody to Love]
[00:00.00] <00:00.04> When <00:00.16> the <00:00.82> truth <00:01.29> is <00:01.63> found <00:03.09> to <00:03.37> be <00:05.92> lies
```

the output is:

```json
[
{
"lineNumber": 0,
"raw": "[ti: Somebody to Love]",
"type": "metadata",
"key": "ti",
"value": " Somebody to Love"
},
{
"lineNumber": 1,
"raw": "[00:00.00] <00:00.04> When <00:00.16> the <00:00.82> truth <00:01.29> is <00:01.63> found <00:03.09> to <00:03.37> be <00:05.92> lies ",
"type": "enhanced_lyric",
"startMillisecond": 0,
"content": " <00:00.04> When <00:00.16> the <00:00.82> truth <00:01.29> is <00:01.63> found <00:03.09> to <00:03.37> be <00:05.92> lies ",
"words": [
{
"index": 0,
"raw": "<00:00.04> When ",
"startMillisecond": 40,
"content": " When "
},
{
"index": 1,
"raw": "<00:00.16> the ",
"startMillisecond": 160,
"content": " the "
},
{
"index": 2,
"raw": "<00:00.82> truth ",
"startMillisecond": 820,
"content": " truth "
},
{
"index": 3,
"raw": "<00:01.29> is ",
"startMillisecond": 1290,
"content": " is "
},
{
"index": 4,
"raw": "<00:01.63> found ",
"startMillisecond": 1630,
"content": " found "
},
{
"index": 5,
"raw": "<00:03.09> to ",
"startMillisecond": 3090,
"content": " to "
},
{
"index": 6,
"raw": "<00:03.37> be ",
"startMillisecond": 3370,
"content": " be "
},
{
"index": 7,
"raw": "<00:05.92> lies ",
"startMillisecond": 5920,
"content": " lies "
}
]
}
]
```

### LineType

types of line:

- `LineType.INVALID` means it's invalid line
- `LineType.LYRIC` means it's lyric line
- `LineType.METADATA` means it's metadata line
- `LineType.LYRIC` means it's lyric line
- `LineType.ENHANCED_LYRIC` means it's enhanced lyric line

## Contributors

<a href="https://github.com/mebtte/clrc/graphs/contributors">
<img src="https://contrib.rocks/image?repo=mebtte/clrc" />
</a>

## License

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dev": "tsc --declaration --watch",
"build": "tsc --declaration",
"lint-staged": "lint-staged",
"prepare": "husky install",
"prepare": "husky install && npm run build",
"prepublish": "npm run build"
},
"repository": {
Expand All @@ -30,6 +30,7 @@
},
"homepage": "https://github.com/mebtte/clrc#readme",
"devDependencies": {
"@types/node": "^18.15.12",
"@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.36.1",
"eslint": "^8.23.0",
Expand Down
4 changes: 2 additions & 2 deletions playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
"@types/react": "^18.0.18",
"@types/react-dom": "^18.0.6",
"@types/styled-components": "^5.1.26",
"clrc": "file:..",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-json-view": "^1.21.3",
"react-scripts": "5.0.1",
"styled-components": "^5.3.5",
"typescript": "^4.8.2",
"clrc": "file:.."
"typescript": "^4.8.2"
},
"scripts": {
"dev": "react-scripts start",
Expand Down
33 changes: 26 additions & 7 deletions playground/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { useState } from 'react';
import React, { useDeferredValue, useEffect, useState } from 'react';
import styled from 'styled-components';
import demoLrc from './lrc';
import Github from './github';
import GlobalStyle from './global_style';
import JsonView from './json_view';
import Github from './github';
import { lrc as lrcDemo, enhancedLrc as enhancedLrcDemo } from './data';
import Option from './option';

const Style = styled.div`
position: absolute;
Expand All @@ -13,10 +14,18 @@ const Style = styled.div`
left: 0;

display: flex;

> .editor {
flex: 1;
min-width: 0;

display: flex;
flex-direction: column;
}
`;
const Textarea = styled.textarea`
flex: 1;
min-width: 0;
min-height: 0;

padding: 10px;

Expand All @@ -29,16 +38,26 @@ const Textarea = styled.textarea`
`;

const App = () => {
const [lrc, setLrc] = useState(demoLrc);
const [enhanced, setEnhanced] = useState(false);

const [lrc, setLrc] = useState(enhanced ? enhancedLrcDemo : lrcDemo);
const onLrcChange = (event: React.ChangeEvent<HTMLTextAreaElement>) =>
setLrc(event.target.value);

useEffect(() => {
setLrc(enhanced ? enhancedLrcDemo : lrcDemo);
}, [enhanced]);

const deferedLrc = useDeferredValue(lrc);
return (
<>
<GlobalStyle />
<Style>
<Textarea value={lrc} onChange={onLrcChange} autoFocus />
<JsonView lrc={lrc} />
<div className="editor">
<Option enhanced={enhanced} onEnhancedChange={setEnhanced} />
<Textarea value={lrc} onChange={onLrcChange} autoFocus />
</div>
<JsonView lrc={deferedLrc} enhanced={enhanced} />
</Style>
<Github />
</>
Expand Down
10 changes: 8 additions & 2 deletions playground/src/lrc.ts → playground/src/data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const lrc = `something wrong
export const lrc = `something wrong
[by:mebtte]
[ar:Greyson Chance]
[01:17.62][00:51.80][01:43.27]Come with me for a little ride, see the shadows passing by
Expand Down Expand Up @@ -30,4 +30,10 @@ const lrc = `something wrong
[03:59.39]Come away with me, it's gonna be all right you'll see, you'll see
[04:24.46]Come away with me`;

export default lrc;
// from https://en.wikipedia.org/wiki/LRC_(file_format)#Enhanced_format|Enhanced%20LRC
export const enhancedLrc = `[by: lrc-maker]
[ti: Somebody to Love]

[00:00.00] <00:00.04> When <00:00.16> the <00:00.82> truth <00:01.29> is <00:01.63> found <00:03.09> to <00:03.37> be <00:05.92> lies
[00:06.47] <00:07.67> And <00:07.94> all <00:08.36> the <00:08.63> joy <00:10.28> within <00:10.53> you <00:13.09> dies
[00:13.34] <00:14.32> Don't <00:14.73> you <00:15.14> want <00:15.57> somebody <00:16.09> to <00:16.46> love`;
12 changes: 7 additions & 5 deletions playground/src/json_view.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useMemo, useDeferredValue } from 'react';
import { useMemo } from 'react';
import styled from 'styled-components';
import JsonView from 'react-json-view';
import { parse } from 'clrc';
import { parse, parseEnhanced } from 'clrc';

const Style = styled.div`
padding: 10px;
Expand All @@ -13,9 +13,11 @@ const Style = styled.div`
background-color: rgb(222 222 222 / 0.2);
`;

const Wrapper = ({ lrc }: { lrc: string }) => {
const deferedLrc = useDeferredValue(lrc);
const parsed = useMemo(() => parse(deferedLrc), [deferedLrc]);
const Wrapper = ({ lrc, enhanced }: { lrc: string; enhanced: boolean }) => {
const parsed = useMemo(
() => (enhanced ? parseEnhanced(lrc) : parse(lrc)),
[lrc, enhanced]
);

return (
<Style>
Expand Down
29 changes: 29 additions & 0 deletions playground/src/option.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import styled from 'styled-components';

const Style = styled.div`
padding: 10px 10px 10px 20px;
`;

function Option({
enhanced,
onEnhancedChange,
}: {
enhanced: boolean;
onEnhancedChange: (e: boolean) => void;
}) {
return (
<Style>
<label>
enhanced:
<input
type="checkbox"
checked={enhanced}
onChange={() => onEnhancedChange(!enhanced)}
/>
</label>
</Style>
);
}

export default Option;
15 changes: 14 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// eslint-disable-next-line no-shadow
export enum LineType {
INVALID = 'invalid',
LYRIC = 'lyric',
METADATA = 'metadata',
LYRIC = 'lyric',
ENHANCED_LYRIC = 'enhanced_lyric',
}

export interface Line {
Expand All @@ -26,3 +27,15 @@ export interface LyricLine extends Line {
export interface InvalidLine extends Line {
type: LineType.INVALID;
}

export interface EnhancedWord {
index: number;
raw: string;
startMillisecond: number;
content: string;
}

export interface EnhancedLyricLine extends Omit<LyricLine, 'type'> {
type: LineType.ENHANCED_LYRIC;
words: EnhancedWord[];
}
21 changes: 19 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
import { LineType, Line, MetadataLine, LyricLine } from './constants';
import {
LineType,
Line,
MetadataLine,
LyricLine,
EnhancedLyricLine,
EnhancedWord,
} from './constants';
import parse from './parse';
import parseEnhanced from './parse_enhanced';

export { parse, LineType, Line, MetadataLine, LyricLine };
export {
parse,
parseEnhanced,
LineType,
Line,
MetadataLine,
LyricLine,
EnhancedLyricLine,
EnhancedWord,
};
Loading