/*
* Copyright (c) 2026 Huawei Device Co., Ltd.
* Licensed under Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with License.
* You may obtain a copy of License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Logger from './Logger';
const TAG = 'LrcParser';
export interface LrcLine {
time: number;
text: string;
}
export class LrcParser {
private lrcLines: LrcLine[] = [];
// [Start parse]
parse(lrcContent: string): void {
Logger.info(TAG, 'Start parsing LRC file');
this.lrcLines = [];
if (!lrcContent || lrcContent.length === 0) {
Logger.error(TAG, 'LRC file content is empty');
return;
}
const lines: string[] = lrcContent.split('\n');
for (const line of lines) {
const trimmedLine: string = line.trim();
if (trimmedLine.length === 0) {
continue;
}
const match = trimmedLine.match(/\[(\d{2}):(\d{2})\.(\d{2,3})\](.*)/);
if (match) {
const minutes: number = parseInt(match[1]);
const seconds: number = parseInt(match[2]);
const milliseconds: number = parseInt(match[3].padEnd(3, '0'));
const text: string = match[4].trim();
const time: number = minutes * 60 * 1000 + seconds * 1000 + milliseconds;
this.lrcLines.push({ time, text });
}
}
this.lrcLines.sort((a, b) => a.time - b.time);
Logger.info(TAG, `LRC file parsing completed, total ${this.lrcLines.length} lines`);
}
// [End parse]
getLrcLines(): LrcLine[] {
return this.lrcLines;
}
getCurrentLineIndex(currentTime: number): number {
if (this.lrcLines.length === 0) {
return -1;
}
let left: number = 0;
let right: number = this.lrcLines.length - 1;
let result: number = -1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (this.lrcLines[mid].time <= currentTime) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
getCurrentLine(currentTime: number): LrcLine | null {
const index: number = this.getCurrentLineIndex(currentTime);
if (index >= 0 && index < this.lrcLines.length) {
return this.lrcLines[index];
}
return null;
}
clear(): void {
this.lrcLines = [];
Logger.info(TAG, 'Cleared lyric data');
}
}