diff --git a/CHANGELOG.md b/CHANGELOG.md index ec02070..02b7da5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to capcut-cli are documented here. The format follows [Keep ## [Unreleased] +### Added + +- `test/fixtures/jianying-9-0-0-windows/` — a real JianYing 9.0.0 (Windows) project captured after the app opened a tool-written draft: the plaintext `draft_info.json` primary alongside the `draft_content.json` / `template-2.tmp` / `draft_meta_info.json` mirrors the app rewrote into encrypted blobs, plus the materialised `Timelines/` layout. A regression test pins that the encrypted mirrors are reported as unparseable rather than breaking canonical selection, and `docs/version-support.md` gains a JianYing 9.0.0 (Windows) row (evidence: reported; storage shape fixture-backed). The write guard is deliberately unchanged — one machine's capture is not a round-trip claim. + ## [0.29.0] — 2026-10-09 ### Added diff --git a/docs/version-support.md b/docs/version-support.md index 59fee0c..3a5f2d8 100644 --- a/docs/version-support.md +++ b/docs/version-support.md @@ -35,6 +35,7 @@ There is no blanket “6.x–9.x tested” claim. Only versions with committed f |---|---|---|---| | 5.9.x | community-reported | expected-compatible | Last widely used plaintext line; no sanitized app-created fixture is currently committed. | | 6.0+ | reported | known-broken for encrypted files | `capcut decrypt` detects encryption and explains the workaround; it does not decrypt the file. Plaintext/exported variants can still be inspected normally, but the write guard refuses mutating writes even on plaintext variants without `--force-write` — the 6.0+ app is the encrypted-draft era and a plaintext write may be ignored or shown as corrupted. | +| 9.0.0 (Windows) | reported; storage shape fixture-backed | tool-written plaintext primary accepted on open; the app encrypts the legacy mirrors on close | A draft written by this CLI was closed and opened in 剪映专业版 9.0.0 on Windows (10.0.19045): the added text segment was present and editable. The capture after that open is committed as `test/fixtures/jianying-9-0-0-windows/` — plaintext `draft_info.json` (the primary, carrying `platform.app_version` 9.0.0 / `app_source` `lv`), with `draft_content.json`, `template-2.tmp` and `draft_meta_info.json`, plus a materialised `Timelines/` layout, rewritten by the app into encrypted blobs. The CLI keeps reading the project through the plaintext primary and never writes into those mirrors. Two more observations from the same build: an app-authored project here is a plaintext `draft_content.json` with **no** `draft_info.json`/`template-2.tmp` at all — so "the primary has been `draft_info.json` since 6.0" (the 11.4.0 row below) does not hold for this build; and a segment written by the app can carry a `target_timerange` with no `start` and no `speed`. The write guard stays as the 6.0+ row describes until a second build confirms the round-trip. | | 11.4.0 (macOS) | reported | plaintext drafts accepted on open — generation is not blocked | A plaintext `draft_info.json` written by a tool is opened, upgraded to the encrypted format in place, and completed with `Timelines/` and a cover by the app itself; the engine probes plaintext vs cipher per file (`DraftIO::getUriCipherTypeStatically`) and the primary file name has been `draft_info.json` since 6.0 — a `draft_content.json` dropped into the folder is what produces "草稿内容已损坏" ([pyJianYingDraft#198](https://github.com/GuanYixuan/pyJianYingDraft/issues/198), 2026-09-10). So encryption limits *reading* an app-authored draft, not writing a new one; the write guard above stays conservative until a fixture from such a build is committed (`--force-write` writes). Media under `~/Desktop`, `~/Documents` or `~/Downloads` triggers a "no access permission" relink prompt on this build (macOS TCC) — `lint` names it and `lint --fix` stages the file into the draft. | ## v0.11 storage and write safety diff --git a/test/fixtures/jianying-9-0-0-windows/README.md b/test/fixtures/jianying-9-0-0-windows/README.md new file mode 100644 index 0000000..c1982ba --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/README.md @@ -0,0 +1,51 @@ +# Fixture: JianYing 9.0.0 on Windows + +A real project folder from 剪映专业版 (JianYing) **9.0.0 on Windows 10**, captured +with `capcut fixture`, after the app had opened it. Only timeline JSON is +committed — no media; home paths, emails and device identifiers are redacted. + +``` +platform.app_version 9.0.0 +platform.app_source lv +tracks 2 text segments +canonical (diagnose) draft_info.json +``` + +## What the capture shows + +Captured **after the app opened a draft that a tool had written**: + +| File | State | Notes | +|---|---|---| +| `draft_info.json` | plaintext JSON, 3485 bytes | the primary; still the bytes the CLI wrote before the open — the app did not rewrite it | +| `draft_content.json` | encrypted blob | rewritten by the app on close | +| `template-2.tmp` | encrypted blob | rewritten by the app on close | +| `draft_meta_info.json` | encrypted blob | rewritten on close | +| `Timelines/project.json`, `Timelines/469574b7-…/draft_content.json` | layout + encrypted blob | the nested layout the app materialised | + +Two facts this bundle pins down on this build: + +1. **A plaintext tool-written primary is accepted.** The draft was written by + `capcut-cli` (a `text` segment added, then a text template applied), closed, + and opened in the app, which showed the added segment and allowed editing it. + The app then encrypted the *legacy mirrors* but left `draft_info.json` + plaintext — so the CLI still reads the project through its canonical file and + never writes into the encrypted mirrors. +2. **`target_timerange.start` is not guaranteed.** The `smoke-test` segment + carries `{"duration":3000000}` with no `start` and no `speed`, while the + `smoke-cta-default` segment carries both. The app renders the first one + normally; `capcut segments -H` printed `NaN:00NaN` / `undefinedx` for it + before the read-side fix in the same series. + +## Scope of the claim + +This is *one machine*. It establishes the storage shape and that this build +opened a tool-written draft; it is not a claim that every JianYing 9.0.0 build +does. `docs/version-support.md` keeps the write guard conservative on the +strength of that — see its JianYing 9.0.0 (Windows) row. + +An app-authored project on the same build looks different: a plaintext +`draft_content.json` and **no** `draft_info.json` / `template-2.tmp` at all. That +shape is not committed here (its content is the owner's), but it is why the +"primary file name is `draft_info.json` since 6.0" note in +`docs/version-support.md` does not hold for this build. diff --git a/test/fixtures/jianying-9-0-0-windows/Timelines/469574b7-ab5c-47f4-af82-f96ea7fbaea9/draft_content.json b/test/fixtures/jianying-9-0-0-windows/Timelines/469574b7-ab5c-47f4-af82-f96ea7fbaea9/draft_content.json new file mode 100644 index 0000000..17b8c96 --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/Timelines/469574b7-ab5c-47f4-af82-f96ea7fbaea9/draft_content.json @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/test/fixtures/jianying-9-0-0-windows/Timelines/project.json b/test/fixtures/jianying-9-0-0-windows/Timelines/project.json new file mode 100644 index 0000000..8eef90e --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/Timelines/project.json @@ -0,0 +1 @@ +{"config":{"color_space":-1,"render_index_track_mode_on":false,"use_float_render":false},"create_time":1791791682378893,"id":"469574b7-ab5c-47f4-af82-f96ea7fbaea9","main_timeline_id":"469574b7-ab5c-47f4-af82-f96ea7fbaea9","timelines":[{"create_time":1791791682378893,"id":"469574b7-ab5c-47f4-af82-f96ea7fbaea9","is_marked_delete":false,"name":"时间线01","update_time":1791791682378893}],"update_time":1791791682378893,"version":0} \ No newline at end of file diff --git a/test/fixtures/jianying-9-0-0-windows/draft_content.json b/test/fixtures/jianying-9-0-0-windows/draft_content.json new file mode 100644 index 0000000..17b8c96 --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/draft_content.json @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/test/fixtures/jianying-9-0-0-windows/draft_info.json b/test/fixtures/jianying-9-0-0-windows/draft_info.json new file mode 100644 index 0000000..d3e3f4f --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/draft_info.json @@ -0,0 +1 @@ +{"id":"469574b7-ab5c-47f4-af82-f96ea7fbaea9","new_version":"","name":"_smoke","config":{},"canvas_config":{"ratio":"16:9","width":1920,"height":1080},"tracks":[{"id":"235808b6-0511-4e81-80dd-246bd8baf520","type":"text","segments":[{"id":"62a041c7-5af2-4aab-88ef-04fd75bcb923","target_timerange":{"duration":3000000},"render_timerange":{},"clip":{"scale":{"x":1,"y":1},"transform":{"x":0,"y":0},"flip":{}},"uniform_scale":{},"material_id":"9b4ae774-d7c1-45ec-b462-558d44838ac7","render_index":15000,"enable_lut":false,"enable_adjust":false,"enable_hsl":false,"responsive_layout":{},"enable_adjust_mask":false,"raw_segment_id":"235808b6-0511-4e81-80dd-246bd8baf520","source":"segmentsourcenormal"},{"id":"f9b0e86a-9080-4224-80be-ba2a80d4191e","material_id":"357ded67-34ba-45e6-930d-ab8b01ca1eaf","raw_segment_id":"235808b6-0511-4e81-80dd-246bd8baf520","target_timerange":{"start":0,"duration":3000000},"source_timerange":{"start":0,"duration":3000000},"speed":1,"volume":1,"visible":true,"reverse":false,"clip":{"alpha":1,"rotation":0,"scale":{"x":1,"y":1},"transform":{"x":0,"y":0.7},"flip":{"horizontal":false,"vertical":false}},"render_index":15000,"track_render_index":0,"track_attribute":0,"extra_material_refs":["c852a521-f867-43dd-adde-f30f635768d3","5cc6b12c-4c07-402a-acd8-58b0cf6b0eae","65659df4-165d-42e8-9440-dca4167d88e1","7d7e5189-970d-47d8-8409-ecdeb021769d"],"common_keyframes":[],"keyframe_refs":[]}],"name":"text"}],"materials":{"texts":[{"id":"9b4ae774-d7c1-45ec-b462-558d44838ac7","type":"text","content":"{\"styles\":[{\"range\":[0,10],\"size\":15,\"bold\":false,\"italic\":false,\"underline\":false,\"fill\":{\"alpha\":1,\"content\":{\"render_type\":\"solid\",\"solid\":{\"alpha\":1,\"color\":[1,1,1]}}}}],\"text\":\"smoke-test\"}","words":{},"current_words":{},"combo_info":{},"caption_template_info":{"resource_id":"","path":""},"line_spacing":0.02,"shadow_point":{"x":0,"y":0},"text_color":"#FFFFFF","font_path":"D:/软件/JianyingPro/10.9.0.14199/Resources/Font/SystemFont/zh-hans.ttf","lyrics_template":{"resource_id":"","path":""}},{"id":"357ded67-34ba-45e6-930d-ab8b01ca1eaf","type":"text","content":"{\"styles\":[{\"range\":[0,17],\"size\":18,\"bold\":false,\"italic\":false,\"underline\":false,\"fill\":{\"alpha\":1,\"content\":{\"render_type\":\"solid\",\"solid\":{\"alpha\":1,\"color\":[1,0.8431372549019608,0]}}}}],\"text\":\"smoke-cta-default\"}","alignment":1,"font_size":18,"text_color":"#FFD700","typesetting":0,"letter_spacing":0,"line_spacing":0.02,"line_feed":1,"line_max_width":0.82,"force_apply_line_max_width":false,"check_flag":7,"fixed_width":-1,"fixed_height":-1}],"speeds":[{"id":"c852a521-f867-43dd-adde-f30f635768d3","type":"speed","speed":1,"mode":0,"curve_speed":null}],"placeholder_infos":[{"id":"5cc6b12c-4c07-402a-acd8-58b0cf6b0eae","type":"placeholder_info","error_path":"","error_text":"","meta_type":"none","res_path":"","res_text":""}],"sound_channel_mappings":[{"id":"65659df4-165d-42e8-9440-dca4167d88e1","type":"none","audio_channel_mapping":0,"is_config_open":false}],"vocal_separations":[{"id":"7d7e5189-970d-47d8-8409-ecdeb021769d","type":"vocal_separation","choice":0,"enter_from":"","final_algorithm":"","production_path":"","removed_sounds":[],"time_range":null}]},"keyframes":{},"platform":{"app_version":"9.0.0","app_source":"lv"},"last_modified_platform":{"app_version":"9.0.0","app_source":"lv"},"extra_info":{},"path":"","uneven_animation_template_info":{},"smart_ads_info":{},"function_assistant_info":{"fps":{}}} \ No newline at end of file diff --git a/test/fixtures/jianying-9-0-0-windows/draft_meta_info.json b/test/fixtures/jianying-9-0-0-windows/draft_meta_info.json new file mode 100644 index 0000000..efbbcfd --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/draft_meta_info.json @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/test/fixtures/jianying-9-0-0-windows/template-2.tmp b/test/fixtures/jianying-9-0-0-windows/template-2.tmp new file mode 100644 index 0000000..17b8c96 --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/template-2.tmp @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/test/jianying-9-0-0-windows.test.mjs b/test/jianying-9-0-0-windows.test.mjs new file mode 100644 index 0000000..4dcd387 --- /dev/null +++ b/test/jianying-9-0-0-windows.test.mjs @@ -0,0 +1,58 @@ +import assert from "node:assert/strict"; +import { dirname, join } from "node:path"; +import { describe, it } from "node:test"; +import { fileURLToPath } from "node:url"; +import { spawnCli } from "./helpers/spawn-cli.mjs"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const FIXTURE = join(__dirname, "fixtures", "jianying-9-0-0-windows"); + +/** + * A real JianYing 9.0.0 (Windows) project that the app opened and closed, so + * the app encrypted `draft_content.json`, `template-2.tmp` and + * `draft_meta_info.json` in place while leaving the primary `draft_info.json` + * plaintext. See the fixture README for the full capture. + * + * What these tests guard: the project stays *readable* through its plaintext + * primary, the version markers are read off that primary, and the write guard + * verdict for this version does not change silently. + */ +describe("JianYing 9.0.0 (Windows): encrypted legacy mirrors", () => { + it("selects the plaintext draft_info.json as canonical", () => { + const r = spawnCli(["diagnose", FIXTURE]); + assert.equal(r.status, 0, `stderr: ${r.stderr}`); + assert.equal(r.json.canonical, "draft_info.json"); + assert.equal(r.json.version, "9.0.0"); + assert.equal(r.json.diverged, false); + }); + + it("reports the app-encrypted mirrors instead of failing on them", () => { + const r = spawnCli(["diagnose", FIXTURE]); + const byName = new Map(r.json.candidates.map((c) => [c.file, c])); + assert.equal(byName.get("draft_info.json").parseable_timeline, true); + for (const name of ["draft_content.json", "template-2.tmp", "draft_meta_info.json"]) { + const candidate = byName.get(name); + assert.ok(candidate?.exists, `${name} should be reported as present`); + assert.equal(candidate.parseable_timeline, false, `${name} is an encrypted blob, not a timeline`); + } + // The readable primary still carries the timeline. + assert.equal(byName.get("draft_info.json").tracks, 1); + }); + + it("reads the version markers from the primary", () => { + const r = spawnCli(["version", FIXTURE]); + assert.equal(r.status, 0, `stderr: ${r.stderr}`); + assert.equal(r.json.app, "JianYing"); + assert.equal(r.json.app_source, "lv"); + assert.equal(r.json.app_version, "9.0.0"); + }); + + it("keeps the conservative write guard for this version", () => { + const r = spawnCli(["version", FIXTURE]); + // Committing a fixture is evidence for the storage shape, not a licence to + // write: a second build still has to confirm the round-trip. + assert.equal(r.json.support.status, "known-broken"); + assert.equal(r.json.support.write_guard, "refuse"); + assert.equal(r.json.support.beyond_known_range, true); + }); +});