@twick/studio 0.15.25 → 0.15.27

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.
@@ -1,5 +1,5 @@
1
1
  import { TrackElement, VideoElement } from '@twick/timeline';
2
- import { ICaptionGenerationPollingResponse } from '../../types';
2
+ import { CaptionPhraseLength, ICaptionGenerationPollingResponse } from '../../types';
3
3
 
4
4
  export declare function GenerateCaptionsPanel({ selectedElement, addCaptionsToTimeline, onGenerateCaptions, getCaptionstatus, pollingIntervalMs, }: {
5
5
  selectedElement: TrackElement;
@@ -7,8 +7,9 @@ export declare function GenerateCaptionsPanel({ selectedElement, addCaptionsToTi
7
7
  s: number;
8
8
  e: number;
9
9
  t: string;
10
+ w?: number[];
10
11
  }[]) => void;
11
- onGenerateCaptions: (videoElement: VideoElement) => Promise<string | null>;
12
+ onGenerateCaptions: (videoElement: VideoElement, language?: string, phraseLength?: CaptionPhraseLength) => Promise<string | null>;
12
13
  getCaptionstatus: (reqId: string) => Promise<ICaptionGenerationPollingResponse>;
13
14
  pollingIntervalMs?: number;
14
15
  }): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import { ProjectJSON, VideoElement } from '@twick/timeline';
2
- import { ICaptionGenerationPollingResponse, ICaptionGenerationService, CaptionEntry } from '../types';
2
+ import { CaptionEntry, CaptionPhraseLength, ICaptionGenerationPollingResponse, ICaptionGenerationService } from '../types';
3
3
 
4
4
  declare class GenerateCaptionsService implements ICaptionGenerationService {
5
5
  /**
@@ -8,13 +8,13 @@ declare class GenerateCaptionsService implements ICaptionGenerationService {
8
8
  */
9
9
  videoElement: VideoElement | null;
10
10
  projectJSON: ProjectJSON | null;
11
- generateSubtiltesApi: (videoUrl: string) => Promise<string>;
11
+ generateSubtiltesApi: (videoUrl: string, language?: string, phraseLength?: CaptionPhraseLength) => Promise<string>;
12
12
  requestStatusApi: (reqId: string) => Promise<ICaptionGenerationPollingResponse>;
13
13
  constructor({ generateSubtiltesApi, requestStatusApi, }: {
14
- generateSubtiltesApi: (videoUrl: string) => Promise<string>;
14
+ generateSubtiltesApi: (videoUrl: string, language?: string, phraseLength?: CaptionPhraseLength) => Promise<string>;
15
15
  requestStatusApi: (reqId: string) => Promise<ICaptionGenerationPollingResponse>;
16
16
  });
17
- generateCaptions(videoElement: VideoElement, projectJSON: ProjectJSON): Promise<string>;
17
+ generateCaptions(videoElement: VideoElement, projectJSON: ProjectJSON, language?: string, phraseLength?: CaptionPhraseLength): Promise<string>;
18
18
  getRequestStatus(reqId: string): Promise<ICaptionGenerationPollingResponse>;
19
19
  updateProjectWithCaptions(captions: CaptionEntry[]): ProjectJSON;
20
20
  generateCaptionVideo(videoUrl: string, videoSize?: {
@@ -1,8 +1,8 @@
1
1
  import { VideoElement } from '@twick/timeline';
2
- import { ICaptionGenerationPollingResponse, StudioConfig, CaptionEntry } from '../types';
2
+ import { ICaptionGenerationPollingResponse, StudioConfig, CaptionEntry, CaptionPhraseLength } from '../types';
3
3
 
4
4
  declare const useGenerateCaptions: (studioConfig?: StudioConfig) => {
5
- onGenerateCaptions: (videoElement: VideoElement) => Promise<string | null>;
5
+ onGenerateCaptions: (videoElement: VideoElement, language?: string, phraseLength?: CaptionPhraseLength) => 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 [phraseLength, setPhraseLength] = react.useState("medium");
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
+ phraseLength
7013
+ );
7007
7014
  if (!reqId) {
7008
7015
  setPollingStatus("error");
7009
7016
  setIsGenerating(false);
@@ -7062,6 +7069,47 @@ 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-phrase-length", children: "Caption length" }),
7098
+ /* @__PURE__ */ jsxRuntime.jsxs(
7099
+ "select",
7100
+ {
7101
+ id: "caption-phrase-length",
7102
+ className: "select-dark",
7103
+ value: phraseLength,
7104
+ onChange: (e) => setPhraseLength(e.target.value),
7105
+ children: [
7106
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "short", children: "Short" }),
7107
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "medium", children: "Medium" }),
7108
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "long", children: "Long" })
7109
+ ]
7110
+ }
7111
+ )
7112
+ ] }),
7065
7113
  !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
7114
  /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { className: "empty-state-icon animate-spin" }),
7067
7115
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-text", children: "Generating captions... Please wait" })
@@ -7597,15 +7645,6 @@ const useStudioOperation = (studioConfig) => {
7597
7645
  const fileName = `${(projectName || "chapters").replace(/\.json$/i, "")}.${format === "youtube" ? "txt" : "json"}`;
7598
7646
  await saveAsFile(content, "text/plain", fileName);
7599
7647
  };
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
7648
  const addCaptionsToTimeline = (captions) => {
7610
7649
  var _a;
7611
7650
  const updatedProjectJSON = (_a = studioConfig == null ? void 0 : studioConfig.captionGenerationService) == null ? void 0 : _a.updateProjectWithCaptions(captions);
@@ -7630,7 +7669,6 @@ const useStudioOperation = (studioConfig) => {
7630
7669
  onNewProject,
7631
7670
  onExportCaptions,
7632
7671
  onExportChapters,
7633
- onGenerateCaptions,
7634
7672
  addCaptionsToTimeline,
7635
7673
  getCaptionstatus
7636
7674
  };
@@ -7739,12 +7777,14 @@ function TwickStudio({ studioConfig }) {
7739
7777
  const useGenerateCaptions = (studioConfig) => {
7740
7778
  var _a;
7741
7779
  const { editor, present } = timeline.useTimelineContext();
7742
- const onGenerateCaptions = async (videoElement) => {
7780
+ const onGenerateCaptions = async (videoElement, language, phraseLength) => {
7743
7781
  if (studioConfig == null ? void 0 : studioConfig.captionGenerationService) {
7744
7782
  const service = studioConfig.captionGenerationService;
7745
7783
  const reqId = await service.generateCaptions(
7746
7784
  videoElement,
7747
- present
7785
+ present,
7786
+ language,
7787
+ phraseLength
7748
7788
  );
7749
7789
  return reqId;
7750
7790
  }