@twick/studio 0.15.25 → 0.15.26

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.
@@ -8,7 +8,7 @@ export declare function GenerateCaptionsPanel({ selectedElement, addCaptionsToTi
8
8
  e: number;
9
9
  t: string;
10
10
  }[]) => void;
11
- onGenerateCaptions: (videoElement: VideoElement) => Promise<string | null>;
11
+ onGenerateCaptions: (videoElement: VideoElement, language?: string, wordsPerPhrase?: number) => Promise<string | null>;
12
12
  getCaptionstatus: (reqId: string) => Promise<ICaptionGenerationPollingResponse>;
13
13
  pollingIntervalMs?: number;
14
14
  }): import("react/jsx-runtime").JSX.Element;
@@ -2,7 +2,7 @@ import { VideoElement } from '@twick/timeline';
2
2
  import { ICaptionGenerationPollingResponse, StudioConfig, CaptionEntry } from '../types';
3
3
 
4
4
  declare const useGenerateCaptions: (studioConfig?: StudioConfig) => {
5
- onGenerateCaptions: (videoElement: VideoElement) => Promise<string | null>;
5
+ onGenerateCaptions: (videoElement: VideoElement, language?: string, wordsPerPhrase?: number) => Promise<string | null>;
6
6
  addCaptionsToTimeline: (captions: CaptionEntry[]) => void;
7
7
  getCaptionstatus: (reqId: string) => Promise<ICaptionGenerationPollingResponse>;
8
8
  pollingIntervalMs: number;
@@ -1,4 +1,3 @@
1
- import { VideoElement } from '@twick/timeline';
2
1
  import { ICaptionGenerationPollingResponse, StudioConfig, CaptionEntry } from '../types';
3
2
 
4
3
  declare const useStudioOperation: (studioConfig?: StudioConfig) => {
@@ -8,7 +7,6 @@ declare const useStudioOperation: (studioConfig?: StudioConfig) => {
8
7
  onNewProject: () => void;
9
8
  onExportCaptions: (format: "srt" | "vtt") => Promise<void>;
10
9
  onExportChapters: (format: "youtube" | "json") => Promise<void>;
11
- onGenerateCaptions: (videoElement: VideoElement) => Promise<string | null>;
12
10
  addCaptionsToTimeline: (captions: CaptionEntry[]) => void;
13
11
  getCaptionstatus: (reqId: string) => Promise<ICaptionGenerationPollingResponse>;
14
12
  };
package/dist/index.js CHANGED
@@ -3028,10 +3028,10 @@ const TEXT_STYLE_PRESETS = [
3028
3028
  applyBackground: false
3029
3029
  },
3030
3030
  {
3031
- id: "impact-caption",
3032
- label: "Impact Caption",
3031
+ id: "bold-caption",
3032
+ label: "Bold Caption",
3033
3033
  description: "Bold white with strong outline",
3034
- fontFamily: VideoEditor.AVAILABLE_TEXT_FONTS.IMPACT,
3034
+ fontFamily: VideoEditor.AVAILABLE_TEXT_FONTS.ROBOTO,
3035
3035
  fontSize: 34,
3036
3036
  fontWeight: 700,
3037
3037
  textColor: "#FFFFFF",
@@ -3131,7 +3131,7 @@ const TEXT_STYLE_PRESETS = [
3131
3131
  id: "cta-pill",
3132
3132
  label: "CTA Pill",
3133
3133
  description: "Call-to-action pill",
3134
- fontFamily: VideoEditor.AVAILABLE_TEXT_FONTS.IMPACT,
3134
+ fontFamily: VideoEditor.AVAILABLE_TEXT_FONTS.LUCKIEST_GUY,
3135
3135
  fontSize: 28,
3136
3136
  fontWeight: 700,
3137
3137
  textColor: "#FFFFFF",
@@ -6943,6 +6943,8 @@ function GenerateCaptionsPanel({
6943
6943
  const [isGenerating, setIsGenerating] = react.useState(false);
6944
6944
  const [pollingStatus, setPollingStatus] = react.useState("idle");
6945
6945
  const [errorMessage, setErrorMessage] = react.useState(null);
6946
+ const [selectedLanguage, setSelectedLanguage] = react.useState("auto");
6947
+ const [wordsPerPhrase, setWordsPerPhrase] = react.useState(4);
6946
6948
  const pollingIntervalRef = react.useRef(null);
6947
6949
  const currentReqIdRef = react.useRef(null);
6948
6950
  react.useEffect(() => {
@@ -7003,7 +7005,12 @@ function GenerateCaptionsPanel({
7003
7005
  setPollingStatus("polling");
7004
7006
  const videoElement = selectedElement;
7005
7007
  try {
7006
- const reqId = await onGenerateCaptions(videoElement);
7008
+ const language = selectedLanguage === "auto" ? void 0 : selectedLanguage;
7009
+ const reqId = await onGenerateCaptions(
7010
+ videoElement,
7011
+ language,
7012
+ wordsPerPhrase
7013
+ );
7007
7014
  if (!reqId) {
7008
7015
  setPollingStatus("error");
7009
7016
  setIsGenerating(false);
@@ -7062,6 +7069,46 @@ function GenerateCaptionsPanel({
7062
7069
  /* @__PURE__ */ jsxRuntime.jsx(Volume2, { className: "empty-state-icon" }),
7063
7070
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-text", children: "Audio detected! You can now generate captions" })
7064
7071
  ] }) }) }),
7072
+ !isLoading && containsAudio === true && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-section", children: [
7073
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-dark", htmlFor: "caption-language", children: "Audio Language" }),
7074
+ /* @__PURE__ */ jsxRuntime.jsxs(
7075
+ "select",
7076
+ {
7077
+ id: "caption-language",
7078
+ className: "select-dark",
7079
+ value: selectedLanguage,
7080
+ onChange: (e) => setSelectedLanguage(e.target.value),
7081
+ children: [
7082
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "auto", children: "Auto (detect)" }),
7083
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "english", children: "English" }),
7084
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "italian", children: "Italian" }),
7085
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "spanish", children: "Spanish" }),
7086
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "portuguese", children: "Portuguese" }),
7087
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "french", children: "French" }),
7088
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "german", children: "German" }),
7089
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "turkish", children: "Turkish" }),
7090
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "indonesian", children: "Indonesian" }),
7091
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "hindi", children: "Hindi" })
7092
+ ]
7093
+ }
7094
+ )
7095
+ ] }),
7096
+ !isLoading && containsAudio === true && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-section", children: [
7097
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-dark", htmlFor: "caption-words-per-phrase", children: "Words per phrase" }),
7098
+ /* @__PURE__ */ jsxRuntime.jsx(
7099
+ "select",
7100
+ {
7101
+ id: "caption-words-per-phrase",
7102
+ className: "select-dark",
7103
+ value: String(wordsPerPhrase),
7104
+ onChange: (e) => setWordsPerPhrase(Number(e.target.value) || 4),
7105
+ children: Array.from({ length: 10 }).map((_, index) => {
7106
+ const value = index + 1;
7107
+ return /* @__PURE__ */ jsxRuntime.jsx("option", { value, children: value }, value);
7108
+ })
7109
+ }
7110
+ )
7111
+ ] }),
7065
7112
  !isLoading && isGenerating && pollingStatus === "polling" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-section", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "empty-state-content", children: [
