@oh-story/dsh 0.1.11 → 0.1.13
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/README.md +17 -11
- package/lib/client.js +85 -35
- package/lib/client.js.map +3 -3
- package/lib/drama/manifest.json +41 -36
- package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +340 -13
- package/lib/drama/skills/short-drama-assets/references/voice-direction.md +4 -2
- package/lib/drama/skills/short-drama-edit/SKILL.md +32 -12
- package/lib/drama/skills/short-drama-edit/references/still-cuts.md +90 -0
- package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +1035 -145
- package/lib/drama/skills/short-drama-edit/scripts/selftest.py +48 -0
- package/lib/drama/skills/short-drama-produce/SKILL.md +6 -1
- package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +12 -0
- package/lib/drama/skills/short-drama-produce/scripts/production_tool.py +138 -9
- package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +6 -0
- package/lib/drama/skills/short-drama-storyboard/SKILL.md +2 -0
- package/lib/drama/skills/short-drama-storyboard/references/production-shot-grammar.md +3 -1
- package/lib/drama/skills/short-drama-video-prompts/SKILL.md +7 -0
- package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +14 -0
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +19 -6
- package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +1 -0
- package/lib/drama/skills/short-drama-video-prompts/references/target-model-profile.md +5 -0
- package/lib/drama/skills/short-drama-video-prompts/references/wan-3.0.md +4 -1
- package/lib/index.js +16 -7
- package/lib/index.js.map +2 -2
- package/lib/novel-to-game/README.md +98 -44
- package/lib/novel-to-game/README_ZH.md +100 -46
- package/lib/novel-to-game/VERSION +1 -1
- package/lib/novel-to-game/examples/jin-ping-mei/build/BUILD_BRIEF.md +27 -202
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/RUN.md +23 -115
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/chamber.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/court_night.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/court_rain.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/garden.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/hall.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/kitchen.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/street.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/street_dawn.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/temple.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/yue/moon.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/angry.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/blush.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/neutral.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/sad.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/smile.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/surprised.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/angry.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/blush.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/neutral.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/sad.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/smile.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/surprised.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/angry.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/blush.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/neutral.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/sad.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/smile.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/surprised.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/angry.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/blush.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/neutral.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/sad.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/smile.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/surprised.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/angry.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/blush.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/neutral.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/sad.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/smile.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/surprised.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/style.css +326 -2503
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/index.html +71 -4
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/adv.js +221 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/audio.js +113 -257
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/main.js +511 -3026
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/menus.js +277 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/petals.js +67 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/stage.js +180 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/store.js +70 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/common.js +198 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/common2.js +204 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/common3.js +198 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/dates.js +186 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/index.js +122 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/meng.js +190 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/pan.js +212 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/pinger.js +198 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/xuee.js +199 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/yue.js +214 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/package.json +2 -2
- package/lib/novel-to-game/examples/jin-ping-mei/build/art/generated-art.json +182 -45
- package/lib/novel-to-game/examples/jin-ping-mei/qa/README.md +7 -17
- package/lib/novel-to-game/examples/jin-ping-mei/qa/verification.json +9 -9
- package/lib/novel-to-game/manifest.json +303 -78
- package/lib/novel-to-game/skills/game-art-direction/references/art-direction-method.md +7 -2
- package/lib/novel-to-game/skills/game-concept/references/concept-method.md +2 -0
- package/lib/novel-to-game/skills/game-world-design/references/narrative-design-method.md +2 -0
- package/lib/novel-to-game/skills/game-world-design/references/world-design-method.md +9 -0
- package/lib/types/client/drama-production-view.d.ts +11 -0
- package/lib/types/client/drama-production-view.d.ts.map +1 -1
- package/lib/types/client/file-activity.d.ts +1 -1
- package/lib/types/client/file-activity.d.ts.map +1 -1
- package/lib/types/client/production-prompts.d.ts +7 -1
- package/lib/types/client/production-prompts.d.ts.map +1 -1
- package/lib/types/client/production-runtime.d.ts +7 -2
- package/lib/types/client/production-runtime.d.ts.map +1 -1
- package/lib/types/drama-adapters.d.ts.map +1 -1
- package/lib/types/skill-provider.d.ts.map +1 -1
- package/lib/types/video-project.d.ts.map +1 -1
- package/lib/video-recap/CHANGELOG.md +108 -1
- package/lib/video-recap/README.en.md +18 -14
- package/lib/video-recap/README.md +18 -14
- package/lib/video-recap/manifest.json +297 -321
- package/lib/video-recap/skills/video-assemble/SKILL.md +18 -16
- package/lib/video-recap/skills/video-assemble/references/explicit-audio-mix.md +3 -1
- package/lib/video-recap/skills/video-assemble/references/jianying/SOURCE.md +5 -5
- package/lib/video-recap/skills/video-assemble/references/packaging.md +4 -4
- package/lib/video-recap/skills/video-assemble/references/subtitle-track.md +10 -10
- package/lib/video-recap/skills/video-assemble/scripts/adoption/audio_mix_binding.py +13 -2
- package/lib/video-recap/skills/video-assemble/scripts/adoption/av_clock.py +109 -0
- package/lib/video-recap/skills/video-assemble/scripts/adoption/strict_publish.py +4 -1
- package/lib/video-recap/skills/video-assemble/scripts/artifacts.py +2 -9
- package/lib/video-recap/skills/video-assemble/scripts/assemble.py +188 -51
- package/lib/video-recap/skills/video-assemble/scripts/assemble_constants.py +0 -1
- package/lib/video-recap/skills/video-assemble/scripts/assembly_contract.py +32 -75
- package/lib/video-recap/skills/video-assemble/scripts/assembly_settings.py +8 -15
- package/lib/video-recap/skills/video-assemble/scripts/audio_mix.py +202 -161
- package/lib/video-recap/skills/video-assemble/scripts/codec_peak.py +112 -0
- package/lib/video-recap/skills/video-assemble/scripts/export_jianying.py +10 -101
- package/lib/video-recap/skills/video-assemble/scripts/jianying/builders.py +44 -475
- package/lib/video-recap/skills/video-assemble/scripts/jianying/model.py +1 -22
- package/lib/video-recap/skills/video-assemble/scripts/jianying/templates.py +0 -3
- package/lib/video-recap/skills/video-assemble/scripts/jianying/timeline_contract.py +36 -103
- package/lib/video-recap/skills/video-assemble/scripts/jianying/tracks.py +0 -8
- package/lib/video-recap/skills/video-assemble/scripts/jianying/writer.py +28 -203
- package/lib/video-recap/skills/video-assemble/scripts/lib.py +20 -34
- package/lib/video-recap/skills/video-assemble/scripts/loudness.py +332 -0
- package/lib/video-recap/skills/video-assemble/scripts/media.py +158 -38
- package/lib/video-recap/skills/video-assemble/scripts/narration_audio.py +30 -16
- package/lib/video-recap/skills/video-assemble/scripts/render_preflight.py +49 -8
- package/lib/video-recap/skills/video-assemble/scripts/source_subtitles.py +17 -6
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/core.py +24 -2
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/track.py +2 -5
- package/lib/video-recap/skills/video-assemble/scripts/subtitles/track_binding.py +2 -9
- package/lib/video-recap/skills/video-assemble/scripts/timeline.py +12 -34
- package/lib/video-recap/skills/video-assemble/scripts/timeline_emit.py +3 -4
- package/lib/video-recap/skills/video-assemble/scripts/visual_render.py +28 -2
- package/lib/video-recap/skills/video-cut/SKILL.md +37 -11
- package/lib/video-recap/skills/video-cut/references/shot-review.md +1 -1
- package/lib/video-recap/skills/video-cut/scripts/cut.py +2 -34
- package/lib/video-recap/skills/video-cut/scripts/cut_cli.py +96 -124
- package/lib/video-recap/skills/video-cut/scripts/cut_contract.py +97 -182
- package/lib/video-recap/skills/video-cut/scripts/cut_render.py +177 -166
- package/lib/video-recap/skills/video-cut/scripts/frame_grid.py +249 -0
- package/lib/video-recap/skills/video-cut/scripts/lib.py +0 -3
- package/lib/video-recap/skills/video-cut/scripts/media_geometry.py +173 -7
- package/lib/video-recap/skills/video-cut/scripts/sentence_boundaries.py +234 -151
- package/lib/video-recap/skills/video-cut/scripts/sentence_gate.py +189 -0
- package/lib/video-recap/skills/video-cut/scripts/shot_review.py +2 -6
- package/lib/video-recap/skills/video-recap/SKILL.md +24 -27
- package/lib/video-recap/skills/video-recap/references/audio-routing.md +8 -6
- package/lib/video-recap/skills/video-recap/references/config-playbook.md +8 -11
- package/lib/video-recap/skills/video-recap/references/data-schema.md +131 -74
- package/lib/video-recap/skills/video-recap/references/resource-library.md +17 -1
- package/lib/video-recap/skills/video-recap/scripts/doctor.py +51 -268
- package/lib/video-recap/skills/video-recap/scripts/final_qc.py +89 -254
- package/lib/video-recap/skills/video-recap/scripts/lib.py +81 -70
- package/lib/video-recap/skills/video-recap/scripts/library.py +40 -4
- package/lib/video-recap/skills/video-recap/scripts/materials.py +13 -80
- package/lib/video-recap/skills/video-recap/scripts/recap_cli.py +49 -17
- package/lib/video-recap/skills/video-recap/scripts/recap_inspect.py +1 -3
- package/lib/video-recap/skills/video-recap/scripts/recap_runner.py +86 -116
- package/lib/video-recap/skills/video-recap/scripts/recap_runtime.py +87 -23
- package/lib/video-recap/skills/video-recap/scripts/recap_source.py +0 -39
- package/lib/video-recap/skills/video-recap/scripts/recap_stage_qc.py +37 -135
- package/lib/video-recap/skills/video-recap/scripts/recap_timeline.py +118 -127
- package/lib/video-recap/skills/video-recap/scripts/resources/__init__.py +4 -0
- package/lib/video-recap/skills/video-recap/scripts/{resource_lock.py → resources/lock.py} +1 -1
- package/lib/video-recap/skills/video-recap/scripts/{project_binding.py → resources/project_binding.py} +78 -17
- package/lib/video-recap/skills/video-reference/SKILL.md +108 -0
- package/lib/video-recap/skills/video-reference/references/reference-schema.md +139 -0
- package/lib/video-recap/skills/video-reference/scripts/lib.py +85 -0
- package/lib/video-recap/skills/video-reference/scripts/reference.py +96 -0
- package/lib/video-recap/skills/video-reference/scripts/reference_check.py +553 -0
- package/lib/video-recap/skills/video-reference/scripts/reference_frames.py +122 -0
- package/lib/video-recap/skills/video-reference/scripts/reference_measure.py +253 -0
- package/lib/video-recap/skills/video-reference/scripts/reference_profile.py +271 -0
- package/lib/video-recap/skills/video-script/SKILL.md +9 -7
- package/lib/video-recap/skills/video-script/scripts/agent_text.py +18 -267
- package/lib/video-recap/skills/video-script/scripts/deslop_qc.py +12 -30
- package/lib/video-recap/skills/video-script/scripts/entry_suggestion.py +125 -0
- package/lib/video-recap/skills/video-script/scripts/evidence_bundle.py +2 -26
- package/lib/video-recap/skills/video-script/scripts/lib.py +5 -15
- package/lib/video-recap/skills/video-script/scripts/lint_summary.py +184 -0
- package/lib/video-recap/skills/video-script/scripts/narration_lint.py +120 -100
- package/lib/video-recap/skills/video-script/scripts/review.py +3 -34
- package/lib/video-recap/skills/video-script/scripts/review_grounding.py +20 -46
- package/lib/video-recap/skills/video-script/scripts/review_response.py +120 -258
- package/lib/video-recap/skills/video-script/scripts/review_runner.py +2 -10
- package/lib/video-recap/skills/video-script/scripts/speech_ownership.py +89 -5
- package/lib/video-recap/skills/video-script/scripts/validate.py +26 -34
- package/lib/video-recap/skills/video-understanding/SKILL.md +29 -4
- package/lib/video-recap/skills/video-understanding/references/data-schema.md +5 -22
- package/lib/video-recap/skills/video-understanding/scripts/agent_text.py +24 -121
- package/lib/video-recap/skills/video-understanding/scripts/asr.py +11 -5
- package/lib/video-recap/skills/video-understanding/scripts/asr_timing_evidence.py +15 -24
- package/lib/video-recap/skills/video-understanding/scripts/briefing/builder.py +59 -25
- package/lib/video-recap/skills/video-understanding/scripts/briefing/context.py +39 -3
- package/lib/video-recap/skills/video-understanding/scripts/briefing/inputs.py +15 -27
- package/lib/video-recap/skills/video-understanding/scripts/briefing/timeline.py +136 -37
- package/lib/video-recap/skills/video-understanding/scripts/consolidate.py +121 -37
- package/lib/video-recap/skills/video-understanding/scripts/detect.py +118 -16
- package/lib/video-recap/skills/video-understanding/scripts/index_normalize.py +359 -0
- package/lib/video-recap/skills/video-understanding/scripts/lib.py +62 -21
- package/lib/video-recap/skills/video-understanding/scripts/storyboard.py +181 -51
- package/lib/video-recap/skills/video-understanding/scripts/timeline_fusion.py +0 -26
- package/lib/video-recap/skills/video-understanding/scripts/understanding_brief.py +37 -14
- package/lib/video-recap/skills/video-understanding/scripts/understanding_cache.py +40 -32
- package/lib/video-recap/skills/video-understanding/scripts/understanding_runner.py +100 -127
- package/lib/video-recap/skills/video-understanding/scripts/understanding_storyboard.py +182 -30
- package/lib/video-recap/skills/video-understanding/scripts/vlm.py +30 -27
- package/lib/video-recap/skills/video-voiceover/SKILL.md +19 -12
- package/lib/video-recap/skills/video-voiceover/references/index-tts.md +3 -3
- package/lib/video-recap/skills/video-voiceover/scripts/approved_text_policy.py +3 -1
- package/lib/video-recap/skills/video-voiceover/scripts/dub.py +60 -135
- package/lib/video-recap/skills/video-voiceover/scripts/lib.py +9 -34
- package/lib/video-recap/skills/video-voiceover/scripts/providers/fish_audio.py +6 -1
- package/lib/video-recap/skills/video-voiceover/scripts/tts_audio.py +64 -1
- package/lib/video-recap/skills/video-voiceover/scripts/tts_cache.py +99 -0
- package/lib/video-recap/skills/video-voiceover/scripts/voiceover.py +177 -200
- package/package.json +45 -45
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/inner_court_accord_five.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/public_day15.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/household/li_jiaoer.webp +0 -0
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/new-guofeng.css +0 -1494
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/assets.js +0 -147
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/data.js +0 -7470
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/engine.js +0 -13066
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/text.js +0 -32
- package/lib/novel-to-game/examples/jin-ping-mei/qa/playable-model.json +0 -99
- package/lib/novel-to-game/examples/jin-ping-mei/qa/verify_playable_model.mjs +0 -152
- package/lib/video-recap/skills/video-assemble/references/foreground-compose.md +0 -118
- package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_combination_segment.json +0 -84
- package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_combination_video_material.json +0 -98
- package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_draft.json +0 -204
- package/lib/video-recap/skills/video-assemble/references/pair-media.md +0 -74
- package/lib/video-recap/skills/video-assemble/scripts/compose_foreground.py +0 -293
- package/lib/video-recap/skills/video-assemble/scripts/pair_media.py +0 -216
- package/lib/video-recap/skills/video-recap/references/shift-left-qc-schema.md +0 -23
- package/lib/video-recap/skills/video-recap/scripts/mimo_qc.py +0 -33
- package/lib/video-recap/skills/video-recap/scripts/qc/__init__.py +0 -1
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_client.py +0 -13
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_contract.py +0 -9
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_evidence.py +0 -287
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_observations.py +0 -175
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_payload.py +0 -206
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_report.py +0 -318
- package/lib/video-recap/skills/video-recap/scripts/qc/mimo_runner.py +0 -130
- package/lib/video-recap/skills/video-recap/scripts/qc_contract.py +0 -320
- package/lib/video-recap/skills/video-script/scripts/timeline_fusion.py +0 -108
- package/lib/video-recap/skills/video-understanding/scripts/brief.py +0 -9
- package/lib/video-recap/skills/video-understanding/scripts/deslop_qc.py +0 -211
- package/lib/video-recap/skills/video-understanding/scripts/narration_lint.py +0 -707
- package/lib/video-recap/skills/video-understanding/scripts/speech_ownership.py +0 -143
- /package/lib/video-recap/skills/video-cut/scripts/{narration_mapping.py → cut_qc.py} +0 -0
package/README.md
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
`oh-story-dsh` 是基于 DeepSeek Harness(DSH)构建的社区小说、短剧、互动游戏与视频解说创作插件,提供:
|
|
8
8
|
|
|
9
9
|
- 13 个 Oh Story 0.8.4 小说 Skills 与 7 个专业 Roles;
|
|
10
|
-
- 11 个 Drama Skills 0.8.
|
|
11
|
-
- 7 个 NovelToGame 0.
|
|
12
|
-
-
|
|
10
|
+
- 11 个 Drama Skills 0.8.1 短剧流程,每集按请求维护最多五份 creator-first Markdown,成片装配另写《剪辑单.md》;
|
|
11
|
+
- 7 个 NovelToGame 0.5.0 Skills、`game-adaptations/<project>` 产物协议与《金瓶梅 · 风月总账》ADV 可玩构建;
|
|
12
|
+
- 7 个 video-recap-skills 0.6.1 Skills(3 个用户入口)、`video-recaps/<project>` 项目约定与轻量视频预览工作台;
|
|
13
13
|
- 小说协议 hooks 与安全的 Session workspace 文件路由;
|
|
14
14
|
- 小说/短剧的文件树、编辑器、Chat 三栏工作台,以及游戏/视频的“左侧工作台 + 右侧 Chat”制作面板;
|
|
15
15
|
- Markdown 与 JSONL 结构化预览;
|
|
@@ -23,19 +23,21 @@
|
|
|
23
23
|
安装命令会临时提供 pnpm;只安装 Node.js 的机器也能执行。DSH 的 `plugin add` 内部需要 pnpm,单独运行 `npx @deepseek-ai/dsh ... plugin add` 不会自动补上它。
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
npx -y --package pnpm@11.7.0 --package @deepseek-ai/dsh@0.
|
|
27
|
-
npx -y @deepseek-ai/dsh@0.
|
|
26
|
+
npx -y --package pnpm@11.7.0 --package @deepseek-ai/dsh@0.2.0-rc.2 dsh plugin --profile web add @oh-story/dsh@0.1.13 &&
|
|
27
|
+
npx -y @deepseek-ai/dsh@0.2.0-rc.2 web
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
也可以直接安装 GitHub Release 中的预构建包:
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
npx -y --package pnpm@11.7.0 --package @deepseek-ai/dsh@0.
|
|
34
|
-
npx -y @deepseek-ai/dsh@0.
|
|
33
|
+
npx -y --package pnpm@11.7.0 --package @deepseek-ai/dsh@0.2.0-rc.2 dsh plugin --profile web add https://github.com/zenstory-ai/oh-story-dsh/releases/download/v0.1.13/oh-story-dsh-0.1.13.tgz &&
|
|
34
|
+
npx -y @deepseek-ai/dsh@0.2.0-rc.2 web
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
保持终端运行。若浏览器未自动打开,访问终端打印的完整 `http://127.0.0.1:3080/?token=...` 链接完成首次认证。
|
|
38
38
|
|
|
39
|
+
`0.2.0-rc.2` 是 npm `latest` 与默认推荐宿主。也可把安装、启动两条命令中的版本同时改为 `0.2.1-alpha.1` 试用 alpha;插件接受 `>=0.2.0-rc.2 <0.2.1-0` 或 `>=0.2.1-alpha.1 <0.2.2-0`,两条线不要混装。
|
|
40
|
+
|
|
39
41
|
需要 Node.js 24+。开始 AI 创作前需要在 DSH 的「设置 → 模型」中添加 Provider 并填入 API Key,或在启动前设置环境变量 `DEEPSEEK_API_KEY`。
|
|
40
42
|
|
|
41
43
|
首次启动时 DSH 会在「文稿」目录下自动建「默认工作区 / Default workspace」并打开其中的空白会话,Oh Story 的使用引导显示在会话首页。点击左侧 Workspaces 旁的「添加工作区 / Add workspace」选择作品文件夹,再在下方「选择工作区 / Choose workspace」中选中该目录(或打开已有会话),目录里已有创作项目时,会显示「小说 / 短剧 / 游戏 / 视频」标签;查看已有作品无需 API Key。
|
|
@@ -64,12 +66,16 @@ npx -y @deepseek-ai/dsh@0.1.7-rc.2 web
|
|
|
64
66
|
给 /path/to/video.mp4 做一个 3 分钟中文解说成片,保留关键原声,字幕烧进画面。
|
|
65
67
|
```
|
|
66
68
|
|
|
67
|
-
宿主机需要 Python 3.10+、`PATH` 上的 ffmpeg/ffprobe
|
|
69
|
+
宿主机需要 Python 3.10+、`PATH` 上的 ffmpeg/ffprobe,以及 `MIMO_API_KEY`;Fish Audio TTS 另需 `FISH_API_KEY`,自建 IndexTTS 需 `INDEX_TTS_ENDPOINT` 与 `INDEX_TTS_VOICE`(`TTS_PROVIDER=index-tts`)。Debian/Ubuntu 用 `sudo apt install ffmpeg`;有 libass `subtitles` 滤镜时烧录字幕,没有时交付外部 SRT(也可另装带 libass 的构建)。工作台的「运行环境」检查只报告 DSH Host 进程是否就绪,不返回 Key 内容,密钥也不会写入项目;Agent 实际的执行世界以 `video-recap --doctor` 为准。
|
|
68
70
|
|
|
69
71
|
短剧生产的图片、视频、语音与音乐不由 DeepSeek 生成,而是由 `short-drama-produce` 调用 GPT Image 2(`OPENAI_API_KEY`)、Seedance(`ARK_API_KEY` + `SEEDANCE_MODEL`)、MiniMax H3(`MINIMAX_API_KEY` + `MINIMAX_VIDEO_MODEL` + `MINIMAX_VIDEO_RESOLUTIONS` + `MINIMAX_VIDEO_MIN_DURATION`/`MINIMAX_VIDEO_MAX_DURATION`)、MiniMax Speech(`MINIMAX_API_KEY`)或 MiniMax Music(`MINIMAX_API_KEY`)生成;Key 在启动 DSH 前写入环境变量,「生产」视图会显示每个供应商是否就绪,插件从不读取 Key 的值。内置 adapter 会自动登记到一份不含凭据的配置文件,自定义时用 `OH_STORY_DRAMA_ADAPTER_CONFIG` 指向自己的文件。
|
|
70
72
|
|
|
73
|
+
声音参考需要额外显式配置:自动生成的通用 profile 不声明 `reference_audio`,因为环境变量里的具体模型未必支持声音输入;只有确认所选模型支持后,才在项目外的自定义 adapter 配置里为该 profile 声明 `reference_roles`(包含 `reference_audio`),并用 `OH_STORY_DRAMA_ADAPTER_CONFIG` 指向它。未声明时会在付费提交前拒绝,不会静默丢掉声音。
|
|
74
|
+
|
|
71
75
|
Drama Skills 0.6.0 不支持把 v0.5 结构化项目原地升级为 creator-first 项目。旧项目应继续锁定 v0.5 并只读保留;迁移时请新建项目根,逐集人工确认当前工作实际需要的 `剧本.md`、`视觉设定.md`、`分镜.md`、`图片提示词.md` 或 `视频提示词.md`,不要预建空文档。
|
|
72
76
|
|
|
77
|
+
0.8.1 的角色参考音频必须绑定具体角色,并通过严格的 `reference_roles`、身份与禁控校验;音频不会出现在图片参考选择器里。NovelToGame 0.5.0 的 ADV 示例不迁移旧存档,升级后清除旧站点存储并重新开始。video-recap 0.6.1 改用 QC schema 2,删除旧 QC 标志/路径;升级既有 `work/` 时可能重新生成 ASR、剪辑、TTS 与索引,不得沿用或伪造旧 PASS。
|
|
78
|
+
|
|
73
79
|
## 没看到界面时
|
|
74
80
|
|
|
75
81
|
- **安装报 `pnpm not found on PATH`**:重新执行上面带 `--package pnpm@11.7.0` 的完整安装命令,确认安装成功后再启动。
|
|
@@ -82,7 +88,7 @@ Drama Skills 0.6.0 不支持把 v0.5 结构化项目原地升级为 creator-firs
|
|
|
82
88
|
插件装进哪个 profile,那个 profile 的每个 Session 就都会加载创作 Skills;工作台只在有创作项目时显示。想让原版 `web` 保持干净、只在创作时打开工作台,就装进独立 profile:
|
|
83
89
|
|
|
84
90
|
```bash
|
|
85
|
-
npx -y --package pnpm@11.7.0 --package @deepseek-ai/dsh@0.
|
|
91
|
+
npx -y --package pnpm@11.7.0 --package @deepseek-ai/dsh@0.2.0-rc.2 dsh plugin --profile story add @oh-story/dsh@0.1.13
|
|
86
92
|
```
|
|
87
93
|
|
|
88
94
|
新 profile 默认没有界面。编辑 `~/.dsh/profiles/story/package.json`,把 `dsh.profile.bundles` 改成 `["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "@oh-story/dsh"]`。
|
|
@@ -90,8 +96,8 @@ npx -y --package pnpm@11.7.0 --package @deepseek-ai/dsh@0.1.7-rc.2 dsh plugin --
|
|
|
90
96
|
`@deepseek-ai/dsh-web-app` 是 DSH 自带的 Web 界面包,需要在创作插件之前加载。
|
|
91
97
|
|
|
92
98
|
```bash
|
|
93
|
-
npx -y @deepseek-ai/dsh@0.
|
|
94
|
-
npx -y @deepseek-ai/dsh@0.
|
|
99
|
+
npx -y @deepseek-ai/dsh@0.2.0-rc.2 web # 原版 DSH
|
|
100
|
+
npx -y @deepseek-ai/dsh@0.2.0-rc.2 --profile story --port 3081 # 创作工作台
|
|
95
101
|
```
|
|
96
102
|
|
|
97
103
|
模型、凭据、workspace 与历史会话由 DSH 统一保存,切换 profile 不会丢。安装与启动请使用同一个 dsh 版本。
|
package/lib/client.js
CHANGED
|
@@ -108,7 +108,7 @@ function parsedArgs(raw) {
|
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
-
function mutationFromArgs(name2, callId, argsRaw, stage) {
|
|
111
|
+
function mutationFromArgs(name2, callId, argsRaw, stage, argumentsComplete) {
|
|
112
112
|
let complete = parsedArgs(argsRaw);
|
|
113
113
|
if (name2 === "write")
|
|
114
114
|
return {
|
|
@@ -156,7 +156,7 @@ function mutationFromArgs(name2, callId, argsRaw, stage) {
|
|
|
156
156
|
path,
|
|
157
157
|
operation: "replace-text",
|
|
158
158
|
oldText: completedString(argsRaw, "old_str"),
|
|
159
|
-
newText: jsonStringPrefix(argsRaw, "new_str")?.value ?? (complete !== void 0 ? "" : void 0),
|
|
159
|
+
newText: jsonStringPrefix(argsRaw, "new_str")?.value ?? (argumentsComplete ?? complete !== void 0 ? "" : void 0),
|
|
160
160
|
replaceAll: complete?.replace_all === !0
|
|
161
161
|
} : command === "insert" ? {
|
|
162
162
|
callId,
|
|
@@ -198,8 +198,20 @@ function sameUndispatchedCalls(left, right) {
|
|
|
198
198
|
function fileMutations(runningCalls, partial = null, undispatched = []) {
|
|
199
199
|
let values = [];
|
|
200
200
|
visitRunning(runningCalls, (call) => {
|
|
201
|
-
if (call.phase
|
|
202
|
-
|
|
201
|
+
if (call.phase === "start") {
|
|
202
|
+
let mutation2 = mutationFromArgs(call.name, call.callId, call.argsRaw, "running");
|
|
203
|
+
mutation2 !== void 0 && values.push(mutation2);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (call.args === void 0 || !["write", "edit", "str_replace_editor"].includes(call.name)) return;
|
|
207
|
+
let fields = {};
|
|
208
|
+
for (let key of ["file_path", "path", "content", "file_text", "new_string", "new_str", "old_string", "old_str", "command", "insert_line", "replace_all"]) {
|
|
209
|
+
if (["old_string", "old_str", "command"].includes(key) && !call.args.complete(key)) continue;
|
|
210
|
+
let value = call.args.text(key) ?? call.args.value(key);
|
|
211
|
+
value !== void 0 && (fields[key] = value);
|
|
212
|
+
}
|
|
213
|
+
if (Object.keys(fields).length === 0) return;
|
|
214
|
+
let mutation = mutationFromArgs(call.name, call.callId, JSON.stringify(fields), "streaming", call.args.closed());
|
|
203
215
|
mutation !== void 0 && values.push(mutation);
|
|
204
216
|
});
|
|
205
217
|
for (let call of undispatched) {
|
|
@@ -814,7 +826,7 @@ function endpoint(path, sessionId, file) {
|
|
|
814
826
|
}
|
|
815
827
|
|
|
816
828
|
// src/client/production-prompts.ts
|
|
817
|
-
var authorityBoundary = "\u53EA\u4F7F\u7528\u5F53\u524D DSH Preset \u53EF\u89C1\u7684\u5DE5\u5177\uFF1B\u6240\u6709\u6587\u4EF6\u3001\u7F51\u7EDC\u3001\u751F\u6210\u548C\u547D\u4EE4\u64CD\u4F5C\u7EE7\u7EED\u9075\u5B88 DSH \u6743\u9650\u4E0E\u5BA1\u6279\u3002", referenceRules = "\u53C2\u8003\
|
|
829
|
+
var authorityBoundary = "\u53EA\u4F7F\u7528\u5F53\u524D DSH Preset \u53EF\u89C1\u7684\u5DE5\u5177\uFF1B\u6240\u6709\u6587\u4EF6\u3001\u7F51\u7EDC\u3001\u751F\u6210\u548C\u547D\u4EE4\u64CD\u4F5C\u7EE7\u7EED\u9075\u5B88 DSH \u6743\u9650\u4E0E\u5BA1\u6279\u3002", referenceRules = "\u53C2\u8003\u8F93\u5165\u4EE5\u6765\u6E90\u6761\u76EE\u81EA\u5DF1\u7684\u58F0\u660E\u4E3A\u51C6\uFF08IMG-* \u7684\u300C\u53C2\u8003\u300D\uFF0CSHOT-*\uFF0FMOTION-* \u7684\u300C\u8F93\u5165\u53C2\u8003\u56FE\u300D\uFF0C\u4EE5\u53CA MOTION-* \u72EC\u7ACB\u7684\u300C\u53C2\u8003\u97F3\u9891\u300D\uFF09\uFF1Areference_bindings \u5FC5\u987B\u4E0E\u8BE5\u6761\u76EE\u9010\u69FD\u4E00\u81F4\uFF0C\u5DE5\u4F5C\u53F0\u5217\u51FA\u7684\u8865\u5145\u53C2\u8003\u53EA\u4F5C\u6838\u5BF9\uFF0C\u6761\u76EE\u91CC\u6CA1\u6709\u58F0\u660E\u7684\u4E0D\u8981\u76F4\u63A5\u52A0\u8FDB job\uFF0C\u786E\u9700\u4F7F\u7528\u65F6\u5148\u8BF7\u62E5\u6709\u8BE5\u6761\u76EE\u7684\u9636\u6BB5\u4FEE\u8BA2\u6587\u6863\u3002\u8D77\u59CB\u5E27\u4E0E\u7ED3\u675F\u5E27\u7684\u89D2\u8272\u53EA\u53D6\u81EA\u6765\u6E90\u6761\u76EE\u81EA\u5DF1\u300C\u8F93\u5165\u53C2\u8003\u56FE\u300D\u5404\u69FD\u4F4D\u8BB0\u5F55\u7684\u7528\u9014\uFF08\u8D77\u59CB\u5E27\uFF0F\u7ED3\u675F\u5E27\uFF09\uFF1ASHOT-* \u770B\u300A\u5206\u955C.md\u300B\uFF0CMOTION-* \u770B\u300A\u89C6\u9891\u63D0\u793A\u8BCD.md\u300B\uFF1B\u518D\u7531\u76EE\u6807\u6A21\u578B\u65B9\u8A00\u7FFB\u6210 adapter \u7684 role\uFF0C\u4E0D\u6309\u6587\u4EF6\u540D\u6216\u5DE5\u4F5C\u53F0\u6E05\u5355\u63A8\u65AD\u3002\u76EE\u6807\u65B9\u8A00\u7528 first_frame\uFF0Flast_frame \u4F4D\u7F6E\u627F\u63A5\u8FD9\u7EC4\u8F93\u5165\u65F6\uFF0C\u7ED3\u675F\u5E27\u53EA\u8FDB last_frame\uFF0C\u7EDD\u4E0D\u964D\u7EA7\u6210\u666E\u901A\u53C2\u8003\u56FE\uFF1B\u65B9\u8A00\u8981\u6C42\u6574\u7EC4\u8D70\u591A\u69FD\u53C2\u8003\u65F6\uFF08\u5982 MiniMax H3 \u7684 full-reference\uFF1A\u9996\u5C3E\u5E27\u8F93\u5165\u4E0E\u53C2\u8003\u8F93\u5165\u4E92\u65A5\uFF0C\u8D77\u59CB\u5E27\u3001\u7ED3\u675F\u5E27\u90FD\u968F\u6574\u7EC4\u4EE5 reference_image \u9001\u5165\uFF09\uFF0C\u6309\u65B9\u8A00\u7FFB\u8BD1\uFF0C\u5E76\u5728\u9884\u89C8\u91CC\u5199\u660E\u7ED3\u675F\u5E27\u5C06\u4F5C\u4E3A\u53C2\u8003\u56FE\u9001\u5165\uFF0C\u6216\u5148\u8BF7\u5206\u955C owner \u53D6\u820D\u3002MOTION-* \u7684\u300C\u53C2\u8003\u97F3\u9891\u300D\u4E0D\u6DF7\u5165\u300C\u8F93\u5165\u53C2\u8003\u56FE\u300D\uFF1A\u5B83\u6392\u5728\u56FE\u7247 binding \u4E4B\u540E\uFF0Crole \u56FA\u5B9A\u4E3A reference_audio\uFF0Ccharacter \u9010\u5B57\u7167\u6284\u8BE5\u884C\u300C\u89D2\u8272\u300D\uFF0C\u97F3\u9891\u987A\u5E8F\u4ECD\u72EC\u7ACB\u4ECE 1 \u7F16\u53F7\uFF1Badapter profile \u672A\u663E\u5F0F\u58F0\u660E\u652F\u6301 reference_audio \u65F6\u5FC5\u987B\u5728\u63D0\u4EA4\u524D\u5931\u8D25\uFF0C\u4E0D\u80FD\u9759\u9ED8\u4E22\u5F03\u6216\u628A\u97F3\u9891\u5F53\u56FE\u7247\u3002", shotStartFrameNote = "\u5206\u955C.md \u7684 SHOT-* \u53EA\u4EA7\u51FA\u8D77\u59CB\u5E27\uFF1B\u8981\u4EA7\u51FA\u7ED3\u675F\u5E27\uFF0C\u5148\u7531\u56FE\u7247\u63D0\u793A\u8BCD\u9636\u6BB5\u5EFA\u7ACB\u72EC\u7ACB\u7684 IMG-* \u6761\u76EE\u518D\u6295\u4EA7\u3002";
|
|
818
830
|
function referenceParagraph(kind) {
|
|
819
831
|
return kind === "image" ? `${referenceRules}${shotStartFrameNote}` : referenceRules;
|
|
820
832
|
}
|
|
@@ -861,25 +873,25 @@ ${referenceParagraph(job.kind)}
|
|
|
861
873
|
|
|
862
874
|
\u628A\u6570\u91CF\u3001\u9010\u9879\u8F93\u51FA\u548C\u6210\u672C\u8FB9\u754C\u5B8C\u6574\u5C55\u793A\u7ED9\u521B\u4F5C\u8005\u3002\u6B64\u6309\u94AE\u53EA\u8868\u8FBE\u201C\u51C6\u5907\u9884\u89C8\u201D\uFF0C\u4E0D\u6784\u6210\u770B\u5230\u9884\u89C8\u540E\u7684\u751F\u4EA7\u786E\u8BA4\uFF1B\u4E0D\u5F97 confirm \u6216 run\u3002\u7528\u6237\u5728\u540E\u7EED\u6D88\u606F\u660E\u786E\u786E\u8BA4\u8FD9\u4EFD\u9884\u89C8\u540E\uFF0C\u624D\u53EF\u8C03\u7528 oh_story_production track_job \u767B\u8BB0\u540C\u4E00\u4E2A\u6279\u6B21\u4EFB\u52A1 ID\uFF0C\u5E76\u8FD0\u884C Provider\u3002${authorityBoundary}`;
|
|
863
875
|
}
|
|
864
|
-
function nativeCompositionPrompt(production, job,
|
|
876
|
+
function nativeCompositionPrompt(production, job, orderedSources) {
|
|
865
877
|
return `/short-drama-edit
|
|
866
878
|
|
|
867
879
|
\u6267\u884C\u521B\u4F5C\u8005\u5DF2\u660E\u786E\u786E\u8BA4\u7684\u6210\u7247\u88C5\u914D\u4EFB\u52A1\u3002
|
|
868
880
|
- \u4EFB\u52A1 ID\uFF1A${job.id}
|
|
869
881
|
- \u5267\u96C6\uFF1A${production.episodeDirectory}
|
|
870
|
-
- \u521B\u4F5C\u8005\u5728\u6210\u7247\u89C6\u56FE\u6392\u5B9A\u7684\u955C\u5E8F\uFF0C\u4E0D\u5F97\u81EA\u884C\u6362\u5E8F\uFF1A
|
|
871
|
-
${
|
|
882
|
+
- \u521B\u4F5C\u8005\u5728\u6210\u7247\u89C6\u56FE\u6392\u5B9A\u7684\u955C\u5E8F\u4E0E\u5B9E\u9645\u6765\u6E90\uFF08\u81EA\u52A8\u6A21\u5F0F\u5DF2\u6309\u89C6\u9891\u4F18\u5148\u89E3\u6790\uFF1B\u663E\u5F0F\u9009\u6E90\u4F18\u5148\u4E8E\u81EA\u52A8\u7ED3\u679C\uFF09\uFF0C\u4E0D\u5F97\u81EA\u884C\u6362\u5E8F\u6216\u66FF\u6362\uFF1A
|
|
883
|
+
${orderedSources.map((source, index) => `${String(index + 1)}. ${source.shotId} \u2192 ${source.sourceId} \xB7 ${source.kind === "video" ? "\u89C6\u9891" : "\u9759\u5E27"} \xB7 ${source.path}${source.kind === "image" ? ` \xB7 \u5206\u955C\u65F6\u957F ${source.durationSeconds === void 0 ? "\u672A\u586B\u5199" : `${String(source.durationSeconds)} \u79D2`}` : ""}`).join(`
|
|
872
884
|
`)}
|
|
873
885
|
- \u526A\u8F91\u5355\uFF1A${production.episodeDirectory}/\u526A\u8F91\u5355.md
|
|
874
886
|
- \u8F93\u51FA\uFF1A${production.episodeDirectory}/\u5236\u4F5C\u6210\u679C/\u6210\u7247/
|
|
875
887
|
|
|
876
|
-
\u5148\u5199\u526A\u8F91\u5355\u518D\u6E32\u67D3\u3002\u9010\u6BB5\u770B\u5B8C\u7D20\u6750\u540E\u5199\u4E0B\u771F\u5B9E\u7684\u5165\u51FA\u70B9\u3001\u53D6\u820D\u7406\u7531\u3001\u58F0\u97F3\u5904\u7406\u4E0E\u5B57\u5E55\uFF0C\u4E0D\u8981\u6309\u955C\u5E8F\u51ED\u7A7A\u586B\u65F6\u95F4\uFF1B\u5B57\u5E55\u9010\u5B57\u53D6\u81EA\u5267\u672C.md\u3002\u526A\u8F91\u5355\u8BB0\u5F55\u7D20\u6750\u53D6\u820D\u3001\u5165\u51FA\u70B9\u3001\u540E\u671F\u5904\u7406\u4E0E\u4EA4\u4ED8\u89C4\u683C\uFF0C\u4E0D\u6539\u5199\u5267\u672C\u3001\u5206\u955C\u6216\u89C6\u9891\u63D0\u793A\u8BCD\u7684\u8BED\u4E49\uFF1B\u4E0D\u8981\u9000\u56DE\u53BB\u751F\u6210\u65B0\u7D20\u6750\u3002
|
|
888
|
+
\u5148\u5199\u526A\u8F91\u5355\u518D\u6E32\u67D3\u3002\u9010\u6BB5\u770B\u5B8C\u7D20\u6750\u540E\u5199\u4E0B\u771F\u5B9E\u7684\u5165\u51FA\u70B9\u3001\u53D6\u820D\u7406\u7531\u3001\u58F0\u97F3\u5904\u7406\u4E0E\u5B57\u5E55\uFF0C\u4E0D\u8981\u6309\u955C\u5E8F\u51ED\u7A7A\u586B\u65F6\u95F4\uFF1B\u5B57\u5E55\u9010\u5B57\u53D6\u81EA\u5267\u672C.md\u3002\u4E0A\u9762\u6807\u4E3A\u89C6\u9891\u7684\u6765\u6E90\u4F7F\u7528\u5BF9\u5E94 MOTION-*\uFF0C\u6807\u4E3A\u9759\u5E27\u7684\u6765\u6E90\u9010\u5B57\u4F7F\u7528\u7ED9\u51FA\u7684 SHOT-* \u6216 IMG-*\uFF1B\u9759\u5E27\u4EE5\u5217\u51FA\u7684\u5206\u955C\u65F6\u957F\u4E3A\u8D77\u70B9\uFF0C\u4F46\u82E5\u5DF2\u6709\u914D\u97F3\uFF0C\u987B\u5148\u91CF\u51FA\u771F\u5B9E\u6709\u58F0\u533A\u95F4\u5E76\u636E\u6B64\u6392\u65F6\u957F\uFF0C\u4E0D\u80FD\u622A\u65AD\u53F0\u8BCD\u3002\u526A\u8F91\u5355\u8BB0\u5F55\u7D20\u6750\u53D6\u820D\u3001\u5165\u51FA\u70B9\u3001\u540E\u671F\u5904\u7406\u4E0E\u4EA4\u4ED8\u89C4\u683C\uFF0C\u4E0D\u6539\u5199\u5267\u672C\u3001\u5206\u955C\u6216\u89C6\u9891\u63D0\u793A\u8BCD\u7684\u8BED\u4E49\uFF1B\u4E0D\u8981\u9000\u56DE\u53BB\u751F\u6210\u65B0\u7D20\u6750\u3002
|
|
877
889
|
|
|
878
|
-
\u89C6\u9891\u63D0\u793A\u8BCD
|
|
890
|
+
\u6309\u5F53\u524D\u5236\u4F5C\u5F62\u6001\u4E3A\u6BCF\u4E00\u955C\u4EA4\u4EE3\u4E0B\u843D\uFF1A\u89C6\u9891\u6BB5\u6765\u6E90\u5199 MOTION-*\uFF1B\u9759\u5E27\u6BB5\u6765\u6E90\u5199\u5206\u955C\u91CC\u7684 SHOT-* \u6216\u56FE\u7247\u63D0\u793A\u8BCD\u91CC\u7684 IMG-*\uFF0C\u4E0D\u5F97\u56E0\u4E3A\u7701\u94B1\u3001\u5931\u8D25\u6216\u6392\u961F\u81EA\u884C\u628A\u89C6\u9891\u6539\u6210\u9759\u5E27\u3002\u5B58\u5728 SHOT-* \u9759\u5E27\u65F6\uFF0C\u5206\u955C\u91CC\u7684\u6BCF\u955C\u5FC5\u987B\u5165\u7247\u6216\u5217\u5165\u300C\u672A\u91C7\u7528\u955C\u5934\u300D\uFF1B\u5B58\u5728\u89C6\u9891\u6BB5\u65F6\uFF0C\u89C6\u9891\u63D0\u793A\u8BCD\u91CC\u7684\u6BCF\u4E2A MOTION-* \u4E5F\u5FC5\u987B\u5165\u7247\u6216\u8BF4\u660E\u672A\u91C7\u7528\u3002\u89C6\u9891\u4E0E\u9759\u5E27\u6DF7\u526A\u65F6\uFF0C\u540C\u4E00\u955C\u7528\u4E86 SHOT-* \u53EF\u540C\u65F6\u8986\u76D6\u5BF9\u5E94 MOTION-*\uFF0C\u7528\u4E86 MOTION-* \u53EF\u540C\u65F6\u8986\u76D6\u5BF9\u5E94 SHOT-*\u3002\u672A\u91C7\u7528\u9879\u5199\u8FDB\u526A\u8F91\u5355\u5F00\u5934\uFF08\u4EA4\u4ED8\u89C4\u683C\u6240\u5728\u5904\u3001\u7B2C\u4E00\u4E2A\u300C## CUT-\u300D\u4E4B\u524D\uFF09\u7684\u4E00\u884C\uFF1A\u300C- \u672A\u91C7\u7528\u955C\u5934\uFF1AMOTION-\u2026\uFF08\u7406\u7531\uFF1A\u6587\u4EF6\u7F3A\u5931\u2014\u2014\u2026\uFF09\uFF1BSHOT-\u2026\uFF08\u7406\u7531\uFF1A\u8D28\u91CF\u4E0D\u53EF\u7528\u2014\u2014\u2026\uFF09\u300D\u3002\u591A\u9879\u7528\u5168\u89D2\u300C\uFF1B\u300D\u8FDE\u63A5\uFF0C\u7406\u7531\u4E0D\u80FD\u4E3A\u7A7A\u3001\u81EA\u8EAB\u4E0D\u542B\u300C\uFF1B\u300D\uFF0C\u5E76\u5199\u660E\u5C5E\u4E8E\u6587\u4EF6\u7F3A\u5931\u3001\u8D28\u91CF\u4E0D\u53EF\u7528\u8FD8\u662F\u53D9\u4E8B\u53D6\u820D\uFF1B\u6F0F\u6389\u4EFB\u4F55\u4E00\u4E2A\uFF0Ccheck \u90FD\u4F1A\u963B\u65AD\u3002
|
|
879
891
|
|
|
880
|
-
\u526A\u8F91\u5355\u843D\u76D8\u540E\u4F9D\u6B21\u8FD0\u884C edit_tool.py \u7684 check \u4E0E render\uFF0Ccheck \u62A5\u51FA\u7684\u95EE\u9898\u5148\u6539\u6587\u6863\u518D\u91CD\u8DD1\u3002\
|
|
892
|
+
\u526A\u8F91\u5355\u843D\u76D8\u540E\u4F9D\u6B21\u8FD0\u884C edit_tool.py \u7684 check \u4E0E render\uFF0Ccheck \u62A5\u51FA\u7684\u95EE\u9898\u5148\u6539\u6587\u6863\u518D\u91CD\u8DD1\u3002\u89C6\u9891 CUT \u7684\u7D20\u6750\u5FC5\u987B\u540C\u5BBD\u3001\u540C\u9AD8\u3001\u540C\u5E27\u7387\uFF1Arender \u4E0D\u66FF\u89C6\u9891\u7F29\u653E\u6216\u6539\u5E27\u7387\uFF1B\u9759\u5E27\u5219\u6309\u4EA4\u4ED8\u89C4\u683C\u7B49\u6BD4\u94FA\u6EE1\u3001\u5C45\u4E2D\u88C1\u5207\u5E76\u6309\u8FD0\u955C\u51FA\u753B\uFF0C\u56E0\u6B64\u53EA\u8981\u6709\u9759\u5E27\u5C31\u5FC5\u987B\u586B\u5199\u300C\u753B\u5E45\u4E0E\u5E27\u7387\u300D\u3002\u89C6\u9891\u88AB check \u62A5\u51FA\u753B\u5E45\u6216\u5E27\u7387\u4E0D\u4E00\u81F4\u65F6\uFF0C\u5728\u5F53\u524D DSH \u6267\u884C\u73AF\u5883\u91CC\u7ECF\u5BA1\u6279\u7528 ffmpeg \u6309\u4EA4\u4ED8\u89C4\u683C\u7EDF\u4E00\u3001\u4FDD\u7559\u6784\u56FE\uFF0C\u65B0\u6587\u4EF6\u5199\u5230 ${production.episodeDirectory}/\u5236\u4F5C\u6210\u679C/\u6210\u7247/\u89C4\u683C\u7EDF\u4E00/\u2014\u2014\u8FD9\u662F\u526A\u8F91\u9636\u6BB5\u81EA\u5DF1\u7684\u4E2D\u95F4\u6587\u4EF6\uFF0C\u4E0D\u653E\u5728\u751F\u4EA7\u9636\u6BB5\u7684\u539F\u7D20\u6750\u65C1\u8FB9\u3001\u4E0D\u8986\u76D6\u5DF2\u751F\u4EA7\u7684\u7D20\u6750\uFF0C\u6587\u4EF6\u540D\u4E5F\u4E0D\u6CBF\u7528\u539F\u6587\u4EF6\u91CC\u7684\u4EFB\u52A1 ID\uFF08\u53EF\u76F4\u63A5\u7528 MOTION ID\uFF09\uFF1B\u5728\u8BE5 CUT \u4E0B\u8BB0\u5F55\u88C1\u5207\u6216\u7559\u8FB9\uFF08\u4E0D\u8981\u5199\u8FDB\u300C\u753B\u9762\u300D\u884C\uFF0C\u5B83\u53EA\u8BA4\u4EAE\u5EA6\u3001\u9971\u548C\u3001\u8272\u6E29\u6216\u300C\u65E0\u300D\u300C\u4E0D\u6821\u300D\uFF09\uFF0C\u628A\u300C\u6765\u6E90\u300D\u6539\u6307\u65B0\u6587\u4EF6\uFF0C\u5165\u51FA\u70B9\u968F\u8F6C\u6362\u53D8\u5316\u65F6\u540C\u6B65\u4FEE\u6539\uFF0C\u518D\u91CD\u8DD1 check\u3002\u9759\u5E27\u6765\u6E90\u5165\u70B9\u5199 0.00\u3001\u51FA\u70B9\u7B49\u4E8E\u65F6\u957F\u4E14\u81F3\u5C11 0.50 \u79D2\uFF1B\u9700\u8981\u8FD0\u52A8\u65F6\u53EA\u7528\u526A\u8F91\u5355\u652F\u6301\u7684\u56FA\u5B9A\u3001\u63A8\u8FD1\u3001\u62C9\u8FDC\u6216\u5E73\u79FB\u5199\u6CD5\u3002
|
|
881
893
|
|
|
882
|
-
\u9ED8\u8BA4\u7684\u786C\u5B57\u5E55\u8DEF\u7EBF\u9700\u8981\u5E26 libass \u7684 ffmpeg\uFF0C\u7F3A libass \u65F6\u5982\u5B9E\u62A5\u51FA\uFF0C\u4E0D\u8981\u6084\u6084\u53BB\u6389\u5B57\u5E55\u3002Remotion \u5728\u9879\u76EE\u5916\u7684 ~/.cache/short-drama-edit/remotion \u91CC\u88C5 Node \u4F9D\u8D56\u3001\u9010\u5E27\u8FC7\u65E0\u5934\u6D4F\u89C8\u5668\uFF1A\u53EF\u9009\u7684 Remotion \u5B57\u5E55\u8DEF\u7EBF\u8981\u5B83\uFF0C\u526A\u8F91\u5355\u91CC\u53EA\u8981\u6709\u300C\u753B\u9762\u6587\u5B57\u300D\u884C\u4E5F\u5FC5\u987B\u8981\u5B83\uFF1B\u53EA\u6709\u521B\u4F5C\u8005\u660E\u786E\u540C\u610F\u8FD9\u6B21\u5B89\u88C5\uFF08\u5728\u8BE5\u76EE\u5F55 npm install\uFF0C0.8 \u4E4B\u524D\u88C5\u8FC7\u7684\u8981\u91CD\u88C5\u4E00\u6B21\uFF09\u65F6\u624D\u8D70\uFF0C\u672A\u540C\u610F\u5C31\u4E0D\u5199\u300C\u753B\u9762\u6587\u5B57\u300D\u884C\uFF0C\u5E76\u544A\u8BC9\u521B\u4F5C\u8005\u753B\u9762\u91CC\u7559\u7ED9\u9762\u677F\u7684\u7A7A\u767D\u4F1A\u4FDD\u6301\u7A7A\u767D\u3002\u526A\u8F91\u5355\u7684\u300C\u58F0\u97F3\u300D\u884C\u53EA\u662F\u8BB0\u5F55\uFF0Crender \u4E0D\u6267\u884C\u5B83\uFF1Arender \u5207\u6BB5\u3001\u540C\u573A\u666F\u81EA\u52A8\u63A5\u955C\uFF08CUT \u5199\u4E86\u300C\u753B\u9762\u300D\u6821\u6B63\u5C31\u66FF\u4EE3\u5B83\uFF0C\u300C\u753B\u9762\uFF1A\u4E0D\u6821\u300D\u8DF3\u8FC7\u5B83\uFF0C\u4EA4\u4ED8\u89C4\u683C\u5199\u300C\u63A5\u955C\u5339\u914D\uFF1A\u65E0\u300D\u6574\u96C6\u5173\u95ED\uFF09\u3001\u786C\u62FC\u63A5\u3001\u6DF7\u5165\u300C\u97F3\u6548\u300D\u884C\u3001\u70E7\u5B57\u5E55\u4E0E\u753B\u9762\u6587\u5B57\u3001\u53EF\u9009\u9897\u7C92\u3001\u7EDF\u4E00\u54CD\u5EA6\u3002\u300C\u97F3\u6548\u300D\
|
|
894
|
+
\u9ED8\u8BA4\u7684\u786C\u5B57\u5E55\u8DEF\u7EBF\u9700\u8981\u5E26 libass \u7684 ffmpeg\uFF0C\u7F3A libass \u65F6\u5982\u5B9E\u62A5\u51FA\uFF0C\u4E0D\u8981\u6084\u6084\u53BB\u6389\u5B57\u5E55\u3002Remotion \u5728\u9879\u76EE\u5916\u7684 ~/.cache/short-drama-edit/remotion \u91CC\u88C5 Node \u4F9D\u8D56\u3001\u9010\u5E27\u8FC7\u65E0\u5934\u6D4F\u89C8\u5668\uFF1A\u53EF\u9009\u7684 Remotion \u5B57\u5E55\u8DEF\u7EBF\u8981\u5B83\uFF0C\u526A\u8F91\u5355\u91CC\u53EA\u8981\u6709\u300C\u753B\u9762\u6587\u5B57\u300D\u884C\u4E5F\u5FC5\u987B\u8981\u5B83\uFF1B\u53EA\u6709\u521B\u4F5C\u8005\u660E\u786E\u540C\u610F\u8FD9\u6B21\u5B89\u88C5\uFF08\u5728\u8BE5\u76EE\u5F55 npm install\uFF0C0.8 \u4E4B\u524D\u88C5\u8FC7\u7684\u8981\u91CD\u88C5\u4E00\u6B21\uFF09\u65F6\u624D\u8D70\uFF0C\u672A\u540C\u610F\u5C31\u4E0D\u5199\u300C\u753B\u9762\u6587\u5B57\u300D\u884C\uFF0C\u5E76\u544A\u8BC9\u521B\u4F5C\u8005\u753B\u9762\u91CC\u7559\u7ED9\u9762\u677F\u7684\u7A7A\u767D\u4F1A\u4FDD\u6301\u7A7A\u767D\u3002\u526A\u8F91\u5355\u7684\u300C\u58F0\u97F3\u300D\u884C\u53EA\u662F\u8BB0\u5F55\uFF0Crender \u4E0D\u6267\u884C\u5B83\uFF1Arender \u5207\u6BB5\u3001\u9759\u5E27\u51FA\u753B\u4E0E\u8FD0\u955C\u3001\u540C\u573A\u666F\u81EA\u52A8\u63A5\u955C\uFF08CUT \u5199\u4E86\u300C\u753B\u9762\u300D\u6821\u6B63\u5C31\u66FF\u4EE3\u5B83\uFF0C\u300C\u753B\u9762\uFF1A\u4E0D\u6821\u300D\u8DF3\u8FC7\u5B83\uFF0C\u4EA4\u4ED8\u89C4\u683C\u5199\u300C\u63A5\u955C\u5339\u914D\uFF1A\u65E0\u300D\u6574\u96C6\u5173\u95ED\uFF09\u3001\u786C\u62FC\u63A5\u3001\u6DF7\u5165\u300C\u97F3\u6548\u300D\u300C\u914D\u97F3\u300D\u300C\u73AF\u5883\u58F0\u300D\u884C\u3001\u70E7\u5B57\u5E55\u4E0E\u753B\u9762\u6587\u5B57\u3001\u53EF\u9009\u9897\u7C92\u3001\u7EDF\u4E00\u54CD\u5EA6\u3002\u914D\u97F3\u53EF\u7528\u8D1F\u8D77\u70B9\u505A J-cut\uFF0C\u4E5F\u53EF\u8DE8\u5207\u70B9\u505A L-cut\uFF1B\u5B57\u5E55\u540C\u6837\u53EF\u8DE8\u5207\u70B9\uFF0C\u6309\u6574\u6761\u7247\u6838\u5BF9\u4E0D\u91CD\u53E0\u4E14\u4E0D\u8D8A\u8FC7\u7ED3\u5C3E\u3002\u300C\u97F3\u6548\u300D\u300C\u914D\u97F3\u300D\u300C\u73AF\u5883\u58F0\u300D\u4E4B\u5916\u7684\u6DF7\u97F3\u3001\u4EA4\u53C9\u6DE1\u5165\u3001\u914D\u4E50\u3001\u8F6C\u573A\u6216\u683C\u5F0F\u8F6C\u6362\u90FD\u662F\u53E6\u4E00\u6B65\u7ECF\u5BA1\u6279\u7684\u5916\u90E8 ffmpeg \u5904\u7406\uFF0C\u5148\u5199\u5230\u4E34\u65F6\u6587\u4EF6\uFF1B\u8FD9\u4E00\u6B65\u6700\u540E\u8981\u50CF render \u4E00\u6837\u6309\u526A\u8F91\u5355\u7684\u300C\u4EA4\u4ED8\u54CD\u5EA6\u300D\u5BF9\u6574\u7247\u505A\u4E24\u904D loudnorm\uFF08I=\u4EA4\u4ED8\u54CD\u5EA6\u3001TP=-1.5\u3001LRA=11\uFF0C\u7B2C\u4E8C\u904D\u4EE3\u5165\u7B2C\u4E00\u904D\u7684\u5B9E\u6D4B\u503C\u5E76\u7528 linear=true\uFF09\uFF0C\u97F3\u9891\u7F16\u7801\u4E3A AAC 192k\u300148 kHz\uFF0C\u7136\u540E\u624D\u66FF\u6362 ${production.episodeDirectory}/\u5236\u4F5C\u6210\u679C/\u6210\u7247/\u6210\u7247.mp4\uFF0C\u5E76\u628A\u547D\u4EE4\u8BB0\u8FDB\u526A\u8F91\u5355\uFF1B\u91CD\u65B0 render \u4F1A\u8986\u76D6\u6210\u7247\uFF0C\u8FD9\u4E9B\u6B65\u9AA4\u8981\u91CD\u505A\u3002\u6700\u540E\u5BF9\u4EA4\u4ED8\u7684\u8FD9\u4EFD\u6210\u7247.mp4 \u8FD0\u884C edit_tool.py verify \u5E76\u62A5\u544A\u5B9E\u6D4B\u6570\u5B57\uFF0C\u300C\u672A\u6D4B\u300D\u9879\u7167\u5B9E\u5199\u672A\u6D4B\u3002
|
|
883
895
|
|
|
884
896
|
ffmpeg \u4E0E ffprobe \u901A\u8FC7\u5F53\u524D DSH \u6267\u884C\u73AF\u5883\u8C03\u7528\uFF0C\u4E0D\u53EF\u7528\u65F6\u5982\u5B9E\u62A5\u51FA\u6765\uFF0C\u4E0D\u8981\u628A\u300C\u6CA1\u6D4B\u300D\u5199\u6210\u300C\u901A\u8FC7\u300D\u3002\u6240\u6709\u547D\u4EE4\u548C\u5199\u5165\u7EE7\u7EED\u9075\u5B88 DSH \u6743\u9650\u4E0E\u5BA1\u6279\uFF0C\u4E0D\u5F97\u4F2A\u9020\u6210\u529F\u3002`;
|
|
885
897
|
}
|
|
@@ -956,6 +968,14 @@ function referencesForTarget(targetId, production, versions, selections, library
|
|
|
956
968
|
});
|
|
957
969
|
return [...new Map([...declared, ...manual].map((version) => [version.id, version])).values()];
|
|
958
970
|
}
|
|
971
|
+
function mediaBelongsToEpisode(path, episodeDirectory) {
|
|
972
|
+
if (path === void 0 || path.startsWith(`${episodeDirectory}/`)) return !0;
|
|
973
|
+
let episodeName = episodeDirectory.split("/").at(-1);
|
|
974
|
+
return episodeName !== void 0 && path.startsWith(`\u4EA4\u4ED8/${episodeName}/`);
|
|
975
|
+
}
|
|
976
|
+
function sequenceSourceEligible(shotId, version) {
|
|
977
|
+
return version.kind === "video" ? version.targetId === shotId : version.targetId === shotId || version.targetId.startsWith("IMG-");
|
|
978
|
+
}
|
|
959
979
|
function queuedItemForJob(jobId, queue) {
|
|
960
980
|
if (jobId.trim() === "") return;
|
|
961
981
|
let escaped = jobId.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"), labelled = new RegExp(`\u4EFB\u52A1\\s*ID\\s*[\uFF1A:]\\s*${escaped}(?:[\\s.,;\u3001\u3002]|$)`, "u");
|
|
@@ -995,18 +1015,22 @@ function reconcileProductionJobs(jobs, queue, sessionRunning, versions) {
|
|
|
995
1015
|
});
|
|
996
1016
|
return settleCompositions(reconciled);
|
|
997
1017
|
}
|
|
998
|
-
function reconcileSequence(shotIds, current, versions, selections) {
|
|
999
|
-
let shotSet = new Set(shotIds), preserved = current.filter((item) => shotSet.has(item.shotId)), present = new Set(preserved.map((item) => item.shotId)), appended = shotIds.filter((shotId) => !present.has(shotId)).map((shotId) => ({ shotId }));
|
|
1000
|
-
return [...preserved, ...appended].map((item) =>
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1018
|
+
function reconcileSequence(shotIds, current, versions, selections, episodeDirectory) {
|
|
1019
|
+
let scopedVersions = episodeDirectory === void 0 ? versions : versions.filter((version) => mediaBelongsToEpisode(version.path, episodeDirectory)), shotSet = new Set(shotIds), preserved = current.filter((item) => shotSet.has(item.shotId)), present = new Set(preserved.map((item) => item.shotId)), appended = shotIds.filter((shotId) => !present.has(shotId)).map((shotId) => ({ shotId }));
|
|
1020
|
+
return [...preserved, ...appended].map((item) => {
|
|
1021
|
+
if (item.sourceVersionId !== void 0) {
|
|
1022
|
+
let explicit = scopedVersions.find((version) => version.id === item.sourceVersionId && sequenceSourceEligible(item.shotId, version));
|
|
1023
|
+
return { ...item, versionId: explicit?.id };
|
|
1024
|
+
}
|
|
1025
|
+
let video = selectedVersionForTarget(item.shotId, scopedVersions, selections, "video"), selectedImageId = selections[item.shotId], selectedImage = selectedImageId === void 0 ? void 0 : scopedVersions.find((version) => version.id === selectedImageId && version.kind === "image" && (version.targetId === item.shotId || version.targetId.startsWith("IMG-"))), shotImage = selectedVersionForTarget(item.shotId, scopedVersions, selections, "image"), preservedImage = scopedVersions.find((version) => version.id === item.versionId && version.kind === "image" && version.targetId.startsWith("IMG-")), image = selectedImage ?? shotImage ?? preservedImage;
|
|
1026
|
+
return { shotId: item.shotId, versionId: video?.id ?? image?.id };
|
|
1027
|
+
});
|
|
1004
1028
|
}
|
|
1005
|
-
function sequenceIssues(sequence, versions) {
|
|
1006
|
-
let versionById = new Map(versions.map((version) => [version.id, version])), issues = [];
|
|
1029
|
+
function sequenceIssues(sequence, versions, episodeDirectory) {
|
|
1030
|
+
let versionById = new Map(versions.filter((version) => episodeDirectory === void 0 || mediaBelongsToEpisode(version.path, episodeDirectory)).map((version) => [version.id, version])), issues = [];
|
|
1007
1031
|
for (let item of sequence) {
|
|
1008
1032
|
let version = item.versionId === void 0 ? void 0 : versionById.get(item.versionId);
|
|
1009
|
-
version === void 0 || version.kind !== "video" ? issues.push(`${item.shotId} \u7F3A\u5C11\u5DF2\u9009\u89C6\u9891\
|
|
1033
|
+
version === void 0 || version.kind !== "video" && version.kind !== "image" ? issues.push(item.sourceVersionId === void 0 ? `${item.shotId} \u7F3A\u5C11\u5DF2\u9009\u89C6\u9891\u6216\u5173\u952E\u5E27\u7D20\u6750` : `${item.shotId} \u663E\u5F0F\u9009\u62E9\u7684\u6210\u7247\u7D20\u6750\u5DF2\u4E0D\u53EF\u7528`) : version.path === void 0 && issues.push(`${item.shotId} \u7684${version.kind === "video" ? "\u89C6\u9891" : "\u5173\u952E\u5E27"}\u6CA1\u6709\u53EF\u4F9B DSH \u8BFB\u53D6\u7684\u5DE5\u4F5C\u533A\u8DEF\u5F84`);
|
|
1010
1034
|
}
|
|
1011
1035
|
return issues;
|
|
1012
1036
|
}
|
|
@@ -1018,7 +1042,17 @@ function reorderSequence(sequence, source, target) {
|
|
|
1018
1042
|
}
|
|
1019
1043
|
|
|
1020
1044
|
// src/client/drama-production-view.tsx
|
|
1021
|
-
var import_jsx_runtime3 = require("react/jsx-runtime"), SECTION_LABELS = { shots: "\u955C\u5934", assets: "\u7D20\u6750", tasks: "\u4EFB\u52A1", sequence: "\u6210\u7247", canvas: "\u753B\u5E03" }, SECTION_ORDER = Object.keys(SECTION_LABELS), STATUS_LABELS = { awaiting_confirmation: "\u7B49\u5F85\u786E\u8BA4", pending: "\u5DF2\u63D0\u4EA4", running: "DSH \u6267\u884C\u4E2D", dispatched_unknown: "\u5F85\u6838\u5BF9", succeeded: "\u5DF2\u5B8C\u6210", failed: "\u5931\u8D25", canceled: "\u5DF2\u53D6\u6D88" }, ASSET_KIND_LABEL = { character: "\u4EBA\u7269", scene: "\u573A\u666F", prop: "\u9053\u5177", state: "\u72B6\u6001", unknown: "\u8BBE\u5B9A" }, JOB_KIND_LABEL = { image: "\u56FE\u7247", video: "\u89C6\u9891", composition: "\u6210\u7247" }, ASSEMBLED_CUT_PATH = "\u5236\u4F5C\u6210\u679C/\u6210\u7247/\u6210\u7247.mp4"
|
|
1045
|
+
var import_jsx_runtime3 = require("react/jsx-runtime"), SECTION_LABELS = { shots: "\u955C\u5934", assets: "\u7D20\u6750", tasks: "\u4EFB\u52A1", sequence: "\u6210\u7247", canvas: "\u753B\u5E03" }, SECTION_ORDER = Object.keys(SECTION_LABELS), STATUS_LABELS = { awaiting_confirmation: "\u7B49\u5F85\u786E\u8BA4", pending: "\u5DF2\u63D0\u4EA4", running: "DSH \u6267\u884C\u4E2D", dispatched_unknown: "\u5F85\u6838\u5BF9", succeeded: "\u5DF2\u5B8C\u6210", failed: "\u5931\u8D25", canceled: "\u5DF2\u53D6\u6D88" }, ASSET_KIND_LABEL = { character: "\u4EBA\u7269", scene: "\u573A\u666F", prop: "\u9053\u5177", state: "\u72B6\u6001", unknown: "\u8BBE\u5B9A" }, JOB_KIND_LABEL = { image: "\u56FE\u7247", video: "\u89C6\u9891", composition: "\u6210\u7247" }, ASSEMBLED_CUT_PATH = "\u5236\u4F5C\u6210\u679C/\u6210\u7247/\u6210\u7247.mp4";
|
|
1046
|
+
function compositionSources(production, sequence, versions) {
|
|
1047
|
+
let versionById = new Map(versions.map((version) => [version.id, version])), shotById = new Map(production.shots.map((shot) => [shot.id, shot]));
|
|
1048
|
+
return sequence.flatMap((item) => {
|
|
1049
|
+
let version = item.versionId === void 0 ? void 0 : versionById.get(item.versionId), path = version?.path;
|
|
1050
|
+
if (version === void 0 || path === void 0) return [];
|
|
1051
|
+
let shot = shotById.get(item.shotId), sourceId = version.kind === "video" ? shot?.motion?.id ?? item.shotId : version.targetId.startsWith("IMG-") ? version.targetId : item.shotId;
|
|
1052
|
+
return [{ shotId: item.shotId, sourceId, kind: version.kind, path, durationSeconds: shot?.durationSeconds }];
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
var MODALITY_LABEL = { image: "\u56FE\u7247", video: "\u89C6\u9891", tts: "\u8BED\u97F3", music: "\u97F3\u4E50" };
|
|
1022
1056
|
function ProductionEnvironment({ sessionId }) {
|
|
1023
1057
|
let [preflight, setPreflight] = (0, import_react.useState)(), [attempt, setAttempt] = (0, import_react.useState)(0);
|
|
1024
1058
|
(0, import_react.useEffect)(() => {
|
|
@@ -1076,7 +1110,7 @@ function DramaProductionView(props) {
|
|
|
1076
1110
|
(0, import_react.useEffect)(() => {
|
|
1077
1111
|
jobsRef.current = props.jobs;
|
|
1078
1112
|
}, [props.jobs]), (0, import_react.useEffect)(() => {
|
|
1079
|
-
let next = reconcileSequence(props.production.shots.map((shot) => shot.id), props.sequence, props.versions, props.selections);
|
|
1113
|
+
let next = reconcileSequence(props.production.shots.map((shot) => shot.id), props.sequence, props.versions, props.selections, props.production.episodeDirectory);
|
|
1080
1114
|
JSON.stringify(next) !== JSON.stringify(props.sequence) && props.onSequenceChange(next);
|
|
1081
1115
|
}, [props.production.shots, props.selections, props.sequence, props.versions]), (0, import_react.useEffect)(() => {
|
|
1082
1116
|
let next = reconcileProductionJobs(props.jobs, props.queue, props.sessionRunning, props.versions);
|
|
@@ -1116,10 +1150,7 @@ ${item.prompt}`).join(`
|
|
|
1116
1150
|
commitJobs(jobsRef.current.map((item) => item.id === job.id ? { ...item, status: "failed", error: error instanceof Error ? error.message : String(error) } : item));
|
|
1117
1151
|
}
|
|
1118
1152
|
}, dispatchComposition = async (job) => {
|
|
1119
|
-
let
|
|
1120
|
-
let version = item.versionId === void 0 ? void 0 : versionById.get(item.versionId);
|
|
1121
|
-
return version === void 0 ? [] : [version.path ?? version.url];
|
|
1122
|
-
});
|
|
1153
|
+
let ordered = compositionSources(props.production, props.sequence, props.versions);
|
|
1123
1154
|
commitJobs([...jobsRef.current, job]), props.onSectionChange("tasks");
|
|
1124
1155
|
try {
|
|
1125
1156
|
await props.onDispatchPrompt(nativeCompositionPrompt(props.production, job, ordered)), setNotice("\u6210\u7247\u4EFB\u52A1\u5DF2\u8FDB\u5165 DSH \u539F\u751F\u961F\u5217\uFF1B\u6587\u4EF6\u3001FFmpeg \u548C\u5199\u5165\u7EE7\u7EED\u53D7 DSH \u6743\u9650\u4E0E\u5BA1\u6279\u63A7\u5236\u3002");
|
|
@@ -1139,7 +1170,7 @@ ${item.prompt}`).join(`
|
|
|
1139
1170
|
setNotice(error instanceof Error ? error.message : String(error));
|
|
1140
1171
|
}
|
|
1141
1172
|
}, composeSequence = () => {
|
|
1142
|
-
let issues = sequenceIssues(props.sequence, props.versions);
|
|
1173
|
+
let issues = sequenceIssues(props.sequence, props.versions, props.production.episodeDirectory);
|
|
1143
1174
|
if (issues.length > 0) {
|
|
1144
1175
|
setNotice(issues[0]);
|
|
1145
1176
|
return;
|
|
@@ -1201,7 +1232,7 @@ ${item.prompt}`).join(`
|
|
|
1201
1232
|
props.section === "shots" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShotBoard, { ...props, onCreateJob: createJob, onBatch: createBatch }),
|
|
1202
1233
|
props.section === "assets" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AssetBoard, { ...props, onCreateJob: createJob }),
|
|
1203
1234
|
props.section === "tasks" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TaskBoard, { jobs: props.jobs, queue: props.queue, sessionRunning: props.sessionRunning, onCancel: cancelJob, onRemoveQueued: removeQueuedJob }),
|
|
1204
|
-
props.section === "sequence" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SequenceBoard, { ...props, onCompose: composeSequence }),
|
|
1235
|
+
props.section === "sequence" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SequenceBoard, { ...props, episodeDirectory: props.production.episodeDirectory, onCompose: composeSequence }),
|
|
1205
1236
|
props.section === "canvas" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ProductionCanvas, { ...props })
|
|
1206
1237
|
] });
|
|
1207
1238
|
}
|
|
@@ -1377,9 +1408,11 @@ function TaskBoard({ jobs, queue, sessionRunning, onCancel, onRemoveQueued }) {
|
|
|
1377
1408
|
] });
|
|
1378
1409
|
}
|
|
1379
1410
|
function SequenceBoard(props) {
|
|
1380
|
-
let composing = compositionInFlight(props.jobs), issues = sequenceIssues(props.sequence, props.
|
|
1411
|
+
let composing = compositionInFlight(props.jobs), scopedVersions = props.versions.filter((version) => props.episodeDirectory === void 0 || mediaBelongsToEpisode(version.path, props.episodeDirectory)), issues = sequenceIssues(props.sequence, scopedVersions, props.episodeDirectory), versionById = new Map(scopedVersions.map((version) => [version.id, version])), move = (index, delta) => {
|
|
1381
1412
|
let source = props.sequence[index], target = props.sequence[index + delta];
|
|
1382
1413
|
source !== void 0 && target !== void 0 && props.onSequenceChange(reorderSequence(props.sequence, index, index + delta));
|
|
1414
|
+
}, chooseSource = (shotId, sourceVersionId) => {
|
|
1415
|
+
props.onSequenceChange(props.sequence.map((item) => item.shotId !== shotId ? item : sourceVersionId === "" ? { shotId: item.shotId, versionId: item.versionId } : { ...item, sourceVersionId, versionId: sourceVersionId }));
|
|
1383
1416
|
};
|
|
1384
1417
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "oh-story-sequence", children: [
|
|
1385
1418
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-sequence-summary", children: [
|
|
@@ -1395,16 +1428,29 @@ function SequenceBoard(props) {
|
|
|
1395
1428
|
issues.length > 3 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { children: [
|
|
1396
1429
|
"\u53E6\u6709 ",
|
|
1397
1430
|
issues.length - 3,
|
|
1398
|
-
" \u4E2A\u963B\u585E\u9879\uFF0C\u8BF7\u5728\u4E0B\u65B9\u955C\u5934\u884C\u8865\u9F50\
|
|
1431
|
+
" \u4E2A\u963B\u585E\u9879\uFF0C\u8BF7\u5728\u4E0B\u65B9\u955C\u5934\u884C\u8865\u9F50\u7D20\u6750\u3002"
|
|
1399
1432
|
] })
|
|
1400
1433
|
] }),
|
|
1401
1434
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ol", { children: props.sequence.map((item, index) => {
|
|
1402
|
-
let version = item.versionId === void 0 ? void 0 : versionById.get(item.versionId);
|
|
1435
|
+
let version = item.versionId === void 0 ? void 0 : versionById.get(item.versionId), choices = scopedVersions.filter((candidate) => candidate.path !== void 0 && sequenceSourceEligible(item.shotId, candidate)), explicitMissing = item.sourceVersionId !== void 0 && !choices.some((choice) => choice.id === item.sourceVersionId);
|
|
1403
1436
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { children: [
|
|
1404
1437
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: String(index + 1).padStart(2, "0") }),
|
|
1405
|
-
version === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-sequence-missing", children: "\u7F3A\u5C11\
|
|
1438
|
+
version === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-sequence-missing", children: "\u7F3A\u5C11\u7D20\u6750" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MediaPreview, { version, interactive: !1 }),
|
|
1406
1439
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: item.shotId }),
|
|
1407
1440
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
1441
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { "aria-label": `\u9009\u62E9 ${item.shotId} \u6210\u7247\u7D20\u6750`, value: item.sourceVersionId ?? "", onChange: (event) => {
|
|
1442
|
+
chooseSource(item.shotId, event.target.value);
|
|
1443
|
+
}, children: [
|
|
1444
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u81EA\u52A8\uFF08\u89C6\u9891\u4F18\u5148\uFF09" }),
|
|
1445
|
+
explicitMissing && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: item.sourceVersionId, disabled: !0, children: "\u5DF2\u9009\u7D20\u6750\u4E0D\u53EF\u7528" }),
|
|
1446
|
+
choices.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("option", { value: choice.id, children: [
|
|
1447
|
+
choice.targetId,
|
|
1448
|
+
" \xB7 ",
|
|
1449
|
+
choice.kind === "video" ? "\u89C6\u9891" : "\u9759\u5E27",
|
|
1450
|
+
" \xB7 ",
|
|
1451
|
+
choice.path?.split("/").at(-1)
|
|
1452
|
+
] }, choice.id))
|
|
1453
|
+
] }),
|
|
1408
1454
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", "aria-label": `\u4E0A\u79FB ${item.shotId}`, disabled: index === 0, onClick: () => {
|
|
1409
1455
|
move(index, -1);
|
|
1410
1456
|
}, children: "\u2191" }),
|
|
@@ -2693,7 +2739,9 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
2693
2739
|
.oh-story-sequence > ol > li .oh-story-media-preview,
|
|
2694
2740
|
.oh-story-sequence-missing { width: 96px; height: 54px; }
|
|
2695
2741
|
.oh-story-sequence-missing { display: grid; place-items: center; border-radius: 5px; color: var(--os-muted); background: var(--dsw-alias-button-ghost-active-fill); }
|
|
2696
|
-
.oh-story-sequence > ol > li >
|
|
2742
|
+
.oh-story-sequence > ol > li > strong { overflow: hidden; text-overflow: ellipsis; }
|
|
2743
|
+
.oh-story-sequence > ol > li > div:last-child { display: grid; width: clamp(160px, 25vw, 260px); min-width: 0; grid-template-columns: minmax(0, 1fr) auto auto; gap: 3px; }
|
|
2744
|
+
.oh-story-sequence > ol > li select { width: 100%; min-width: 0; }
|
|
2697
2745
|
.oh-story-canvas-shell { position: relative; display: flex; height: max(580px, calc(100% - 84px)); min-height: 580px; flex-direction: column; overflow: hidden; }
|
|
2698
2746
|
.oh-story-canvas-shell > .oh-story-projection-note { z-index: 3; flex: none; margin: 8px 168px 8px 8px; }
|
|
2699
2747
|
.oh-story-canvas-controls { position: absolute; z-index: 4; top: 8px; right: 8px; display: flex; align-items: center; gap: 3px; padding: 3px; border: 1px solid var(--os-border); border-radius: 8px; background: var(--dsw-alias-bg-base); }
|
|
@@ -2877,7 +2925,9 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
2877
2925
|
[data-oh-story-layout="compact"] .oh-story-sequence > ol > li { grid-template-columns: 24px 64px minmax(0, 1fr); gap: 5px; }
|
|
2878
2926
|
[data-oh-story-layout="compact"] .oh-story-sequence > ol > li .oh-story-media-preview,
|
|
2879
2927
|
[data-oh-story-layout="compact"] .oh-story-sequence-missing { width: 64px; height: 40px; }
|
|
2880
|
-
[data-oh-story-layout="compact"] .oh-story-sequence > ol > li > div:last-child { grid-column:
|
|
2928
|
+
[data-oh-story-layout="compact"] .oh-story-sequence > ol > li > div:last-child { grid-column: 1 / -1; width: auto; }
|
|
2929
|
+
[data-oh-story-layout="compact"] .oh-story-sequence > ol > li select { grid-column: 1 / -1; }
|
|
2930
|
+
[data-oh-story-layout="compact"] .oh-story-sequence > ol > li button:first-of-type { grid-column: 2; }
|
|
2881
2931
|
[data-oh-story-layout="compact"] .oh-story-canvas-shell > .oh-story-projection-note { overflow: hidden; max-height: 48px; margin: 8px; }
|
|
2882
2932
|
[data-oh-story-layout="compact"] .oh-story-canvas-controls { position: static; flex: none; align-self: flex-end; margin: 0 8px 8px; }
|
|
2883
2933
|
|