diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a8fca20..9f07eb72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Decisiveness now rescales after embed guidance, score slider and DynaShift, so it acts on their combined result. ### Fixed +- Shot views: "from behind / above / below" now counts as a stated view only with a camera word ("seen from behind"), not as a body action, so those shots can get a view. - An H3 latent node (Reference-to-Video / Empty AV Latent) whose `length` is not linked now follows the project's frames, instead of keeping an old typed number that made the sampler refuse the run; the settings export shows it as "follows project". - A view added by Shot views (POV...) no longer makes the shot look like it already has a camera move. - Export settings no longer prints a loader input the node no longer has (a stale `sla_enabled: on`) or SLA's settings while `sla` is off. diff --git a/shot_camera.py b/shot_camera.py index 6e4c81d4..38d4b6d6 100644 --- a/shot_camera.py +++ b/shot_camera.py @@ -542,8 +542,12 @@ def add_shot_cuts(text, seconds, seed=0, chance=0.5, pieces=()): # frame, which a new view would contradict; every later shot starts on a new angle anyway. VIEWS = ("POV view", "POV view from above", "POV view from below", "Side view", "View from above", "View from below", "View from behind", "Front view") -VIEW_STATED = re.compile(r"\b(pov|(?:side|front|rear|back|top|overhead|bird'?s[- ]eye)[- ]view|" - r"view from|from (?:above|below|behind))\b", re.I) +# A view the shot already asks for. "from behind" / "from above" alone are also body actions +# ("enters from behind", "drips from above"), so they count only when a camera word goes with +# them ("seen from behind", "shot from above", "camera from below"). +VIEW_STATED = re.compile(r"\b(pov|(?:side|front|rear|back|top|overhead|bird'?s[- ]eye)[- ]view|view from|" + r"(?:seen|shot|filmed|viewed|captured|camera|angle|footage)\b[^.!?,;]{0,20}?" + r"\bfrom (?:above|below|behind))\b", re.I) OPENER = re.compile(r"^\s*At \d\d:\d\d\.\d{3},[^.!?]*[.!?]\s*") diff --git a/tests/test_shot_camera.py b/tests/test_shot_camera.py index bf236a3e..dfd55d4d 100644 --- a/tests/test_shot_camera.py +++ b/tests/test_shot_camera.py @@ -434,3 +434,14 @@ def test_some_shots_hold_still_on_one_object_and_pans_are_the_minority(): kinds["other"] += 1 assert kinds["hold"] > 20 and 0 < kinds["pan"] < kinds["other"], kinds assert kinds["pan"] < 0.3 * 300, kinds + + +def test_a_body_action_from_behind_is_not_a_stated_view(): + for text in ("She is taken from behind by him.", "Water drips from above onto her.", + "He enters from below the stairs."): + assert not sc.VIEW_STATED.search(text), text + for text in ("POV view, she waves.", "Seen from behind, she walks.", "Shot from above, the room.", + "Side view of the table.", "The camera films from below."): + assert sc.VIEW_STATED.search(text), text + out, added = sc.add_shot_views("[Shot 1] A.\n[Shot 2] She is taken from behind by him.", seed=1, chance=1.0) + assert added and added[0]["shot"] == 2