7066
7113
  /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { className: "empty-state-icon animate-spin" }),
7067
7114
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-text", children: "Generating captions... Please wait" })
@@ -7597,15 +7644,6 @@ const useStudioOperation = (studioConfig) => {
7597
7644
  const fileName = `${(projectName || "chapters").replace(/\.json$/i, "")}.${format === "youtube" ? "txt" : "json"}`;
7598
7645
  await saveAsFile(content, "text/plain", fileName);
7599
7646
  };
7600
- const onGenerateCaptions = async (videoElement) => {
7601
- if (studioConfig == null ? void 0 : studioConfig.captionGenerationService) {
7602
- const service = studioConfig.captionGenerationService;
7603
- const reqId = await service.generateCaptions(videoElement, present);
7604
- return reqId;
7605
- }
7606
- alert("Generate captions not supported in demo mode");
7607
- return null;
7608
- };
7609
7647
  const addCaptionsToTimeline = (captions) => {
7610
7648
  var _a;
7611
7649
  const updatedProjectJSON = (_a = studioConfig == null ? void 0 : studioConfig.captionGenerationService) == null ? void 0 : _a.updateProjectWithCaptions(captions);
@@ -7630,7 +7668,6 @@ const useStudioOperation = (studioConfig) => {
7630
7668
  onNewProject,
7631
7669
  onExportCaptions,
7632
7670
  onExportChapters,
7633
- onGenerateCaptions,
7634
7671
  addCaptionsToTimeline,
7635
7672
  getCaptionstatus
7636
7673
  };
@@ -7739,12 +7776,14 @@ function TwickStudio({ studioConfig }) {
7739
7776
  const useGenerateCaptions = (studioConfig) => {
7740
7777
  var _a;
7741
7778
  const { editor, present } = timeline.useTimelineContext();
7742
- const onGenerateCaptions = async (videoElement) => {
7779
+ const onGenerateCaptions = async (videoElement, language, wordsPerPhrase) => {
7743
7780
  if (studioConfig == null ? void 0 : studioConfig.captionGenerationService) {
7744
7781
  const service = studioConfig.captionGenerationService;
7745
7782
  const reqId = await service.generateCaptions(
7746
7783
  videoElement,
7747
- present
7784
+ present,
7785
+ language,
7786
+ wordsPerPhrase
7748
7787
  );
7749
7788
  return reqId;
7750
7789
  }