clipugc 1.0.0 → 1.1.0
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/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/stories.d.ts +9 -0
- package/dist/commands/stories.js +165 -0
- package/dist/commands/stories.js.map +1 -0
- package/dist/services/stories.service.d.ts +84 -0
- package/dist/services/stories.service.js +55 -0
- package/dist/services/stories.service.js.map +1 -0
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import { registerImagesCommands } from './commands/images.js';
|
|
|
9
9
|
import { registerAdsCommands } from './commands/ads.js';
|
|
10
10
|
import { registerVideosCommands } from './commands/videos.js';
|
|
11
11
|
import { registerHooksCommands } from './commands/hooks.js';
|
|
12
|
+
import { registerStoriesCommands } from './commands/stories.js';
|
|
12
13
|
export function createCli() {
|
|
13
14
|
const program = new Command();
|
|
14
15
|
program
|
|
@@ -28,6 +29,7 @@ export function createCli() {
|
|
|
28
29
|
registerVideosCommands(program);
|
|
29
30
|
registerAdsCommands(program);
|
|
30
31
|
registerHooksCommands(program);
|
|
32
|
+
registerStoriesCommands(program);
|
|
31
33
|
return program;
|
|
32
34
|
}
|
|
33
35
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,UAAU,SAAS;IACvB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,SAAS,CAAC;SACf,WAAW,CACV,yGAAyG;QACzG,2FAA2F,CAC5F;SACA,OAAO,CAAC,UAAU,EAAE,EAAE,eAAe,EAAE,uBAAuB,CAAC;SAC/D,MAAM,CAAC,QAAQ,EAAE,iCAAiC,CAAC;SACnD,kBAAkB,CAAC,wBAAwB,CAAC;SAC5C,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAElC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,0BAA0B,CAAC,OAAO,CAAC,CAAC;IACpC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC/B,uBAAuB,CAAC,OAAO,CAAC,CAAC;IAEjC,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { ValidationError } from '../utils/errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* `clipugc stories` — ongoing episodic videos of an AI character's life. Each episode's
|
|
5
|
+
* script is drafted for free and only generated after `episodes approve` (charged).
|
|
6
|
+
* Every episode continues the story — and starts on the previous episode's last frame.
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerStoriesCommands(program: Command): void;
|
|
9
|
+
export { ValidationError };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { createApiClient } from '../services/api.js';
|
|
2
|
+
import { approveEpisode, createStory, downloadEpisode, draftEpisode, getEpisode, getStory, listStories, STORY_RESOLUTIONS, } from '../services/stories.service.js';
|
|
3
|
+
import { formatStatus, isJsonMode, printJson, printTable } from '../utils/output.js';
|
|
4
|
+
import { waitForCompletion } from '../utils/poll.js';
|
|
5
|
+
import { ValidationError } from '../utils/errors.js';
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
const SERIES_COLUMNS = [
|
|
8
|
+
{ header: 'STORY ID', value: (s) => s.id },
|
|
9
|
+
{ header: 'Title', value: (s) => s.title },
|
|
10
|
+
{ header: 'Character', value: (s) => s.character?.name },
|
|
11
|
+
{ header: 'Episodes', value: (s) => s.episode_count },
|
|
12
|
+
{ header: 'Quality', value: (s) => (s.resolution === '768P' ? 'HD' : 'Standard') },
|
|
13
|
+
];
|
|
14
|
+
const EPISODE_COLUMNS = [
|
|
15
|
+
{ header: 'EPISODE ID', value: (e) => e.id },
|
|
16
|
+
{ header: '#', value: (e) => e.episode_number },
|
|
17
|
+
{ header: 'Title', value: (e) => e.title },
|
|
18
|
+
{ header: 'Status', value: (e) => formatStatus(e.status) },
|
|
19
|
+
{ header: 'Length', value: (e) => (e.duration_seconds ? `${e.duration_seconds}s` : undefined) },
|
|
20
|
+
];
|
|
21
|
+
function printScript(episode) {
|
|
22
|
+
logger.info('');
|
|
23
|
+
logger.info(`Episode ${episode.episode_number ?? '?'} — ${episode.title ?? 'Untitled'}`);
|
|
24
|
+
(episode.script ?? []).forEach((scene, index) => {
|
|
25
|
+
logger.info(` Scene ${index + 1}: ${scene.action}`);
|
|
26
|
+
if (scene.dialogue)
|
|
27
|
+
logger.info(` She says: "${scene.dialogue}"`);
|
|
28
|
+
});
|
|
29
|
+
logger.info('');
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* `clipugc stories` — ongoing episodic videos of an AI character's life. Each episode's
|
|
33
|
+
* script is drafted for free and only generated after `episodes approve` (charged).
|
|
34
|
+
* Every episode continues the story — and starts on the previous episode's last frame.
|
|
35
|
+
*/
|
|
36
|
+
export function registerStoriesCommands(program) {
|
|
37
|
+
const stories = program
|
|
38
|
+
.command('stories')
|
|
39
|
+
.description("Ongoing story series: your AI character's life, one talking episode at a time");
|
|
40
|
+
stories
|
|
41
|
+
.command('list')
|
|
42
|
+
.description('List your story series')
|
|
43
|
+
.action(async (_opts, cmd) => {
|
|
44
|
+
const json = isJsonMode(cmd);
|
|
45
|
+
const api = await createApiClient();
|
|
46
|
+
const { stories: items, raw } = await listStories(api);
|
|
47
|
+
if (json)
|
|
48
|
+
return printJson(raw);
|
|
49
|
+
printTable(items, SERIES_COLUMNS);
|
|
50
|
+
});
|
|
51
|
+
stories
|
|
52
|
+
.command('create')
|
|
53
|
+
.description('Start a new story series for one of your characters')
|
|
54
|
+
.requiredOption('--character <id>', 'The character the story is about')
|
|
55
|
+
.requiredOption('--title <title>', 'Story title')
|
|
56
|
+
.requiredOption('--premise <premise>', "What her life is about (drives every episode's script)")
|
|
57
|
+
.option('--tone <tone>', 'Optional tone, e.g. "dry humor, cliffhangers"')
|
|
58
|
+
.option('--resolution <res>', `Video quality: ${STORY_RESOLUTIONS.join(' or ')} (default 480P)`)
|
|
59
|
+
.action(async (opts, cmd) => {
|
|
60
|
+
const json = isJsonMode(cmd);
|
|
61
|
+
const api = await createApiClient();
|
|
62
|
+
const series = await createStory(api, {
|
|
63
|
+
characterId: opts.character,
|
|
64
|
+
title: opts.title,
|
|
65
|
+
premise: opts.premise,
|
|
66
|
+
tone: opts.tone,
|
|
67
|
+
resolution: opts.resolution,
|
|
68
|
+
});
|
|
69
|
+
if (json)
|
|
70
|
+
return printJson(series);
|
|
71
|
+
logger.success(`Story ${series.id} created: ${series.title}`);
|
|
72
|
+
logger.info(`Draft the first episode: clipugc stories draft ${series.id}`);
|
|
73
|
+
});
|
|
74
|
+
stories
|
|
75
|
+
.command('show <id>')
|
|
76
|
+
.description('Show a story and its episodes')
|
|
77
|
+
.action(async (id, _opts, cmd) => {
|
|
78
|
+
const json = isJsonMode(cmd);
|
|
79
|
+
const api = await createApiClient();
|
|
80
|
+
const { story, episodes } = await getStory(api, id);
|
|
81
|
+
if (json)
|
|
82
|
+
return printJson({ story, episodes });
|
|
83
|
+
printTable([story], SERIES_COLUMNS);
|
|
84
|
+
if (story.story_summary)
|
|
85
|
+
logger.info(`\nStory so far:\n${story.story_summary}\n`);
|
|
86
|
+
printTable(episodes, EPISODE_COLUMNS);
|
|
87
|
+
});
|
|
88
|
+
stories
|
|
89
|
+
.command('draft <id>')
|
|
90
|
+
.description("Draft the next episode's script (free — nothing is generated yet)")
|
|
91
|
+
.option('--minutes <n>', 'Episode length in minutes: 1, 2 or 5 (default 1)', (v) => Number.parseInt(v, 10))
|
|
92
|
+
.option('--direction <text>', 'Write the plot yourself; omit to let the AI continue the story')
|
|
93
|
+
.action(async (id, opts, cmd) => {
|
|
94
|
+
const json = isJsonMode(cmd);
|
|
95
|
+
const api = await createApiClient();
|
|
96
|
+
const { episode, cost_credits } = await draftEpisode(api, id, {
|
|
97
|
+
minutes: opts.minutes,
|
|
98
|
+
direction: opts.direction,
|
|
99
|
+
});
|
|
100
|
+
if (json)
|
|
101
|
+
return printJson({ episode, cost_credits });
|
|
102
|
+
printScript(episode);
|
|
103
|
+
logger.info(`Generating this episode costs ${cost_credits ?? '?'} credits.`);
|
|
104
|
+
logger.info(`Approve it: clipugc stories approve ${id} ${episode.id} [--wait]`);
|
|
105
|
+
});
|
|
106
|
+
stories
|
|
107
|
+
.command('approve <id> <episodeId>')
|
|
108
|
+
.description('Approve a drafted episode: charges credits and generates it scene by scene')
|
|
109
|
+
.option('--wait', 'Wait until the episode finishes rendering')
|
|
110
|
+
.option('--output <path>', 'With --wait: also download the finished episode here')
|
|
111
|
+
.action(async (id, episodeId, opts, cmd) => {
|
|
112
|
+
const json = isJsonMode(cmd);
|
|
113
|
+
const api = await createApiClient();
|
|
114
|
+
const episode = await approveEpisode(api, id, episodeId);
|
|
115
|
+
if (!opts.wait) {
|
|
116
|
+
if (json)
|
|
117
|
+
return printJson(episode);
|
|
118
|
+
logger.success(`Episode ${episode.episode_number ?? episodeId} is generating.`);
|
|
119
|
+
logger.info(`Check progress: clipugc stories status ${id} ${episodeId}`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const finished = await waitForCompletion(() => getEpisode(api, id, episodeId), {
|
|
123
|
+
label: `Episode ${episode.episode_number ?? episodeId}`,
|
|
124
|
+
intervalMs: 10_000,
|
|
125
|
+
quiet: json,
|
|
126
|
+
});
|
|
127
|
+
if (opts.output || !json) {
|
|
128
|
+
const path = await downloadEpisode(api, id, episodeId, opts.output);
|
|
129
|
+
if (!json)
|
|
130
|
+
logger.success(`Saved to ${path}`);
|
|
131
|
+
}
|
|
132
|
+
if (json)
|
|
133
|
+
printJson(finished);
|
|
134
|
+
});
|
|
135
|
+
stories
|
|
136
|
+
.command('status <id> <episodeId>')
|
|
137
|
+
.description("Check an episode's generation progress")
|
|
138
|
+
.action(async (id, episodeId, _opts, cmd) => {
|
|
139
|
+
const json = isJsonMode(cmd);
|
|
140
|
+
const api = await createApiClient();
|
|
141
|
+
const episode = await getEpisode(api, id, episodeId);
|
|
142
|
+
if (json)
|
|
143
|
+
return printJson(episode);
|
|
144
|
+
printTable([episode], EPISODE_COLUMNS);
|
|
145
|
+
if (episode.status === 'processing') {
|
|
146
|
+
logger.info(`Scenes completed: ${episode.scenes_completed ?? 0}/${episode.scene_count ?? '?'}`);
|
|
147
|
+
}
|
|
148
|
+
if (episode.error)
|
|
149
|
+
logger.warn(`Error: ${episode.error}`);
|
|
150
|
+
});
|
|
151
|
+
stories
|
|
152
|
+
.command('download <id> <episodeId>')
|
|
153
|
+
.description('Download a completed episode')
|
|
154
|
+
.option('--output <path>', 'Where to save the .mp4')
|
|
155
|
+
.action(async (id, episodeId, opts, cmd) => {
|
|
156
|
+
const json = isJsonMode(cmd);
|
|
157
|
+
const api = await createApiClient();
|
|
158
|
+
const path = await downloadEpisode(api, id, episodeId, opts.output);
|
|
159
|
+
if (json)
|
|
160
|
+
return printJson({ saved_to: path });
|
|
161
|
+
logger.success(`Saved to ${path}`);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
export { ValidationError };
|
|
165
|
+
//# sourceMappingURL=stories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stories.js","sourceRoot":"","sources":["../../src/commands/stories.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { ApiClient } from './api.js';
|
|
2
|
+
/**
|
|
3
|
+
* Stories — ongoing episodic videos of an AI character's life (`/stories` endpoints).
|
|
4
|
+
*
|
|
5
|
+
* Flow: create a series → draft an episode script (free) → approve it (charges credits,
|
|
6
|
+
* generates scene-by-scene with native speech) → poll status → download the episode.
|
|
7
|
+
*/
|
|
8
|
+
export interface StorySeries {
|
|
9
|
+
id: number | string;
|
|
10
|
+
title: string;
|
|
11
|
+
premise?: string;
|
|
12
|
+
tone?: string | null;
|
|
13
|
+
/** 480P (standard) | 768P (HD) */
|
|
14
|
+
resolution?: string;
|
|
15
|
+
status?: string;
|
|
16
|
+
episode_count?: number;
|
|
17
|
+
story_summary?: string | null;
|
|
18
|
+
character?: {
|
|
19
|
+
id?: number | string;
|
|
20
|
+
name?: string;
|
|
21
|
+
};
|
|
22
|
+
created_at?: string;
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface StoryScene {
|
|
26
|
+
action: string;
|
|
27
|
+
dialogue?: string | null;
|
|
28
|
+
location?: string | null;
|
|
29
|
+
}
|
|
30
|
+
export interface StoryEpisode {
|
|
31
|
+
id: number | string;
|
|
32
|
+
story_series_id?: number | string;
|
|
33
|
+
episode_number?: number;
|
|
34
|
+
title?: string | null;
|
|
35
|
+
/** draft | script_ready | processing | stitching | completed | failed */
|
|
36
|
+
status: string;
|
|
37
|
+
script?: StoryScene[];
|
|
38
|
+
summary?: string | null;
|
|
39
|
+
scene_count?: number;
|
|
40
|
+
scenes_completed?: number;
|
|
41
|
+
duration_seconds?: number;
|
|
42
|
+
credits_charged?: number | null;
|
|
43
|
+
video_url?: string | null;
|
|
44
|
+
thumbnail_url?: string | null;
|
|
45
|
+
error?: string | null;
|
|
46
|
+
created_at?: string;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
}
|
|
49
|
+
export declare const STORY_RESOLUTIONS: string[];
|
|
50
|
+
/** GET /stories */
|
|
51
|
+
export declare function listStories(api: ApiClient): Promise<{
|
|
52
|
+
stories: StorySeries[];
|
|
53
|
+
raw: unknown;
|
|
54
|
+
}>;
|
|
55
|
+
/** POST /stories */
|
|
56
|
+
export declare function createStory(api: ApiClient, input: {
|
|
57
|
+
characterId: string;
|
|
58
|
+
title: string;
|
|
59
|
+
premise: string;
|
|
60
|
+
tone?: string;
|
|
61
|
+
resolution?: string;
|
|
62
|
+
}): Promise<StorySeries>;
|
|
63
|
+
/** GET /stories/{id} — the series plus all its episodes. */
|
|
64
|
+
export declare function getStory(api: ApiClient, id: string): Promise<{
|
|
65
|
+
story: StorySeries;
|
|
66
|
+
episodes: StoryEpisode[];
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* POST /stories/{id}/episodes — draft the next episode's script. Free. Pass `direction`
|
|
70
|
+
* to write the plot yourself; leave it out and the AI continues the story.
|
|
71
|
+
*/
|
|
72
|
+
export declare function draftEpisode(api: ApiClient, id: string, opts?: {
|
|
73
|
+
minutes?: number;
|
|
74
|
+
direction?: string;
|
|
75
|
+
}): Promise<{
|
|
76
|
+
episode: StoryEpisode;
|
|
77
|
+
cost_credits?: number;
|
|
78
|
+
}>;
|
|
79
|
+
/** POST /stories/{id}/episodes/{episodeId}/approve — charges credits, starts generation. */
|
|
80
|
+
export declare function approveEpisode(api: ApiClient, id: string, episodeId: string, scenes?: StoryScene[]): Promise<StoryEpisode>;
|
|
81
|
+
/** GET /stories/{id}/episodes/{episodeId} — status; also nudges a lost-webhook scene along. */
|
|
82
|
+
export declare function getEpisode(api: ApiClient, id: string, episodeId: string): Promise<StoryEpisode>;
|
|
83
|
+
/** Save a completed episode's video to disk (the URL is short-lived — fetch fresh first). */
|
|
84
|
+
export declare function downloadEpisode(api: ApiClient, id: string, episodeId: string, outPath?: string): Promise<string>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ValidationError } from '../utils/errors.js';
|
|
2
|
+
import { saveUrlToFile } from '../utils/download.js';
|
|
3
|
+
export const STORY_RESOLUTIONS = ['480P', '768P'];
|
|
4
|
+
/** GET /stories */
|
|
5
|
+
export async function listStories(api) {
|
|
6
|
+
const raw = await api.get('/stories');
|
|
7
|
+
return { stories: raw?.stories ?? [], raw };
|
|
8
|
+
}
|
|
9
|
+
/** POST /stories */
|
|
10
|
+
export async function createStory(api, input) {
|
|
11
|
+
if (input.resolution !== undefined && !STORY_RESOLUTIONS.includes(input.resolution)) {
|
|
12
|
+
throw new ValidationError(`--resolution must be one of: ${STORY_RESOLUTIONS.join(', ')} (got "${input.resolution}").`);
|
|
13
|
+
}
|
|
14
|
+
return api.post('/stories', {
|
|
15
|
+
body: {
|
|
16
|
+
character_id: Number(input.characterId),
|
|
17
|
+
title: input.title,
|
|
18
|
+
premise: input.premise,
|
|
19
|
+
tone: input.tone,
|
|
20
|
+
resolution: input.resolution,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/** GET /stories/{id} — the series plus all its episodes. */
|
|
25
|
+
export async function getStory(api, id) {
|
|
26
|
+
const data = await api.get(`/stories/${encodeURIComponent(id)}`);
|
|
27
|
+
return { story: data.story, episodes: data.episodes ?? [] };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* POST /stories/{id}/episodes — draft the next episode's script. Free. Pass `direction`
|
|
31
|
+
* to write the plot yourself; leave it out and the AI continues the story.
|
|
32
|
+
*/
|
|
33
|
+
export async function draftEpisode(api, id, opts = {}) {
|
|
34
|
+
if (opts.minutes !== undefined && (!Number.isInteger(opts.minutes) || opts.minutes < 1 || opts.minutes > 5)) {
|
|
35
|
+
throw new ValidationError('--minutes must be an integer between 1 and 5.');
|
|
36
|
+
}
|
|
37
|
+
return api.post(`/stories/${encodeURIComponent(id)}/episodes`, { body: { minutes: opts.minutes, direction: opts.direction } });
|
|
38
|
+
}
|
|
39
|
+
/** POST /stories/{id}/episodes/{episodeId}/approve — charges credits, starts generation. */
|
|
40
|
+
export async function approveEpisode(api, id, episodeId, scenes) {
|
|
41
|
+
return api.post(`/stories/${encodeURIComponent(id)}/episodes/${encodeURIComponent(episodeId)}/approve`, scenes && scenes.length > 0 ? { body: { scenes } } : undefined);
|
|
42
|
+
}
|
|
43
|
+
/** GET /stories/{id}/episodes/{episodeId} — status; also nudges a lost-webhook scene along. */
|
|
44
|
+
export async function getEpisode(api, id, episodeId) {
|
|
45
|
+
return api.get(`/stories/${encodeURIComponent(id)}/episodes/${encodeURIComponent(episodeId)}`);
|
|
46
|
+
}
|
|
47
|
+
/** Save a completed episode's video to disk (the URL is short-lived — fetch fresh first). */
|
|
48
|
+
export async function downloadEpisode(api, id, episodeId, outPath) {
|
|
49
|
+
const episode = await getEpisode(api, id, episodeId);
|
|
50
|
+
if (episode.status !== 'completed' || !episode.video_url) {
|
|
51
|
+
throw new ValidationError(`Episode ${episodeId} has no downloadable video yet (status: ${episode.status}).`);
|
|
52
|
+
}
|
|
53
|
+
return saveUrlToFile(episode.video_url, outPath ?? `story_${id}_episode_${episode.episode_number ?? episodeId}.mp4`);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=stories.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stories.service.js","sourceRoot":"","sources":["../../src/services/stories.service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clipugc",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Official CLI for ClipUGC
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Official CLI for ClipUGC — create AI characters, generate looks, and produce UGC-style videos for your mobile app from the terminal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"clipugc": "./dist/index.js"
|