From 2869a7daba329b06c8bf1e77506b90eea42cef84 Mon Sep 17 00:00:00 2001
From: Pushpender Saini <54404738+PushpenderSaini0@users.noreply.github.com>
Date: Thu, 22 Jun 2023 16:50:11 +0530
Subject: [PATCH] Add SRT export
---
src/components/Transcript.tsx | 87 +++++++++++++++++++++--------------
src/utils/AudioUtils.ts | 57 +++++++++++++++++++----
2 files changed, 99 insertions(+), 45 deletions(-)
diff --git a/src/components/Transcript.tsx b/src/components/Transcript.tsx
index 4ba47721..7aed8073 100644
--- a/src/components/Transcript.tsx
+++ b/src/components/Transcript.tsx
@@ -1,7 +1,7 @@
import { useRef, useEffect } from "react";
import { TranscriberData } from "../hooks/useTranscriber";
-import { formatAudioTimestamp } from "../utils/AudioUtils";
+import { formatAudioTimestamp, formatSrtTimeRange } from "../utils/AudioUtils";
interface Props {
transcribedData: TranscriberData | undefined;
@@ -38,14 +38,32 @@ export default function Transcript({ transcribedData }: Props) {
const blob = new Blob([jsonData], { type: "application/json" });
saveBlob(blob, "transcript.json");
};
+ const exportSRT = () => {
+ let chunks = transcribedData?.chunks ?? [];
+ let srt = "";
+ for (let i = 0; i < chunks.length; i++) {
+ srt += `${i + 1}\n`;
+ // TODO - Check why 2nd timestamp is number | null
+ srt += `${formatSrtTimeRange(chunks[i].timestamp[0], chunks[i].timestamp[1] ?? chunks[i].timestamp[0])}\n`;
+ srt += `${chunks[i].text}\n\n`;
+ }
+ const blob = new Blob([srt], { type: "text/plain" });
+ saveBlob(blob, "transcript.srt");
+ }
+
+ const exportButtons = [
+ { name: "TXT", onClick: exportTXT, },
+ { name: "JSON", onClick: exportJSON, },
+ { name: "SRT", onClick: exportSRT, },
+ ]
// Scroll to the bottom when the component updates
useEffect(() => {
if (divRef.current) {
const diff = Math.abs(
divRef.current.offsetHeight +
- divRef.current.scrollTop -
- divRef.current.scrollHeight,
+ divRef.current.scrollTop -
+ divRef.current.scrollHeight,
);
if (diff <= 64) {
@@ -56,38 +74,37 @@ export default function Transcript({ transcribedData }: Props) {
});
return (
-
- {transcribedData &&
- transcribedData.chunks.map((chunk, i) => (
-
-
- {formatAudioTimestamp(chunk.timestamp[0])}
+ <>
+
+ {transcribedData &&
+ transcribedData.chunks.map((chunk, i) => (
+
+
+ {formatAudioTimestamp(chunk.timestamp[0])}
+
+ {chunk.text}
- {chunk.text}
-
- ))}
- {transcribedData && !transcribedData.isBusy && (
-
-
-
-
- )}
-
+ ))}
+
+ {
+ transcribedData && !transcribedData.isBusy && (
+ < div className='w-full text-right mx-2'>
+ {exportButtons.map((button, i) => (
+
+ ))}
+
+ )
+ }
+ >
);
}
diff --git a/src/utils/AudioUtils.ts b/src/utils/AudioUtils.ts
index 82e848b6..307f4945 100644
--- a/src/utils/AudioUtils.ts
+++ b/src/utils/AudioUtils.ts
@@ -1,14 +1,51 @@
-function padTime(time: number) {
- return String(time).padStart(2, "0");
+const HOURS_IN_SECONDS = 3600;
+const MINUTES_IN_SECONDS = 60;
+
+function padTime(time: number, padding: number = 2) {
+ return String(time).padStart(padding, "0");
+}
+
+function formatTimestamp(time: number) {
+
+ const hours = Math.floor(time / HOURS_IN_SECONDS);
+ const hoursRemainder = time - hours * HOURS_IN_SECONDS;
+
+ const minutes = Math.floor(hoursRemainder / MINUTES_IN_SECONDS);
+ const minutesRemainder = hoursRemainder - minutes * MINUTES_IN_SECONDS;
+
+ const seconds = Math.floor(minutesRemainder);
+ const secondsRemainder = minutesRemainder - seconds;
+
+ const milliseconds = Math.floor(secondsRemainder * 1000);
+
+ return { hours, minutes, seconds, milliseconds };
}
export function formatAudioTimestamp(time: number) {
- const hours = (time / (60 * 60)) | 0;
- time -= hours * (60 * 60);
- const minutes = (time / 60) | 0;
- time -= minutes * 60;
- const seconds = time | 0;
- return `${hours ? padTime(hours) + ":" : ""}${padTime(minutes)}:${padTime(
- seconds,
- )}`;
+
+ const { hours, minutes, seconds } = formatTimestamp(time);
+
+ // Hide hours if not needed
+ const hoursString = hours ? padTime(hours) + ":" : "";
+ const minutesString = padTime(minutes) + ":";
+ const secondsString = padTime(seconds);
+
+ return `${hoursString}${minutesString}${secondsString}`;
}
+
+function formatSrtTimestamp(time: number) {
+
+ const { hours, minutes, seconds, milliseconds } = formatTimestamp(time);
+
+ const hoursString = padTime(hours) + ":";
+ const minutesString = padTime(minutes) + ":";
+ const secondsString = padTime(seconds) + ",";
+ const millisecondsString = padTime(milliseconds, 3);
+
+ return `${hoursString}${minutesString}${secondsString}${millisecondsString}`;
+}
+
+
+export function formatSrtTimeRange(start: number, end: number) {
+ return `${formatSrtTimestamp(start)} --> ${formatSrtTimestamp(end)}`;
+}
\ No newline at end of file