@kenkaiiii/gg-editor 0.7.0 → 0.7.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.
- package/dist/cli.js +64 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/audio-mix.d.ts.map +1 -1
- package/dist/core/audio-mix.js +8 -1
- package/dist/core/audio-mix.js.map +1 -1
- package/dist/core/audio-mix.test.js +1 -1
- package/dist/core/audio-mix.test.js.map +1 -1
- package/dist/core/auth/api-keys.d.ts +1 -1
- package/dist/core/auth/api-keys.d.ts.map +1 -1
- package/dist/core/auth/api-keys.js +2 -1
- package/dist/core/auth/api-keys.js.map +1 -1
- package/dist/core/auth/login.d.ts.map +1 -1
- package/dist/core/auth/login.js.map +1 -1
- package/dist/core/beats.d.ts +59 -0
- package/dist/core/beats.d.ts.map +1 -0
- package/dist/core/beats.js +122 -0
- package/dist/core/beats.js.map +1 -0
- package/dist/core/beats.test.d.ts +2 -0
- package/dist/core/beats.test.d.ts.map +1 -0
- package/dist/core/beats.test.js +86 -0
- package/dist/core/beats.test.js.map +1 -0
- package/dist/core/brand-kit.d.ts +80 -0
- package/dist/core/brand-kit.d.ts.map +1 -0
- package/dist/core/brand-kit.js +96 -0
- package/dist/core/brand-kit.js.map +1 -0
- package/dist/core/brand-kit.test.d.ts +2 -0
- package/dist/core/brand-kit.test.d.ts.map +1 -0
- package/dist/core/brand-kit.test.js +76 -0
- package/dist/core/brand-kit.test.js.map +1 -0
- package/dist/core/bundled-sfx.d.ts +64 -0
- package/dist/core/bundled-sfx.d.ts.map +1 -0
- package/dist/core/bundled-sfx.js +218 -0
- package/dist/core/bundled-sfx.js.map +1 -0
- package/dist/core/bundled-sfx.test.d.ts +2 -0
- package/dist/core/bundled-sfx.test.d.ts.map +1 -0
- package/dist/core/bundled-sfx.test.js +81 -0
- package/dist/core/bundled-sfx.test.js.map +1 -0
- package/dist/core/child-abort.d.ts +57 -0
- package/dist/core/child-abort.d.ts.map +1 -0
- package/dist/core/child-abort.js +95 -0
- package/dist/core/child-abort.js.map +1 -0
- package/dist/core/child-abort.test.d.ts +2 -0
- package/dist/core/child-abort.test.d.ts.map +1 -0
- package/dist/core/child-abort.test.js +88 -0
- package/dist/core/child-abort.test.js.map +1 -0
- package/dist/core/clip-scoring.d.ts +44 -0
- package/dist/core/clip-scoring.d.ts.map +1 -0
- package/dist/core/clip-scoring.js +165 -0
- package/dist/core/clip-scoring.js.map +1 -0
- package/dist/core/clip-scoring.test.d.ts +2 -0
- package/dist/core/clip-scoring.test.d.ts.map +1 -0
- package/dist/core/clip-scoring.test.js +113 -0
- package/dist/core/clip-scoring.test.js.map +1 -0
- package/dist/core/emoji-captions.d.ts +45 -0
- package/dist/core/emoji-captions.d.ts.map +1 -0
- package/dist/core/emoji-captions.js +121 -0
- package/dist/core/emoji-captions.js.map +1 -0
- package/dist/core/face-reframe.d.ts +91 -0
- package/dist/core/face-reframe.d.ts.map +1 -0
- package/dist/core/face-reframe.js +141 -0
- package/dist/core/face-reframe.js.map +1 -0
- package/dist/core/face-reframe.test.d.ts +2 -0
- package/dist/core/face-reframe.test.d.ts.map +1 -0
- package/dist/core/face-reframe.test.js +171 -0
- package/dist/core/face-reframe.test.js.map +1 -0
- package/dist/core/filler-words.d.ts +57 -9
- package/dist/core/filler-words.d.ts.map +1 -1
- package/dist/core/filler-words.js +61 -9
- package/dist/core/filler-words.js.map +1 -1
- package/dist/core/filler-words.test.js +91 -17
- package/dist/core/filler-words.test.js.map +1 -1
- package/dist/core/hook-rewrite.d.ts +48 -0
- package/dist/core/hook-rewrite.d.ts.map +1 -0
- package/dist/core/hook-rewrite.js +151 -0
- package/dist/core/hook-rewrite.js.map +1 -0
- package/dist/core/hook-rewrite.test.d.ts +2 -0
- package/dist/core/hook-rewrite.test.d.ts.map +1 -0
- package/dist/core/hook-rewrite.test.js +58 -0
- package/dist/core/hook-rewrite.test.js.map +1 -0
- package/dist/core/hosts/lazy.d.ts.map +1 -1
- package/dist/core/hosts/lazy.js +2 -0
- package/dist/core/hosts/lazy.js.map +1 -1
- package/dist/core/hosts/premiere/adapter.d.ts +1 -0
- package/dist/core/hosts/premiere/adapter.d.ts.map +1 -1
- package/dist/core/hosts/premiere/adapter.js.map +1 -1
- package/dist/core/hosts/premiere/bridge-source.d.ts.map +1 -1
- package/dist/core/hosts/premiere/bridge-source.js +6 -3
- package/dist/core/hosts/premiere/bridge-source.js.map +1 -1
- package/dist/core/hosts/resolve/adapter.d.ts +1 -0
- package/dist/core/hosts/resolve/adapter.d.ts.map +1 -1
- package/dist/core/hosts/resolve/adapter.js.map +1 -1
- package/dist/core/hosts/resolve/bridge-source.d.ts.map +1 -1
- package/dist/core/hosts/resolve/bridge-source.js +31 -4
- package/dist/core/hosts/resolve/bridge-source.js.map +1 -1
- package/dist/core/hosts/resolve/bridge.d.ts +2 -19
- package/dist/core/hosts/resolve/bridge.d.ts.map +1 -1
- package/dist/core/hosts/resolve/bridge.js +70 -41
- package/dist/core/hosts/resolve/bridge.js.map +1 -1
- package/dist/core/hosts/resolve/bridge.test.js +130 -0
- package/dist/core/hosts/resolve/bridge.test.js.map +1 -1
- package/dist/core/hosts/types.d.ts +6 -0
- package/dist/core/hosts/types.d.ts.map +1 -1
- package/dist/core/hosts/types.js.map +1 -1
- package/dist/core/logger.d.ts +32 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +188 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/loop-match.d.ts +57 -0
- package/dist/core/loop-match.d.ts.map +1 -0
- package/dist/core/loop-match.js +91 -0
- package/dist/core/loop-match.js.map +1 -0
- package/dist/core/media/ffmpeg.d.ts.map +1 -1
- package/dist/core/media/ffmpeg.js +14 -3
- package/dist/core/media/ffmpeg.js.map +1 -1
- package/dist/core/multi-format.d.ts +67 -0
- package/dist/core/multi-format.d.ts.map +1 -0
- package/dist/core/multi-format.js +127 -0
- package/dist/core/multi-format.js.map +1 -0
- package/dist/core/multi-format.test.d.ts +2 -0
- package/dist/core/multi-format.test.d.ts.map +1 -0
- package/dist/core/multi-format.test.js +151 -0
- package/dist/core/multi-format.test.js.map +1 -0
- package/dist/core/python/beats.py +61 -0
- package/dist/core/python/face_reframe.py +163 -0
- package/dist/core/python/sidecar-path.d.ts +13 -0
- package/dist/core/python/sidecar-path.d.ts.map +1 -0
- package/dist/core/python/sidecar-path.js +24 -0
- package/dist/core/python/sidecar-path.js.map +1 -0
- package/dist/core/python.d.ts +57 -0
- package/dist/core/python.d.ts.map +1 -0
- package/dist/core/python.js +107 -0
- package/dist/core/python.js.map +1 -0
- package/dist/core/python.test.d.ts +2 -0
- package/dist/core/python.test.d.ts.map +1 -0
- package/dist/core/python.test.js +129 -0
- package/dist/core/python.test.js.map +1 -0
- package/dist/core/retention-structure.d.ts +81 -0
- package/dist/core/retention-structure.d.ts.map +1 -0
- package/dist/core/retention-structure.js +206 -0
- package/dist/core/retention-structure.js.map +1 -0
- package/dist/core/retention-structure.test.d.ts +2 -0
- package/dist/core/retention-structure.test.d.ts.map +1 -0
- package/dist/core/retention-structure.test.js +88 -0
- package/dist/core/retention-structure.test.js.map +1 -0
- package/dist/core/review.d.ts +17 -0
- package/dist/core/review.d.ts.map +1 -1
- package/dist/core/review.js +20 -24
- package/dist/core/review.js.map +1 -1
- package/dist/core/safe-paths.d.ts +11 -0
- package/dist/core/safe-paths.d.ts.map +1 -1
- package/dist/core/safe-paths.js +26 -10
- package/dist/core/safe-paths.js.map +1 -1
- package/dist/core/safe-paths.test.js +16 -0
- package/dist/core/safe-paths.test.js.map +1 -1
- package/dist/core/skills-loader.d.ts +48 -2
- package/dist/core/skills-loader.d.ts.map +1 -1
- package/dist/core/skills-loader.js +97 -19
- package/dist/core/skills-loader.js.map +1 -1
- package/dist/core/skills-loader.test.js +63 -1
- package/dist/core/skills-loader.test.js.map +1 -1
- package/dist/core/srt.d.ts +42 -7
- package/dist/core/srt.d.ts.map +1 -1
- package/dist/core/srt.js +101 -32
- package/dist/core/srt.js.map +1 -1
- package/dist/core/srt.test.js +54 -1
- package/dist/core/srt.test.js.map +1 -1
- package/dist/core/thumbnail-compose.d.ts +58 -0
- package/dist/core/thumbnail-compose.d.ts.map +1 -0
- package/dist/core/thumbnail-compose.js +101 -0
- package/dist/core/thumbnail-compose.js.map +1 -0
- package/dist/core/thumbnail-promise.d.ts +46 -0
- package/dist/core/thumbnail-promise.d.ts.map +1 -0
- package/dist/core/thumbnail-promise.js +133 -0
- package/dist/core/thumbnail-promise.js.map +1 -0
- package/dist/core/thumbnail-promise.test.d.ts +2 -0
- package/dist/core/thumbnail-promise.test.d.ts.map +1 -0
- package/dist/core/thumbnail-promise.test.js +52 -0
- package/dist/core/thumbnail-promise.test.js.map +1 -0
- package/dist/core/viral-moments.d.ts +70 -0
- package/dist/core/viral-moments.d.ts.map +1 -0
- package/dist/core/viral-moments.js +192 -0
- package/dist/core/viral-moments.js.map +1 -0
- package/dist/core/viral-moments.test.d.ts +2 -0
- package/dist/core/viral-moments.test.d.ts.map +1 -0
- package/dist/core/viral-moments.test.js +153 -0
- package/dist/core/viral-moments.test.js.map +1 -0
- package/dist/core/whisper.d.ts +16 -0
- package/dist/core/whisper.d.ts.map +1 -1
- package/dist/core/whisper.js +72 -5
- package/dist/core/whisper.js.map +1 -1
- package/dist/core/whisper.test.js +111 -1
- package/dist/core/whisper.test.js.map +1 -1
- package/dist/core/youtube-metadata.d.ts +44 -0
- package/dist/core/youtube-metadata.d.ts.map +1 -0
- package/dist/core/youtube-metadata.js +168 -0
- package/dist/core/youtube-metadata.js.map +1 -0
- package/dist/core/youtube-metadata.test.d.ts +2 -0
- package/dist/core/youtube-metadata.test.d.ts.map +1 -0
- package/dist/core/youtube-metadata.test.js +132 -0
- package/dist/core/youtube-metadata.test.js.map +1 -0
- package/dist/prompt-commands.d.ts +24 -0
- package/dist/prompt-commands.d.ts.map +1 -0
- package/dist/prompt-commands.js +243 -0
- package/dist/prompt-commands.js.map +1 -0
- package/dist/prompt-commands.test.d.ts +2 -0
- package/dist/prompt-commands.test.d.ts.map +1 -0
- package/dist/prompt-commands.test.js +46 -0
- package/dist/prompt-commands.test.js.map +1 -0
- package/dist/skills.d.ts +6 -6
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +1426 -445
- package/dist/skills.js.map +1 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +108 -0
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/add-fades.d.ts.map +1 -1
- package/dist/tools/add-fades.js +2 -1
- package/dist/tools/add-fades.js.map +1 -1
- package/dist/tools/add-sfx-at-cuts.d.ts.map +1 -1
- package/dist/tools/add-sfx-at-cuts.js +36 -11
- package/dist/tools/add-sfx-at-cuts.js.map +1 -1
- package/dist/tools/add-sfx-to-timeline.d.ts +34 -0
- package/dist/tools/add-sfx-to-timeline.d.ts.map +1 -0
- package/dist/tools/add-sfx-to-timeline.js +169 -0
- package/dist/tools/add-sfx-to-timeline.js.map +1 -0
- package/dist/tools/add-sfx-to-timeline.test.d.ts +2 -0
- package/dist/tools/add-sfx-to-timeline.test.d.ts.map +1 -0
- package/dist/tools/add-sfx-to-timeline.test.js +181 -0
- package/dist/tools/add-sfx-to-timeline.test.js.map +1 -0
- package/dist/tools/audit-first-frame.d.ts +36 -0
- package/dist/tools/audit-first-frame.d.ts.map +1 -0
- package/dist/tools/audit-first-frame.js +181 -0
- package/dist/tools/audit-first-frame.js.map +1 -0
- package/dist/tools/audit-retention-structure.d.ts +20 -0
- package/dist/tools/audit-retention-structure.d.ts.map +1 -0
- package/dist/tools/audit-retention-structure.js +95 -0
- package/dist/tools/audit-retention-structure.js.map +1 -0
- package/dist/tools/audit-retention-structure.test.d.ts +2 -0
- package/dist/tools/audit-retention-structure.test.d.ts.map +1 -0
- package/dist/tools/audit-retention-structure.test.js +93 -0
- package/dist/tools/audit-retention-structure.test.js.map +1 -0
- package/dist/tools/bleep-words.d.ts +59 -0
- package/dist/tools/bleep-words.d.ts.map +1 -0
- package/dist/tools/bleep-words.js +211 -0
- package/dist/tools/bleep-words.js.map +1 -0
- package/dist/tools/bleep-words.test.d.ts +2 -0
- package/dist/tools/bleep-words.test.d.ts.map +1 -0
- package/dist/tools/bleep-words.test.js +96 -0
- package/dist/tools/bleep-words.test.js.map +1 -0
- package/dist/tools/burn-subtitles.d.ts.map +1 -1
- package/dist/tools/burn-subtitles.js +10 -5
- package/dist/tools/burn-subtitles.js.map +1 -1
- package/dist/tools/clean-audio.d.ts.map +1 -1
- package/dist/tools/clean-audio.js +2 -1
- package/dist/tools/clean-audio.js.map +1 -1
- package/dist/tools/cluster-takes.js +2 -1
- package/dist/tools/cluster-takes.js.map +1 -1
- package/dist/tools/compose-thumbnail-variants.d.ts +70 -0
- package/dist/tools/compose-thumbnail-variants.d.ts.map +1 -0
- package/dist/tools/compose-thumbnail-variants.js +274 -0
- package/dist/tools/compose-thumbnail-variants.js.map +1 -0
- package/dist/tools/compose-thumbnail.d.ts +6 -13
- package/dist/tools/compose-thumbnail.d.ts.map +1 -1
- package/dist/tools/compose-thumbnail.js +44 -81
- package/dist/tools/compose-thumbnail.js.map +1 -1
- package/dist/tools/concat-videos.d.ts.map +1 -1
- package/dist/tools/concat-videos.js +12 -5
- package/dist/tools/concat-videos.js.map +1 -1
- package/dist/tools/concat-videos.test.d.ts +2 -0
- package/dist/tools/concat-videos.test.d.ts.map +1 -0
- package/dist/tools/concat-videos.test.js +103 -0
- package/dist/tools/concat-videos.test.js.map +1 -0
- package/dist/tools/crossfade-videos.d.ts.map +1 -1
- package/dist/tools/crossfade-videos.js +2 -1
- package/dist/tools/crossfade-videos.js.map +1 -1
- package/dist/tools/cut-filler-words.d.ts.map +1 -1
- package/dist/tools/cut-filler-words.js +24 -8
- package/dist/tools/cut-filler-words.js.map +1 -1
- package/dist/tools/detect-speaker-changes.js +2 -1
- package/dist/tools/detect-speaker-changes.js.map +1 -1
- package/dist/tools/extract-audio.d.ts.map +1 -1
- package/dist/tools/extract-audio.js +13 -7
- package/dist/tools/extract-audio.js.map +1 -1
- package/dist/tools/face-reframe.d.ts +30 -0
- package/dist/tools/face-reframe.d.ts.map +1 -0
- package/dist/tools/face-reframe.js +143 -0
- package/dist/tools/face-reframe.js.map +1 -0
- package/dist/tools/face-reframe.test.d.ts +2 -0
- package/dist/tools/face-reframe.test.d.ts.map +1 -0
- package/dist/tools/face-reframe.test.js +139 -0
- package/dist/tools/face-reframe.test.js.map +1 -0
- package/dist/tools/find-viral-moments.d.ts +23 -0
- package/dist/tools/find-viral-moments.d.ts.map +1 -0
- package/dist/tools/find-viral-moments.js +176 -0
- package/dist/tools/find-viral-moments.js.map +1 -0
- package/dist/tools/find-viral-moments.test.d.ts +2 -0
- package/dist/tools/find-viral-moments.test.d.ts.map +1 -0
- package/dist/tools/find-viral-moments.test.js +144 -0
- package/dist/tools/find-viral-moments.test.js.map +1 -0
- package/dist/tools/generate-gif.d.ts.map +1 -1
- package/dist/tools/generate-gif.js +47 -40
- package/dist/tools/generate-gif.js.map +1 -1
- package/dist/tools/generate-gif.test.d.ts +2 -0
- package/dist/tools/generate-gif.test.d.ts.map +1 -0
- package/dist/tools/generate-gif.test.js +115 -0
- package/dist/tools/generate-gif.test.js.map +1 -0
- package/dist/tools/generate-outro.d.ts +18 -0
- package/dist/tools/generate-outro.d.ts.map +1 -0
- package/dist/tools/generate-outro.js +175 -0
- package/dist/tools/generate-outro.js.map +1 -0
- package/dist/tools/generate-youtube-metadata.d.ts +23 -0
- package/dist/tools/generate-youtube-metadata.d.ts.map +1 -0
- package/dist/tools/generate-youtube-metadata.js +103 -0
- package/dist/tools/generate-youtube-metadata.js.map +1 -0
- package/dist/tools/generate-youtube-metadata.test.d.ts +2 -0
- package/dist/tools/generate-youtube-metadata.test.d.ts.map +1 -0
- package/dist/tools/generate-youtube-metadata.test.js +118 -0
- package/dist/tools/generate-youtube-metadata.test.js.map +1 -0
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +130 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/index.test.js +27 -1
- package/dist/tools/index.test.js.map +1 -1
- package/dist/tools/ken-burns.d.ts.map +1 -1
- package/dist/tools/ken-burns.js +2 -1
- package/dist/tools/ken-burns.js.map +1 -1
- package/dist/tools/loop-match-short.d.ts +22 -0
- package/dist/tools/loop-match-short.d.ts.map +1 -0
- package/dist/tools/loop-match-short.js +107 -0
- package/dist/tools/loop-match-short.js.map +1 -0
- package/dist/tools/mix-audio.d.ts.map +1 -1
- package/dist/tools/mix-audio.js +2 -1
- package/dist/tools/mix-audio.js.map +1 -1
- package/dist/tools/normalize-loudness.d.ts.map +1 -1
- package/dist/tools/normalize-loudness.js +2 -1
- package/dist/tools/normalize-loudness.js.map +1 -1
- package/dist/tools/path-traversal.test.d.ts +15 -0
- package/dist/tools/path-traversal.test.d.ts.map +1 -0
- package/dist/tools/path-traversal.test.js +223 -0
- package/dist/tools/path-traversal.test.js.map +1 -0
- package/dist/tools/pick-best-takes.js +2 -1
- package/dist/tools/pick-best-takes.js.map +1 -1
- package/dist/tools/punch-in.d.ts.map +1 -1
- package/dist/tools/punch-in.js +2 -1
- package/dist/tools/punch-in.js.map +1 -1
- package/dist/tools/read-transcript.js +2 -1
- package/dist/tools/read-transcript.js.map +1 -1
- package/dist/tools/render-multi-format.d.ts +35 -0
- package/dist/tools/render-multi-format.d.ts.map +1 -0
- package/dist/tools/render-multi-format.js +206 -0
- package/dist/tools/render-multi-format.js.map +1 -0
- package/dist/tools/render-multi-format.test.d.ts +2 -0
- package/dist/tools/render-multi-format.test.d.ts.map +1 -0
- package/dist/tools/render-multi-format.test.js +312 -0
- package/dist/tools/render-multi-format.test.js.map +1 -0
- package/dist/tools/render.d.ts.map +1 -1
- package/dist/tools/render.js +2 -2
- package/dist/tools/render.js.map +1 -1
- package/dist/tools/rewrite-hook.d.ts +32 -0
- package/dist/tools/rewrite-hook.d.ts.map +1 -0
- package/dist/tools/rewrite-hook.js +65 -0
- package/dist/tools/rewrite-hook.js.map +1 -0
- package/dist/tools/score-clip.d.ts +30 -0
- package/dist/tools/score-clip.d.ts.map +1 -0
- package/dist/tools/score-clip.js +109 -0
- package/dist/tools/score-clip.js.map +1 -0
- package/dist/tools/score-clip.test.d.ts +2 -0
- package/dist/tools/score-clip.test.d.ts.map +1 -0
- package/dist/tools/score-clip.test.js +110 -0
- package/dist/tools/score-clip.test.js.map +1 -0
- package/dist/tools/search-tools.d.ts +34 -0
- package/dist/tools/search-tools.d.ts.map +1 -0
- package/dist/tools/search-tools.js +86 -0
- package/dist/tools/search-tools.js.map +1 -0
- package/dist/tools/search-tools.test.d.ts +2 -0
- package/dist/tools/search-tools.test.d.ts.map +1 -0
- package/dist/tools/search-tools.test.js +60 -0
- package/dist/tools/search-tools.test.js.map +1 -0
- package/dist/tools/snap-cuts-to-beats.d.ts +18 -0
- package/dist/tools/snap-cuts-to-beats.d.ts.map +1 -0
- package/dist/tools/snap-cuts-to-beats.js +110 -0
- package/dist/tools/snap-cuts-to-beats.js.map +1 -0
- package/dist/tools/snap-cuts-to-beats.test.d.ts +2 -0
- package/dist/tools/snap-cuts-to-beats.test.d.ts.map +1 -0
- package/dist/tools/snap-cuts-to-beats.test.js +99 -0
- package/dist/tools/snap-cuts-to-beats.test.js.map +1 -0
- package/dist/tools/speed-ramp.d.ts.map +1 -1
- package/dist/tools/speed-ramp.js +2 -1
- package/dist/tools/speed-ramp.js.map +1 -1
- package/dist/tools/stabilize-video.d.ts.map +1 -1
- package/dist/tools/stabilize-video.js +2 -1
- package/dist/tools/stabilize-video.js.map +1 -1
- package/dist/tools/suggest-broll.d.ts +34 -0
- package/dist/tools/suggest-broll.d.ts.map +1 -0
- package/dist/tools/suggest-broll.js +367 -0
- package/dist/tools/suggest-broll.js.map +1 -0
- package/dist/tools/suggest-broll.test.d.ts +2 -0
- package/dist/tools/suggest-broll.test.d.ts.map +1 -0
- package/dist/tools/suggest-broll.test.js +217 -0
- package/dist/tools/suggest-broll.test.js.map +1 -0
- package/dist/tools/text-based-cut.d.ts +33 -0
- package/dist/tools/text-based-cut.d.ts.map +1 -0
- package/dist/tools/text-based-cut.js +172 -0
- package/dist/tools/text-based-cut.js.map +1 -0
- package/dist/tools/text-based-cut.test.d.ts +2 -0
- package/dist/tools/text-based-cut.test.d.ts.map +1 -0
- package/dist/tools/text-based-cut.test.js +32 -0
- package/dist/tools/text-based-cut.test.js.map +1 -0
- package/dist/tools/transcribe.d.ts +1 -1
- package/dist/tools/transition-videos.d.ts +1 -1
- package/dist/tools/transition-videos.d.ts.map +1 -1
- package/dist/tools/transition-videos.js +2 -1
- package/dist/tools/transition-videos.js.map +1 -1
- package/dist/tools/trim-dead-air.d.ts +59 -0
- package/dist/tools/trim-dead-air.d.ts.map +1 -0
- package/dist/tools/trim-dead-air.js +215 -0
- package/dist/tools/trim-dead-air.js.map +1 -0
- package/dist/tools/trim-dead-air.test.d.ts +2 -0
- package/dist/tools/trim-dead-air.test.d.ts.map +1 -0
- package/dist/tools/trim-dead-air.test.js +75 -0
- package/dist/tools/trim-dead-air.test.js.map +1 -0
- package/dist/tools/verify-thumbnail-promise.d.ts +33 -0
- package/dist/tools/verify-thumbnail-promise.d.ts.map +1 -0
- package/dist/tools/verify-thumbnail-promise.js +112 -0
- package/dist/tools/verify-thumbnail-promise.js.map +1 -0
- package/dist/tools/verify-thumbnail-promise.test.d.ts +2 -0
- package/dist/tools/verify-thumbnail-promise.test.d.ts.map +1 -0
- package/dist/tools/verify-thumbnail-promise.test.js +38 -0
- package/dist/tools/verify-thumbnail-promise.test.js.map +1 -0
- package/dist/tools/write-keyword-captions.d.ts +7 -0
- package/dist/tools/write-keyword-captions.d.ts.map +1 -1
- package/dist/tools/write-keyword-captions.js +35 -4
- package/dist/tools/write-keyword-captions.js.map +1 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +75 -11
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/tool-formatters.d.ts +30 -0
- package/dist/ui/tool-formatters.d.ts.map +1 -0
- package/dist/ui/tool-formatters.js +461 -0
- package/dist/ui/tool-formatters.js.map +1 -0
- package/dist/ui/tool-formatters.test.d.ts +2 -0
- package/dist/ui/tool-formatters.test.d.ts.map +1 -0
- package/dist/ui/tool-formatters.test.js +143 -0
- package/dist/ui/tool-formatters.test.js.map +1 -0
- package/package.json +10 -9
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { AgentTool } from "@kenkaiiii/gg-agent";
|
|
3
|
+
import { type ExtractedFrame } from "../core/frames.js";
|
|
4
|
+
import { type ShotScore } from "../core/vision.js";
|
|
5
|
+
declare const ComposeThumbnailVariantsParams: z.ZodObject<{
|
|
6
|
+
input: z.ZodString;
|
|
7
|
+
outputDir: z.ZodString;
|
|
8
|
+
text: z.ZodString;
|
|
9
|
+
count: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
intervalSec: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
minSpacingSec: z.ZodOptional<z.ZodNumber>;
|
|
12
|
+
strategy: z.ZodOptional<z.ZodEnum<{
|
|
13
|
+
label: "label";
|
|
14
|
+
expression: "expression";
|
|
15
|
+
mixed: "mixed";
|
|
16
|
+
}>>;
|
|
17
|
+
model: z.ZodOptional<z.ZodString>;
|
|
18
|
+
detail: z.ZodOptional<z.ZodEnum<{
|
|
19
|
+
low: "low";
|
|
20
|
+
high: "high";
|
|
21
|
+
}>>;
|
|
22
|
+
fontFile: z.ZodOptional<z.ZodString>;
|
|
23
|
+
fontSize: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
fontColor: z.ZodOptional<z.ZodString>;
|
|
25
|
+
outlineColor: z.ZodOptional<z.ZodString>;
|
|
26
|
+
position: z.ZodOptional<z.ZodEnum<{
|
|
27
|
+
top: "top";
|
|
28
|
+
center: "center";
|
|
29
|
+
bottom: "bottom";
|
|
30
|
+
}>>;
|
|
31
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
interface VariantPick {
|
|
34
|
+
frame: ExtractedFrame;
|
|
35
|
+
score: ShotScore;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* compose_thumbnail_variants — generate N thumbnails for A/B testing.
|
|
39
|
+
*
|
|
40
|
+
* Samples frames at `intervalSec`, scores via vision rubric, picks the
|
|
41
|
+
* top-N spaced ≥ minSpacingSec apart, burns the headline. YouTube
|
|
42
|
+
* native A/B is now standard — variants beat single guesses.
|
|
43
|
+
*
|
|
44
|
+
* Strategies:
|
|
45
|
+
* - "mixed" (default): 3 distinct frames, same label.
|
|
46
|
+
* - "expression": same as mixed — picked separately for face-driven
|
|
47
|
+
* content where the agent wants to emphasise expression variation.
|
|
48
|
+
* - "label": ONE best frame, 3 LLM-generated label variations.
|
|
49
|
+
* Use when the source only has one usable visual.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createComposeThumbnailVariantsTool(cwd: string): AgentTool<typeof ComposeThumbnailVariantsParams>;
|
|
52
|
+
/**
|
|
53
|
+
* Greedy top-N selection with minimum spacing. Sort by score desc, walk
|
|
54
|
+
* the list, accept a candidate only if it's ≥ minSpacingSec away from
|
|
55
|
+
* every already-accepted pick. Stable — ties preserve input order.
|
|
56
|
+
*
|
|
57
|
+
* Pure — exported for testing.
|
|
58
|
+
*/
|
|
59
|
+
export declare function pickTopSpaced(paired: VariantPick[], count: number, minSpacingSec: number): VariantPick[];
|
|
60
|
+
/**
|
|
61
|
+
* Ask the LLM for N label variations. Pure-ish (network call) — exported
|
|
62
|
+
* for testing under a mocked fetch.
|
|
63
|
+
*/
|
|
64
|
+
export declare function generateLabelVariations(headline: string, n: number, opts?: {
|
|
65
|
+
apiKey?: string;
|
|
66
|
+
model?: string;
|
|
67
|
+
signal?: AbortSignal;
|
|
68
|
+
}): Promise<string[]>;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=compose-thumbnail-variants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose-thumbnail-variants.d.ts","sourceRoot":"","sources":["../../src/tools/compose-thumbnail-variants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAIrD,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAG3E,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGhE,QAAA,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgClC,CAAC;AAEH,UAAU,WAAW;IACnB,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,SAAS,CAAC;CAClB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kCAAkC,CAChD,GAAG,EAAE,MAAM,GACV,SAAS,CAAC,OAAO,8BAA8B,CAAC,CA6JlD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,WAAW,EAAE,EACrB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,WAAW,EAAE,CAaf;AASD;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,CAAC,EAAE,MAAM,EACT,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAO,GACnE,OAAO,CAAC,MAAM,EAAE,CAAC,CAyCnB"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { resolve as resolvePath, join } from "node:path";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { resolveApiKey } from "../core/auth/api-keys.js";
|
|
4
|
+
import { loadBrandKit } from "../core/brand-kit.js";
|
|
5
|
+
import { compact, err } from "../core/format.js";
|
|
6
|
+
import { extractAtInterval } from "../core/frames.js";
|
|
7
|
+
import { checkFfmpeg, probeMedia } from "../core/media/ffmpeg.js";
|
|
8
|
+
import { composeThumbnailFrame } from "../core/thumbnail-compose.js";
|
|
9
|
+
import { scoreFrames } from "../core/vision.js";
|
|
10
|
+
import { pickBrandFont } from "./compose-thumbnail.js";
|
|
11
|
+
const ComposeThumbnailVariantsParams = z.object({
|
|
12
|
+
input: z.string().describe("Source video (relative resolves to cwd)."),
|
|
13
|
+
outputDir: z.string().describe("Directory for the variant images. Created if missing."),
|
|
14
|
+
text: z.string().min(1).describe("Headline burned on each variant."),
|
|
15
|
+
count: z.number().int().min(1).max(5).optional().describe("How many variants. Default 3."),
|
|
16
|
+
intervalSec: z
|
|
17
|
+
.number()
|
|
18
|
+
.positive()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Sampling interval. Default = totalSec/40 (≈40 candidates over the video)."),
|
|
21
|
+
minSpacingSec: z
|
|
22
|
+
.number()
|
|
23
|
+
.min(0)
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Minimum seconds between picked variants. Default 10."),
|
|
26
|
+
strategy: z
|
|
27
|
+
.enum(["expression", "label", "mixed"])
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Variant generation strategy. 'mixed' (default) = 3 distinct frames + same label. " +
|
|
30
|
+
"'expression' = 3 best frames, all same label (vary expression only — face-driven " +
|
|
31
|
+
"content). 'label' = ONE best frame + 3 LLM-generated label variations (use when the " +
|
|
32
|
+
"source has only one usable face / product / screen)."),
|
|
33
|
+
model: z.string().optional().describe("OpenAI model. Default gpt-4o-mini."),
|
|
34
|
+
detail: z.enum(["low", "high"]).optional().describe("Vision detail. Default low."),
|
|
35
|
+
fontFile: z.string().optional(),
|
|
36
|
+
fontSize: z.number().int().positive().optional(),
|
|
37
|
+
fontColor: z.string().optional(),
|
|
38
|
+
outlineColor: z.string().optional(),
|
|
39
|
+
position: z.enum(["top", "center", "bottom"]).optional(),
|
|
40
|
+
width: z.number().int().positive().optional(),
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* compose_thumbnail_variants — generate N thumbnails for A/B testing.
|
|
44
|
+
*
|
|
45
|
+
* Samples frames at `intervalSec`, scores via vision rubric, picks the
|
|
46
|
+
* top-N spaced ≥ minSpacingSec apart, burns the headline. YouTube
|
|
47
|
+
* native A/B is now standard — variants beat single guesses.
|
|
48
|
+
*
|
|
49
|
+
* Strategies:
|
|
50
|
+
* - "mixed" (default): 3 distinct frames, same label.
|
|
51
|
+
* - "expression": same as mixed — picked separately for face-driven
|
|
52
|
+
* content where the agent wants to emphasise expression variation.
|
|
53
|
+
* - "label": ONE best frame, 3 LLM-generated label variations.
|
|
54
|
+
* Use when the source only has one usable visual.
|
|
55
|
+
*/
|
|
56
|
+
export function createComposeThumbnailVariantsTool(cwd) {
|
|
57
|
+
return {
|
|
58
|
+
name: "compose_thumbnail_variants",
|
|
59
|
+
description: "Generate N thumbnail variants for A/B testing. Samples frames across the video, scores " +
|
|
60
|
+
"each via vision LLM, picks top-N distinct frames (≥minSpacingSec apart), burns the " +
|
|
61
|
+
"headline. `strategy` controls what varies: 'expression' (default for face-driven " +
|
|
62
|
+
"content) picks 3 frames with the SAME label; 'label' picks ONE frame + generates 3 " +
|
|
63
|
+
"distinct labels via LLM (use when only one usable face / product / screen exists); " +
|
|
64
|
+
"'mixed' = current behaviour (3 frames + same label). Output ordered best-first. " +
|
|
65
|
+
"Auto-applies brand kit (fonts.heading, colors.primary). YouTube native A/B is now " +
|
|
66
|
+
"standard — ship variants, not a single guess. Requires OPENAI_API_KEY + ffmpeg. Pair " +
|
|
67
|
+
"with `generate_youtube_metadata` before publish.",
|
|
68
|
+
parameters: ComposeThumbnailVariantsParams,
|
|
69
|
+
async execute(args, ctx) {
|
|
70
|
+
try {
|
|
71
|
+
if (!checkFfmpeg())
|
|
72
|
+
return err("ffmpeg not on PATH", "install ffmpeg");
|
|
73
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
74
|
+
return err("OPENAI_API_KEY not set", "export OPENAI_API_KEY=...");
|
|
75
|
+
}
|
|
76
|
+
const inAbs = resolvePath(cwd, args.input);
|
|
77
|
+
const outDir = resolvePath(cwd, args.outputDir);
|
|
78
|
+
const probe = probeMedia(inAbs);
|
|
79
|
+
if (!probe)
|
|
80
|
+
return err(`probe failed for ${inAbs}`, "verify file exists and is media");
|
|
81
|
+
if (probe.durationSec <= 0)
|
|
82
|
+
return err("source has zero duration");
|
|
83
|
+
const count = Math.min(5, Math.max(1, args.count ?? 3));
|
|
84
|
+
const minSpacing = Math.max(0, args.minSpacingSec ?? 10);
|
|
85
|
+
const interval = args.intervalSec && args.intervalSec > 0
|
|
86
|
+
? args.intervalSec
|
|
87
|
+
: Math.max(1, probe.durationSec / 40);
|
|
88
|
+
const strategy = args.strategy ?? "mixed";
|
|
89
|
+
// Brand-kit fallback: only fill in fontFile / outlineColor when the
|
|
90
|
+
// caller didn't pass an explicit value.
|
|
91
|
+
const brand = loadBrandKit(cwd);
|
|
92
|
+
const brandFont = pickBrandFont(cwd, brand?.fonts?.heading);
|
|
93
|
+
const fontFile = args.fontFile ?? brandFont;
|
|
94
|
+
const outlineColor = args.outlineColor ?? brand?.colors?.primary;
|
|
95
|
+
const brandKitLoaded = brand !== null;
|
|
96
|
+
// Sample frames across the whole video.
|
|
97
|
+
const frames = await extractAtInterval(inAbs, interval, probe.durationSec, {
|
|
98
|
+
maxWidth: 1280,
|
|
99
|
+
signal: ctx.signal,
|
|
100
|
+
});
|
|
101
|
+
if (frames.length === 0)
|
|
102
|
+
return err("no frames extracted", "lower intervalSec");
|
|
103
|
+
// Score each frame.
|
|
104
|
+
const scores = await scoreFrames(frames, {
|
|
105
|
+
model: args.model,
|
|
106
|
+
detail: args.detail,
|
|
107
|
+
signal: ctx.signal,
|
|
108
|
+
});
|
|
109
|
+
// Pair scores with their source frames + pick top-N respecting
|
|
110
|
+
// minSpacingSec.
|
|
111
|
+
const paired = scores.map((s, i) => ({ frame: frames[i], score: s }));
|
|
112
|
+
// ── label strategy: 1 frame, 3 LLM-generated labels ────────────
|
|
113
|
+
if (strategy === "label") {
|
|
114
|
+
const top = paired.sort((a, b) => b.score.score - a.score.score)[0];
|
|
115
|
+
if (!top)
|
|
116
|
+
return err("no variants survived spacing constraint", "lower minSpacingSec");
|
|
117
|
+
const labels = await generateLabelVariations(args.text, count, {
|
|
118
|
+
model: args.model,
|
|
119
|
+
signal: ctx.signal,
|
|
120
|
+
});
|
|
121
|
+
const variants = [];
|
|
122
|
+
for (let i = 0; i < labels.length; i++) {
|
|
123
|
+
const outPath = join(outDir, `variant-${i + 1}.jpg`);
|
|
124
|
+
await composeThumbnailFrame({
|
|
125
|
+
input: inAbs,
|
|
126
|
+
output: outPath,
|
|
127
|
+
atSec: top.frame.atSec,
|
|
128
|
+
text: labels[i],
|
|
129
|
+
fontFile,
|
|
130
|
+
fontSize: args.fontSize,
|
|
131
|
+
fontColor: args.fontColor,
|
|
132
|
+
outlineColor,
|
|
133
|
+
position: args.position,
|
|
134
|
+
width: args.width,
|
|
135
|
+
signal: ctx.signal,
|
|
136
|
+
}, cwd);
|
|
137
|
+
variants.push({
|
|
138
|
+
path: outPath,
|
|
139
|
+
atSec: +top.frame.atSec.toFixed(2),
|
|
140
|
+
score: top.score.score,
|
|
141
|
+
why: top.score.why,
|
|
142
|
+
label: labels[i],
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return compact({
|
|
146
|
+
variants,
|
|
147
|
+
count: variants.length,
|
|
148
|
+
totalScored: paired.length,
|
|
149
|
+
strategy,
|
|
150
|
+
brandKitLoaded,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// ── mixed / expression strategies: N frames, same label ────────
|
|
154
|
+
const picks = pickTopSpaced(paired, count, minSpacing);
|
|
155
|
+
if (picks.length === 0) {
|
|
156
|
+
return err("no variants survived spacing constraint", "lower minSpacingSec");
|
|
157
|
+
}
|
|
158
|
+
// Burn the headline on each pick.
|
|
159
|
+
const variants = [];
|
|
160
|
+
for (let i = 0; i < picks.length; i++) {
|
|
161
|
+
const p = picks[i];
|
|
162
|
+
const outPath = join(outDir, `variant-${i + 1}.jpg`);
|
|
163
|
+
await composeThumbnailFrame({
|
|
164
|
+
input: inAbs,
|
|
165
|
+
output: outPath,
|
|
166
|
+
atSec: p.frame.atSec,
|
|
167
|
+
text: args.text,
|
|
168
|
+
fontFile,
|
|
169
|
+
fontSize: args.fontSize,
|
|
170
|
+
fontColor: args.fontColor,
|
|
171
|
+
outlineColor,
|
|
172
|
+
position: args.position,
|
|
173
|
+
width: args.width,
|
|
174
|
+
signal: ctx.signal,
|
|
175
|
+
}, cwd);
|
|
176
|
+
variants.push({
|
|
177
|
+
path: outPath,
|
|
178
|
+
atSec: +p.frame.atSec.toFixed(2),
|
|
179
|
+
score: p.score.score,
|
|
180
|
+
why: p.score.why,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
return compact({
|
|
184
|
+
variants,
|
|
185
|
+
count: variants.length,
|
|
186
|
+
totalScored: paired.length,
|
|
187
|
+
strategy,
|
|
188
|
+
brandKitLoaded,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
return err(e.message);
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Greedy top-N selection with minimum spacing. Sort by score desc, walk
|
|
199
|
+
* the list, accept a candidate only if it's ≥ minSpacingSec away from
|
|
200
|
+
* every already-accepted pick. Stable — ties preserve input order.
|
|
201
|
+
*
|
|
202
|
+
* Pure — exported for testing.
|
|
203
|
+
*/
|
|
204
|
+
export function pickTopSpaced(paired, count, minSpacingSec) {
|
|
205
|
+
const sorted = [...paired].sort((a, b) => {
|
|
206
|
+
if (b.score.score !== a.score.score)
|
|
207
|
+
return b.score.score - a.score.score;
|
|
208
|
+
return a.frame.atSec - b.frame.atSec;
|
|
209
|
+
});
|
|
210
|
+
const kept = [];
|
|
211
|
+
for (const p of sorted) {
|
|
212
|
+
if (kept.length >= count)
|
|
213
|
+
break;
|
|
214
|
+
const tooClose = kept.some((k) => Math.abs(k.frame.atSec - p.frame.atSec) < minSpacingSec);
|
|
215
|
+
if (tooClose)
|
|
216
|
+
continue;
|
|
217
|
+
kept.push(p);
|
|
218
|
+
}
|
|
219
|
+
return kept;
|
|
220
|
+
}
|
|
221
|
+
const LABEL_SYSTEM = `You distill a YouTube headline into thumbnail labels. Given an input headline, output exactly N distinct 2-4-word labels. Each label should attack the same headline from a DIFFERENT angle (e.g. one curiosity-driven, one outcome-driven, one number-driven). Labels render large on a 100x56 mobile-feed thumbnail — no punctuation, no quotes, ALL CAPS preferred when it fits.
|
|
222
|
+
|
|
223
|
+
Output JSON with this EXACT shape:
|
|
224
|
+
{ "labels": ["...", "...", "..."] }
|
|
225
|
+
|
|
226
|
+
No prose, no extra keys.`;
|
|
227
|
+
/**
|
|
228
|
+
* Ask the LLM for N label variations. Pure-ish (network call) — exported
|
|
229
|
+
* for testing under a mocked fetch.
|
|
230
|
+
*/
|
|
231
|
+
export async function generateLabelVariations(headline, n, opts = {}) {
|
|
232
|
+
const apiKey = opts.apiKey ?? resolveApiKey("OPENAI_API_KEY", "openai");
|
|
233
|
+
if (!apiKey)
|
|
234
|
+
throw new Error("OPENAI_API_KEY required for compose_thumbnail_variants.");
|
|
235
|
+
const model = opts.model ?? "gpt-4o-mini";
|
|
236
|
+
const body = {
|
|
237
|
+
model,
|
|
238
|
+
messages: [
|
|
239
|
+
{ role: "system", content: LABEL_SYSTEM },
|
|
240
|
+
{ role: "user", content: `HEADLINE:\n${headline}\n\nN: ${n}` },
|
|
241
|
+
],
|
|
242
|
+
response_format: { type: "json_object" },
|
|
243
|
+
temperature: 0,
|
|
244
|
+
};
|
|
245
|
+
const res = await fetch("https://api.openai.com/v1/chat/completions", {
|
|
246
|
+
method: "POST",
|
|
247
|
+
headers: {
|
|
248
|
+
Authorization: `Bearer ${apiKey}`,
|
|
249
|
+
"Content-Type": "application/json",
|
|
250
|
+
},
|
|
251
|
+
body: JSON.stringify(body),
|
|
252
|
+
signal: opts.signal,
|
|
253
|
+
});
|
|
254
|
+
if (!res.ok) {
|
|
255
|
+
const text = await res.text().catch(() => "");
|
|
256
|
+
throw new Error(`OpenAI HTTP ${res.status}: ${text.slice(0, 200)}`);
|
|
257
|
+
}
|
|
258
|
+
const data = (await res.json());
|
|
259
|
+
const content = data.choices[0]?.message?.content;
|
|
260
|
+
if (!content)
|
|
261
|
+
throw new Error("compose_thumbnail_variants: empty model response");
|
|
262
|
+
const parsed = JSON.parse(content);
|
|
263
|
+
const arr = Array.isArray(parsed.labels) ? parsed.labels : [];
|
|
264
|
+
const labels = arr
|
|
265
|
+
.map((v) => String(v ?? "").trim())
|
|
266
|
+
.filter((v) => v.length > 0)
|
|
267
|
+
.slice(0, n);
|
|
268
|
+
// Pad with the headline itself if the model under-delivers, so caller
|
|
269
|
+
// always gets N entries.
|
|
270
|
+
while (labels.length < n)
|
|
271
|
+
labels.push(headline);
|
|
272
|
+
return labels;
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=compose-thumbnail-variants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose-thumbnail-variants.js","sourceRoot":"","sources":["../../src/tools/compose-thumbnail-variants.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { AgentTool } from "@kenkaiiii/gg-agent";
|
|
3
|
+
import { escapeDrawtextValue, pickFont } from "../core/thumbnail-compose.js";
|
|
3
4
|
declare const ComposeThumbnailParams: z.ZodObject<{
|
|
4
5
|
input: z.ZodString;
|
|
5
6
|
output: z.ZodString;
|
|
@@ -17,19 +18,11 @@ declare const ComposeThumbnailParams: z.ZodObject<{
|
|
|
17
18
|
width: z.ZodOptional<z.ZodNumber>;
|
|
18
19
|
}, z.core.$strip>;
|
|
19
20
|
export declare function createComposeThumbnailTool(cwd: string): AgentTool<typeof ComposeThumbnailParams>;
|
|
21
|
+
export { escapeDrawtextValue, pickFont };
|
|
20
22
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* g0ldyy/comet, ehendrix23/tesla_dashcam):
|
|
25
|
-
* 1. `\\` first → `\\\\`
|
|
26
|
-
* 2. `:` → `\\:`
|
|
27
|
-
* 3. `'` → `\\'`
|
|
28
|
-
* 4. `%` → `\\%` (because `%{...}` is used for runtime expansions like timecode)
|
|
29
|
-
* 5. newlines → literal `\\n` (drawtext renders `\\n` as a line break)
|
|
30
|
-
*
|
|
31
|
-
* Backslash MUST come first so subsequent escapes don't double-escape it.
|
|
23
|
+
* Resolve a brand-kit `fonts.heading` value to a readable absolute path.
|
|
24
|
+
* Returns undefined when the kit doesn't define one or the file is missing.
|
|
25
|
+
* Pure-ish (touches the filesystem) — exported for testing.
|
|
32
26
|
*/
|
|
33
|
-
export declare function
|
|
34
|
-
export {};
|
|
27
|
+
export declare function pickBrandFont(cwd: string, heading: string | undefined): string | undefined;
|
|
35
28
|
//# sourceMappingURL=compose-thumbnail.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose-thumbnail.d.ts","sourceRoot":"","sources":["../../src/tools/compose-thumbnail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKrD,QAAA,MAAM,sBAAsB;;;;;;;;;;;;;;;iBAyB1B,CAAC;
|
|
1
|
+
{"version":3,"file":"compose-thumbnail.d.ts","sourceRoot":"","sources":["../../src/tools/compose-thumbnail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKrD,OAAO,EAAyB,mBAAmB,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAEpG,QAAA,MAAM,sBAAsB;;;;;;;;;;;;;;;iBAyB1B,CAAC;AAEH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,sBAAsB,CAAC,CAqDhG;AAGD,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,CAAC;AAEzC;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAQ1F"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { existsSync
|
|
2
|
-
import {
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { resolve as resolvePath } from "node:path";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { loadBrandKit } from "../core/brand-kit.js";
|
|
4
5
|
import { compact, err } from "../core/format.js";
|
|
5
|
-
import { checkFfmpeg
|
|
6
|
+
import { checkFfmpeg } from "../core/media/ffmpeg.js";
|
|
6
7
|
import { safeResolveOutputPath } from "../core/safe-paths.js";
|
|
8
|
+
import { composeThumbnailFrame, escapeDrawtextValue, pickFont } from "../core/thumbnail-compose.js";
|
|
7
9
|
const ComposeThumbnailParams = z.object({
|
|
8
10
|
input: z.string().describe("Source video."),
|
|
9
11
|
output: z.string().describe("Thumbnail .jpg or .png."),
|
|
@@ -28,13 +30,6 @@ const ComposeThumbnailParams = z.object({
|
|
|
28
30
|
.optional()
|
|
29
31
|
.describe("Optional output width (height auto). Common: 1280 for YouTube."),
|
|
30
32
|
});
|
|
31
|
-
const SYSTEM_FONT_GUESSES = [
|
|
32
|
-
"/System/Library/Fonts/Helvetica.ttc",
|
|
33
|
-
"/System/Library/Fonts/Supplemental/Arial.ttf",
|
|
34
|
-
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
|
|
35
|
-
"/usr/share/fonts/TTF/DejaVuSans-Bold.ttf",
|
|
36
|
-
"C:\\Windows\\Fonts\\Arial.ttf",
|
|
37
|
-
];
|
|
38
33
|
export function createComposeThumbnailTool(cwd) {
|
|
39
34
|
return {
|
|
40
35
|
name: "compose_thumbnail",
|
|
@@ -49,47 +44,33 @@ export function createComposeThumbnailTool(cwd) {
|
|
|
49
44
|
try {
|
|
50
45
|
const inAbs = resolvePath(cwd, args.input);
|
|
51
46
|
const resolved = safeResolveOutputPath(cwd, args.output);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"-ss",
|
|
74
|
-
String(args.atSec),
|
|
75
|
-
"-i",
|
|
76
|
-
inAbs,
|
|
77
|
-
"-frames:v",
|
|
78
|
-
"1",
|
|
79
|
-
"-vf",
|
|
80
|
-
vf,
|
|
81
|
-
"-q:v",
|
|
82
|
-
"2",
|
|
83
|
-
outAbs,
|
|
84
|
-
], { signal: ctx.signal });
|
|
85
|
-
if (r.code !== 0) {
|
|
86
|
-
return err(`ffmpeg drawtext exited ${r.code}`, "verify atSec is in range and ffmpeg has --enable-libfreetype");
|
|
87
|
-
}
|
|
47
|
+
// Brand-kit fallback: when fontFile / outlineColor aren't passed, fall
|
|
48
|
+
// back to the kit so a single tool call can pick up channel defaults.
|
|
49
|
+
const brand = loadBrandKit(cwd);
|
|
50
|
+
const brandFont = pickBrandFont(cwd, brand?.fonts?.heading);
|
|
51
|
+
const brandOutline = brand?.colors?.primary;
|
|
52
|
+
const fontFile = args.fontFile ?? brandFont;
|
|
53
|
+
const outlineColor = args.outlineColor ?? brandOutline;
|
|
54
|
+
const brandKitLoaded = brand !== null;
|
|
55
|
+
const r = await composeThumbnailFrame({
|
|
56
|
+
input: inAbs,
|
|
57
|
+
output: resolved.path,
|
|
58
|
+
atSec: args.atSec,
|
|
59
|
+
text: args.text,
|
|
60
|
+
fontFile,
|
|
61
|
+
fontSize: args.fontSize,
|
|
62
|
+
fontColor: args.fontColor,
|
|
63
|
+
outlineColor,
|
|
64
|
+
position: args.position,
|
|
65
|
+
width: args.width,
|
|
66
|
+
signal: ctx.signal,
|
|
67
|
+
}, cwd);
|
|
88
68
|
return compact({
|
|
89
69
|
ok: true,
|
|
90
|
-
path:
|
|
70
|
+
path: r.path,
|
|
91
71
|
atSec: args.atSec,
|
|
92
|
-
fontFile,
|
|
72
|
+
fontFile: r.fontFile,
|
|
73
|
+
brandKitLoaded,
|
|
93
74
|
...(resolved.redirected ? { redirected: true, reason: resolved.reason } : {}),
|
|
94
75
|
});
|
|
95
76
|
}
|
|
@@ -99,40 +80,22 @@ export function createComposeThumbnailTool(cwd) {
|
|
|
99
80
|
},
|
|
100
81
|
};
|
|
101
82
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
if (existsSync(p))
|
|
106
|
-
return p;
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
/* ignore */
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return undefined;
|
|
113
|
-
}
|
|
114
|
-
function escapeFilterPath(p) {
|
|
115
|
-
return p.replace(/\\/g, "\\\\").replace(/:/g, "\\:").replace(/'/g, "\\'");
|
|
116
|
-
}
|
|
83
|
+
// Re-exports for backwards compatibility — older tests import these from here.
|
|
84
|
+
export { escapeDrawtextValue, pickFont };
|
|
117
85
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* g0ldyy/comet, ehendrix23/tesla_dashcam):
|
|
122
|
-
* 1. `\\` first → `\\\\`
|
|
123
|
-
* 2. `:` → `\\:`
|
|
124
|
-
* 3. `'` → `\\'`
|
|
125
|
-
* 4. `%` → `\\%` (because `%{...}` is used for runtime expansions like timecode)
|
|
126
|
-
* 5. newlines → literal `\\n` (drawtext renders `\\n` as a line break)
|
|
127
|
-
*
|
|
128
|
-
* Backslash MUST come first so subsequent escapes don't double-escape it.
|
|
86
|
+
* Resolve a brand-kit `fonts.heading` value to a readable absolute path.
|
|
87
|
+
* Returns undefined when the kit doesn't define one or the file is missing.
|
|
88
|
+
* Pure-ish (touches the filesystem) — exported for testing.
|
|
129
89
|
*/
|
|
130
|
-
export function
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
90
|
+
export function pickBrandFont(cwd, heading) {
|
|
91
|
+
if (!heading)
|
|
92
|
+
return undefined;
|
|
93
|
+
const abs = resolvePath(cwd, heading);
|
|
94
|
+
try {
|
|
95
|
+
return existsSync(abs) ? abs : undefined;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
137
100
|
}
|
|
138
101
|
//# sourceMappingURL=compose-thumbnail.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose-thumbnail.js","sourceRoot":"","sources":["../../src/tools/compose-thumbnail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"compose-thumbnail.js","sourceRoot":"","sources":["../../src/tools/compose-thumbnail.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"concat-videos.d.ts","sourceRoot":"","sources":["../../src/tools/concat-videos.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAE3D;AACD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKrD,QAAA,MAAM,kBAAkB;;;;;;iBAatB,CAAC;AAEH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"concat-videos.d.ts","sourceRoot":"","sources":["../../src/tools/concat-videos.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAE3D;AACD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKrD,QAAA,MAAM,kBAAkB;;;;;;iBAatB,CAAC;AAEH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,kBAAkB,CAAC,CA6ExF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, resolve as resolvePath } from "node:path";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -46,14 +46,21 @@ export function createConcatVideosTool(cwd) {
|
|
|
46
46
|
mkdirSync(dirname(outAbs), { recursive: true });
|
|
47
47
|
if (lossless) {
|
|
48
48
|
// concat demuxer: build a list file `file 'path'\n` and feed it.
|
|
49
|
+
// The list file is a temp scratch artifact — clean it up no matter
|
|
50
|
+
// how this branch exits (success, ffmpeg non-zero, or thrown error).
|
|
49
51
|
const listPath = join(tmpdir(), `gg-concat-${Date.now()}.txt`);
|
|
50
52
|
const body = buildConcatListBody(absInputs);
|
|
51
53
|
writeFileSync(listPath, body, "utf8");
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
try {
|
|
55
|
+
const r = await runFfmpeg(["-f", "concat", "-safe", "0", "-i", listPath, "-c", "copy", outAbs], { signal: ctx.signal });
|
|
56
|
+
if (r.code !== 0) {
|
|
57
|
+
return err(`ffmpeg concat-demuxer exited ${r.code}`, "sources may differ in codec/res/fps; retry with lossless=false");
|
|
58
|
+
}
|
|
59
|
+
return compact({ ok: true, path: outAbs, mode: "lossless" });
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
rmSync(listPath, { force: true });
|
|
55
63
|
}
|
|
56
|
-
return compact({ ok: true, path: outAbs, mode: "lossless" });
|
|
57
64
|
}
|
|
58
65
|
// Filter-based concat (re-encode).
|
|
59
66
|
const args = [];
|