emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/subed 6eba992 376/389: Add ability to proportionally scale


From: ELPA Syncer
Subject: [nongnu] elpa/subed 6eba992 376/389: Add ability to proportionally scale subtitles.
Date: Fri, 3 Dec 2021 11:01:01 -0500 (EST)

branch: elpa/subed
commit 6eba992e13f2204b2f992b5227ef77fcb43dd8d0
Author: Troy Brown <brownts@users.noreply.github.com>
Commit: Troy Brown <brownts@users.noreply.github.com>

    Add ability to proportionally scale subtitles.
---
 README.org                 |  11 ++
 subed/subed-common.el      | 136 ++++++++++++++
 subed/subed.el             |   2 +
 tests/test-subed-common.el | 443 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 592 insertions(+)

diff --git a/README.org b/README.org
index fe471d2..edd222b 100644
--- a/README.org
+++ b/README.org
@@ -30,6 +30,17 @@ SubRip ( ~.srt~) and WebVTT ( ~.vtt~ ).
    - Shift the current subtitle forward (~C-M-f~) or backward (~C-M-b~) 
together
      with all following subtitles.  This is basically a convenience shortcut 
for
      ~C-SPC M-> C-M-n/p~.
+   - Scale all subtitles or all marked subtitles forward (~C-M-x~) or backward
+     (~C-M-S-x~) in time without changing subtitle duration.  A prefix argument
+     sets the number of milliseconds for the current session (e.g. ~C-u 500
+     C-M-x~ moves the last [or last marked] subtitle forward 500ms and
+     proportionally scales all [or all marked] subtitles based on this time
+     extension.  Similarly, ~C-u 500 C-M-S-x~ moves the last [or last marked]
+     subtitle backward 500ms and proportionally scales all [or all marked]
+     subtitles based on this time contraction).  This can be extremely useful 
to
+     correct synchronization issues in existing subtitle files.  First, adjust
+     the starting time if necessary (e.g. ~C-M-f~), then adjust the ending and
+     scale constituent subtitles (e.g. ~C-M-x~).
    - Show CPS (characters per second) for the current subtitle.
    - Insert HTML-like tags (~C-c C-t C-t~, with an optional attribute
      when prefixed by ~C-u~), in particular italics (~C-c C-t C-i~) or
diff --git a/subed/subed-common.el b/subed/subed-common.el
index 91a9cdd..ebe6795 100644
--- a/subed/subed-common.el
+++ b/subed/subed-common.el
@@ -27,6 +27,7 @@
 
 ;;; Code:
 
