@vargai/sdk 0.1.1 → 0.1.2

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.
Files changed (46) hide show
  1. package/.github/workflows/ci.yml +23 -0
  2. package/.husky/README.md +102 -0
  3. package/.husky/commit-msg +9 -0
  4. package/.husky/pre-commit +12 -0
  5. package/.husky/pre-push +9 -0
  6. package/.size-limit.json +8 -0
  7. package/.test-hooks.ts +5 -0
  8. package/CONTRIBUTING.md +150 -0
  9. package/LICENSE.md +53 -0
  10. package/README.md +7 -0
  11. package/action/captions/index.ts +202 -12
  12. package/action/captions/tiktok.ts +538 -0
  13. package/action/cut/index.ts +119 -0
  14. package/action/fade/index.ts +116 -0
  15. package/action/merge/index.ts +177 -0
  16. package/action/remove/index.ts +184 -0
  17. package/action/split/index.ts +133 -0
  18. package/action/transition/index.ts +154 -0
  19. package/action/trim/index.ts +117 -0
  20. package/bun.lock +299 -8
  21. package/cli/index.ts +1 -1
  22. package/commitlint.config.js +22 -0
  23. package/index.ts +12 -0
  24. package/lib/ass.ts +547 -0
  25. package/lib/fal.ts +75 -1
  26. package/lib/ffmpeg.ts +400 -0
  27. package/lib/higgsfield/example.ts +22 -29
  28. package/lib/higgsfield/index.ts +3 -2
  29. package/lib/higgsfield/soul.ts +0 -5
  30. package/lib/remotion/SKILL.md +240 -21
  31. package/lib/remotion/cli.ts +34 -0
  32. package/package.json +20 -3
  33. package/pipeline/cookbooks/scripts/animate-frames-parallel.ts +83 -0
  34. package/pipeline/cookbooks/scripts/combine-scenes.sh +53 -0
  35. package/pipeline/cookbooks/scripts/generate-frames-parallel.ts +98 -0
  36. package/pipeline/cookbooks/scripts/still-to-video.sh +37 -0
  37. package/pipeline/cookbooks/text-to-tiktok.md +669 -0
  38. package/scripts/.gitkeep +0 -0
  39. package/service/music/index.ts +29 -14
  40. package/tsconfig.json +1 -1
  41. package/HIGGSFIELD_REWRITE_SUMMARY.md +0 -300
  42. package/TEST_RESULTS.md +0 -122
  43. package/output.txt +0 -1
  44. package/scripts/produce-menopause-campaign.sh +0 -202
  45. package/test-import.ts +0 -7
  46. package/test-services.ts +0 -97
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env bun
2
+
3
+ /**
4
+ * transition action
5
+ * join two videos with a transition effect
6
+ */
7
+
8
+ import { existsSync } from "node:fs";
9
+ import type { ActionMeta } from "../../cli/types";
10
+ import { xfadeVideos } from "../../lib/ffmpeg";
11
+
12
+ export const meta: ActionMeta = {
13
+ name: "transition",
14
+ type: "action",
15
+ description: "join two videos with a transition effect",
16
+ inputType: "video",
17
+ outputType: "video",
18
+ schema: {
19
+ input: {
20
+ type: "object",
21
+ required: ["video1", "video2", "type", "output"],
22
+ properties: {
23
+ video1: {
24
+ type: "string",
25
+ format: "file-path",
26
+ description: "first video file",
27
+ },
28
+ video2: {
29
+ type: "string",
30
+ format: "file-path",
31
+ description: "second video file",
32
+ },
33
+ type: {
34
+ type: "string",
35
+ enum: [
36
+ "crossfade",
37
+ "dissolve",
38
+ "wipeleft",
39
+ "wiperight",
40
+ "slideup",
41
+ "slidedown",
42
+ ],
43
+ description: "transition effect type",
44
+ },
45
+ duration: {
46
+ type: "number",
47
+ default: 1,
48
+ description: "transition duration in seconds",
49
+ },
50
+ fit: {
51
+ type: "string",
52
+ enum: ["pad", "crop", "blur", "stretch"],
53
+ default: "pad",
54
+ description:
55
+ "how to handle different resolutions: pad (black bars), crop (center), blur (TikTok style), stretch",
56
+ },
57
+ output: {
58
+ type: "string",
59
+ format: "file-path",
60
+ description: "output video path",
61
+ },
62
+ },
63
+ },
64
+ output: { type: "string", format: "file-path", description: "video path" },
65
+ },
66
+ async run(options) {
67
+ const { video1, video2, type, duration, fit, output } = options as {
68
+ video1: string;
69
+ video2: string;
70
+ type:
71
+ | "crossfade"
72
+ | "dissolve"
73
+ | "wipeleft"
74
+ | "wiperight"
75
+ | "slideup"
76
+ | "slidedown";
77
+ duration?: number;
78
+ fit?: "pad" | "crop" | "blur" | "stretch";
79
+ output: string;
80
+ };
81
+ return transition({ video1, video2, type, duration, fit, output });
82
+ },
83
+ };
84
+
85
+ export interface TransitionOptions {
86
+ video1: string;
87
+ video2: string;
88
+ type:
89
+ | "crossfade"
90
+ | "dissolve"
91
+ | "wipeleft"
92
+ | "wiperight"
93
+ | "slideup"
94
+ | "slidedown";
95
+ duration?: number;
96
+ fit?: "pad" | "crop" | "blur" | "stretch";
97
+ output: string;
98
+ }
99
+
100
+ export interface TransitionResult {
101
+ output: string;
102
+ transitionType: string;
103
+ transitionDuration: number;
104
+ }
105
+
106
+ /**
107
+ * join two videos with a transition effect
108
+ */
109
+ export async function transition(
110
+ options: TransitionOptions,
111
+ ): Promise<TransitionResult> {
112
+ const { video1, video2, type, duration = 1, fit = "pad", output } = options;
113
+
114
+ if (!video1 || !video2) {
115
+ throw new Error("video1 and video2 are required");
116
+ }
117
+ if (!type) {
118
+ throw new Error("type is required");
119
+ }
120
+ if (!output) {
121
+ throw new Error("output is required");
122
+ }
123
+ if (!existsSync(video1)) {
124
+ throw new Error(`video file not found: ${video1}`);
125
+ }
126
+ if (!existsSync(video2)) {
127
+ throw new Error(`video file not found: ${video2}`);
128
+ }
129
+
130
+ console.log(
131
+ `[transition] applying ${type} effect (${duration}s, fit: ${fit})`,
132
+ );
133
+
134
+ await xfadeVideos({
135
+ input1: video1,
136
+ input2: video2,
137
+ output,
138
+ transition: type,
139
+ duration,
140
+ fit,
141
+ });
142
+
143
+ return {
144
+ output,
145
+ transitionType: type,
146
+ transitionDuration: duration,
147
+ };
148
+ }
149
+
150
+ // cli
151
+ if (import.meta.main) {
152
+ const { runCli } = await import("../../cli/runner");
153
+ runCli(meta);
154
+ }
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env bun
2
+
3
+ /**
4
+ * trim action
5
+ * extract a segment from video (keep only start-end)
6
+ */
7
+
8
+ import { existsSync } from "node:fs";
9
+ import { basename, dirname, extname, join } from "node:path";
10
+ import type { ActionMeta } from "../../cli/types";
11
+ import { trimVideo } from "../../lib/ffmpeg";
12
+
13
+ export const meta: ActionMeta = {
14
+ name: "trim",
15
+ type: "action",
16
+ description: "extract a segment from video (keep only start-end)",
17
+ inputType: "video",
18
+ outputType: "video",
19
+ schema: {
20
+ input: {
21
+ type: "object",
22
+ required: ["video", "start", "end"],
23
+ properties: {
24
+ video: {
25
+ type: "string",
26
+ format: "file-path",
27
+ description: "input video file",
28
+ },
29
+ start: {
30
+ type: "number",
31
+ description: "start time in seconds",
32
+ },
33
+ end: {
34
+ type: "number",
35
+ description: "end time in seconds",
36
+ },
37
+ output: {
38
+ type: "string",
39
+ format: "file-path",
40
+ description: "output video path (auto-generated if not provided)",
41
+ },
42
+ },
43
+ },
44
+ output: { type: "string", format: "file-path", description: "video path" },
45
+ },
46
+ async run(options) {
47
+ const { video, start, end, output } = options as {
48
+ video: string;
49
+ start: number;
50
+ end: number;
51
+ output?: string;
52
+ };
53
+ return trim({ video, start, end, output });
54
+ },
55
+ };
56
+
57
+ export interface TrimOptions {
58
+ video: string;
59
+ start: number;
60
+ end: number;
61
+ output?: string;
62
+ }
63
+
64
+ export interface TrimResult {
65
+ output: string;
66
+ duration: number;
67
+ }
68
+
69
+ /**
70
+ * extract a segment from video
71
+ */
72
+ export async function trim(options: TrimOptions): Promise<TrimResult> {
73
+ const { video, start, end, output } = options;
74
+
75
+ if (!video) {
76
+ throw new Error("video is required");
77
+ }
78
+ if (start === undefined || end === undefined) {
79
+ throw new Error("start and end are required");
80
+ }
81
+ if (start >= end) {
82
+ throw new Error("start must be less than end");
83
+ }
84
+ if (!existsSync(video)) {
85
+ throw new Error(`video file not found: ${video}`);
86
+ }
87
+
88
+ const duration = end - start;
89
+
90
+ // Generate output path if not provided
91
+ const outputPath =
92
+ output ||
93
+ join(
94
+ dirname(video),
95
+ `${basename(video, extname(video))}_trimmed${extname(video)}`,
96
+ );
97
+
98
+ console.log(`[trim] extracting ${start}s - ${end}s (${duration}s)...`);
99
+
100
+ await trimVideo({
101
+ input: video,
102
+ output: outputPath,
103
+ start,
104
+ duration,
105
+ });
106
+
107
+ return {
108
+ output: outputPath,
109
+ duration,
110
+ };
111
+ }
112
+
113
+ // cli
114
+ if (import.meta.main) {
115
+ const { runCli } = await import("../../cli/runner");
116
+ runCli(meta);
117
+ }