aboutsummaryrefslogtreecommitdiffstats
path: root/src/app/game/game.utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/game/game.utils.ts')
-rw-r--r--src/app/game/game.utils.ts55
1 files changed, 55 insertions, 0 deletions
diff --git a/src/app/game/game.utils.ts b/src/app/game/game.utils.ts
new file mode 100644
index 0000000..b2037e5
--- /dev/null
+++ b/src/app/game/game.utils.ts
@@ -0,0 +1,55 @@
+export interface GameLine {
+ millisecond: number;
+ content: string;
+}
+
+export function parseLrcLines(
+ lrcText: string,
+ options?: { skipBacking?: boolean }
+): GameLine[] {
+ const result: GameLine[] = [];
+ const lineRegex = /\[(\d{2,3}):(\d{2})\.(\d{2,3})\]/g;
+ const { skipBacking = false } = options ?? {};
+
+ for (const rawLine of lrcText.split("\n")) {
+ const timestamps: number[] = [];
+ let match: RegExpExecArray | null;
+ let lastIndex = 0;
+
+ lineRegex.lastIndex = 0;
+ while ((match = lineRegex.exec(rawLine)) !== null) {
+ const minutes = parseInt(match[1], 10);
+ const seconds = parseInt(match[2], 10);
+ const msField = match[3];
+ const ms =
+ msField.length === 2
+ ? parseInt(msField, 10) * 10
+ : parseInt(msField, 10);
+ timestamps.push(minutes * 60_000 + seconds * 1_000 + ms);
+ lastIndex = match.index + match[0].length;
+ }
+
+ if (timestamps.length === 0) continue;
+
+ const content = (skipBacking
+ ? rawLine.slice(lastIndex).replace(/\([^)]*\)/g, "")
+ : rawLine.slice(lastIndex)
+ ).trim();
+
+ for (const ms of timestamps) {
+ result.push({ millisecond: ms, content });
+ }
+ }
+
+ result.sort((a, b) => a.millisecond - b.millisecond);
+ return result;
+}
+
+export function calculateCPSNeeded(text: string, seconds: number): number {
+ return text.length / seconds;
+}
+
+export function formatTime(ms: number): string {
+ const s = Math.max(0, Math.floor(ms / 1000));
+ return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
+}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage