@x12i/youtube-video-uploader-cli 1.2.0 → 1.4.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/src/index.d.ts CHANGED
@@ -8,11 +8,29 @@ export interface VideoMetadata {
8
8
  tags: string[];
9
9
  categoryId?: string;
10
10
  privacyStatus?: 'private' | 'unlisted' | 'public';
11
+ defaultLanguage?: string;
12
+ defaultAudioLanguage?: string;
13
+ license?: string;
14
+ embeddable?: boolean;
15
+ publicStatsViewable?: boolean;
16
+ selfDeclaredMadeForKids?: boolean;
17
+ notifySubscribers?: boolean;
18
+ trackNumber?: number;
19
+ playlistPosition?: number;
11
20
  filePath: string;
12
21
  }
13
22
 
23
+ export interface PlaylistConfig {
24
+ key?: string;
25
+ snippet?: Record<string, any>;
26
+ status?: Record<string, any>;
27
+ publishStatusAfterQc?: string;
28
+ }
29
+
14
30
  export interface MetadataConfig {
15
31
  playlistId: string | null;
32
+ playlist?: PlaylistConfig | null;
33
+ templateVariables: Record<string, string | null>;
16
34
  privacyStatus: 'private' | 'unlisted' | 'public';
17
35
  categoryId: string;
18
36
  videos: VideoMetadata[];
@@ -22,6 +40,9 @@ export interface BatchUploadOptions {
22
40
  metadataFile?: string;
23
41
  force?: boolean;
24
42
  dryRun?: boolean;
43
+ limit?: number;
44
+ safeQuota?: boolean;
45
+ maxQuota?: number;
25
46
  tokenFile?: string;
26
47
  clientSecretsFile?: string;
27
48
  clientId?: string;
@@ -34,19 +55,26 @@ export interface BatchUploadResult {
34
55
  total: number;
35
56
  uploaded: Array<{ filename: string; videoId: string; url: string; addedToPlaylist: boolean }>;
36
57
  skipped: Array<{ filename: string; videoId?: string; reason: string }>;
58
+ deferred: Array<{ filename: string; reason: string }>;
37
59
  failed: Array<{ filename: string; error: Error }>;
38
60
  estimatedQuota: number;
61
+ playlistId?: string | null;
39
62
  }
40
63
 
41
64
  export declare class UploadState {
42
65
  constructor(targetFolder?: string, stateFilename?: string);
66
+ listUploads(): Array<{ filename: string; videoId: string; uploadedAt: string; playlistId?: string }>;
43
67
  getUpload(filename: string): { videoId: string; uploadedAt: string; playlistId?: string } | null;
44
68
  recordUpload(filename: string, videoId: string, playlistId?: string | null): void;
45
69
  recordPlaylist(filename: string, playlistId: string): void;
70
+ getPlaylist(key?: string): { playlistId: string; url: string; createdAt: string | null } | null;
71
+ recordPlaylistInfo(key: string, playlistId: string, url?: string): void;
46
72
  save(): void;
47
73
  }
48
74
 
49
75
  export function loadMetadata(targetFolder?: string, customMetadataPath?: string): MetadataConfig;
76
+ export function interpolateTemplates(text: string, variables?: Record<string, string | null | undefined>): string;
77
+
50
78
  export function authenticate(options?: {
51
79
  clientId?: string;
52
80
  clientSecret?: string;
@@ -67,9 +95,16 @@ export function uploadVideo(
67
95
  export function addToPlaylist(
68
96
  youtube: youtube_v3.Youtube,
69
97
  playlistId: string,
70
- videoId: string
98
+ videoId: string,
99
+ position?: number
71
100
  ): Promise<any>;
72
101
 
102
+ export function createPlaylist(
103
+ youtube: youtube_v3.Youtube,
104
+ snippet: Record<string, any>,
105
+ status?: Record<string, any>
106
+ ): Promise<{ playlistId: string; url: string; data: any }>;
107
+
73
108
  export function batchUpload(
74
109
  targetFolder?: string,
75
110
  options?: BatchUploadOptions
@@ -77,10 +112,13 @@ export function batchUpload(
77
112
 
78
113
  export const QUOTA_PER_VIDEO_UPLOAD: number;
79
114
  export const QUOTA_PER_PLAYLIST_ITEM: number;
115
+ export const QUOTA_PER_PLAYLIST_CREATE: number;
80
116
  export const DAILY_DEFAULT_QUOTA: number;
81
117
  export const DEFAULT_CATEGORY_ID: string;
82
118
  export const DEFAULT_PRIVACY_STATUS: string;
83
119
  export const VALID_PRIVACY_STATUSES: Set<string>;
120
+ export const DEFAULT_STATE_FILENAME: string;
121
+ export const YOUTUBE_SCOPES: string[];
84
122
 
85
123
  // ─── Playlist video swap ───────────────────────────────────────────────────
86
124
 
@@ -118,7 +156,7 @@ export class SwapStore {
118
156
  export function uploadNewVideo(
119
157
  youtube: youtube_v3.Youtube,
120
158
  newVideoPath: string,
121
- opts?: { oldVideoId?: string; meta?: VideoMetadata; retries?: number }
159
+ opts?: { oldVideoId?: string; meta?: Partial<VideoMetadata>; retries?: number }
122
160
  ): Promise<{ videoId: string; url: string }>;
123
161
 
124
162
  export function findPlaylistItem(
@@ -144,7 +182,7 @@ export function swapSong(params: {
144
182
  newVideoPath: string;
145
183
  playlistId: string;
146
184
  oldVideoId: string;
147
- meta?: VideoMetadata;
185
+ meta?: Partial<VideoMetadata>;
148
186
  stateDir?: string;
149
187
  stateFile?: string;
150
188
  fresh?: boolean;
@@ -154,3 +192,494 @@ export function swapSong(params: {
154
192
  export const QUOTA_PER_SWAP: number;
155
193
  export const DEFAULT_SWAP_STATE_FILENAME: string;
156
194
  export const SWAP_STATUSES: string[];
195
+
196
+ // ─── Metadata & Title Updates ──────────────────────────────────────────────
197
+
198
+ export interface BatchUpdateMetadataOptions {
199
+ titlePostfix?: string;
200
+ titlePrefix?: string;
201
+ playlistPostfix?: string;
202
+ playlistTitle?: string;
203
+ metadataFile?: string;
204
+ updateLocalMetadata?: boolean;
205
+ syncMetadata?: boolean;
206
+ singleVideoId?: string;
207
+ singleVideoTitle?: string;
208
+ singlePlaylistId?: string;
209
+ dryRun?: boolean;
210
+ tokenFile?: string;
211
+ clientSecretsFile?: string;
212
+ clientId?: string;
213
+ clientSecret?: string;
214
+ onEvent?: (event: { type: string; [key: string]: any }) => void;
215
+ }
216
+
217
+ export interface VideoPlanItem {
218
+ filename: string;
219
+ videoId: string;
220
+ oldTitle: string;
221
+ newTitle: string;
222
+ changed: boolean;
223
+ }
224
+
225
+ export interface PlaylistPlanItem {
226
+ playlistId: string;
227
+ oldTitle: string;
228
+ newTitle: string;
229
+ changed: boolean;
230
+ }
231
+
232
+ export interface BatchUpdateMetadataResult {
233
+ playlist?: PlaylistPlanItem | null;
234
+ videos: VideoPlanItem[];
235
+ estimatedQuota: number;
236
+ dryRun: boolean;
237
+ }
238
+
239
+ export function updateVideoSnippet(
240
+ youtube: youtube_v3.Youtube,
241
+ videoId: string,
242
+ snippetUpdates: Record<string, any>
243
+ ): Promise<{ videoId: string; title: string; data: any }>;
244
+
245
+ export function updateVideoTitle(
246
+ youtube: youtube_v3.Youtube,
247
+ videoId: string,
248
+ newTitle: string
249
+ ): Promise<{ videoId: string; title: string; data: any }>;
250
+
251
+ export function updatePlaylistSnippet(
252
+ youtube: youtube_v3.Youtube,
253
+ playlistId: string,
254
+ snippetUpdates: Record<string, any>
255
+ ): Promise<{ playlistId: string; title: string; data: any }>;
256
+
257
+ export function updatePlaylistTitle(
258
+ youtube: youtube_v3.Youtube,
259
+ playlistId: string,
260
+ newTitle: string
261
+ ): Promise<{ playlistId: string; title: string; data: any }>;
262
+
263
+ export function batchUpdateMetadata(
264
+ targetFolder?: string,
265
+ options?: BatchUpdateMetadataOptions
266
+ ): Promise<BatchUpdateMetadataResult>;
267
+
268
+ export const QUOTA_PER_VIDEO_UPDATE: number;
269
+ export const QUOTA_PER_PLAYLIST_UPDATE: number;
270
+ export const QUOTA_PER_LIST: number;
271
+
272
+ // ─── Automated Stock Media Sourcing (Pexels + Pixabay) ──────────────────────
273
+
274
+ export interface UnifiedResult {
275
+ provider: 'pexels' | 'pixabay';
276
+ id: string;
277
+ type: 'video' | 'photo';
278
+ rank: number;
279
+ pageUrl: string;
280
+ previewUrl: string;
281
+ downloadUrl: string;
282
+ width: number;
283
+ height: number;
284
+ duration?: number;
285
+ orientation: 'landscape' | 'portrait' | 'square';
286
+ tags: string[];
287
+ creator: { name: string; profileUrl?: string };
288
+ license: 'Pexels License' | 'Pixabay Content License';
289
+ raw: unknown;
290
+ }
291
+
292
+ export interface MediaSearchOptions {
293
+ query: string;
294
+ type?: 'video' | 'photo';
295
+ provider?: 'auto' | 'pexels' | 'pixabay';
296
+ mergeStrategy?: 'fallback' | 'merge';
297
+ providerOrder?: Array<'pexels' | 'pixabay'>;
298
+ orientation?: 'landscape' | 'portrait' | 'square';
299
+ page?: number;
300
+ perPage?: number;
301
+ safeSearch?: boolean;
302
+ pexelsKey?: string;
303
+ pixabayKey?: string;
304
+ useCache?: boolean;
305
+ cacheDir?: string;
306
+ fetchFn?: typeof fetch;
307
+ }
308
+
309
+ export interface CandidateCriteria {
310
+ preferredWidth?: number;
311
+ preferredHeight?: number;
312
+ minWidth?: number;
313
+ minHeight?: number;
314
+ orientation?: 'landscape' | 'portrait' | 'square';
315
+ targetDuration?: number;
316
+ minDuration?: number;
317
+ maxDuration?: number;
318
+ avoidReuse?: boolean;
319
+ cacheDir?: string;
320
+ usedAssetSet?: Set<string>;
321
+ providerOrder?: Array<'pexels' | 'pixabay'>;
322
+ }
323
+
324
+ export interface CandidateScore {
325
+ score: number;
326
+ breakdown: {
327
+ rank: number;
328
+ resolution: number;
329
+ orientation: number;
330
+ duration: number;
331
+ novelty: number;
332
+ };
333
+ }
334
+
335
+ export interface RankedCandidate {
336
+ candidate: UnifiedResult;
337
+ score: number;
338
+ breakdown: CandidateScore['breakdown'];
339
+ }
340
+
341
+ export interface ComposeVideoOptions {
342
+ backgroundPath: string;
343
+ audioPath: string;
344
+ outputPath: string;
345
+ mode?: 'video-loop' | 'video-trim' | 'ken-burns';
346
+ targetWidth?: number;
347
+ targetHeight?: number;
348
+ fps?: number;
349
+ dryRun?: boolean;
350
+ onProgress?: (progress: { percent?: number; timemark?: string }) => void;
351
+ }
352
+
353
+ export interface ResolveMediaOptions {
354
+ compose?: boolean;
355
+ force?: boolean;
356
+ dryRun?: boolean;
357
+ allowRepeatMedia?: boolean;
358
+ provider?: 'auto' | 'pexels' | 'pixabay';
359
+ type?: 'video' | 'photo';
360
+ orientation?: 'landscape' | 'portrait' | 'square';
361
+ cacheDir?: string;
362
+ pexelsKey?: string;
363
+ pixabayKey?: string;
364
+ autoMedia?: boolean;
365
+ onEvent?: (event: { type: string; [key: string]: any }) => void;
366
+ }
367
+
368
+ export interface ResolvedMediaItem {
369
+ songKey: string;
370
+ resolvedMedia: {
371
+ provider: 'pexels' | 'pixabay';
372
+ assetId: string;
373
+ type: 'video' | 'photo';
374
+ pageUrl: string;
375
+ localPath: string;
376
+ width: number;
377
+ height: number;
378
+ duration?: number;
379
+ license: string;
380
+ credit: string;
381
+ resolvedAt: string;
382
+ };
383
+ generatedVideoPath?: string;
384
+ }
385
+
386
+ export interface ResolveMediaResult {
387
+ resolved: ResolvedMediaItem[];
388
+ skipped: Array<{ songKey: string; reason: string }>;
389
+ errors: Array<{ songKey: string; error: string }>;
390
+ }
391
+
392
+ export function searchPexels(options: {
393
+ query: string;
394
+ type?: 'video' | 'photo';
395
+ orientation?: 'landscape' | 'portrait' | 'square';
396
+ page?: number;
397
+ perPage?: number;
398
+ apiKey: string;
399
+ fetchFn?: typeof fetch;
400
+ }): Promise<UnifiedResult[]>;
401
+
402
+ export function searchPixabay(options: {
403
+ query: string;
404
+ type?: 'video' | 'photo';
405
+ orientation?: 'landscape' | 'portrait' | 'square';
406
+ page?: number;
407
+ perPage?: number;
408
+ safeSearch?: boolean;
409
+ apiKey: string;
410
+ fetchFn?: typeof fetch;
411
+ }): Promise<UnifiedResult[]>;
412
+
413
+ export function searchMedia(options: MediaSearchOptions): Promise<UnifiedResult[]>;
414
+
415
+ export function resolveProviderCredentials(options?: {
416
+ pexelsKey?: string;
417
+ pixabayKey?: string;
418
+ providerOrder?: Array<'pexels' | 'pixabay'>;
419
+ }): {
420
+ pexelsKey?: string;
421
+ pixabayKey?: string;
422
+ providerOrder: Array<'pexels' | 'pixabay'>;
423
+ };
424
+
425
+ export const DEFAULT_MEDIA_CACHE_DIR: string;
426
+ export const CACHE_TTL_MS: number;
427
+
428
+ export function createSearchCacheKey(params: {
429
+ provider: string;
430
+ type: string;
431
+ query: string;
432
+ orientation?: string;
433
+ }): string;
434
+
435
+ export function getCachedSearch(cacheDir: string, cacheKey: string, ttlMs?: number): any[] | null;
436
+ export function setCachedSearch(cacheDir: string, cacheKey: string, results: any[]): void;
437
+ export function readUsedAssetsLedger(cacheDir?: string): Record<string, { provider: string; assetId: string; usedAt: string; songKey?: string }>;
438
+ export function isAssetUsed(cacheDir: string, provider: string, assetId: string): boolean;
439
+ export function recordUsedAsset(cacheDir: string, assetInfo: { provider: string; assetId: string; songKey?: string }): void;
440
+
441
+ export function scoreCandidate(candidate: UnifiedResult, criteria?: CandidateCriteria): CandidateScore;
442
+ export function rankCandidates(results?: UnifiedResult[], criteria?: CandidateCriteria): RankedCandidate[];
443
+ export function selectBest(results?: UnifiedResult[], criteria?: CandidateCriteria): UnifiedResult | null;
444
+
445
+ export function inferExtension(contentType?: string, url?: string, type?: 'video' | 'photo'): string;
446
+ export function downloadAsset(
447
+ asset: UnifiedResult,
448
+ options?: {
449
+ cacheDir?: string;
450
+ targetPath?: string;
451
+ force?: boolean;
452
+ maxRetries?: number;
453
+ fetchFn?: typeof fetch;
454
+ }
455
+ ): Promise<{ localPath: string; size: number; ext: string; fromCache: boolean }>;
456
+
457
+ export function getMediaDuration(filePath: string): Promise<number>;
458
+ export function composeVideo(options: ComposeVideoOptions): Promise<{ outputPath: string; duration: number; dryRun?: boolean; command?: string }>;
459
+
460
+ export function deriveSearchQuery(item?: {
461
+ title?: string;
462
+ tags?: string[];
463
+ artist?: string;
464
+ album?: { title?: string };
465
+ filename?: string;
466
+ }): string;
467
+
468
+ export function formatMediaCredit(asset: UnifiedResult): string;
469
+ export function writeAttributionsFile(targetDir: string, resolvedItems: Array<{ songKey: string; resolvedMedia: object }>): void;
470
+ export function resolveMediaForMetadata(metadataFilePathOrDir: string, options?: ResolveMediaOptions): Promise<ResolveMediaResult>;
471
+
472
+ // ─── Batch Video Actions Pipeline ──────────────────────────────────────────
473
+
474
+ export interface ShortenAction {
475
+ type: 'shorten';
476
+ cutPoint: string | number;
477
+ fadeDuration?: number;
478
+ paddingDuration?: number;
479
+ paddingFill?: 'black' | 'freeze-frame';
480
+ fadeTargets?: Array<'audio' | 'video'>;
481
+ }
482
+
483
+ export interface ReplaceBackgroundAction {
484
+ type: 'replace-background';
485
+ query?: string;
486
+ provider?: 'pexels' | 'pixabay' | 'auto';
487
+ orientation?: 'landscape' | 'portrait' | 'square';
488
+ mode?: 'video-loop' | 'video-trim' | 'ken-burns';
489
+ mediaType?: 'video' | 'photo';
490
+ avoidReuse?: boolean;
491
+ }
492
+
493
+ export interface JourneyOverlayAction {
494
+ type: 'journey-overlay';
495
+ centerText?: string;
496
+ centerConcepts?: string[];
497
+ conceptsDisplayMode?: 'intro' | 'full';
498
+ conceptDisplaySeconds?: number;
499
+ conceptFadeSeconds?: number;
500
+ showSidebar?: boolean;
501
+ }
502
+
503
+ export type VideoAction = ShortenAction | ReplaceBackgroundAction | JourneyOverlayAction | { type: string; [key: string]: any };
504
+
505
+ export interface JourneyConfig {
506
+ enabled?: boolean;
507
+ mode?: 'before-current' | 'all';
508
+ position?: 'left' | 'right';
509
+ style?: 'badge' | 'panel';
510
+ badgeText?: string;
511
+ displayDuration?: number | 'full';
512
+ sidebarDisplayDuration?: number | 'full';
513
+ sidebarLabel?: 'title' | 'stage' | 'both';
514
+ theme?: 'dark' | 'light';
515
+ maxCenterChars?: number;
516
+ maxVisibleRows?: number;
517
+ }
518
+
519
+ export interface PlannedEntry {
520
+ index: number;
521
+ songKey: string;
522
+ filename: string;
523
+ title: string;
524
+ sourcePath: string;
525
+ targetPath: string;
526
+ actions: VideoAction[];
527
+ rawEntry?: any;
528
+ }
529
+
530
+ export interface BatchActionsPlan {
531
+ sourceDir: string;
532
+ outputDir: string;
533
+ hasShorten: boolean;
534
+ rawMetadata: any;
535
+ journeyConfig: JourneyConfig;
536
+ entries: PlannedEntry[];
537
+ dryRun: boolean;
538
+ force: boolean;
539
+ }
540
+
541
+ export interface BatchApplyActionsOptions {
542
+ metadataFile?: string;
543
+ actionsFile?: string;
544
+ outputDir?: string;
545
+ outputSuffix?: string;
546
+ only?: string;
547
+ force?: boolean;
548
+ dryRun?: boolean;
549
+ pexelsKey?: string;
550
+ pixabayKey?: string;
551
+ cacheDir?: string;
552
+ fetchFn?: typeof fetch;
553
+ onEvent?: (event: { type: string; [key: string]: any }) => void;
554
+ }
555
+
556
+ export interface BatchApplyActionsResult {
557
+ sourceDir: string;
558
+ outputDir: string;
559
+ total: number;
560
+ processed: Array<{
561
+ songKey: string;
562
+ filename: string;
563
+ outputPath: string;
564
+ actionsApplied: string[];
565
+ steps?: string[];
566
+ }>;
567
+ skipped: Array<{
568
+ songKey: string;
569
+ filename: string;
570
+ reason?: string;
571
+ }>;
572
+ failed: Array<{
573
+ songKey: string;
574
+ filename: string;
575
+ error: Error;
576
+ }>;
577
+ dryRun: boolean;
578
+ }
579
+
580
+ export function parseTimeSeconds(time: string | number): number;
581
+ export function getVideoMetadata(filePath: string): Promise<{ duration: number; width: number; height: number; fps: number; sampleRate: number }>;
582
+ export function shortenVideo(params: {
583
+ inputPath: string;
584
+ outputPath: string;
585
+ cutPoint: string | number;
586
+ fadeDuration?: number;
587
+ paddingDuration?: number;
588
+ paddingFill?: 'black' | 'freeze-frame';
589
+ fadeTargets?: Array<'audio' | 'video'>;
590
+ dryRun?: boolean;
591
+ onWarn?: (msg: string) => void;
592
+ }): Promise<{ outputPath: string; duration: number; dryRun?: boolean; command?: string }>;
593
+
594
+ export function extractAudio(inputVideoPath: string, outputAudioPath: string): Promise<string>;
595
+ export function replaceBackground(params: {
596
+ inputPath: string;
597
+ outputPath: string;
598
+ action?: Partial<ReplaceBackgroundAction>;
599
+ entry?: any;
600
+ context?: any;
601
+ dryRun?: boolean;
602
+ }): Promise<{ outputPath: string; duration?: number; dryRun?: boolean; command?: string; asset?: any }>;
603
+
604
+ export function resolveJourneyTracks(params: {
605
+ currentSongKey: string;
606
+ rawMetadata?: any;
607
+ mode?: 'before-current' | 'all';
608
+ maxVisibleRows?: number;
609
+ sidebarLabel?: 'title' | 'stage' | 'both';
610
+ }): Array<{ index: number; title: string; isCurrent: boolean; isUpcoming: boolean; isOverflow?: boolean }>;
611
+
612
+ export function generateJourneySvg(params: {
613
+ width?: number;
614
+ height?: number;
615
+ tracks?: Array<{ index: number; title: string; isCurrent: boolean; isUpcoming: boolean; isOverflow?: boolean }>;
616
+ centerText?: string;
617
+ showSidebar?: boolean;
618
+ theme?: 'dark' | 'light';
619
+ position?: 'left' | 'right';
620
+ style?: 'badge' | 'panel';
621
+ stage?: string;
622
+ step?: number;
623
+ totalSteps?: number;
624
+ badgeText?: string;
625
+ }): string;
626
+
627
+ export function renderSvgToPng(svgContent: string, width?: number, height?: number): Buffer;
628
+
629
+ export function applyJourneyOverlay(params: {
630
+ inputPath: string;
631
+ outputPath: string;
632
+ action?: Partial<JourneyOverlayAction>;
633
+ entry?: any;
634
+ rawMetadata?: any;
635
+ journeyConfig?: JourneyConfig;
636
+ dryRun?: boolean;
637
+ onWarn?: (msg: string) => void;
638
+ }): Promise<{ outputPath: string; duration?: number; dryRun?: boolean; command?: string }>;
639
+
640
+ export function runActionsPipeline(
641
+ entry: PlannedEntry | { songKey?: string; filename: string; sourcePath: string; targetPath?: string },
642
+ actions?: VideoAction[],
643
+ context?: {
644
+ outputDir?: string;
645
+ rawMetadata?: any;
646
+ journeyConfig?: JourneyConfig;
647
+ dryRun?: boolean;
648
+ force?: boolean;
649
+ pexelsKey?: string;
650
+ pixabayKey?: string;
651
+ cacheDir?: string;
652
+ fetchFn?: typeof fetch;
653
+ onEvent?: (event: any) => void;
654
+ onWarn?: (msg: string) => void;
655
+ }
656
+ ): Promise<{
657
+ songKey: string;
658
+ filename: string;
659
+ outputPath: string;
660
+ actionsApplied: string[];
661
+ skipped?: boolean;
662
+ reason?: string;
663
+ dryRun?: boolean;
664
+ steps?: string[];
665
+ }>;
666
+
667
+ export function resolveOutputDirectory(sourceDir: string, options?: { outputDir?: string; outputSuffix?: string; hasShorten?: boolean }): string;
668
+ export function resolveEntryActions(params: { songKey: string; filename: string; rawEntry?: any; rawMetadata?: any; actionsFileConfig?: any }): VideoAction[];
669
+ export function planBatchActions(sourceDir: string, options?: BatchApplyActionsOptions): BatchActionsPlan;
670
+ export function cloneMetadataForOutput(rawMetadata: any, outputDir: string, results?: Array<any>): any;
671
+ export function batchApplyActions(targetDir?: string, options?: BatchApplyActionsOptions): Promise<BatchApplyActionsResult>;
672
+
673
+ export function previewJourney(
674
+ songKey: string,
675
+ options?: {
676
+ dir?: string;
677
+ metadata?: string;
678
+ centerText?: string;
679
+ output?: string;
680
+ width?: number;
681
+ height?: number;
682
+ }
683
+ ): Promise<{ outputPath: string; width: number; height: number; tracksCount: number }>;
684
+
685
+
package/src/index.js CHANGED
@@ -1,12 +1,20 @@
1
1
  export { authenticate, resolveOAuthCredentials, YOUTUBE_SCOPES } from './auth.js';
2
- export { loadMetadata, DEFAULT_CATEGORY_ID, DEFAULT_PRIVACY_STATUS, VALID_PRIVACY_STATUSES } from './metadata.js';
2
+ export {
3
+ loadMetadata,
4
+ interpolateTemplates,
5
+ DEFAULT_CATEGORY_ID,
6
+ DEFAULT_PRIVACY_STATUS,
7
+ VALID_PRIVACY_STATUSES,
8
+ } from './metadata.js';
3
9
  export { UploadState, DEFAULT_STATE_FILENAME } from './state.js';
4
10
  export {
5
11
  uploadVideo,
6
12
  addToPlaylist,
13
+ createPlaylist,
7
14
  batchUpload,
8
15
  QUOTA_PER_VIDEO_UPLOAD,
9
16
  QUOTA_PER_PLAYLIST_ITEM,
17
+ QUOTA_PER_PLAYLIST_CREATE,
10
18
  DAILY_DEFAULT_QUOTA,
11
19
  } from './uploader.js';
12
20
  export { SwapStore, DEFAULT_SWAP_STATE_FILENAME, SWAP_STATUSES } from './swap/store.js';
@@ -18,3 +26,76 @@ export {
18
26
  finalizeSwap,
19
27
  } from './swap/steps.js';
20
28
  export { swapSong, QUOTA_PER_SWAP } from './swap/swapSong.js';
29
+ export {
30
+ updateVideoSnippet,
31
+ updateVideoTitle,
32
+ updatePlaylistSnippet,
33
+ updatePlaylistTitle,
34
+ batchUpdateMetadata,
35
+ QUOTA_PER_VIDEO_UPDATE,
36
+ QUOTA_PER_PLAYLIST_UPDATE,
37
+ QUOTA_PER_LIST,
38
+ } from './update.js';
39
+ export {
40
+ searchPexels,
41
+ searchPixabay,
42
+ searchMedia,
43
+ resolveProviderCredentials,
44
+ } from './providers/index.js';
45
+ export {
46
+ DEFAULT_MEDIA_CACHE_DIR,
47
+ CACHE_TTL_MS,
48
+ createSearchCacheKey,
49
+ getCachedSearch,
50
+ setCachedSearch,
51
+ readUsedAssetsLedger,
52
+ isAssetUsed,
53
+ recordUsedAsset,
54
+ } from './media/cache.js';
55
+ export {
56
+ scoreCandidate,
57
+ rankCandidates,
58
+ selectBest,
59
+ } from './media/select.js';
60
+ export {
61
+ downloadAsset,
62
+ inferExtension,
63
+ } from './media/download.js';
64
+ export {
65
+ composeVideo,
66
+ getMediaDuration,
67
+ } from './media/compose.js';
68
+ export {
69
+ deriveSearchQuery,
70
+ formatMediaCredit,
71
+ writeAttributionsFile,
72
+ resolveMediaForMetadata,
73
+ } from './media/resolve.js';
74
+ export {
75
+ shortenVideo,
76
+ parseTimeSeconds,
77
+ getVideoMetadata,
78
+ replaceBackground,
79
+ extractAudio,
80
+ applyJourneyOverlay,
81
+ generateJourneySvg,
82
+ renderSvgToPng,
83
+ resolveJourneyTracks,
84
+ runActionsPipeline,
85
+ } from './actions/index.js';
86
+ export {
87
+ resolveOutputDirectory,
88
+ resolveEntryActions,
89
+ planBatchActions,
90
+ } from './batch/plan.js';
91
+ export {
92
+ cloneMetadataForOutput,
93
+ } from './batch/clone-metadata.js';
94
+ export {
95
+ batchApplyActions,
96
+ } from './cli/apply-actions.js';
97
+ export {
98
+ previewJourney,
99
+ } from './cli/preview-journey.js';
100
+
101
+