[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"))))))
- [nongnu] elpa/subed 3b4b56a 384/389: Merge pull request #49 from sachac/fix-vtt-spaces, (continued)
- [nongnu] elpa/subed 3b4b56a 384/389: Merge pull request #49 from sachac/fix-vtt-spaces, ELPA Syncer, 2021/12/03
- [nongnu] elpa/subed bee9e63 342/389: subed-vtt: Fix syncing point with player, ELPA Syncer, 2021/12/03
- [nongnu] elpa/subed 016c6a5 363/389: subed-split-subtitle: Handle more cases, ELPA Syncer, 2021/12/03
- [nongnu] elpa/subed 6164f88 380/389: Keep track of video being played, ELPA Syncer, 2021/12/03
- [nongnu] elpa/subed 70561f0 381/389: Make hours optional in VTT files, following the spec, ELPA Syncer, 2021/12/03
- [nongnu] elpa/subed bf3e832 382/389: Check if subed--cps-overlay exists before trying to update it, ELPA Syncer, 2021/12/03
- [nongnu] elpa/subed b6e08c2 383/389: Handle spaces in between VTT subtitles, ELPA Syncer, 2021/12/03
- [nongnu] elpa/subed 564b6fe 386/389: Add preliminary support for comments in VTT files, ELPA Syncer, 2021/12/03
- [nongnu] elpa/subed d5751c5 334/389: Change default faces to inherit color values, ELPA Syncer, 2021/12/03
- [nongnu] elpa/subed 65ed21c 350/389: Add tests/test-subed-vtt.el, ELPA Syncer, 2021/12/03
- [nongnu] elpa/subed 6eba992 376/389: Add ability to proportionally scale subtitles.,
ELPA Syncer <=
- [nongnu] elpa/subed 7d1aa59 385/389: Make timestamp-to-msecs a generic function, ELPA Syncer, 2021/12/03