@lucaismyname/ginger 0.0.38 → 0.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -16
- package/dist/client.cjs +1 -1
- package/dist/client.js +2 -2
- package/dist/context/GingerProvider.d.ts.map +1 -1
- package/dist/equalizer/useGingerEqualizer.test.d.ts +2 -0
- package/dist/equalizer/useGingerEqualizer.test.d.ts.map +1 -0
- package/dist/{ginger-Ca8910_n.js → ginger-CgHqHrrG.js} +309 -304
- package/dist/{ginger-Ca8910_n.js.map → ginger-CgHqHrrG.js.map} +1 -1
- package/dist/{ginger-DrD8F4HX.cjs → ginger-DFdZGaMi.cjs} +2 -2
- package/dist/{ginger-DrD8F4HX.cjs.map → ginger-DFdZGaMi.cjs.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +2 -2
- package/dist/store.test.d.ts +2 -0
- package/dist/store.test.d.ts.map +1 -0
- package/dist/testing/index.cjs +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/transcript/index.cjs +7 -7
- package/dist/transcript/index.cjs.map +1 -1
- package/dist/transcript/index.js +57 -52
- package/dist/transcript/index.js.map +1 -1
- package/dist/transcript/useGingerTranscriptSync.d.ts.map +1 -1
- package/dist/transcript/useGingerTranscriptSync.test.d.ts +2 -0
- package/dist/transcript/useGingerTranscriptSync.test.d.ts.map +1 -0
- package/dist/{useGingerChapterProgress-TeWWJ8Fd.cjs → useGingerChapterProgress-COLWYX2-.cjs} +2 -2
- package/dist/{useGingerChapterProgress-TeWWJ8Fd.cjs.map → useGingerChapterProgress-COLWYX2-.cjs.map} +1 -1
- package/dist/{useGingerChapterProgress-Dbwiwnko.js → useGingerChapterProgress-Jj_zfnds.js} +2 -2
- package/dist/{useGingerChapterProgress-Dbwiwnko.js.map → useGingerChapterProgress-Jj_zfnds.js.map} +1 -1
- package/dist/waveform/index.cjs +1 -1
- package/dist/waveform/index.cjs.map +1 -1
- package/dist/waveform/index.d.ts +1 -1
- package/dist/waveform/index.d.ts.map +1 -1
- package/dist/waveform/index.js +129 -129
- package/dist/waveform/index.js.map +1 -1
- package/dist/waveform/useAudioPeaks.d.ts +14 -1
- package/dist/waveform/useAudioPeaks.d.ts.map +1 -1
- package/package.json +6 -4
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./ginger-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./ginger-DFdZGaMi.cjs"),s=require("./useGinger-BXgia32v.cjs"),r=require("./useGingerChapterProgress-COLWYX2-.cjs"),i=require("./liveAudioGraph-0cpHD_Ic.cjs"),n=require("./selectors-YXnP8Y8g.cjs"),a=require("./GingerSplitContexts-C7puo0M7.cjs");exports.Chapters=e.Chapters;exports.Ginger=e.Ginger;exports.LyricsSynced=e.LyricsSynced;exports.Pause=e.Pause;exports.Play=e.Play;exports.RepeatGlyph=e.RepeatGlyph;exports.ShuffleIcon=e.ShuffleIcon;exports.SkipBack=e.SkipBack;exports.SkipForward=e.SkipForward;exports.Volume2=e.Volume2;exports.VolumeX=e.VolumeX;exports.Wrapper=e.Wrapper;exports.clampPlaybackRate=e.clampPlaybackRate;exports.clampVolume=e.clampVolume;exports.defaultGingerLocale=e.defaultGingerLocale;exports.parseLrc=e.parseLrc;exports.useGingerChapters=e.useGingerChapters;exports.useGingerLocale=e.useGingerLocale;exports.useGingerLyricsSync=e.useGingerLyricsSync;exports.usePlayPauseBinding=e.usePlayPauseBinding;exports.useSeekBarBinding=e.useSeekBarBinding;exports.useVolumeSlider=e.useVolumeSlider;exports.useGinger=s.useGinger;exports.createGingerStore=r.createGingerStore;exports.useGingerChapterProgress=r.useGingerChapterProgress;exports.useGingerDebugLog=r.useGingerDebugLog;exports.useGingerKeyboardShortcuts=r.useGingerKeyboardShortcuts;exports.useGingerLiveAnalyzer=r.useGingerLiveAnalyzer;exports.useGingerPlaybackHistory=r.useGingerPlaybackHistory;exports.useGingerSleepTimer=r.useGingerSleepTimer;exports.useGingerVolumeFade=r.useGingerVolumeFade;exports.useNextTrackPrefetch=r.useNextTrackPrefetch;exports.useSeekDrag=r.useSeekDrag;exports.attachLiveAnalyser=i.attachLiveAnalyser;exports.detachLiveAnalyser=i.detachLiveAnalyser;exports.setProcessingChain=i.setProcessingChain;exports.derivePlaybackUiState=n.derivePlaybackUiState;exports.gingerStateFromContextValues=a.gingerStateFromContextValues;exports.gingerStateFromContexts=a.gingerStateFromContexts;exports.useGingerMedia=a.useGingerMedia;exports.useGingerPlayback=a.useGingerPlayback;exports.useGingerState=a.useGingerState;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as s, G as r, L as i, P as t, a as u, R as n, S as o, b as g, c, V as l, d as p, W as G, e as m, f as y, g as S, p as d, u as f, h, i as P, j as k, k as L, l as b } from "./ginger-
|
|
1
|
+
import { C as s, G as r, L as i, P as t, a as u, R as n, S as o, b as g, c, V as l, d as p, W as G, e as m, f as y, g as S, p as d, u as f, h, i as P, j as k, k as L, l as b } from "./ginger-CgHqHrrG.js";
|
|
2
2
|
import { u as C } from "./useGinger-hpp2pAGY.js";
|
|
3
|
-
import { c as v, u as B, a as F, b as A, d as R, e as D, f as T, g as W, h as j, i as w } from "./useGingerChapterProgress-
|
|
3
|
+
import { c as v, u as B, a as F, b as A, d as R, e as D, f as T, g as W, h as j, i as w } from "./useGingerChapterProgress-Jj_zfnds.js";
|
|
4
4
|
import { a as H, d as I, s as K } from "./liveAudioGraph-DvPaxBCP.js";
|
|
5
5
|
import { d as N } from "./selectors-BalBCc7X.js";
|
|
6
6
|
import { g as X, a as q, u as E, b as J, c as O } from "./GingerSplitContexts-BzBExb95.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.test.d.ts","sourceRoot":"","sources":["../src/store.test.ts"],"names":[],"mappings":""}
|
package/dist/testing/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Al=require("react/jsx-runtime"),Xi=require("react"),yt=require("react-dom"),Il=require("../ginger-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Al=require("react/jsx-runtime"),Xi=require("react"),yt=require("react-dom"),Il=require("../ginger-DFdZGaMi.cjs");function Pc(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const ur=Pc(Xi);function Tc(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var wi={exports:{}},ne={};/**
|
|
2
2
|
* @license React
|
|
3
3
|
* react-dom-test-utils.production.min.js
|
|
4
4
|
*
|
package/dist/testing/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsxs as Rc, jsx as Pc } from "react/jsx-runtime";
|
|
|
2
2
|
import * as ur from "react";
|
|
3
3
|
import Us from "react";
|
|
4
4
|
import yt from "react-dom";
|
|
5
|
-
import { G as Ml } from "../ginger-
|
|
5
|
+
import { G as Ml } from "../ginger-CgHqHrrG.js";
|
|
6
6
|
function Tc(e) {
|
|
7
7
|
return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
|
|
8
8
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("react"),
|
|
2
|
-
`).split(/\n\s*\n/);for(const
|
|
3
|
-
`).map(
|
|
4
|
-
`));f&&
|
|
5
|
-
`);if(
|
|
6
|
-
`).map(p=>p.trimEnd());if(
|
|
7
|
-
`));
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("react"),F=require("../GingerSplitContexts-C7puo0M7.cjs");function g(n){return n.replace(/<[^>]+>/g,"").trim()}function T(n){const e=n.trim().replace(",",".").split(":");if(e.length===3){const i=Number(e[0]),t=Number(e[1]),s=Number(e[2]);return[i,t,s].every(Number.isFinite)?i*3600+t*60+s:Number.NaN}if(e.length===2){const i=Number(e[0]),t=Number(e[1]);return[i,t].every(Number.isFinite)?i*60+t:Number.NaN}return Number.NaN}function S(n){const r=n.indexOf("-->");if(r<0)return null;const e=n.slice(0,r).trim(),t=n.slice(r+3).trim().match(/^(\S+)/);return t?{start:e,end:t[1]}:null}function b(n){const r=[],e=n.replace(/\r\n/g,`
|
|
2
|
+
`).split(/\n\s*\n/);for(const i of e){const t=i.split(`
|
|
3
|
+
`).map(m=>m.trim()).filter(m=>m.length>0);if(t.length===0)continue;let s=0;/^\d+$/.test(t[0])&&(s=1);const c=t[s];if(!c)continue;const o=S(c);if(!o)continue;const a=T(o.start),u=T(o.end);if(!Number.isFinite(a)||!Number.isFinite(u))continue;const l=t.slice(s+1),f=g(l.join(`
|
|
4
|
+
`));f&&r.push({startTime:a,endTime:u,text:f})}return r.sort((i,t)=>i.startTime-t.startTime)}function N(n){const r=[];let e=n.replace(/\r\n/g,`
|
|
5
|
+
`);if(e.startsWith("WEBVTT")){const t=e.search(/\n\s*\n/);e=t>=0?e.slice(t).trim():""}const i=e.split(/\n\s*\n/);for(const t of i){const c=t.split(`
|
|
6
|
+
`).map(p=>p.trimEnd());if(c.length===0||c[0].startsWith("NOTE")||c[0].startsWith("STYLE")||c[0].startsWith("REGION"))continue;let o=0,a,u=c[o];if(u.includes("-->")||(a=c[o],o+=1,u=c[o]),!(u!=null&&u.includes("-->")))continue;const l=S(u);if(!l)continue;const f=T(l.start),m=T(l.end);if(!Number.isFinite(f)||!Number.isFinite(m))continue;const x=c.slice(o+1).filter(p=>p.trim().length>0),h=g(x.join(`
|
|
7
|
+
`));h&&r.push({startTime:f,endTime:m,text:h,...a?{id:a}:{}})}return r.sort((t,s)=>t.startTime-s.startTime)}function y(n){return n.trimStart().startsWith("WEBVTT")?N(n):b(n)}function v(n,r){return r==="vtt"?N(n):r==="srt"?b(n):y(n)}function L(n,r){let e=0,i=n.length-1,t=-1;for(;e<=i;){const s=e+Math.floor((i-e)/2),c=n[s];if(!c)break;c.startTime<=r?(t=s,e=s+1):i=s-1}return t}function M(n){const{transcript:r,format:e="auto"}=n,{currentTime:i}=F.useGingerMedia(),t=d.useMemo(()=>Array.isArray(r)?[...r].filter(o=>Number.isFinite(o.startTime)&&Number.isFinite(o.endTime)&&o.startTime>=0&&o.endTime>=o.startTime).sort((o,a)=>o.startTime-a.startTime):v(r,e),[r,e]),s=d.useMemo(()=>L(t,i),[i,t]),c=d.useMemo(()=>s<0?[]:t.slice(0,s+1).filter(o=>i>=o.startTime&&i<o.endTime),[i,t,s]);return{cues:t,activeIndex:s,activeCue:s>=0?t[s]??null:null,activeCues:c}}exports.parseSrt=b;exports.parseTimestampToSeconds=T;exports.parseTranscriptAuto=y;exports.parseVtt=N;exports.useGingerTranscriptSync=M;
|
|
8
8
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../src/transcript/parseTranscript.ts","../../src/transcript/useGingerTranscriptSync.ts"],"sourcesContent":["/**\n * A single timed transcript cue (SRT / WebVTT).\n */\nexport type TranscriptCue = {\n /** Start time in seconds. */\n startTime: number;\n /** End time in seconds. */\n endTime: number;\n text: string;\n /** Present for WebVTT cues that declare an identifier line. */\n id?: string;\n};\n\nfunction stripHtmlTags(text: string): string {\n return text.replace(/<[^>]+>/g, \"\").trim();\n}\n\n/** Parse `HH:MM:SS.mmm` / `HH:MM:SS,mmm` / `MM:SS.mmm` (WebVTT) to seconds. */\nexport function parseTimestampToSeconds(raw: string): number {\n const t = raw.trim().replace(\",\", \".\");\n const segs = t.split(\":\");\n if (segs.length === 3) {\n const h = Number(segs[0]);\n const m = Number(segs[1]);\n const sec = Number(segs[2]);\n if (![h, m, sec].every(Number.isFinite)) return Number.NaN;\n return h * 3600 + m * 60 + sec;\n }\n if (segs.length === 2) {\n const m = Number(segs[0]);\n const sec = Number(segs[1]);\n if (![m, sec].every(Number.isFinite)) return Number.NaN;\n return m * 60 + sec;\n }\n return Number.NaN;\n}\n\nfunction parseTimingLine(line: string): { start: string; end: string } | null {\n const arrow = line.indexOf(\"-->\");\n if (arrow < 0) return null;\n const start = line.slice(0, arrow).trim();\n const rest = line.slice(arrow + 3).trim();\n const endMatch = rest.match(/^(\\S+)/);\n if (!endMatch) return null;\n return { start, end: endMatch[1]! };\n}\n\n/**\n * Parse SubRip (`.srt`) content into ordered cues.\n */\nexport function parseSrt(srt: string): TranscriptCue[] {\n const cues: TranscriptCue[] = [];\n const blocks = srt.replace(/\\r\\n/g, \"\\n\").split(/\\n\\s*\\n/);\n\n for (const block of blocks) {\n const lines = block\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0);\n if (lines.length === 0) continue;\n\n let i = 0;\n if (/^\\d+$/.test(lines[0]!)) {\n i = 1;\n }\n const timingLine = lines[i];\n if (!timingLine) continue;\n const times = parseTimingLine(timingLine);\n if (!times) continue;\n const startTime = parseTimestampToSeconds(times.start);\n const endTime = parseTimestampToSeconds(times.end);\n if (!Number.isFinite(startTime) || !Number.isFinite(endTime)) continue;\n const textLines = lines.slice(i + 1);\n const text = stripHtmlTags(textLines.join(\"\\n\"));\n if (!text) continue;\n cues.push({ startTime, endTime, text });\n }\n\n return cues.sort((a, b) => a.startTime - b.startTime);\n}\n\n/**\n * Parse WebVTT (`.vtt`) content into ordered cues. Ignores `NOTE` blocks and region/style headers.\n */\nexport function parseVtt(vtt: string): TranscriptCue[] {\n const cues: TranscriptCue[] = [];\n let body = vtt.replace(/\\r\\n/g, \"\\n\");\n if (body.startsWith(\"WEBVTT\")) {\n const firstBlank = body.search(/\\n\\s*\\n/);\n body = firstBlank >= 0 ? body.slice(firstBlank).trim() : \"\";\n }\n\n const blocks = body.split(/\\n\\s*\\n/);\n\n for (const block of blocks) {\n const rawLines = block.split(\"\\n\");\n const lines = rawLines.map((l) => l.trimEnd());\n if (lines.length === 0) continue;\n if (\n lines[0]!.startsWith(\"NOTE\") ||\n lines[0]!.startsWith(\"STYLE\") ||\n lines[0]!.startsWith(\"REGION\")\n ) {\n continue;\n }\n\n let i = 0;\n let id: string | undefined;\n let timingLine = lines[i]!;\n if (!timingLine.includes(\"-->\")) {\n id = lines[i]!;\n i += 1;\n timingLine = lines[i]!;\n }\n if (!timingLine?.includes(\"-->\")) continue;\n\n const times = parseTimingLine(timingLine);\n if (!times) continue;\n const startTime = parseTimestampToSeconds(times.start);\n const endTime = parseTimestampToSeconds(times.end);\n if (!Number.isFinite(startTime) || !Number.isFinite(endTime)) continue;\n\n const textLines = lines.slice(i + 1).filter((l) => l.trim().length > 0);\n const text = stripHtmlTags(textLines.join(\"\\n\"));\n if (!text) continue;\n cues.push({ startTime, endTime, text, ...(id ? { id } : {}) });\n }\n\n return cues.sort((a, b) => a.startTime - b.startTime);\n}\n\n/**\n * Auto-detect format: WebVTT if the string starts with `WEBVTT`, otherwise SRT.\n */\nexport function parseTranscriptAuto(input: string): TranscriptCue[] {\n const trimmed = input.trimStart();\n if (trimmed.startsWith(\"WEBVTT\")) {\n return parseVtt(input);\n }\n return parseSrt(input);\n}\n","import { useMemo } from \"react\";\nimport { useGingerMedia } from \"../context/GingerSplitContexts\";\nimport { type TranscriptCue, parseSrt, parseTranscriptAuto, parseVtt } from \"./parseTranscript\";\n\nexport type UseGingerTranscriptSyncOptions = {\n transcript: string | TranscriptCue[];\n /** Default: `\"auto\"` (WEBVTT header → VTT, else SRT). Ignored when `transcript` is a cue array. */\n format?: \"vtt\" | \"srt\" | \"auto\";\n};\n\nexport type GingerTranscriptSyncState = {\n cues: TranscriptCue[];\n /** Last cue index where `startTime <= currentTime` (same scan as lyrics sync). */\n activeIndex: number;\n activeCue: TranscriptCue | null;\n /** All cues active at `currentTime` (`startTime <= t < endTime`), including overlaps. */\n activeCues: TranscriptCue[];\n};\n\nfunction parseString(transcript: string, format: \"vtt\" | \"srt\" | \"auto\"): TranscriptCue[] {\n if (format === \"vtt\") return parseVtt(transcript);\n if (format === \"srt\") return parseSrt(transcript);\n return parseTranscriptAuto(transcript);\n}\n\n/**\n * Syncs SRT / WebVTT transcript cues to the current Ginger playback time.\n *\n * ```ts\n * import { useGingerTranscriptSync } from \"@lucaismyname/ginger/transcript\";\n * ```\n */\nexport function useGingerTranscriptSync(\n options: UseGingerTranscriptSyncOptions,\n): GingerTranscriptSyncState {\n const { transcript, format = \"auto\" } = options;\n const { currentTime } = useGingerMedia();\n\n const cues = useMemo(() => {\n if (Array.isArray(transcript)) {\n return [...transcript]\n .filter(\n (c) =>\n Number.isFinite(c.startTime) &&\n Number.isFinite(c.endTime) &&\n c.startTime >= 0 &&\n c.endTime >= c.startTime,\n )\n .sort((a, b) => a.startTime - b.startTime);\n }\n return parseString(transcript, format);\n }, [transcript, format]);\n\n const activeIndex = useMemo(() => {\n for (let i = cues.length - 1; i >= 0; i -= 1) {\n if (currentTime >= cues[i]!.startTime) return i;\n }\n return -1;\n }, [currentTime, cues]);\n\n const activeCues = useMemo(() => {\n return cues.filter((c) => currentTime >= c.startTime && currentTime < c.endTime);\n }, [currentTime, cues]);\n\n return {\n cues,\n activeIndex,\n activeCue: activeIndex >= 0 ? (cues[activeIndex] ?? null) : null,\n activeCues,\n };\n}\n"],"names":["stripHtmlTags","text","parseTimestampToSeconds","raw","segs","h","m","sec","parseTimingLine","line","arrow","start","endMatch","parseSrt","srt","cues","blocks","block","lines","l","i","timingLine","times","startTime","endTime","textLines","a","b","parseVtt","vtt","body","firstBlank","id","parseTranscriptAuto","input","parseString","transcript","format","useGingerTranscriptSync","options","currentTime","useGingerMedia","useMemo","c","activeIndex","activeCues"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/transcript/parseTranscript.ts","../../src/transcript/useGingerTranscriptSync.ts"],"sourcesContent":["/**\n * A single timed transcript cue (SRT / WebVTT).\n */\nexport type TranscriptCue = {\n /** Start time in seconds. */\n startTime: number;\n /** End time in seconds. */\n endTime: number;\n text: string;\n /** Present for WebVTT cues that declare an identifier line. */\n id?: string;\n};\n\nfunction stripHtmlTags(text: string): string {\n return text.replace(/<[^>]+>/g, \"\").trim();\n}\n\n/** Parse `HH:MM:SS.mmm` / `HH:MM:SS,mmm` / `MM:SS.mmm` (WebVTT) to seconds. */\nexport function parseTimestampToSeconds(raw: string): number {\n const t = raw.trim().replace(\",\", \".\");\n const segs = t.split(\":\");\n if (segs.length === 3) {\n const h = Number(segs[0]);\n const m = Number(segs[1]);\n const sec = Number(segs[2]);\n if (![h, m, sec].every(Number.isFinite)) return Number.NaN;\n return h * 3600 + m * 60 + sec;\n }\n if (segs.length === 2) {\n const m = Number(segs[0]);\n const sec = Number(segs[1]);\n if (![m, sec].every(Number.isFinite)) return Number.NaN;\n return m * 60 + sec;\n }\n return Number.NaN;\n}\n\nfunction parseTimingLine(line: string): { start: string; end: string } | null {\n const arrow = line.indexOf(\"-->\");\n if (arrow < 0) return null;\n const start = line.slice(0, arrow).trim();\n const rest = line.slice(arrow + 3).trim();\n const endMatch = rest.match(/^(\\S+)/);\n if (!endMatch) return null;\n return { start, end: endMatch[1]! };\n}\n\n/**\n * Parse SubRip (`.srt`) content into ordered cues.\n */\nexport function parseSrt(srt: string): TranscriptCue[] {\n const cues: TranscriptCue[] = [];\n const blocks = srt.replace(/\\r\\n/g, \"\\n\").split(/\\n\\s*\\n/);\n\n for (const block of blocks) {\n const lines = block\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0);\n if (lines.length === 0) continue;\n\n let i = 0;\n if (/^\\d+$/.test(lines[0]!)) {\n i = 1;\n }\n const timingLine = lines[i];\n if (!timingLine) continue;\n const times = parseTimingLine(timingLine);\n if (!times) continue;\n const startTime = parseTimestampToSeconds(times.start);\n const endTime = parseTimestampToSeconds(times.end);\n if (!Number.isFinite(startTime) || !Number.isFinite(endTime)) continue;\n const textLines = lines.slice(i + 1);\n const text = stripHtmlTags(textLines.join(\"\\n\"));\n if (!text) continue;\n cues.push({ startTime, endTime, text });\n }\n\n return cues.sort((a, b) => a.startTime - b.startTime);\n}\n\n/**\n * Parse WebVTT (`.vtt`) content into ordered cues. Ignores `NOTE` blocks and region/style headers.\n */\nexport function parseVtt(vtt: string): TranscriptCue[] {\n const cues: TranscriptCue[] = [];\n let body = vtt.replace(/\\r\\n/g, \"\\n\");\n if (body.startsWith(\"WEBVTT\")) {\n const firstBlank = body.search(/\\n\\s*\\n/);\n body = firstBlank >= 0 ? body.slice(firstBlank).trim() : \"\";\n }\n\n const blocks = body.split(/\\n\\s*\\n/);\n\n for (const block of blocks) {\n const rawLines = block.split(\"\\n\");\n const lines = rawLines.map((l) => l.trimEnd());\n if (lines.length === 0) continue;\n if (\n lines[0]!.startsWith(\"NOTE\") ||\n lines[0]!.startsWith(\"STYLE\") ||\n lines[0]!.startsWith(\"REGION\")\n ) {\n continue;\n }\n\n let i = 0;\n let id: string | undefined;\n let timingLine = lines[i]!;\n if (!timingLine.includes(\"-->\")) {\n id = lines[i]!;\n i += 1;\n timingLine = lines[i]!;\n }\n if (!timingLine?.includes(\"-->\")) continue;\n\n const times = parseTimingLine(timingLine);\n if (!times) continue;\n const startTime = parseTimestampToSeconds(times.start);\n const endTime = parseTimestampToSeconds(times.end);\n if (!Number.isFinite(startTime) || !Number.isFinite(endTime)) continue;\n\n const textLines = lines.slice(i + 1).filter((l) => l.trim().length > 0);\n const text = stripHtmlTags(textLines.join(\"\\n\"));\n if (!text) continue;\n cues.push({ startTime, endTime, text, ...(id ? { id } : {}) });\n }\n\n return cues.sort((a, b) => a.startTime - b.startTime);\n}\n\n/**\n * Auto-detect format: WebVTT if the string starts with `WEBVTT`, otherwise SRT.\n */\nexport function parseTranscriptAuto(input: string): TranscriptCue[] {\n const trimmed = input.trimStart();\n if (trimmed.startsWith(\"WEBVTT\")) {\n return parseVtt(input);\n }\n return parseSrt(input);\n}\n","import { useMemo } from \"react\";\nimport { useGingerMedia } from \"../context/GingerSplitContexts\";\nimport { type TranscriptCue, parseSrt, parseTranscriptAuto, parseVtt } from \"./parseTranscript\";\n\nexport type UseGingerTranscriptSyncOptions = {\n transcript: string | TranscriptCue[];\n /** Default: `\"auto\"` (WEBVTT header → VTT, else SRT). Ignored when `transcript` is a cue array. */\n format?: \"vtt\" | \"srt\" | \"auto\";\n};\n\nexport type GingerTranscriptSyncState = {\n cues: TranscriptCue[];\n /** Last cue index where `startTime <= currentTime` (same scan as lyrics sync). */\n activeIndex: number;\n activeCue: TranscriptCue | null;\n /** All cues active at `currentTime` (`startTime <= t < endTime`), including overlaps. */\n activeCues: TranscriptCue[];\n};\n\nfunction parseString(transcript: string, format: \"vtt\" | \"srt\" | \"auto\"): TranscriptCue[] {\n if (format === \"vtt\") return parseVtt(transcript);\n if (format === \"srt\") return parseSrt(transcript);\n return parseTranscriptAuto(transcript);\n}\n\nfunction findLastCueIndexAtOrBeforeTime(cues: TranscriptCue[], currentTime: number): number {\n let low = 0;\n let high = cues.length - 1;\n let best = -1;\n\n while (low <= high) {\n const mid = low + Math.floor((high - low) / 2);\n const cue = cues[mid];\n if (!cue) break;\n if (cue.startTime <= currentTime) {\n best = mid;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n return best;\n}\n\n/**\n * Syncs SRT / WebVTT transcript cues to the current Ginger playback time.\n *\n * ```ts\n * import { useGingerTranscriptSync } from \"@lucaismyname/ginger/transcript\";\n * ```\n */\nexport function useGingerTranscriptSync(\n options: UseGingerTranscriptSyncOptions,\n): GingerTranscriptSyncState {\n const { transcript, format = \"auto\" } = options;\n const { currentTime } = useGingerMedia();\n\n const cues = useMemo(() => {\n if (Array.isArray(transcript)) {\n return [...transcript]\n .filter(\n (c) =>\n Number.isFinite(c.startTime) &&\n Number.isFinite(c.endTime) &&\n c.startTime >= 0 &&\n c.endTime >= c.startTime,\n )\n .sort((a, b) => a.startTime - b.startTime);\n }\n return parseString(transcript, format);\n }, [transcript, format]);\n\n const activeIndex = useMemo(() => {\n return findLastCueIndexAtOrBeforeTime(cues, currentTime);\n }, [currentTime, cues]);\n\n const activeCues = useMemo(() => {\n if (activeIndex < 0) return [];\n return cues\n .slice(0, activeIndex + 1)\n .filter((c) => currentTime >= c.startTime && currentTime < c.endTime);\n }, [currentTime, cues, activeIndex]);\n\n return {\n cues,\n activeIndex,\n activeCue: activeIndex >= 0 ? (cues[activeIndex] ?? null) : null,\n activeCues,\n };\n}\n"],"names":["stripHtmlTags","text","parseTimestampToSeconds","raw","segs","h","m","sec","parseTimingLine","line","arrow","start","endMatch","parseSrt","srt","cues","blocks","block","lines","l","i","timingLine","times","startTime","endTime","textLines","a","b","parseVtt","vtt","body","firstBlank","id","parseTranscriptAuto","input","parseString","transcript","format","findLastCueIndexAtOrBeforeTime","currentTime","low","high","best","mid","cue","useGingerTranscriptSync","options","useGingerMedia","useMemo","c","activeIndex","activeCues"],"mappings":"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"}
|
package/dist/transcript/index.js
CHANGED
|
@@ -1,99 +1,104 @@
|
|
|
1
|
-
import { useMemo as
|
|
2
|
-
import { u as
|
|
3
|
-
function
|
|
1
|
+
import { useMemo as N } from "react";
|
|
2
|
+
import { u as L } from "../GingerSplitContexts-BzBExb95.js";
|
|
3
|
+
function p(n) {
|
|
4
4
|
return n.replace(/<[^>]+>/g, "").trim();
|
|
5
5
|
}
|
|
6
6
|
function T(n) {
|
|
7
|
-
const
|
|
8
|
-
if (
|
|
9
|
-
const
|
|
10
|
-
return [
|
|
7
|
+
const e = n.trim().replace(",", ".").split(":");
|
|
8
|
+
if (e.length === 3) {
|
|
9
|
+
const i = Number(e[0]), t = Number(e[1]), s = Number(e[2]);
|
|
10
|
+
return [i, t, s].every(Number.isFinite) ? i * 3600 + t * 60 + s : Number.NaN;
|
|
11
11
|
}
|
|
12
|
-
if (
|
|
13
|
-
const
|
|
14
|
-
return [
|
|
12
|
+
if (e.length === 2) {
|
|
13
|
+
const i = Number(e[0]), t = Number(e[1]);
|
|
14
|
+
return [i, t].every(Number.isFinite) ? i * 60 + t : Number.NaN;
|
|
15
15
|
}
|
|
16
16
|
return Number.NaN;
|
|
17
17
|
}
|
|
18
18
|
function h(n) {
|
|
19
19
|
const r = n.indexOf("-->");
|
|
20
20
|
if (r < 0) return null;
|
|
21
|
-
const
|
|
22
|
-
return t ? { start:
|
|
21
|
+
const e = n.slice(0, r).trim(), t = n.slice(r + 3).trim().match(/^(\S+)/);
|
|
22
|
+
return t ? { start: e, end: t[1] } : null;
|
|
23
23
|
}
|
|
24
24
|
function g(n) {
|
|
25
|
-
const r = [],
|
|
25
|
+
const r = [], e = n.replace(/\r\n/g, `
|
|
26
26
|
`).split(/\n\s*\n/);
|
|
27
|
-
for (const
|
|
28
|
-
const t =
|
|
27
|
+
for (const i of e) {
|
|
28
|
+
const t = i.split(`
|
|
29
29
|
`).map((a) => a.trim()).filter((a) => a.length > 0);
|
|
30
30
|
if (t.length === 0) continue;
|
|
31
|
-
let
|
|
32
|
-
/^\d+$/.test(t[0]) && (
|
|
33
|
-
const c = t[
|
|
31
|
+
let s = 0;
|
|
32
|
+
/^\d+$/.test(t[0]) && (s = 1);
|
|
33
|
+
const c = t[s];
|
|
34
34
|
if (!c) continue;
|
|
35
|
-
const
|
|
36
|
-
if (!
|
|
37
|
-
const m = T(
|
|
35
|
+
const o = h(c);
|
|
36
|
+
if (!o) continue;
|
|
37
|
+
const m = T(o.start), u = T(o.end);
|
|
38
38
|
if (!Number.isFinite(m) || !Number.isFinite(u)) continue;
|
|
39
|
-
const l = t.slice(
|
|
39
|
+
const l = t.slice(s + 1), f = p(l.join(`
|
|
40
40
|
`));
|
|
41
41
|
f && r.push({ startTime: m, endTime: u, text: f });
|
|
42
42
|
}
|
|
43
|
-
return r.sort((
|
|
43
|
+
return r.sort((i, t) => i.startTime - t.startTime);
|
|
44
44
|
}
|
|
45
|
-
function
|
|
45
|
+
function x(n) {
|
|
46
46
|
const r = [];
|
|
47
|
-
let
|
|
47
|
+
let e = n.replace(/\r\n/g, `
|
|
48
48
|
`);
|
|
49
|
-
if (
|
|
50
|
-
const t =
|
|
51
|
-
|
|
49
|
+
if (e.startsWith("WEBVTT")) {
|
|
50
|
+
const t = e.search(/\n\s*\n/);
|
|
51
|
+
e = t >= 0 ? e.slice(t).trim() : "";
|
|
52
52
|
}
|
|
53
|
-
const
|
|
54
|
-
for (const t of
|
|
53
|
+
const i = e.split(/\n\s*\n/);
|
|
54
|
+
for (const t of i) {
|
|
55
55
|
const c = t.split(`
|
|
56
|
-
`).map((
|
|
56
|
+
`).map((d) => d.trimEnd());
|
|
57
57
|
if (c.length === 0 || c[0].startsWith("NOTE") || c[0].startsWith("STYLE") || c[0].startsWith("REGION"))
|
|
58
58
|
continue;
|
|
59
|
-
let
|
|
60
|
-
if (u.includes("-->") || (m = c[
|
|
59
|
+
let o = 0, m, u = c[o];
|
|
60
|
+
if (u.includes("-->") || (m = c[o], o += 1, u = c[o]), !(u != null && u.includes("-->"))) continue;
|
|
61
61
|
const l = h(u);
|
|
62
62
|
if (!l) continue;
|
|
63
63
|
const f = T(l.start), a = T(l.end);
|
|
64
64
|
if (!Number.isFinite(f) || !Number.isFinite(a)) continue;
|
|
65
|
-
const
|
|
65
|
+
const F = c.slice(o + 1).filter((d) => d.trim().length > 0), b = p(F.join(`
|
|
66
66
|
`));
|
|
67
67
|
b && r.push({ startTime: f, endTime: a, text: b, ...m ? { id: m } : {} });
|
|
68
68
|
}
|
|
69
|
-
return r.sort((t,
|
|
69
|
+
return r.sort((t, s) => t.startTime - s.startTime);
|
|
70
70
|
}
|
|
71
|
-
function
|
|
72
|
-
return n.trimStart().startsWith("WEBVTT") ?
|
|
71
|
+
function S(n) {
|
|
72
|
+
return n.trimStart().startsWith("WEBVTT") ? x(n) : g(n);
|
|
73
73
|
}
|
|
74
|
-
function
|
|
75
|
-
return r === "vtt" ?
|
|
74
|
+
function W(n, r) {
|
|
75
|
+
return r === "vtt" ? x(n) : r === "srt" ? g(n) : S(n);
|
|
76
76
|
}
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
function k(n, r) {
|
|
78
|
+
let e = 0, i = n.length - 1, t = -1;
|
|
79
|
+
for (; e <= i; ) {
|
|
80
|
+
const s = e + Math.floor((i - e) / 2), c = n[s];
|
|
81
|
+
if (!c) break;
|
|
82
|
+
c.startTime <= r ? (t = s, e = s + 1) : i = s - 1;
|
|
83
|
+
}
|
|
84
|
+
return t;
|
|
85
|
+
}
|
|
86
|
+
function E(n) {
|
|
87
|
+
const { transcript: r, format: e = "auto" } = n, { currentTime: i } = L(), t = N(() => Array.isArray(r) ? [...r].filter(
|
|
88
|
+
(o) => Number.isFinite(o.startTime) && Number.isFinite(o.endTime) && o.startTime >= 0 && o.endTime >= o.startTime
|
|
89
|
+
).sort((o, m) => o.startTime - m.startTime) : W(r, e), [r, e]), s = N(() => k(t, i), [i, t]), c = N(() => s < 0 ? [] : t.slice(0, s + 1).filter((o) => i >= o.startTime && i < o.endTime), [i, t, s]);
|
|
85
90
|
return {
|
|
86
91
|
cues: t,
|
|
87
|
-
activeIndex:
|
|
88
|
-
activeCue:
|
|
92
|
+
activeIndex: s,
|
|
93
|
+
activeCue: s >= 0 ? t[s] ?? null : null,
|
|
89
94
|
activeCues: c
|
|
90
95
|
};
|
|
91
96
|
}
|
|
92
97
|
export {
|
|
93
98
|
g as parseSrt,
|
|
94
99
|
T as parseTimestampToSeconds,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
S as parseTranscriptAuto,
|
|
101
|
+
x as parseVtt,
|
|
102
|
+
E as useGingerTranscriptSync
|
|
98
103
|
};
|
|
99
104
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/transcript/parseTranscript.ts","../../src/transcript/useGingerTranscriptSync.ts"],"sourcesContent":["/**\n * A single timed transcript cue (SRT / WebVTT).\n */\nexport type TranscriptCue = {\n /** Start time in seconds. */\n startTime: number;\n /** End time in seconds. */\n endTime: number;\n text: string;\n /** Present for WebVTT cues that declare an identifier line. */\n id?: string;\n};\n\nfunction stripHtmlTags(text: string): string {\n return text.replace(/<[^>]+>/g, \"\").trim();\n}\n\n/** Parse `HH:MM:SS.mmm` / `HH:MM:SS,mmm` / `MM:SS.mmm` (WebVTT) to seconds. */\nexport function parseTimestampToSeconds(raw: string): number {\n const t = raw.trim().replace(\",\", \".\");\n const segs = t.split(\":\");\n if (segs.length === 3) {\n const h = Number(segs[0]);\n const m = Number(segs[1]);\n const sec = Number(segs[2]);\n if (![h, m, sec].every(Number.isFinite)) return Number.NaN;\n return h * 3600 + m * 60 + sec;\n }\n if (segs.length === 2) {\n const m = Number(segs[0]);\n const sec = Number(segs[1]);\n if (![m, sec].every(Number.isFinite)) return Number.NaN;\n return m * 60 + sec;\n }\n return Number.NaN;\n}\n\nfunction parseTimingLine(line: string): { start: string; end: string } | null {\n const arrow = line.indexOf(\"-->\");\n if (arrow < 0) return null;\n const start = line.slice(0, arrow).trim();\n const rest = line.slice(arrow + 3).trim();\n const endMatch = rest.match(/^(\\S+)/);\n if (!endMatch) return null;\n return { start, end: endMatch[1]! };\n}\n\n/**\n * Parse SubRip (`.srt`) content into ordered cues.\n */\nexport function parseSrt(srt: string): TranscriptCue[] {\n const cues: TranscriptCue[] = [];\n const blocks = srt.replace(/\\r\\n/g, \"\\n\").split(/\\n\\s*\\n/);\n\n for (const block of blocks) {\n const lines = block\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0);\n if (lines.length === 0) continue;\n\n let i = 0;\n if (/^\\d+$/.test(lines[0]!)) {\n i = 1;\n }\n const timingLine = lines[i];\n if (!timingLine) continue;\n const times = parseTimingLine(timingLine);\n if (!times) continue;\n const startTime = parseTimestampToSeconds(times.start);\n const endTime = parseTimestampToSeconds(times.end);\n if (!Number.isFinite(startTime) || !Number.isFinite(endTime)) continue;\n const textLines = lines.slice(i + 1);\n const text = stripHtmlTags(textLines.join(\"\\n\"));\n if (!text) continue;\n cues.push({ startTime, endTime, text });\n }\n\n return cues.sort((a, b) => a.startTime - b.startTime);\n}\n\n/**\n * Parse WebVTT (`.vtt`) content into ordered cues. Ignores `NOTE` blocks and region/style headers.\n */\nexport function parseVtt(vtt: string): TranscriptCue[] {\n const cues: TranscriptCue[] = [];\n let body = vtt.replace(/\\r\\n/g, \"\\n\");\n if (body.startsWith(\"WEBVTT\")) {\n const firstBlank = body.search(/\\n\\s*\\n/);\n body = firstBlank >= 0 ? body.slice(firstBlank).trim() : \"\";\n }\n\n const blocks = body.split(/\\n\\s*\\n/);\n\n for (const block of blocks) {\n const rawLines = block.split(\"\\n\");\n const lines = rawLines.map((l) => l.trimEnd());\n if (lines.length === 0) continue;\n if (\n lines[0]!.startsWith(\"NOTE\") ||\n lines[0]!.startsWith(\"STYLE\") ||\n lines[0]!.startsWith(\"REGION\")\n ) {\n continue;\n }\n\n let i = 0;\n let id: string | undefined;\n let timingLine = lines[i]!;\n if (!timingLine.includes(\"-->\")) {\n id = lines[i]!;\n i += 1;\n timingLine = lines[i]!;\n }\n if (!timingLine?.includes(\"-->\")) continue;\n\n const times = parseTimingLine(timingLine);\n if (!times) continue;\n const startTime = parseTimestampToSeconds(times.start);\n const endTime = parseTimestampToSeconds(times.end);\n if (!Number.isFinite(startTime) || !Number.isFinite(endTime)) continue;\n\n const textLines = lines.slice(i + 1).filter((l) => l.trim().length > 0);\n const text = stripHtmlTags(textLines.join(\"\\n\"));\n if (!text) continue;\n cues.push({ startTime, endTime, text, ...(id ? { id } : {}) });\n }\n\n return cues.sort((a, b) => a.startTime - b.startTime);\n}\n\n/**\n * Auto-detect format: WebVTT if the string starts with `WEBVTT`, otherwise SRT.\n */\nexport function parseTranscriptAuto(input: string): TranscriptCue[] {\n const trimmed = input.trimStart();\n if (trimmed.startsWith(\"WEBVTT\")) {\n return parseVtt(input);\n }\n return parseSrt(input);\n}\n","import { useMemo } from \"react\";\nimport { useGingerMedia } from \"../context/GingerSplitContexts\";\nimport { type TranscriptCue, parseSrt, parseTranscriptAuto, parseVtt } from \"./parseTranscript\";\n\nexport type UseGingerTranscriptSyncOptions = {\n transcript: string | TranscriptCue[];\n /** Default: `\"auto\"` (WEBVTT header → VTT, else SRT). Ignored when `transcript` is a cue array. */\n format?: \"vtt\" | \"srt\" | \"auto\";\n};\n\nexport type GingerTranscriptSyncState = {\n cues: TranscriptCue[];\n /** Last cue index where `startTime <= currentTime` (same scan as lyrics sync). */\n activeIndex: number;\n activeCue: TranscriptCue | null;\n /** All cues active at `currentTime` (`startTime <= t < endTime`), including overlaps. */\n activeCues: TranscriptCue[];\n};\n\nfunction parseString(transcript: string, format: \"vtt\" | \"srt\" | \"auto\"): TranscriptCue[] {\n if (format === \"vtt\") return parseVtt(transcript);\n if (format === \"srt\") return parseSrt(transcript);\n return parseTranscriptAuto(transcript);\n}\n\n/**\n * Syncs SRT / WebVTT transcript cues to the current Ginger playback time.\n *\n * ```ts\n * import { useGingerTranscriptSync } from \"@lucaismyname/ginger/transcript\";\n * ```\n */\nexport function useGingerTranscriptSync(\n options: UseGingerTranscriptSyncOptions,\n): GingerTranscriptSyncState {\n const { transcript, format = \"auto\" } = options;\n const { currentTime } = useGingerMedia();\n\n const cues = useMemo(() => {\n if (Array.isArray(transcript)) {\n return [...transcript]\n .filter(\n (c) =>\n Number.isFinite(c.startTime) &&\n Number.isFinite(c.endTime) &&\n c.startTime >= 0 &&\n c.endTime >= c.startTime,\n )\n .sort((a, b) => a.startTime - b.startTime);\n }\n return parseString(transcript, format);\n }, [transcript, format]);\n\n const activeIndex = useMemo(() => {\n for (let i = cues.length - 1; i >= 0; i -= 1) {\n if (currentTime >= cues[i]!.startTime) return i;\n }\n return -1;\n }, [currentTime, cues]);\n\n const activeCues = useMemo(() => {\n return cues.filter((c) => currentTime >= c.startTime && currentTime < c.endTime);\n }, [currentTime, cues]);\n\n return {\n cues,\n activeIndex,\n activeCue: activeIndex >= 0 ? (cues[activeIndex] ?? null) : null,\n activeCues,\n };\n}\n"],"names":["stripHtmlTags","text","parseTimestampToSeconds","raw","segs","h","m","sec","parseTimingLine","line","arrow","start","endMatch","parseSrt","srt","cues","blocks","block","lines","l","i","timingLine","times","startTime","endTime","textLines","a","b","parseVtt","vtt","body","firstBlank","id","parseTranscriptAuto","input","parseString","transcript","format","useGingerTranscriptSync","options","currentTime","useGingerMedia","useMemo","c","activeIndex","activeCues"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/transcript/parseTranscript.ts","../../src/transcript/useGingerTranscriptSync.ts"],"sourcesContent":["/**\n * A single timed transcript cue (SRT / WebVTT).\n */\nexport type TranscriptCue = {\n /** Start time in seconds. */\n startTime: number;\n /** End time in seconds. */\n endTime: number;\n text: string;\n /** Present for WebVTT cues that declare an identifier line. */\n id?: string;\n};\n\nfunction stripHtmlTags(text: string): string {\n return text.replace(/<[^>]+>/g, \"\").trim();\n}\n\n/** Parse `HH:MM:SS.mmm` / `HH:MM:SS,mmm` / `MM:SS.mmm` (WebVTT) to seconds. */\nexport function parseTimestampToSeconds(raw: string): number {\n const t = raw.trim().replace(\",\", \".\");\n const segs = t.split(\":\");\n if (segs.length === 3) {\n const h = Number(segs[0]);\n const m = Number(segs[1]);\n const sec = Number(segs[2]);\n if (![h, m, sec].every(Number.isFinite)) return Number.NaN;\n return h * 3600 + m * 60 + sec;\n }\n if (segs.length === 2) {\n const m = Number(segs[0]);\n const sec = Number(segs[1]);\n if (![m, sec].every(Number.isFinite)) return Number.NaN;\n return m * 60 + sec;\n }\n return Number.NaN;\n}\n\nfunction parseTimingLine(line: string): { start: string; end: string } | null {\n const arrow = line.indexOf(\"-->\");\n if (arrow < 0) return null;\n const start = line.slice(0, arrow).trim();\n const rest = line.slice(arrow + 3).trim();\n const endMatch = rest.match(/^(\\S+)/);\n if (!endMatch) return null;\n return { start, end: endMatch[1]! };\n}\n\n/**\n * Parse SubRip (`.srt`) content into ordered cues.\n */\nexport function parseSrt(srt: string): TranscriptCue[] {\n const cues: TranscriptCue[] = [];\n const blocks = srt.replace(/\\r\\n/g, \"\\n\").split(/\\n\\s*\\n/);\n\n for (const block of blocks) {\n const lines = block\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0);\n if (lines.length === 0) continue;\n\n let i = 0;\n if (/^\\d+$/.test(lines[0]!)) {\n i = 1;\n }\n const timingLine = lines[i];\n if (!timingLine) continue;\n const times = parseTimingLine(timingLine);\n if (!times) continue;\n const startTime = parseTimestampToSeconds(times.start);\n const endTime = parseTimestampToSeconds(times.end);\n if (!Number.isFinite(startTime) || !Number.isFinite(endTime)) continue;\n const textLines = lines.slice(i + 1);\n const text = stripHtmlTags(textLines.join(\"\\n\"));\n if (!text) continue;\n cues.push({ startTime, endTime, text });\n }\n\n return cues.sort((a, b) => a.startTime - b.startTime);\n}\n\n/**\n * Parse WebVTT (`.vtt`) content into ordered cues. Ignores `NOTE` blocks and region/style headers.\n */\nexport function parseVtt(vtt: string): TranscriptCue[] {\n const cues: TranscriptCue[] = [];\n let body = vtt.replace(/\\r\\n/g, \"\\n\");\n if (body.startsWith(\"WEBVTT\")) {\n const firstBlank = body.search(/\\n\\s*\\n/);\n body = firstBlank >= 0 ? body.slice(firstBlank).trim() : \"\";\n }\n\n const blocks = body.split(/\\n\\s*\\n/);\n\n for (const block of blocks) {\n const rawLines = block.split(\"\\n\");\n const lines = rawLines.map((l) => l.trimEnd());\n if (lines.length === 0) continue;\n if (\n lines[0]!.startsWith(\"NOTE\") ||\n lines[0]!.startsWith(\"STYLE\") ||\n lines[0]!.startsWith(\"REGION\")\n ) {\n continue;\n }\n\n let i = 0;\n let id: string | undefined;\n let timingLine = lines[i]!;\n if (!timingLine.includes(\"-->\")) {\n id = lines[i]!;\n i += 1;\n timingLine = lines[i]!;\n }\n if (!timingLine?.includes(\"-->\")) continue;\n\n const times = parseTimingLine(timingLine);\n if (!times) continue;\n const startTime = parseTimestampToSeconds(times.start);\n const endTime = parseTimestampToSeconds(times.end);\n if (!Number.isFinite(startTime) || !Number.isFinite(endTime)) continue;\n\n const textLines = lines.slice(i + 1).filter((l) => l.trim().length > 0);\n const text = stripHtmlTags(textLines.join(\"\\n\"));\n if (!text) continue;\n cues.push({ startTime, endTime, text, ...(id ? { id } : {}) });\n }\n\n return cues.sort((a, b) => a.startTime - b.startTime);\n}\n\n/**\n * Auto-detect format: WebVTT if the string starts with `WEBVTT`, otherwise SRT.\n */\nexport function parseTranscriptAuto(input: string): TranscriptCue[] {\n const trimmed = input.trimStart();\n if (trimmed.startsWith(\"WEBVTT\")) {\n return parseVtt(input);\n }\n return parseSrt(input);\n}\n","import { useMemo } from \"react\";\nimport { useGingerMedia } from \"../context/GingerSplitContexts\";\nimport { type TranscriptCue, parseSrt, parseTranscriptAuto, parseVtt } from \"./parseTranscript\";\n\nexport type UseGingerTranscriptSyncOptions = {\n transcript: string | TranscriptCue[];\n /** Default: `\"auto\"` (WEBVTT header → VTT, else SRT). Ignored when `transcript` is a cue array. */\n format?: \"vtt\" | \"srt\" | \"auto\";\n};\n\nexport type GingerTranscriptSyncState = {\n cues: TranscriptCue[];\n /** Last cue index where `startTime <= currentTime` (same scan as lyrics sync). */\n activeIndex: number;\n activeCue: TranscriptCue | null;\n /** All cues active at `currentTime` (`startTime <= t < endTime`), including overlaps. */\n activeCues: TranscriptCue[];\n};\n\nfunction parseString(transcript: string, format: \"vtt\" | \"srt\" | \"auto\"): TranscriptCue[] {\n if (format === \"vtt\") return parseVtt(transcript);\n if (format === \"srt\") return parseSrt(transcript);\n return parseTranscriptAuto(transcript);\n}\n\nfunction findLastCueIndexAtOrBeforeTime(cues: TranscriptCue[], currentTime: number): number {\n let low = 0;\n let high = cues.length - 1;\n let best = -1;\n\n while (low <= high) {\n const mid = low + Math.floor((high - low) / 2);\n const cue = cues[mid];\n if (!cue) break;\n if (cue.startTime <= currentTime) {\n best = mid;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n return best;\n}\n\n/**\n * Syncs SRT / WebVTT transcript cues to the current Ginger playback time.\n *\n * ```ts\n * import { useGingerTranscriptSync } from \"@lucaismyname/ginger/transcript\";\n * ```\n */\nexport function useGingerTranscriptSync(\n options: UseGingerTranscriptSyncOptions,\n): GingerTranscriptSyncState {\n const { transcript, format = \"auto\" } = options;\n const { currentTime } = useGingerMedia();\n\n const cues = useMemo(() => {\n if (Array.isArray(transcript)) {\n return [...transcript]\n .filter(\n (c) =>\n Number.isFinite(c.startTime) &&\n Number.isFinite(c.endTime) &&\n c.startTime >= 0 &&\n c.endTime >= c.startTime,\n )\n .sort((a, b) => a.startTime - b.startTime);\n }\n return parseString(transcript, format);\n }, [transcript, format]);\n\n const activeIndex = useMemo(() => {\n return findLastCueIndexAtOrBeforeTime(cues, currentTime);\n }, [currentTime, cues]);\n\n const activeCues = useMemo(() => {\n if (activeIndex < 0) return [];\n return cues\n .slice(0, activeIndex + 1)\n .filter((c) => currentTime >= c.startTime && currentTime < c.endTime);\n }, [currentTime, cues, activeIndex]);\n\n return {\n cues,\n activeIndex,\n activeCue: activeIndex >= 0 ? (cues[activeIndex] ?? null) : null,\n activeCues,\n };\n}\n"],"names":["stripHtmlTags","text","parseTimestampToSeconds","raw","segs","h","m","sec","parseTimingLine","line","arrow","start","endMatch","parseSrt","srt","cues","blocks","block","lines","l","i","timingLine","times","startTime","endTime","textLines","a","b","parseVtt","vtt","body","firstBlank","id","parseTranscriptAuto","input","parseString","transcript","format","findLastCueIndexAtOrBeforeTime","currentTime","low","high","best","mid","cue","useGingerTranscriptSync","options","useGingerMedia","useMemo","c","activeIndex","activeCues"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useGingerTranscriptSync.d.ts","sourceRoot":"","sources":["../../src/transcript/useGingerTranscriptSync.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAA2C,MAAM,mBAAmB,CAAC;AAEhG,MAAM,MAAM,8BAA8B,GAAG;IAC3C,UAAU,EAAE,MAAM,GAAG,aAAa,EAAE,CAAC;IACrC,mGAAmG;IACnG,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;IAChC,yFAAyF;IACzF,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B,CAAC;
|
|
1
|
+
{"version":3,"file":"useGingerTranscriptSync.d.ts","sourceRoot":"","sources":["../../src/transcript/useGingerTranscriptSync.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAA2C,MAAM,mBAAmB,CAAC;AAEhG,MAAM,MAAM,8BAA8B,GAAG;IAC3C,UAAU,EAAE,MAAM,GAAG,aAAa,EAAE,CAAC;IACrC,mGAAmG;IACnG,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;IAChC,yFAAyF;IACzF,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B,CAAC;AA4BF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,8BAA8B,GACtC,yBAAyB,CAoC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useGingerTranscriptSync.test.d.ts","sourceRoot":"","sources":["../../src/transcript/useGingerTranscriptSync.test.tsx"],"names":[],"mappings":""}
|
package/dist/{useGingerChapterProgress-TeWWJ8Fd.cjs → useGingerChapterProgress-COLWYX2-.cjs}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const t=require("react"),z=require("./useGinger-BXgia32v.cjs"),N=require("./liveAudioGraph-0cpHD_Ic.cjs"),w=require("./GingerSplitContexts-C7puo0M7.cjs"),U=require("./selectors-YXnP8Y8g.cjs"),D=require("./ginger-
|
|
2
|
-
//# sourceMappingURL=useGingerChapterProgress-
|
|
1
|
+
"use strict";const t=require("react"),z=require("./useGinger-BXgia32v.cjs"),N=require("./liveAudioGraph-0cpHD_Ic.cjs"),w=require("./GingerSplitContexts-C7puo0M7.cjs"),U=require("./selectors-YXnP8Y8g.cjs"),D=require("./ginger-DFdZGaMi.cjs"),C=new Uint8Array(0),F=new Uint8Array(0);function X(s={}){const{enabled:e=!0,fftSize:r=2048,smoothingTimeConstant:n=.8,minDecibels:u=-100,maxDecibels:c=-30}=s,{audioRef:a,state:o}=z.useGinger(),d=t.useMemo(()=>({fftSize:r,smoothingTimeConstant:n,minDecibels:u,maxDecibels:c}),[r,n,u,c]),[l,m]=t.useState(0),[f,i]=t.useState(null),[h,R]=t.useState(!1),[S,p]=t.useState({frequencyBinCount:0,sampleRate:0}),g=t.useRef(C),v=t.useRef(F),E=t.useCallback(async()=>{const x=y.current;x&&x.state==="suspended"&&await x.resume()},[]),y=t.useRef(null),I=t.useRef(null);return t.useLayoutEffect(()=>{if(!e||typeof window>"u")return;let x=!1,b=null,A=null,T=0;const q=()=>{const k=y.current;k&&R(k.state==="suspended")},V=()=>{if(x)return;const k=I.current,P=g.current,M=v.current;k&&P.length>0&&M.length>0&&(k.getByteFrequencyData(P),k.getByteTimeDomainData(M),m(G=>G+1)),T=requestAnimationFrame(V)},B=()=>{const k=a.current;if(!k||x)return"no-element";try{const{id:P,context:M,analyser:G}=N.attachLiveAnalyser(k,d);b=P,A=k,y.current=M,I.current=G,R(M.state==="suspended"),i(null),M.addEventListener("statechange",q);const L=G.frequencyBinCount,H=G.fftSize;return g.current=new Uint8Array(L),v.current=new Uint8Array(H),p({frequencyBinCount:L,sampleRate:M.sampleRate}),T=requestAnimationFrame(V),"ok"}catch(P){const M=P instanceof Error?P.message:"Failed to attach live analyser";return i(M),y.current=null,I.current=null,g.current=C,v.current=F,p({frequencyBinCount:0,sampleRate:0}),"error"}},K=B();if(K!=="ok"){let k=0;const P=120;let M=0;const G=()=>{if(x)return;const L=B();L==="ok"||L==="error"||(M+=1,!(M>=P)&&(k=requestAnimationFrame(G)))};return K==="no-element"&&(k=requestAnimationFrame(G)),()=>{var L;x=!0,cancelAnimationFrame(k),cancelAnimationFrame(T),b!=null&&A&&N.detachLiveAnalyser(A,b),(L=y.current)==null||L.removeEventListener("statechange",q),y.current=null,I.current=null,g.current=C,v.current=F}}return()=>{var k;x=!0,cancelAnimationFrame(T),b!=null&&A&&N.detachLiveAnalyser(A,b),(k=y.current)==null||k.removeEventListener("statechange",q),y.current=null,I.current=null,g.current=C,v.current=F,p({frequencyBinCount:0,sampleRate:0})}},[e,a,d,o.currentIndex]),{frequencyData:g.current,timeDomainData:v.current,frequencyBinCount:S.frequencyBinCount,sampleRate:S.sampleRate,isSuspended:h,error:f,resume:E,frame:l}}function O(s=!0,e={}){const{togglePlayPause:r,next:n,prev:u}=w.useGingerPlayback(),{toggleMute:c,seek:a,currentTime:o,duration:d}=w.useGingerMedia(),{mute:l,seekForward:m,seekBackward:f}=e;t.useEffect(()=>{if(!s||typeof window>"u")return;const i=(e.playPause??" ").toLowerCase(),h=(e.next??"ArrowRight").toLowerCase(),R=(e.previous??"ArrowLeft").toLowerCase(),S=l==null?void 0:l.toLowerCase(),p=m==null?void 0:m.toLowerCase(),g=f==null?void 0:f.toLowerCase(),v=e.seekSeconds??5,E=y=>{const I=y.target;if(I&&(["INPUT","TEXTAREA","SELECT"].includes(I.tagName)||I.isContentEditable))return;const x=y.key.toLowerCase();if(x===i)y.preventDefault(),r();else if(x===h)y.preventDefault(),n();else if(x===R)y.preventDefault(),u();else if(S&&x===S)y.preventDefault(),c();else if(p&&x===p){y.preventDefault();const b=d>0?d:Number.POSITIVE_INFINITY;a(Math.min(b,o+v))}else g&&x===g&&(y.preventDefault(),a(Math.max(0,o-v)))};return window.addEventListener("keydown",E),()=>window.removeEventListener("keydown",E)},[e.next,e.playPause,e.previous,e.seekSeconds,o,d,s,l,n,u,a,f,m,c,r])}function Y(s){const{durationMs:e,stopAfterTracks:r,respectPause:n=!0,enabled:u=!0,onFire:c}=s,{currentIndex:a,pause:o,isPaused:d}=w.useGingerPlayback(),l=t.useRef(r??0),m=t.useRef(a),f=t.useRef(e??0),i=t.useRef(null);t.useEffect(()=>{l.current=r??0},[r]);const h=t.useRef(e);t.useEffect(()=>{h.current!==e&&(f.current=e??0,h.current=e)},[e]),t.useEffect(()=>{if(!u||!e||e<=0){f.current=e??0,i.current=null;return}if(n&&d){if(i.current!==null){const S=Date.now()-i.current;f.current=Math.max(0,f.current-S),i.current=null}return}i.current=Date.now();const R=setTimeout(()=>{f.current=0,i.current=null,o(),c==null||c()},f.current);return()=>{if(clearTimeout(R),i.current!==null){const S=Date.now()-i.current;f.current=Math.max(0,f.current-S),i.current=null}}},[e,u,d,c,o,n]),t.useEffect(()=>{if(!u||!r||r<=0)return;const R=m.current;m.current=a,a!==R&&(l.current-=1,l.current<=0&&(o(),c==null||c()))},[a,u,c,o,r])}function _(s=!1){const e=w.useGingerState(),r=t.useRef(e);t.useEffect(()=>{if(!s||typeof console>"u")return;const n=r.current;n!==e&&console.debug("[ginger]",{from:{currentIndex:n.currentIndex,isPaused:n.isPaused,currentTime:n.currentTime,repeatMode:n.repeatMode},to:{currentIndex:e.currentIndex,isPaused:e.isPaused,currentTime:e.currentTime,repeatMode:e.repeatMode}}),r.current=e},[s,e])}function j(s){return Math.max(0,Math.min(1,s))}function J(s){const e=w.useGingerMedia(),r=w.useGingerPlayback(),{seek:n}=e,[u,c]=t.useState(0),[a,o]=t.useState(!1),d=U.progressFraction(w.gingerStateFromContextValues(r,e)),l=a?u:d,m=t.useCallback(f=>{if(!(s>0))return;const i=f.currentTarget,h=i.getBoundingClientRect(),R=g=>{const v=j((g-h.left)/h.width);c(v),n(v*s)};o(!0),i.setPointerCapture(f.pointerId),R(f.clientX);const S=g=>R(g.clientX),p=g=>{R(g.clientX),o(!1),i.releasePointerCapture(f.pointerId),i.removeEventListener("pointermove",S),i.removeEventListener("pointerup",p),i.removeEventListener("pointercancel",p)};i.addEventListener("pointermove",S),i.addEventListener("pointerup",p),i.addEventListener("pointercancel",p)},[s,n]);return{fraction:u,displayFraction:l,isDragging:a,onPointerDown:m}}function Q(s={}){const{enabled:e=!0,crossOrigin:r}=s,{tracks:n,currentIndex:u,repeatMode:c,playbackMode:a}=w.useGingerPlayback();t.useEffect(()=>{var m;if(!e||typeof document>"u")return;const o=U.computeNextIndex({tracks:n,currentIndex:u,repeatMode:c,playbackMode:a});if(o===u)return;const d=((m=n[o])==null?void 0:m.fileUrl)??"";if(!d)return;const l=document.createElement("audio");return l.preload="auto",r&&(l.crossOrigin=r),l.src=d,l.load(),()=>{l.removeAttribute("src"),l.load()}},[e,r,n,u,c,a])}function W(s={}){let e=D.createInitialState({tracks:s.tracks??[],currentIndex:s.currentIndex,playlistMeta:s.playlistMeta,isPaused:s.isPaused,isShuffled:s.isShuffled,repeatMode:s.repeatMode,playbackMode:s.playbackMode,volume:s.volume,muted:s.muted,playbackRate:s.playbackRate});const r=new Set,n=a=>{const o=D.gingerReducer(e,a);if(o!==e){e=o;for(const d of r)d(e)}};return{getState:()=>e,dispatch:n,subscribe:a=>(r.add(a),()=>r.delete(a)),init:a=>{n({type:"INIT",payload:a})},clampVolume:D.clampVolume,clampPlaybackRate:D.clampPlaybackRate}}function Z(s={}){const{maxLength:e=50}=s,{tracks:r,currentIndex:n}=w.useGingerPlayback(),[u,c]=t.useState([]),a=t.useRef(null),o=t.useRef(r);o.current=r,t.useEffect(()=>{const l=r[n];if(!l||a.current===n)return;a.current=n;const m={track:l,index:n,playedAt:Date.now()};c(f=>{const i=[...f,m];return i.length>e?i.slice(i.length-e):i})},[n,r,e]);const d=t.useCallback(()=>c([]),[]);return{history:u,clearHistory:d}}function $(){const{setVolume:s,volume:e}=w.useGingerMedia(),[r,n]=t.useState(!1),u=t.useRef(0),c=t.useRef(!1),a=t.useCallback(()=>{cancelAnimationFrame(u.current),c.current=!0,n(!1)},[]);return{fadeVolumeTo:t.useCallback(({targetVolume:d,durationMs:l,onComplete:m})=>{cancelAnimationFrame(u.current),c.current=!1;const f=p=>Math.min(1,Math.max(0,p)),i=f(d),h=performance.now();let R=e;n(!0);const S=p=>{if(c.current)return;const g=p-h,v=Math.min(1,g/Math.max(1,l)),E=R+(i-R)*v;s(f(E)),v<1?u.current=requestAnimationFrame(S):(n(!1),m==null||m())};u.current=requestAnimationFrame(p=>{R=e,S(p)})},[s,e]),cancelFade:a,isFading:r}}function ee(){const{tracks:s,currentIndex:e}=w.useGingerPlayback(),{currentTime:r,duration:n}=w.useGingerMedia(),u=t.useMemo(()=>{var a;return[...((a=s[e])==null?void 0:a.chapters)??[]].filter(o=>o&&Number.isFinite(o.startSeconds)&&o.startSeconds>=0).sort((o,d)=>o.startSeconds-d.startSeconds)},[s,e]);return t.useMemo(()=>{if(u.length===0)return{progress:0,elapsed:0,remaining:0};let c=-1;for(let h=u.length-1;h>=0;h--)if(r>=u[h].startSeconds){c=h;break}if(c===-1)return{progress:0,elapsed:0,remaining:0};const a=u[c],o=u[c+1],d=(o==null?void 0:o.startSeconds)??(n>0?n:r),l=Math.max(0,d-a.startSeconds),m=Math.max(0,r-a.startSeconds),f=Math.max(0,d-r);return{progress:l>0?Math.min(1,m/l):0,elapsed:m,remaining:f}},[u,r,n])}exports.createGingerStore=W;exports.useGingerChapterProgress=ee;exports.useGingerDebugLog=_;exports.useGingerKeyboardShortcuts=O;exports.useGingerLiveAnalyzer=X;exports.useGingerPlaybackHistory=Z;exports.useGingerSleepTimer=Y;exports.useGingerVolumeFade=$;exports.useNextTrackPrefetch=Q;exports.useSeekDrag=J;
|
|
2
|
+
//# sourceMappingURL=useGingerChapterProgress-COLWYX2-.cjs.map
|