branch: elpa/subed commit 0519eb16ad618880fbc9cfd272ebb13e2ceab619 Author: Sacha Chua <sa...@sachachua.com> Commit: Sacha Chua <sa...@sachachua.com>
1.2.1: Adjust loops when setting start or stop time * NEWS.org: Document 1.2.1. * subed/subed-common.el (set-subtitle-time-start): Update loop start if it's within the current subtitle. (set-subtitle-time-stop): Update loop end if it's within the current subtitle. * subed/subed.el: Increase version. * tests/test-subed-common.el ("COMMON"): Add tests for setting the start/stop time when looping. * tests/test-subed-vtt.el ("VTT"): Add test for updating the loop time when merging. * subed/subed-ass.el (subed--merge-with-next): Always set the stop time, ignoring time boundaries. * subed/subed-srt.el (subed--merge-with-next): Always set the stop time, ignoring time boundaries. * subed/subed-tsv.el (subed--merge-with-next): Always set the stop time, ignoring time boundaries. * subed/subed-vtt.el (subed--merge-with-next): Always set the stop time, ignoring time boundaries. Fixes #63. --- NEWS.org | 5 ++ subed/subed-ass.el | 3 +- subed/subed-common.el | 16 ++++ subed/subed-srt.el | 3 +- subed/subed-tsv.el | 3 +- subed/subed-vtt.el | 3 +- subed/subed.el | 2 +- tests/test-subed-common.el | 212 ++++++++++++++++++++++++++++----------------- tests/test-subed-vtt.el | 14 ++- 9 files changed, 175 insertions(+), 86 deletions(-) diff --git a/NEWS.org b/NEWS.org index e9586a853c..818ffb53db 100644 --- a/NEWS.org +++ b/NEWS.org @@ -1,6 +1,11 @@ #+OPTIONS: toc:nil * subed news +** Version 1.2.1 - 2023-03-21 - Sacha Chua + +Adjusting the starting or stopping timestamp (including via merges) +should now also update the looping start and stop times. + ** Version 1.2.0 - 2023-03-10 - Sacha Chua I changed ~subed-mode~ so that it doesn't add functions to local diff --git a/subed/subed-ass.el b/subed/subed-ass.el index 4898af12b1..9f534ad0b3 100644 --- a/subed/subed-ass.el +++ b/subed/subed-ass.el @@ -273,7 +273,8 @@ function for MAJOR-MODE." (subed-jump-to-subtitle-text) (delete-region pos (point)) (insert " ") - (subed-set-subtitle-time-stop new-end)) + (let ((subed-enforce-time-boundaries nil)) + (subed-set-subtitle-time-stop new-end))) (error "No subtitle to merge into"))))) (cl-defmethod subed--auto-insert (&context (major-mode subed-ass-mode)) diff --git a/subed/subed-common.el b/subed/subed-common.el index 77483ebeb2..5940467a3b 100644 --- a/subed/subed-common.el +++ b/subed/subed-common.el @@ -411,6 +411,14 @@ Return the new subtitle start time in milliseconds." (subed-set-subtitle-time-stop (- msecs subed-subtitle-spacing)) (message "Adjusted previous stop time to %s to maintain spacing" (subed-msecs-to-timestamp (subed-subtitle-msecs-stop))))))))) + ;; Update loop start if it's within the current subtitle + (when (and subed--subtitle-loop-start + (>= subed--subtitle-loop-start + (floor (- (subed-subtitle-msecs-start) + (* 1000 (or subed-loop-seconds-before 0))))) + (< subed--subtitle-loop-start (subed-subtitle-msecs-stop))) + (setq subed--subtitle-loop-start + (floor (- msecs (* 1000 (or subed-loop-seconds-before 0)))))) (when (and (subed-jump-to-subtitle-time-start sub-id) (looking-at subed--regexp-timestamp)) (replace-match @@ -477,6 +485,14 @@ Return the new subtitle stop time in milliseconds." (subed-set-subtitle-time-start (+ msecs subed-subtitle-spacing)) (message "Adjusted next start time to %s to maintain spacing" (subed-msecs-to-timestamp (subed-subtitle-msecs-start))))))))) + ;; Update loop end if it's within the current subtitle + (when (and subed--subtitle-loop-stop + (> subed--subtitle-loop-stop (subed-subtitle-msecs-start)) + (<= subed--subtitle-loop-stop + (floor (+ (subed-subtitle-msecs-stop) + (* 1000 (or subed-loop-seconds-after 0)))))) + (setq subed--subtitle-loop-stop + (floor (+ msecs (* 1000 (or subed-loop-seconds-after 0)))))) (when (and (subed-jump-to-subtitle-time-stop) (looking-at subed--regexp-timestamp)) diff --git a/subed/subed-srt.el b/subed/subed-srt.el index 7169904409..d56fb0914e 100644 --- a/subed/subed-srt.el +++ b/subed/subed-srt.el @@ -282,7 +282,8 @@ Use the format-specific function for MAJOR-MODE." (subed-jump-to-subtitle-text) (delete-region pos (point)) (insert "\n") - (subed-set-subtitle-time-stop new-end) + (let ((subed-enforce-time-boundaries nil)) + (subed-set-subtitle-time-stop new-end)) (subed-regenerate-ids-soon)) (error "No subtitle to merge into"))))) diff --git a/subed/subed-tsv.el b/subed/subed-tsv.el index 33ee1784f3..54346c0d4f 100644 --- a/subed/subed-tsv.el +++ b/subed/subed-tsv.el @@ -430,7 +430,8 @@ Use the format-specific function for MAJOR-MODE." (subed-jump-to-subtitle-text) (delete-region pos (point)) (insert " ") - (subed-set-subtitle-time-stop new-end)) + (let ((subed-enforce-time-boundaries nil)) + (subed-set-subtitle-time-stop new-end))) (error "No subtitle to merge into"))))) diff --git a/subed/subed-vtt.el b/subed/subed-vtt.el index 644c3dc821..6682e6f379 100644 --- a/subed/subed-vtt.el +++ b/subed/subed-vtt.el @@ -315,7 +315,8 @@ Use the format-specific function for MAJOR-MODE." (subed-jump-to-subtitle-text) (delete-region pos (point)) (insert "\n") - (subed-set-subtitle-time-stop new-end)) + (let ((subed-enforce-time-boundaries nil)) + (subed-set-subtitle-time-stop new-end))) (error "No subtitle to merge into"))))) ;;; Maintenance diff --git a/subed/subed.el b/subed/subed.el index 4f223e92be..6c2f2f208a 100644 --- a/subed/subed.el +++ b/subed/subed.el @@ -1,6 +1,6 @@ ;;; subed.el --- A major mode for editing subtitles -*- lexical-binding: t; -*- -;; Version: 1.2.0 +;; Version: 1.2.1 ;; Maintainer: Sacha Chua <sa...@sachachua.com> ;; Author: Random User ;; Keywords: convenience, files, hypermedia, multimedia diff --git a/tests/test-subed-common.el b/tests/test-subed-common.el index bd7c9384d5..cf22b5fea1 100644 --- a/tests/test-subed-common.el +++ b/tests/test-subed-common.el @@ -7211,124 +7211,176 @@ This is another. (insert mock-srt-data) (subed-jump-to-subtitle-id 3) (subed-set-subtitle-time-start temp-time nil t) - (expect (subed-subtitle-msecs-start) :to-equal temp-time)))))) + (expect (subed-subtitle-msecs-start) :to-equal temp-time))))) + (describe "when looping" + (it "updates the loop stop time for the current subtitle." + (with-temp-srt-buffer + (insert mock-srt-data) + (subed-jump-to-subtitle-text 2) + (let ((subed-loop-seconds-before 1) + (subed-loop-seconds-after 1)) + (subed--set-subtitle-loop) + (expect subed--subtitle-loop-start :to-equal (subed-timestamp-to-msecs "00:02:01,234")) + (expect subed--subtitle-loop-stop :to-equal (subed-timestamp-to-msecs "00:02:11,345")) + (subed-set-subtitle-time-start (subed-timestamp-to-msecs "00:02:00,234")) + (expect subed--subtitle-loop-start :to-equal (subed-timestamp-to-msecs "00:01:59,234")) + (expect subed--subtitle-loop-stop :to-equal (subed-timestamp-to-msecs "00:02:11,345"))))) + (it "leaves other subtitle loops alone." + (with-temp-srt-buffer + (insert mock-srt-data) + (subed-jump-to-subtitle-text 2) + (let ((subed-loop-seconds-before 1) + (subed-loop-seconds-after 1)) + (subed--set-subtitle-loop) + (expect subed--subtitle-loop-start :to-equal (subed-timestamp-to-msecs "00:02:01,234")) + (expect subed--subtitle-loop-stop :to-equal (subed-timestamp-to-msecs "00:02:11,345")) + (subed-jump-to-subtitle-text 1) + (subed-set-subtitle-time-start (subed-timestamp-to-msecs "00:01:00,000")) + (expect subed--subtitle-loop-start :to-equal (subed-timestamp-to-msecs "00:02:01,234")) + (expect subed--subtitle-loop-stop :to-equal (subed-timestamp-to-msecs "00:02:11,345"))))))) (describe "Setting subtitle stop time" (describe "when this causes an overlap" (describe "when time boundaries are enforced by errors" :var ((subed-subtitle-spacing 100)) (it "continues when setting the last subtitle's stop time." (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 3) - (let ((subed-enforce-time-boundaries 'error)) - (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:30,000"))) - (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:30,000")))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 3) + (let ((subed-enforce-time-boundaries 'error)) + (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:30,000"))) + (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:30,000")))) (it "ignores the next subtitle's start time if there's enough spacing." (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 2) - (let ((subed-enforce-time-boundaries 'error)) - (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:01,000"))) - (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:01,000")) - (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:03,45")))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 2) + (let ((subed-enforce-time-boundaries 'error)) + (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:01,000"))) + (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:01,000")) + (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:03,45")))) (it "ignores the next subtitle's start time if spacing is unspecified." (let ((subed-subtitle-spacing nil) (subed-enforce-time-boundaries 'error)) (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 2) - (let ((subed-enforce-time-boundaries 'error)) - (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:05,000"))) - (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:05,000")) - (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:03,45"))))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 2) + (let ((subed-enforce-time-boundaries 'error)) + (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:05,000"))) + (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:05,000")) + (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:03,45"))))) (it "reports an error if the change violates spacing." (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 2) - (let ((subed-enforce-time-boundaries 'error) - (subed-subtitle-spacing 100)) - (expect (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:05,000")) - :to-throw 'error))))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 2) + (let ((subed-enforce-time-boundaries 'error) + (subed-subtitle-spacing 100)) + (expect (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:05,000")) + :to-throw 'error))))) (describe "when time boundaries are enforced by adjusting" :var ((subed-subtitle-spacing 100)) (it "continues when setting the last subtitle's stop time." (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 3) - (let ((subed-enforce-time-boundaries 'adjust)) - (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:30,000"))) - (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:30,000")))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 3) + (let ((subed-enforce-time-boundaries 'adjust)) + (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:30,000"))) + (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:30,000")))) (it "ignores the next subtitle's start time if there's enough spacing." (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 2) - (let ((subed-enforce-time-boundaries 'adjust)) - (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:01,000"))) - (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:01,000")) - (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:03,45")))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 2) + (let ((subed-enforce-time-boundaries 'adjust)) + (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:01,000"))) + (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:01,000")) + (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:03,45")))) (it "ignores the next subtitle's start time if spacing is unspecified." (let ((subed-subtitle-spacing nil)) (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 2) - (let ((subed-enforce-time-boundaries 'adjust)) - (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:05,000"))) - (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:05,000")) - (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:03,45"))))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 2) + (let ((subed-enforce-time-boundaries 'adjust)) + (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:05,000"))) + (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:05,000")) + (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:03,45"))))) (it "adjusts the next subtitle's start time to maintain spacing." (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 2) - (let ((subed-enforce-time-boundaries 'adjust) - (subed-subtitle-spacing 100)) - (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:05,000"))) - (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:05,000")) - (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:05,100")))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 2) + (let ((subed-enforce-time-boundaries 'adjust) + (subed-subtitle-spacing 100)) + (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:05,000"))) + (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:05,000")) + (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:05,100")))) (it "adjusts the next subtitle's stop time, but not the one after it." ;; TODO: Decide if we want to change this expectation (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 1) - (let ((subed-enforce-time-boundaries 'adjust) - (subed-subtitle-spacing 100)) - (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:05,000"))) - (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:05,000")) - (expect (subed-subtitle-msecs-start 2) :to-equal (subed-timestamp-to-msecs "00:03:05,100")) - (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:03,45")))))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 1) + (let ((subed-enforce-time-boundaries 'adjust) + (subed-subtitle-spacing 100)) + (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:03:05,000"))) + (expect (subed-subtitle-msecs-stop) :to-equal (subed-timestamp-to-msecs "00:03:05,000")) + (expect (subed-subtitle-msecs-start 2) :to-equal (subed-timestamp-to-msecs "00:03:05,100")) + (expect (subed-subtitle-msecs-start 3) :to-equal (subed-timestamp-to-msecs "00:03:03,45")))))) (describe "when it will result in invalid duration" (it "adjusts the start time as needed." (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 3) - (let ((subed-enforce-time-boundaries 'adjust) - (temp-time (subed-timestamp-to-msecs "00:03:01,000"))) - (subed-set-subtitle-time-stop temp-time) - (expect (subed-subtitle-msecs-start) :to-equal temp-time) - (expect (subed-subtitle-msecs-stop) :to-equal temp-time)))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 3) + (let ((subed-enforce-time-boundaries 'adjust) + (temp-time (subed-timestamp-to-msecs "00:03:01,000"))) + (subed-set-subtitle-time-stop temp-time) + (expect (subed-subtitle-msecs-start) :to-equal temp-time) + (expect (subed-subtitle-msecs-stop) :to-equal temp-time)))) (it "throws an error when enforcing time boundaries." (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 3) - (let ((subed-enforce-time-boundaries 'error) - (temp-time (subed-timestamp-to-msecs "00:03:01,000"))) - (expect (subed-set-subtitle-time-stop temp-time) - :to-throw 'error)))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 3) + (let ((subed-enforce-time-boundaries 'error) + (temp-time (subed-timestamp-to-msecs "00:03:01,000"))) + (expect (subed-set-subtitle-time-stop temp-time) + :to-throw 'error)))) (it "changes it when ignoring time boundaries." (with-temp-srt-buffer - (insert mock-srt-data) - (subed-jump-to-subtitle-id 3) - (let ((subed-enforce-time-boundaries nil) - (temp-time (subed-timestamp-to-msecs "00:03:01,000"))) - (subed-set-subtitle-time-stop temp-time) - (expect (subed-subtitle-msecs-stop) :to-equal temp-time)))) + (insert mock-srt-data) + (subed-jump-to-subtitle-id 3) + (let ((subed-enforce-time-boundaries nil) + (temp-time (subed-timestamp-to-msecs "00:03:01,000"))) + (subed-set-subtitle-time-stop temp-time) + (expect (subed-subtitle-msecs-stop) :to-equal temp-time)))) (it "changes it when negative durations are allowed." + (with-temp-srt-buffer + (insert mock-srt-data) + (subed-jump-to-subtitle-id 3) + (let ((subed-enforce-time-boundaries 'error) + (temp-time (subed-timestamp-to-msecs "00:03:01,000"))) + (subed-set-subtitle-time-stop temp-time nil t) + (expect (subed-subtitle-msecs-stop) :to-equal temp-time))))) + (describe "when looping" + (it "updates the loop stop time for the current subtitle." (with-temp-srt-buffer (insert mock-srt-data) - (subed-jump-to-subtitle-id 3) - (let ((subed-enforce-time-boundaries 'error) - (temp-time (subed-timestamp-to-msecs "00:03:01,000"))) - (subed-set-subtitle-time-stop temp-time nil t) - (expect (subed-subtitle-msecs-stop) :to-equal temp-time)))))) + (subed-jump-to-subtitle-text 2) + (let ((subed-loop-seconds-before 1) + (subed-loop-seconds-after 1)) + (subed--set-subtitle-loop) + (expect subed--subtitle-loop-start :to-equal (subed-timestamp-to-msecs "00:02:01,234")) + (expect subed--subtitle-loop-stop :to-equal (subed-timestamp-to-msecs "00:02:11,345")) + (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:02:13,345")) + (expect subed--subtitle-loop-start :to-equal (subed-timestamp-to-msecs "00:02:01,234")) + (expect subed--subtitle-loop-stop :to-equal (subed-timestamp-to-msecs "00:02:14,345"))))) + (it "leaves other subtitle loops alone." + (with-temp-srt-buffer + (insert mock-srt-data) + (subed-jump-to-subtitle-text 2) + (let ((subed-loop-seconds-before 1) + (subed-loop-seconds-after 1)) + (subed--set-subtitle-loop) + (expect subed--subtitle-loop-start :to-equal (subed-timestamp-to-msecs "00:02:01,234")) + (expect subed--subtitle-loop-stop :to-equal (subed-timestamp-to-msecs "00:02:11,345")) + (subed-jump-to-subtitle-text 1) + (subed-set-subtitle-time-stop (subed-timestamp-to-msecs "00:01:04,123")) + (expect subed--subtitle-loop-start :to-equal (subed-timestamp-to-msecs "00:02:01,234")) + (expect subed--subtitle-loop-stop :to-equal (subed-timestamp-to-msecs "00:02:11,345"))))))) (describe "Adjusting subtitle start/stop time" :var (subed-subtitle-time-adjusted-hook) (it "runs the appropriate hook." diff --git a/tests/test-subed-vtt.el b/tests/test-subed-vtt.el index a06dada324..a5d1e71740 100644 --- a/tests/test-subed-vtt.el +++ b/tests/test-subed-vtt.el @@ -1302,7 +1302,19 @@ This is another test here. (subed-merge-with-next) (expect (subed-subtitle-text) :to-equal "Bar.\nBaz.") (expect (subed-subtitle-msecs-start) :to-equal 122234) - (expect (subed-subtitle-msecs-stop) :to-equal 195500)))) + (expect (subed-subtitle-msecs-stop) :to-equal 195500))) + (it "updates looping." + (with-temp-vtt-buffer + (insert mock-vtt-data) + (subed-jump-to-subtitle-text "00:02:02.234") + (let ((subed-loop-seconds-before 1) + (subed-loop-seconds-after 1)) + (subed--set-subtitle-loop) + (expect subed--subtitle-loop-start :to-equal (subed-timestamp-to-msecs "00:02:01.234")) + (expect subed--subtitle-loop-stop :to-equal (subed-timestamp-to-msecs "00:02:11.345")) + (subed-merge-with-next) + (expect subed--subtitle-loop-start :to-equal (subed-timestamp-to-msecs "00:02:01.234")) + (expect subed--subtitle-loop-stop :to-equal (subed-timestamp-to-msecs "00:03:16.500")))))) (describe "Font-locking" (it "recognizes VTT syntax." (with-temp-vtt-buffer