+(require 'cl-macs)
 (require 'subed-config)
 (require 'subed-debug)
 (require 'subed-mpv)
@@ -339,6 +340,88 @@ but we move the start time first."
       (cl-flet ((move-subtitle (subed--get-move-subtitle-func msecs)))
         (move-subtitle msecs)))))
 
+(defun subed--scale-subtitles-in-region (msecs beg end)
+  "Scale subtitles in region specified by BEG and END after moving END MSECS 
milliseconds."
+  (let* ((beg-point (save-excursion ; normalized to fixed location over BEG
+                      (goto-char beg)
+                      (subed-jump-to-subtitle-end)
+                      (point)))
+         (beg-next-point (save-excursion
+                           (goto-char beg-point)
+                           (subed-forward-subtitle-end)
+                           (point)))
+         (end-point (save-excursion ; normalized to fixed location over END
+                      (goto-char end)
+                      (subed-jump-to-subtitle-end)
+                      (point)))
+         (end-prev-point (save-excursion
+                           (goto-char end-point)
+                           (subed-backward-subtitle-end)
+                           (point)))
+         (beg-start-msecs (save-excursion
+                            (goto-char beg-point)
+                            (subed-subtitle-msecs-start)))
+         (old-end-start-msecs (save-excursion
+                                (goto-char end-point)
+                                (subed-subtitle-msecs-start))))
+    ;; check for improper range (BEG after END)
+    (unless (<= beg end)
+      (user-error "Can't scale with improper range"))
+    ;; check for 0 or 1 subtitle scenario
+    (unless (/= beg-point end-point)
+      (user-error "Can't scale with fewer than 3 subtitles"))
+    ;; check for 2 subtitle scenario
+    (unless (/= beg-point end-prev-point)
+      (user-error "Can't scale with only 2 subtitles"))
+    ;; check for missing timestamps
+    (unless beg-start-msecs
+      (user-error "Can't scale when first subtitle timestamp missing"))
+    (unless old-end-start-msecs
+      (user-error "Can't scale when last subtitle timestamp missing"))
+    ;; check for range with 0 time interval
+    (unless (/= beg-start-msecs old-end-start-msecs)
+      (user-error "Can't scale subtitle range with 0 time interval"))
+
+    (unless (= msecs 0)
+      (subed-with-subtitle-replay-disabled
+        (cl-flet ((move-subtitle (subed--get-move-subtitle-func msecs)))
+          (let* ((new-end-start-msecs (+ old-end-start-msecs msecs))
+                 (scale-factor (/ (float (- new-end-start-msecs 
beg-start-msecs))
+                                  (float (- old-end-start-msecs 
beg-start-msecs))))
+                 (scale-subtitles
+                  (lambda (&optional reverse)
+                    (subed-for-each-subtitle beg-next-point end-prev-point 
reverse
+                      (let ((old-start-msecs (subed-subtitle-msecs-start)))
+                        (unless old-start-msecs
+                          (user-error "Can't scale when subtitle timestamp 
missing"))
+                        (let* ((new-start-msecs
+                                (+ beg-start-msecs
+                                   (round (* (- old-start-msecs 
beg-start-msecs) scale-factor))))
+                               (delta-msecs (- new-start-msecs 
old-start-msecs)))
+                          (unless (and (<= beg-start-msecs old-start-msecs)
+                                       (>= old-end-start-msecs 
old-start-msecs))
+                            (user-error "Can't scale when nonchronological 
subtitles exist"))
+                          (move-subtitle delta-msecs 
:ignore-negative-duration)))))))
+            (atomic-change-group
+              (if (> msecs 0)
+                  (save-excursion
+                    ;; Moving forward - Start on last subtitle to see if we
+                    ;; can move forward.
+                    (goto-char end)
+                    (let ((adjusted-msecs (move-subtitle msecs)))
+                      (unless (and adjusted-msecs
+                                   (= msecs adjusted-msecs))
+                        (user-error "Can't scale when extension would overlap 
subsequent subtitles")))
+                    (funcall scale-subtitles :reverse))
+                (save-excursion
+                  ;; Moving backward - Make sure the last subtitle will not
+                  ;; precede the first subtitle.
+                  (unless (> new-end-start-msecs beg-start-msecs)
+                    (user-error "Can't scale when contraction would eliminate 
region"))
+                  (goto-char end)
+                  (move-subtitle msecs :ignore-negative-duration)
+                  (funcall scale-subtitles))))))))))
+
 (defun subed--move-subtitles-in-region (msecs beg end)
   "Move subtitles in region specified by BEG and END by MSECS milliseconds."
   (unless (= msecs 0)
@@ -374,6 +457,59 @@ but we move the start time first."
               (subed-for-each-subtitle (point) end nil
                 (move-subtitle msecs :ignore-negative-duration)))))))))
 
+(defun subed-scale-subtitles (msecs &optional beg end)
+  "Scale subtitles between BEG and END after moving END MSECS.
+Use a negative MSECS value to move END backward.
+If END is nil, END will be the last subtitle in the buffer.
+If BEG is nil, BEG will be the first subtitle in the buffer."
+  (let ((beg (or beg (point-min)))
+        (end (or end (point-max))))
+    (subed--scale-subtitles-in-region msecs beg end)
+    (when (subed-replay-adjusted-subtitle-p)
+      (save-excursion
+        (goto-char end)
+        (subed-jump-to-subtitle-id)
+        (subed-mpv-jump (subed-subtitle-msecs-start))))))
+
+(defun subed-scale-subtitles-forward (&optional arg)
+  "Scale subtitles after region is extended `subed-milliseconds-adjust'.
+
+Scaling adjusts start and stop by the same amount, preserving
+subtitle duration.
+
+All subtitles that are fully or partially in the active region
+are moved so they are placed proportionally in the new range.
+
+If prefix argument ARG is given, it is used to extend the end of the region
+`subed-milliseconds-adjust' before proportionally adjusting subtitles.  If the
+prefix argument is given but not numerical,
+`subed-milliseconds-adjust' is reset to its default value.
+
+Example usage:
+  \\[universal-argument] 1000 \\[subed-scale-subtitles-forward] Extend region 
1000ms forward in time and scale subtitles in region
+           \\[subed-scale-subtitles-forward] Extend region another 1000ms 
forward in time and scale subtitles again
+   \\[universal-argument] 500 \\[subed-scale-subtitles-forward] Extend region 
500ms forward in time and scale subtitles in region
+           \\[subed-scale-subtitles-forward] Extend region another 500ms 
forward in time and scale subtitles again
+       \\[universal-argument] \\[subed-scale-subtitles-forward] Extend region 
100ms (the default) forward in time and scale subtitles in region
+           \\[subed-scale-subtitles-forward] Extend region another 100ms (the 
default) forward in time and scale subtitles again"
+  (interactive "P")
+  (let ((deactivate-mark nil)
+        (msecs (subed-get-milliseconds-adjust arg))
+        (beg (when mark-active (region-beginning)))
+        (end (when mark-active (region-end))))
+    (subed-scale-subtitles msecs beg end)))
+
+(defun subed-scale-subtitles-backward (&optional arg)
+  "Scale subtitles after region is shortened `subed-milliseconds-adjust'.
+
+See `subed-scale-subtitles-forward' about ARG."
+  (interactive "P")
+  (let ((deactivate-mark nil)
+        (msecs (* -1 (subed-get-milliseconds-adjust arg)))
+        (beg (when mark-active (region-beginning)))
+        (end (when mark-active (region-end))))
+    (subed-scale-subtitles msecs beg end)))
+
 (defun subed-move-subtitles (msecs &optional beg end)
   "Move subtitles between BEG and END MSECS milliseconds forward.
 Use a negative MSECS value to move subtitles backward.
diff --git a/subed/subed.el b/subed/subed.el
index ee4edbc..e148fe7 100644
--- a/subed/subed.el
+++ b/subed/subed.el
@@ -60,6 +60,8 @@
     (define-key subed-mode-map (kbd "C-M-p") #'subed-move-subtitle-backward)
     (define-key subed-mode-map (kbd "C-M-f") #'subed-shift-subtitle-forward)
     (define-key subed-mode-map (kbd "C-M-b") #'subed-shift-subtitle-backward)
+    (define-key subed-mode-map (kbd "C-M-x") #'subed-scale-subtitles-forward)
+    (define-key subed-mode-map (kbd "C-M-S-x") 
#'subed-scale-subtitles-backward)
     (define-key subed-mode-map (kbd "M-i") #'subed-insert-subtitle)
     (define-key subed-mode-map (kbd "C-M-i") #'subed-insert-subtitle-adjacent)
     (define-key subed-mode-map (kbd "M-k") #'subed-kill-subtitle)
diff --git a/tests/test-subed-common.el b/tests/test-subed-common.el
index efe38c4..f0f1490 100644
--- a/tests/test-subed-common.el
+++ b/tests/test-subed-common.el
@@ -2423,3 +2423,446 @@ This is another.
         (subed-backward-subtitle-time-start)
         (expect (subed-subtitle-msecs-stop) :to-equal 63061)
         (expect (subed-subtitle-text) :to-equal "Foo.")))))
+
+(describe "Scaling subtitles"
+  (it "without providing beginning and end."
+    (with-temp-srt-buffer
+      (insert mock-srt-data)
+      (spy-on 'subed-scale-subtitles :and-call-through)
+      (subed-scale-subtitles-forward 1000)
+      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+      (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
+      (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
+      (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
+      (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
+      (subed-scale-subtitles-backward 1000)
+      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+      (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+      (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+      (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+      (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)
+      (expect (spy-calls-all-args 'subed-scale-subtitles) :to-equal
+              '((+1000 nil nil)
+                (-1000 nil nil)))))
+  (it "without providing end."
+    (with-temp-srt-buffer
+      (insert mock-srt-data)
+      (subed-scale-subtitles 1000 (point-min) nil)
+      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+      (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
+      (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
+      (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
+      (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
+      (subed-scale-subtitles -1000 (point-min) nil)
+      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+      (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+      (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+      (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+      (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)))
+  (it "without providing beginning."
+    (with-temp-srt-buffer
+      (insert mock-srt-data)
+      (subed-scale-subtitles 1000 nil (point-max))
+      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+      (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
+      (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
+      (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
+      (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
+      (subed-scale-subtitles -1000 nil (point-max))
+      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+      (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+      (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+      (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+      (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)))
+  (it "with active region on entire buffer."
+    (with-temp-srt-buffer
+      (insert mock-srt-data)
+      (let ((beg (point-min))
+            (end (point-max)))
+        (spy-on 'subed-scale-subtitles :and-call-through)
+        (spy-on 'region-beginning :and-return-value beg)
+        (spy-on 'region-end :and-return-value end)
+        (setq mark-active t)
+        (subed-scale-subtitles-forward 1000)
+        (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+        (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+        (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
+        (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
+        (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
+        (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
+        (subed-scale-subtitles-backward 1000)
+        (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+        (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+        (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+        (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+        (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+        (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)
+        (expect (spy-calls-all-args 'subed-scale-subtitles) :to-equal
+                `((+1000 ,beg ,end)
+                  (-1000 ,beg ,end))))))
+  (it "with a zero msec extension/contraction."
+    (with-temp-srt-buffer
+      (insert mock-srt-data)
+      (subed-scale-subtitles-forward 0)
+      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+      (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+      (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+      (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+      (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)
+      (subed-scale-subtitles-backward 0)
+      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+      (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+      (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+      (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+      (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)))
+  (it "with active region on one subtitle."
+    (with-temp-srt-buffer
+      (insert mock-srt-data)
+      (let ((beg 77) ; point at ID of third subtitle
+            (end (point-max)))
+        (spy-on 'region-beginning :and-return-value beg)
+        (spy-on 'region-end :and-return-value end)
+        (spy-on 'user-error :and-call-through)
+        (setq mark-active t)
+        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale with fewer than 3 subtitles")))
+        (expect (buffer-string) :to-equal mock-srt-data))))
+  (it "with active region on two subtitles."
+    (with-temp-srt-buffer
+      (insert mock-srt-data)
+      (let ((beg 39) ; point at ID of second subtitle
+            (end (point-max)))
+        (spy-on 'region-beginning :and-return-value beg)
+        (spy-on 'region-end :and-return-value end)
+        (spy-on 'user-error :and-call-through)
+        (setq mark-active t)
+        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale with only 2 subtitles")))
+        (expect (buffer-string) :to-equal mock-srt-data))))
+  (it "with active region contraction."
+    (with-temp-srt-buffer
+      (insert (concat "1\n"
+                      "00:00:43,233 --> 00:00:45,861\n"
+                      "a\n"
+                      "\n"
+                      "2\n"
+                      "00:00:51,675 --> 00:00:54,542\n"
+                      "b\n"
+                      "\n"
+                      "3\n"
+                      "00:01:00,717 --> 00:01:02,378\n"
+                      "c\n"
+                      "\n"
+                      "4\n"
+                      "00:01:02,452 --> 00:01:05,216\n"
+                      "d\n"))
+      (let ((beg (point-min))
+            (end 103)) ; point at TEXT of third subtitle
+        (spy-on 'region-beginning :and-return-value beg)
+        (spy-on 'region-end :and-return-value end)
+        (setq mark-active t)
+        (subed-scale-subtitles-backward 1000)
+        (expect (subed-subtitle-msecs-start 1) :to-equal 43233)
+        (expect (subed-subtitle-msecs-stop 1) :to-equal 45861)
+        (expect (subed-subtitle-msecs-start 2) :to-equal 51192)
+        (expect (subed-subtitle-msecs-stop 2) :to-equal 54059)
+        (expect (subed-subtitle-msecs-start 3) :to-equal 59717)
+        (expect (subed-subtitle-msecs-stop 3) :to-equal 61378)
+        (expect (subed-subtitle-msecs-start 4) :to-equal 62452)
+        (expect (subed-subtitle-msecs-stop 4) :to-equal 65216))))
+  (it "with active region extension."
+    (with-temp-srt-buffer
+      (insert (concat "1\n"
+                      "00:00:43,233 --> 00:00:45,861\n"
+                      "a\n"
+                      "\n"
+                      "2\n"
+                      "00:00:51,192 --> 00:00:54,059\n"
+                      "b\n"
+                      "\n"
+                      "3\n"
+                      "00:00:59,717 --> 00:01:01,378\n"
+                      "c\n"
+                      "\n"
+                      "4\n"
+                      "00:01:02,452 --> 00:01:05,216\n"
+                      "d\n"))
+      (let ((beg (point-min))
+            (end 103)) ; point at TEXT of third subtitle
+        (spy-on 'region-beginning :and-return-value beg)
+        (spy-on 'region-end :and-return-value end)
+        (setq mark-active t)
+        (setq-local subed-subtitle-spacing 0)
+        (subed-scale-subtitles-forward 1000)
+        (expect (subed-subtitle-msecs-start 1) :to-equal 43233)
+        (expect (subed-subtitle-msecs-stop 1) :to-equal 45861)
+        (expect (subed-subtitle-msecs-start 2) :to-equal 51675)
+        (expect (subed-subtitle-msecs-stop 2) :to-equal 54542)
+        (expect (subed-subtitle-msecs-start 3) :to-equal 60717)
+        (expect (subed-subtitle-msecs-stop 3) :to-equal 62378)
+        (expect (subed-subtitle-msecs-start 4) :to-equal 62452)
+        (expect (subed-subtitle-msecs-stop 4) :to-equal 65216))))
+  (it "when active region extension overlaps next subtitle."
+    (with-temp-srt-buffer
+      (let ((initial-contents
+              (concat "1\n"
+                      "00:00:43,233 --> 00:00:45,861\n"
+                      "a\n"
+                      "\n"
+                      "2\n"
+                      "00:00:51,675 --> 00:00:54,542\n"
+                      "b\n"
+                      "\n"
+                      "3\n"
+                      "00:01:00,717 --> 00:01:02,378\n"
+                      "c\n"
+                      "\n"
+                      "4\n"
+                      "00:01:02,452 --> 00:01:05,216\n"
+                      "d\n"))
+            (beg 1)
+            (end 103)) ; point at TEXT of third subtitle
+        (spy-on 'region-beginning :and-return-value beg)
+        (spy-on 'region-end :and-return-value end)
+        (spy-on 'user-error :and-call-through)
+        (insert initial-contents)
+        (setq mark-active t)
+        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when extension would overlap subsequent 
subtitles")))
+        (expect (buffer-string) :to-equal initial-contents))))
+  (it "when end subtitle start time moved to same time as begin subtitle start 
time."
+    (with-temp-srt-buffer
+      (insert mock-srt-data)
+      (let ((beg (point-min))
+            (end (point-max))
+            (delta (- (subed-subtitle-msecs-start 3)
+                      (subed-subtitle-msecs-start 1))))
+        (spy-on 'region-beginning :and-return-value beg)
+        (spy-on 'region-end :and-return-value end)
+        (spy-on 'user-error :and-call-through)
+        (setq mark-active t)
+        (expect (subed-scale-subtitles-backward delta) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when contraction would eliminate region")))
+        (expect (buffer-string) :to-equal mock-srt-data))))
+  (it "when end subtitle start time moved to just before begin subtitle start 
time."
+    (with-temp-srt-buffer
+      (insert mock-srt-data)
+      (let ((beg (point-min))
+            (end (point-max))
+            (delta (- (subed-subtitle-msecs-start 3)
+                      (subed-subtitle-msecs-start 1))))
+        (spy-on 'region-beginning :and-return-value beg)
+        (spy-on 'region-end :and-return-value end)
+        (spy-on 'user-error :and-call-through)
+        (setq mark-active t)
+        (expect (subed-scale-subtitles-backward (+ delta 1)) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when contraction would eliminate region")))
+        (expect (buffer-string) :to-equal mock-srt-data))))
+  (it "when end subtitle start time moved to just after begin subtitle start 
time."
+    (with-temp-srt-buffer
+      (insert mock-srt-data)
+      (let ((beg (point-min))
+            (end (point-max))
+            (delta (- (subed-subtitle-msecs-start 3)
+                      (subed-subtitle-msecs-start 1))))
+        (spy-on 'region-beginning :and-return-value beg)
+        (spy-on 'region-end :and-return-value end)
+        (setq mark-active t)
+        (subed-scale-subtitles-backward (- delta 1))
+        (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+        (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+        (expect (subed-subtitle-msecs-start 2) :to-equal 61001)
+        (expect (subed-subtitle-msecs-stop 2) :to-equal 69112)
+        (expect (subed-subtitle-msecs-start 3) :to-equal 61001)
+        (expect (subed-subtitle-msecs-stop 3) :to-equal 73051))))
+  (it "when begin start time same as end start time."
+    (with-temp-srt-buffer
+     (let ((initial-contents
+              (concat "1\n"
+                      "00:01:01,000 --> 00:01:05,123\n"
+                      "Foo.\n"
+                      "\n"
+                      "2\n"
+                      "00:01:01,000 --> 00:01:05,123\n"
+                      "Bar.\n"
+                      "\n"
+                      "3\n"
+                      "00:01:01,000 --> 00:01:05,123\n"
+                      "Baz.\n")))
+        (spy-on 'user-error :and-call-through)
+        (insert initial-contents)
+        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale subtitle range with 0 time interval")))
+        (expect (buffer-string) :to-equal initial-contents)
+        (spy-calls-reset 'user-error)
+        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale subtitle range with 0 time interval")))
+        (expect (buffer-string) :to-equal initial-contents))))
+  (it "when buffer is empty."
+    (spy-on 'user-error :and-call-through)
+    (with-temp-srt-buffer
+      (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+      (expect (spy-calls-all-args 'user-error) :to-equal
+              '(("Can't scale with fewer than 3 subtitles")))
+      (expect (buffer-string) :to-equal "")
+      (spy-calls-reset 'user-error)
+      (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+      (expect (spy-calls-all-args 'user-error) :to-equal
+              '(("Can't scale with fewer than 3 subtitles")))
+      (expect (buffer-string) :to-equal "")))
+  (it "when buffer contains one subtitle."
+    (spy-on 'user-error :and-call-through)
+    (with-temp-srt-buffer
+      (let ((initial-contents
+              (concat "1\n"
+                      "00:01:01,000 --> 00:01:05,123\n"
+                      "Foo.\n")))
+        (insert initial-contents)
+        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale with fewer than 3 subtitles")))
+        (expect (buffer-string) :to-equal initial-contents)
+        (spy-calls-reset 'user-error)
+        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale with fewer than 3 subtitles")))
+        (expect (buffer-string) :to-equal initial-contents))))
+  (it "when buffer contains two subtitles."
+    (spy-on 'user-error :and-call-through)
+    (with-temp-srt-buffer
+      (let ((initial-contents
+              (concat "1\n"
+                      "00:01:01,000 --> 00:01:05,123\n"
+                      "Foo.\n"
+                      "\n"
+                      "2\n"
+                      "00:02:02,234 --> 00:02:10,345\n"
+                      "Bar.\n")))
+        (insert initial-contents)
+        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale with only 2 subtitles")))
+        (expect (buffer-string) :to-equal initial-contents)
+        (spy-calls-reset 'user-error)
+        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale with only 2 subtitles")))
+        (expect (buffer-string) :to-equal initial-contents))))
+  (it "with subtitle in region containing start time after end start time."
+    (spy-on 'user-error :and-call-through)
+    (with-temp-srt-buffer
+      (let ((initial-contents
+              (concat "1\n"
+                      "00:01:01,000 --> 00:01:05,123\n"
+                      "Foo.\n"
+                      "\n"
+                      "2\n"
+                      "00:03:03,45 --> 00:03:15,5\n"
+                      "Baz.\n"
+                      "\n"
+                      "3\n"
+                      "00:02:02,234 --> 00:02:10,345\n"
+                      "Bar.\n")))
+        (insert initial-contents)
+        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when nonchronological subtitles exist")))
+        (expect (buffer-string) :to-equal initial-contents)
+        (spy-calls-reset 'user-error)
+        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when nonchronological subtitles exist")))
+        (expect (buffer-string) :to-equal initial-contents))))
+  (it "with first subtitle containing no timestamp."
+    (spy-on 'user-error :and-call-through)
+    (with-temp-srt-buffer
+      (let ((initial-contents
+              (concat "1\n"
+                      "a\n"
+                      "\n"
+                      "2\n"
+                      "00:00:51,675 --> 00:00:54,542\n"
+                      "b\n"
+                      "\n"
+                      "3\n"
+                      "00:01:00,717 --> 00:01:02,378\n"
+                      "c\n")))
+        (insert initial-contents)
+        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when first subtitle timestamp missing")))
+        (expect (buffer-string) :to-equal initial-contents)
+        (spy-calls-reset 'user-error)
+        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when first subtitle timestamp missing")))
+        (expect (buffer-string) :to-equal initial-contents))))
+  (it "with last subtitle containing no timestamp."
+    (spy-on 'user-error :and-call-through)
+    (with-temp-srt-buffer
+      (let ((initial-contents
+              (concat "1\n"
+                      "00:00:43,233 --> 00:00:45,861\n"
+                      "a\n"
+                      "\n"
+                      "2\n"
+                      "00:00:51,675 --> 00:00:54,542\n"
+                      "b\n"
+                      "\n"
+                      "3\n"
+                      "c\n")))
+        (insert initial-contents)
+        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when last subtitle timestamp missing")))
+        (expect (buffer-string) :to-equal initial-contents)
+        (spy-calls-reset 'user-error)
+        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when last subtitle timestamp missing")))
+        (expect (buffer-string) :to-equal initial-contents))))
+  (it "with subtitle in region containing no timestamp."
+    (spy-on 'user-error :and-call-through)
+    (with-temp-srt-buffer
+      (let ((initial-contents
+              (concat "1\n"
+                      "00:00:43,233 --> 00:00:45,861\n"
+                      "a\n"
+                      "\n"
+                      "2\n"
+                      "b\n"
+                      "\n"
+                      "3\n"
+                      "00:01:00,717 --> 00:01:02,378\n"
+                      "c\n")))
+        (insert initial-contents)
+        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when subtitle timestamp missing")))
+        (expect (buffer-string) :to-equal initial-contents)
+        (spy-calls-reset 'user-error)
+        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+        (expect (spy-calls-all-args 'user-error) :to-equal
+                '(("Can't scale when subtitle timestamp missing")))
+        (expect (buffer-string) :to-equal initial-contents))))
+  (it "with out-of-order range."
+    (spy-on 'user-error :and-call-through)
+    (with-temp-srt-buffer
+     (expect (subed-scale-subtitles 1000 5 4) :to-throw 'error)
+     (expect (spy-calls-all-args 'user-error) :to-equal
+             '(("Can't scale with improper range"))))))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]