faceless-cli 1.0.0 → 1.1.6

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/package.json CHANGED
@@ -1,37 +1,37 @@
1
1
  {
2
- "name": "faceless-cli",
3
- "version": "1.0.0",
4
- "description": "CLI for Faceless.so: create AI faceless videos, run automated series and publish to YouTube, TikTok, Instagram and more.",
5
- "type": "module",
6
- "bin": {
7
- "faceless": "bin/faceless.js",
8
- "fcl": "bin/faceless.js"
9
- },
10
- "files": [
11
- "bin",
12
- "src",
13
- "README.md",
14
- "LICENSE"
15
- ],
16
- "engines": {
17
- "node": ">=18"
18
- },
19
- "license": "MIT",
20
- "homepage": "https://faceless.so",
21
- "keywords": [
22
- "faceless",
23
- "cli",
24
- "mcp",
25
- "ai",
26
- "video",
27
- "faceless-video",
28
- "youtube",
29
- "tiktok",
30
- "social-media",
31
- "scheduling"
32
- ],
33
- "dependencies": {
34
- "@modelcontextprotocol/sdk": "^1.29.0",
35
- "commander": "^13.0.0"
36
- }
2
+ "name": "faceless-cli",
3
+ "version": "1.1.6",
4
+ "description": "CLI for Faceless.so: create AI faceless videos, run automated series and publish to YouTube, TikTok, Instagram and more.",
5
+ "type": "module",
6
+ "bin": {
7
+ "faceless": "bin/faceless.js",
8
+ "fcl": "bin/faceless.js"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "src",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "engines": {
17
+ "node": ">=18"
18
+ },
19
+ "license": "MIT",
20
+ "homepage": "https://faceless.so",
21
+ "keywords": [
22
+ "faceless",
23
+ "cli",
24
+ "mcp",
25
+ "ai",
26
+ "video",
27
+ "faceless-video",
28
+ "youtube",
29
+ "tiktok",
30
+ "social-media",
31
+ "scheduling"
32
+ ],
33
+ "dependencies": {
34
+ "@modelcontextprotocol/sdk": "^1.29.0",
35
+ "commander": "^13.0.0"
36
+ }
37
37
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "generatedFrom": "src/backend/api/v1/spec/registry.mjs",
3
- "version": "1.0.0",
3
+ "version": "1.1.6",
4
4
  "baseUrl": "https://faceless.so/api/v1",
5
5
  "operations": [
6
6
  {
@@ -317,7 +317,7 @@
317
317
  "name": "Ocean facts",
318
318
  "platform": "tts",
319
319
  "model": "storyboard",
320
- "renderedVideoUrl": null,
320
+ "renderedVideoUrl": "https://exports.faceless.so/renders/665f1b2a9c31a2b3c4d5e801/1730000000000.mp4",
321
321
  "createdAt": "2026-07-30T10:00:00.000Z"
322
322
  }
323
323
  ],
@@ -363,6 +363,24 @@
363
363
  "voiceId": "EXAVITQu4vr4xnSDxMaL",
364
364
  "status": "completed",
365
365
  "renderedVideoUrl": "https://exports.faceless.so/renders/665f1b2a9c31a2b3c4d5e801/1722333444555.mp4",
366
+ "thumbnailUrl": "https://exports.faceless.so/thumbnails/665f1b2a9c31a2b3c4d5e801/1/a1b2c3d4.jpg",
367
+ "thumbnails": {
368
+ "status": "ready",
369
+ "generation": 1,
370
+ "aspect": "9:16",
371
+ "selectedVariantId": "a1b2c3d4-0000-4000-8000-000000000001",
372
+ "selectedBy": "ai",
373
+ "variants": [
374
+ {
375
+ "id": "a1b2c3d4-0000-4000-8000-000000000001",
376
+ "url": "https://exports.faceless.so/thumbnails/665f1b2a9c31a2b3c4d5e801/1/a1b2c3d4.jpg",
377
+ "hookText": "OCEAN RIVERS",
378
+ "source": "ai",
379
+ "score": 88,
380
+ "grade": "S"
381
+ }
382
+ ]
383
+ },
366
384
  "createdAt": "2026-07-30T10:00:00.000Z"
367
385
  }
368
386
  }
@@ -535,6 +553,69 @@
535
553
  "name": "Ocean facts",
536
554
  "youtubePost": {
537
555
  "title": "The ocean has rivers underwater"
556
+ },
557
+ "thumbnailUrl": "https://exports.faceless.so/thumbnails/665f1b2a9c31a2b3c4d5e801/1/a1b2c3d4.jpg",
558
+ "thumbnails": {
559
+ "status": "ready",
560
+ "selectedBy": "ai",
561
+ "variants": [
562
+ "https://exports.faceless.so/thumbnails/665f1b2a9c31a2b3c4d5e801/a.jpg"
563
+ ]
564
+ }
565
+ }
566
+ }
567
+ },
568
+ {
569
+ "operationId": "selectVideoThumbnail",
570
+ "method": "post",
571
+ "path": "/videos/{id}/thumbnail",
572
+ "resource": "videos",
573
+ "summary": "Choose which thumbnail a video uses",
574
+ "description": "Selects one of the video's thumbnail variants as the effective thumbnail. Read the available variants from GET /videos/{id} (the thumbnails object). The choice is marked as a user pick, so later automatic regenerations will not overwrite it, and it is what gets pushed to YouTube and used as the Instagram Reels cover at post time. Thumbnails are free and generated automatically after a video completes.",
575
+ "scopes": [
576
+ "videos:write"
577
+ ],
578
+ "status": 200,
579
+ "idempotent": false,
580
+ "terminalStates": null,
581
+ "creditCost": "none",
582
+ "cli": {
583
+ "command": "videos select-thumbnail"
584
+ },
585
+ "mcp": {
586
+ "name": "faceless_select_video_thumbnail",
587
+ "enabled": true
588
+ },
589
+ "querySchema": null,
590
+ "requestSchema": {
591
+ "type": "object",
592
+ "properties": {
593
+ "variantId": {
594
+ "type": "string",
595
+ "minLength": 1,
596
+ "description": "Variant id from the thumbnails.variants array on GET /videos/{id}"
597
+ }
598
+ },
599
+ "required": [
600
+ "variantId"
601
+ ],
602
+ "additionalProperties": false
603
+ },
604
+ "requestExample": {
605
+ "variantId": "a1b2c3d4-0000-4000-8000-000000000002"
606
+ },
607
+ "responseExample": {
608
+ "success": true,
609
+ "data": {
610
+ "id": "665f1b2a9c31a2b3c4d5e801",
611
+ "thumbnailUrl": "https://exports.faceless.so/thumbnails/665f1b2a9c31a2b3c4d5e801/1/b2c3d4e5.jpg",
612
+ "thumbnails": {
613
+ "status": "ready",
614
+ "selectedVariantId": "a1b2c3d4-0000-4000-8000-000000000002",
615
+ "selectedBy": "user",
616
+ "variants": [
617
+ "https://exports.faceless.so/thumbnails/665f1b2a9c31a2b3c4d5e801/a.jpg"
618
+ ]
538
619
  }
539
620
  }
540
621
  }
@@ -573,8 +654,10 @@
573
654
  "status": "processing",
574
655
  "percentCompleted": 62,
575
656
  "readyForEditing": false,
576
- "errorMessages": [],
577
- "renderedVideoUrl": null
657
+ "errorMessages": [
658
+ "b-roll fetch timed out, retried"
659
+ ],
660
+ "renderedVideoUrl": "https://exports.faceless.so/renders/665f1b2a9c31a2b3c4d5e801/1730000000000.mp4"
578
661
  }
579
662
  }
580
663
  },
@@ -770,6 +853,22 @@
770
853
  },
771
854
  "description": "Connected account ids to auto-post to (from GET /accounts)"
772
855
  },
856
+ "generateThumbnails": {
857
+ "type": "boolean",
858
+ "description": "Generate 3 AI thumbnail variants for every episode and auto-select the best. Free. Defaults to true."
859
+ },
860
+ "thumbnailSettings": {
861
+ "type": "object",
862
+ "properties": {
863
+ "styleHint": {
864
+ "type": "string",
865
+ "maxLength": 200,
866
+ "description": "Free-text art direction for the thumbnail backgrounds, e.g. \"moody neon, close-up faces\""
867
+ }
868
+ },
869
+ "additionalProperties": false,
870
+ "description": "Thumbnail generation options. Ignored when generateThumbnails is false."
871
+ },
773
872
  "autoPostTime": {
774
873
  "type": "string",
775
874
  "description": "Daily auto-post time \"HH:mm\" in the series timezone"
@@ -1015,6 +1114,22 @@
1015
1114
  },
1016
1115
  "description": "Connected account ids to auto-post to (from GET /accounts)"
1017
1116
  },
1117
+ "generateThumbnails": {
1118
+ "type": "boolean",
1119
+ "description": "Generate 3 AI thumbnail variants for every episode and auto-select the best. Free. Defaults to true."
1120
+ },
1121
+ "thumbnailSettings": {
1122
+ "type": "object",
1123
+ "properties": {
1124
+ "styleHint": {
1125
+ "type": "string",
1126
+ "maxLength": 200,
1127
+ "description": "Free-text art direction for the thumbnail backgrounds, e.g. \"moody neon, close-up faces\""
1128
+ }
1129
+ },
1130
+ "additionalProperties": false,
1131
+ "description": "Thumbnail generation options. Ignored when generateThumbnails is false."
1132
+ },
1018
1133
  "autoPostTime": {
1019
1134
  "type": "string",
1020
1135
  "description": "Daily auto-post time \"HH:mm\" in the series timezone"
@@ -1528,8 +1643,20 @@
1528
1643
  "channelName": "Deep Sea Facts"
1529
1644
  }
1530
1645
  ],
1531
- "tiktok": [],
1532
- "instagram": []
1646
+ "tiktok": [
1647
+ {
1648
+ "id": "665f1b2a9c31a2b3c4d5e901",
1649
+ "username": "mychannel",
1650
+ "status": "connected"
1651
+ }
1652
+ ],
1653
+ "instagram": [
1654
+ {
1655
+ "id": "665f1b2a9c31a2b3c4d5e902",
1656
+ "username": "mychannel",
1657
+ "status": "connected"
1658
+ }
1659
+ ]
1533
1660
  }
1534
1661
  }
1535
1662
  },
package/src/index.mjs CHANGED
@@ -435,6 +435,19 @@ videos
435
435
  print(result, { json: cmd.optsWithGlobals().json });
436
436
  });
437
437
 
438
+ videos
439
+ .command("select-thumbnail <id>")
440
+ .description(getOp("selectVideoThumbnail").summary)
441
+ .requiredOption("--variant <variantId>", "variant id from the thumbnails.variants array on `faceless videos get <id>`")
442
+ .action(async (id, opts, cmd) => {
443
+ const result = await execute(
444
+ "selectVideoThumbnail",
445
+ { pathParams: { id }, body: { variantId: opts.variant } },
446
+ cmd
447
+ );
448
+ print(result, { json: cmd.optsWithGlobals().json });
449
+ });
450
+
438
451
  withWaitFlags(
439
452
  videos.command("status <id>").description(getOp("getVideoStatus").summary),
440
453
  "video"