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

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

[nongnu] elpa/subed 350b85c64b 2/2: Support optional cue identifiers in


From: ELPA Syncer
Subject: [nongnu] elpa/subed 350b85c64b 2/2: Support optional cue identifiers in WebVTT files
Date: Mon, 7 Nov 2022 06:59:27 -0500 (EST)

branch: elpa/subed
commit 350b85c64b7544c709d08112382fa2a04b271ccf
Author: Sacha Chua <sacha@sachachua.com>
Commit: Sacha Chua <sacha@sachachua.com>

    Support optional cue identifiers in WebVTT files
    
    * subed/subed-common.el (subed-save-excursion): Allow edebugging.
    (subed-convert): Allow conversion to text.
    * subed/subed-vtt.el (subed--subtitle-id): Support optional cue
    identifiers.
    (subed--jump-to-subtitle-id): Support optional cue
    identifiers.
    (subed--jump-to-subtitle-time-start): Since subed--subtitle-id might
    point to a cue identifier, we need to look for the subtitle timestamp
    instead.
    (subed--jump-to-subtitle-time-stop): Support optional cue identifiers.
    (subed--jump-to-subtitle-end): Support optional cue identifiers.
    (subed--backward-subtitle-id): Support optional cue identifiers.
    (subed--sanitize-format): Clean up subtitles a bit better.
    * subed/subed.el: Increase the version.
    * tests/test-subed-vtt.el ("VTT"): Remove the test for spaces between
    subtitles, since that's not part of the spec. Split up complex tests.
    Add a test for handling optional cue identifiers.
---
 NEWS.org                |  9 +++++
 subed/subed-common.el   | 21 ++++++-----
 subed/subed-vtt.el      | 97 ++++++++++++++++++++++++++++---------------------
 subed/subed.el          |  2 +-
 tests/test-subed-vtt.el | 50 ++++++++++++++++---------
 5 files changed, 109 insertions(+), 70 deletions(-)

diff --git a/NEWS.org b/NEWS.org
index c587dc7dc8..804b3c7f4d 100644
--- a/NEWS.org
+++ b/NEWS.org
@@ -1,4 +1,13 @@
 * subed news
+** Version 1.0.17 - 2022-11-07 - Sacha Chua
+
+New command subed-align in the subed-align.el file lets you use aeneas
+for forced alignment. This can assign timestamps to each line of text.
+
+VTT files can now have optional cue identifiers. A cue identifier is a
+line of text before the timestamps that can identify the cue. It
+should not contain "-->".
+
 ** Version 1.0.16 - 2022-10-26 - Sacha Chua
 
 When you load word data, subtitle words that were successfully matched
diff --git a/subed/subed-common.el b/subed/subed-common.el
index d60fc82eeb..8974109491 100644
--- a/subed/subed-common.el
+++ b/subed/subed-common.el
@@ -384,6 +384,7 @@ scheduled call is canceled and another call is scheduled in
   "Restore relative point within current subtitle after executing BODY.
 This also works if the buffer changes (e.g. when sorting
 subtitles) as long the subtitle IDs don't change."
+  (declare (debug t))
   (save-excursion
     `(let ((sub-id (subed-subtitle-id))
            (sub-pos (subed-subtitle-relative-point)))
@@ -1852,7 +1853,7 @@ If LIST is nil, use the subtitles in the current buffer."
 (defun subed-convert (format)
   "Create a buffer with the current subtitles converted to FORMAT.
 You may need to add some extra information to the buffer."
-  (interactive (list (completing-read "To format: " '("VTT" "SRT" "ASS" 
"TSV"))))
+  (interactive (list (completing-read "To format: " '("VTT" "SRT" "ASS" "TSV" 
"TXT"))))
   (let* ((subtitles (subed-subtitle-list))
          (new-filename (concat (file-name-base (or (buffer-file-name) 
(buffer-name))) "." (downcase format)))
          buf)
@@ -1860,15 +1861,17 @@ You may need to add some extra information to the 
buffer."
               (yes-or-no-p (format "%s exists. Overwrite? " new-filename)))
       (find-file new-filename)
       (erase-buffer)
-      (pcase format
-        ("VTT" (require 'subed-vtt) (subed-vtt-mode))
-        ("SRT" (require 'subed-srt) (subed-srt-mode))
-        ("ASS" (require 'subed-ass) (subed-ass-mode))
-        ("TSV" (require 'subed-tsv) (subed-tsv-mode)))
       (save-excursion
-        (subed-auto-insert)
-        (mapc (lambda (sub) (apply #'subed-append-subtitle nil (cdr sub))) 
subtitles)
-        (subed-regenerate-ids))
+        (if (string= format "TXT")
+            (insert (mapconcat (lambda (o) (elt o 3)) subtitles "\n"))
+          (pcase format
+            ("VTT" (require 'subed-vtt) (subed-vtt-mode))
+            ("SRT" (require 'subed-srt) (subed-srt-mode))
+            ("ASS" (require 'subed-ass) (subed-ass-mode))
+            ("TSV" (require 'subed-tsv) (subed-tsv-mode)))
+          (subed-auto-insert)
+          (mapc (lambda (sub) (apply #'subed-append-subtitle nil (cdr sub))) 
subtitles)
+          (subed-regenerate-ids)))
       (current-buffer))))
 
 (provide 'subed-common)
diff --git a/subed/subed-vtt.el b/subed/subed-vtt.el
index ade738721d..8b587cae83 100644
--- a/subed/subed-vtt.el
+++ b/subed/subed-vtt.el
@@ -75,9 +75,8 @@ Use the format-specific function for MAJOR-MODE."
   "Return the ID of the subtitle at point or nil if there is no ID.
 Use the format-specific function for MAJOR-MODE."
   (save-excursion
-    (when (and (subed-jump-to-subtitle-time-start)
-               (looking-at subed--regexp-timestamp))
-      (match-string 0))))
+    (when (subed-jump-to-subtitle-id)
+      (match-string 1))))
 
 (cl-defmethod subed--subtitle-id-at-msecs (msecs &context (major-mode 
subed-vtt-mode))
   "Return the ID of the subtitle at MSECS milliseconds.
@@ -109,7 +108,7 @@ format-specific function for MAJOR-MODE."
   "Move to the ID of a subtitle and return point.
 If SUB-ID is not given, focus the current subtitle's ID.
 Return point or nil if no subtitle ID could be found.
-WebVTT doesn't use IDs, so we use the starting timestamp instead.
+WebVTT IDs are optional.  If an ID is not specified, use the timestamp instead.
 Use the format-specific function for MAJOR-MODE."
   (let ((orig-point (point)) found)
     (if (stringp sub-id)
@@ -121,23 +120,23 @@ Use the format-specific function for MAJOR-MODE."
           (setq found (re-search-forward regex nil t))
           (if found
               (goto-char (match-beginning 2))
-            (goto-char orig-point)))
-      ;; Find one or more blank lines.
-      (or (re-search-forward "\\(^[[:blank:]]*\n\\)+" nil t)
-          (goto-char (point-max)))
+            (goto-char orig-point)
+            nil))
+
       ;; Find two or more blank lines or the beginning of the buffer, followed
-      ;; by line starting with a timestamp.
-      (let* ((regex (concat  "\\(" subed--regexp-separator "\\|\\`\\)"
-                             "\\(?:" subed-vtt--regexp-identifier "\\)?"
-                             "\\(" subed--regexp-timestamp "\\)")))
-        (setq found (re-search-backward regex nil t))
-        (when found
-          (goto-char (match-beginning 2)))))
-    ;; Make extra sure we're on a timestamp, return nil if we're not
-    (if (and found (looking-at "^\\(\\([0-9]+:\\)?[0-9]+:[0-9]+\\.[0-9]+\\)"))
-        (point)
-      (goto-char orig-point)
-      nil)))
+      ;; by an optional line and a timestamp.
+      (or (and (re-search-backward subed--regexp-separator nil t)
+               (goto-char (match-end 0)))
+          (goto-char (point-min)))
+      (cond
+       ((looking-at (concat "\\(" subed-vtt--regexp-timestamp "\\) *--> *" 
subed-vtt--regexp-timestamp " *\n"))
+        ;; no ID, use the timestamp
+        (point))
+       ((looking-at (concat "\\(.*\\)\n" subed-vtt--regexp-timestamp " *--> *" 
subed-vtt--regexp-timestamp " *\n"))
+        (point))
+       (t
+        (goto-char orig-point)
+        nil)))))
 
 (cl-defmethod subed--jump-to-subtitle-time-start (&context (major-mode 
subed-vtt-mode) &optional sub-id)
   "Move point to subtitle's start time.
@@ -145,15 +144,18 @@ If SUB-ID is not given, use subtitle on point.
 Return point or nil if no start time could be found.
 Use the format-specific function for MAJOR-MODE."
   (when (subed-jump-to-subtitle-id sub-id)
-    (when (looking-at subed--regexp-timestamp)
-      (point))))
+    (if (looking-at subed--regexp-timestamp)
+        (point)
+      (when (re-search-forward subed--regexp-timestamp nil t)
+        (goto-char (match-beginning 0))
+        (point)))))
 
 (cl-defmethod subed--jump-to-subtitle-time-stop (&context (major-mode 
subed-vtt-mode) &optional sub-id)
   "Move point to subtitle's stop time.
 If SUB-ID is not given, use subtitle on point.
 Return point or nil if no stop time could be found.
 Use the format-specific function for MAJOR-MODE."
-  (when (subed-jump-to-subtitle-id sub-id)
+  (when (subed-jump-to-subtitle-time-start sub-id)
     (re-search-forward " *--> *" (point-at-eol) t)
     (when (looking-at subed--regexp-timestamp)
       (point))))
@@ -163,7 +165,7 @@ Use the format-specific function for MAJOR-MODE."
 If SUB-ID is not given, use subtitle on point.
 Return point or nil if a the subtitle's text can't be found.
 Use the format-specific function for MAJOR-MODE."
-  (when (subed-jump-to-subtitle-id sub-id)
+  (when (subed-jump-to-subtitle-time-start sub-id)
     (forward-line 1)
     (point)))
 
@@ -178,23 +180,33 @@ can be found.  Use the format-specific function for 
MAJOR-MODE."
     ;; `subed-vtt--regexp-separator' here because if subtitle text is empty,
     ;; it may be the only empty line in the separator, i.e. there's only one
     ;; "\n".
-    (let ((regex (concat "\\([[:blank:]]*\n\\)+"
-                         "\\(?:NOTE[ \n]\\(?:.+?\n\\)+\n\\)*"
-                         "\\(" subed--regexp-timestamp 
"\\)\\|\\([[:blank:]]*\n*\\)\\'")))
-      (when (re-search-forward regex nil t)
-        (goto-char (match-beginning 0))))
-    (unless (= (point) orig-point)
-      (point))))
+    (let ((regex subed-vtt--regexp-separator))
+      (if (eolp)
+          (unless (= (point) orig-point)
+            (point))
+        (if (re-search-forward regex nil t)
+            (goto-char (match-beginning 0))
+          (goto-char (point-max))
+          (skip-syntax-backward " "))
+        (unless (= (point) orig-point)
+          (point))))))
 
 (cl-defmethod subed--forward-subtitle-id (&context (major-mode subed-vtt-mode))
   "Move point to next subtitle's ID.
 Return point or nil if there is no next subtitle.  Use the
 format-specific function for MAJOR-MODE."
-  (when (re-search-forward (concat subed--regexp-separator
-                                   "\\(?:" subed-vtt--regexp-identifier "\\)?"
-                                   subed--regexp-timestamp)
-                           nil t)
-    (subed-jump-to-subtitle-id)))
+  (let ((orig-point (point)))
+    (if (and
+         (re-search-forward subed--regexp-separator nil t)
+         (re-search-forward (concat "^" subed--regexp-timestamp
+                                    " *--> *" subed--regexp-timestamp)
+                            nil t))
+        (or (subed-jump-to-subtitle-id)
+            (progn
+              (goto-char orig-point)
+              nil))
+      (goto-char orig-point)
+      nil)))
 
 (cl-defmethod subed--backward-subtitle-id (&context (major-mode 
subed-vtt-mode))
   "Move point to previous subtitle's ID.
@@ -202,12 +214,12 @@ Return point or nil if there is no previous subtitle.  
Use the
 format-specific function for MAJOR-MODE."
   (let ((orig-point (point)))
     (when (subed-jump-to-subtitle-id)
-      (if (re-search-backward (concat "\\(" subed--regexp-separator 
"\\|\\`[[:space:]]*\\)\\(" subed--regexp-timestamp "\\)") nil t)
-          (progn
-            (goto-char (match-beginning 2))
-            (point))
-        (goto-char orig-point)
-        nil))))
+      (or
+       (catch 'found
+         (while (re-search-backward subed--regexp-separator nil t)
+           (when (subed-jump-to-subtitle-id)
+             (throw 'found (point)))))
+       (progn (goto-char orig-point) nil)))))
 
 ;;; Manipulation
 
@@ -323,6 +335,7 @@ Use the format-specific function for MAJOR-MODE."
      (goto-char (point-min))
      (when (re-search-forward "[[:graph:]]" nil t)
        (goto-char (point-max))
+       (skip-chars-backward " \t\n")
        (subed-jump-to-subtitle-end)
        (unless (looking-at "\n\\'")
          (delete-region (point) (point-max))
diff --git a/subed/subed.el b/subed/subed.el
index 955dc06902..adf7bdf365 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.0.16
+;; Version: 1.0.17
 ;; Maintainer: Sacha Chua <sacha@sachachua.com>
 ;; Author: Random User
 ;; Keywords: convenience, files, hypermedia, multimedia
diff --git a/tests/test-subed-vtt.el b/tests/test-subed-vtt.el
index ed360d7ee5..b846360a6e 100644
--- a/tests/test-subed-vtt.el
+++ b/tests/test-subed-vtt.el
@@ -3,6 +3,7 @@
 (load-file "./tests/undercover-init.el")
 (require 'subed)
 (require 'subed-vtt)
+(require 'subed-common)
 
 (defvar mock-vtt-data
   "WEBVTT
@@ -311,16 +312,6 @@ Baz.
          (backward-char 2)
          (expect (subed-jump-to-subtitle-end) :to-be 112)
          (expect (looking-back "^Baz.$") :to-be t)))
-      (it "handles spaces in between subtitles."
-        (with-temp-vtt-buffer
-         (insert mock-vtt-data)
-         (goto-char (point-min))
-         (re-search-forward "Foo\\.\n")
-         (replace-match "Foo.\n ")
-         (goto-char (point-min))
-         (subed-forward-subtitle-id)
-         (expect (subed-jump-to-subtitle-end) :to-be 43)
-         (expect (looking-back "^Foo.$") :to-be t)))
       (it "returns nil if subtitle end cannot be found."
         (with-temp-vtt-buffer
          (expect (subed-jump-to-subtitle-end) :to-be nil)))
@@ -386,10 +377,11 @@ Baz.
          (expect (looking-at (regexp-quote "00:02:02.234")) :to-be t)
          (expect (subed-forward-subtitle-id) :to-be 81)
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)))
-      (it "returns nil and doesn't move when there is no next subtitle."
+      (it "returns nil in an empty buffer."
         (with-temp-vtt-buffer
          (expect (thing-at-point 'word) :to-equal nil)
-         (expect (subed-forward-subtitle-id) :to-be nil))
+         (expect (subed-forward-subtitle-id) :to-be nil)))
+      (it "moves forward in a buffer."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (subed-jump-to-subtitle-text "00:01:01.000")
@@ -399,20 +391,21 @@ Baz.
          (subed-jump-to-subtitle-time-stop "00:02:02.234")
          (expect (looking-at (regexp-quote "00:02:10.345")) :to-be t)
          (expect (subed-forward-subtitle-id) :to-be 81)
-         (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t))
+         (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)))
+      (it "doesn't move when at the last subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (subed-jump-to-subtitle-text "00:03:03.45")
          (expect (thing-at-point 'word) :to-equal "Baz")
          (expect (subed-forward-subtitle-id) :to-be nil)
-         (expect (thing-at-point 'word) :to-equal "Baz"))
+         (expect (thing-at-point 'word) :to-equal "Baz")))
+      (it "doesn't move when at the last subtitle's time stop."
         (with-temp-vtt-buffer
          (insert (concat mock-vtt-data "\n\n"))
          (subed-jump-to-subtitle-time-stop "00:03:03.45")
          (expect (thing-at-point 'word) :to-equal "00")
          (expect (subed-forward-subtitle-id) :to-be nil)
-         (expect (thing-at-point 'word) :to-equal "00")))
-      )
+         (expect (thing-at-point 'word) :to-equal "00"))))
     (describe "to previous subtitle ID"
       (it "returns point when there is a previous subtitle."
         (with-temp-vtt-buffer
@@ -910,6 +903,7 @@ Baz.
         (with-temp-vtt-buffer
          (insert (concat "00:00:01.000 --> 00:00:02.000\n"
                          "\n"))
+         (forward-char -1)
          (subed-jump-to-subtitle-text)
          (expect (subed-append-subtitle) :to-equal 63)
          (expect (buffer-string) :to-equal (concat "00:00:01.000 --> 
00:00:02.000\n"
@@ -1117,7 +1111,7 @@ Baz.
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
        (goto-char (point-max))
-       (insert " \n\t\n\n")
+       (insert " \n\n\n")
        (expect (buffer-string) :not :to-equal mock-vtt-data)
        (subed-sanitize)
        (expect (buffer-string) :to-equal mock-vtt-data)))
@@ -1306,4 +1300,24 @@ This is another test here.
        (expect (face-at-point) :to-equal 'subed-time-face)
        (re-search-forward "-->")
        (backward-char 1)
-       (expect (face-at-point) :to-equal 'subed-time-separator-face)))))
+       (expect (face-at-point) :to-equal 'subed-time-separator-face))))
+  (describe "with cues"
+    (it "parses properly."
+      (with-temp-vtt-buffer
+       (insert "WEBVTT - This file has cues.
+
+14
+00:01:14.815 --> 00:01:18.114
+- What?
+- Where are we now?
+
+15
+00:01:18.171 --> 00:01:20.991
+- This is big bat country.
+
+16
+00:01:21.058 --> 00:01:23.868
+- [ Bats Screeching ]
+- They won't get in your hair. They're after the bugs.")
+       (expect (elt (car (subed-subtitle-list)) 3)
+               :to-equal "- What?\n- Where are we now?")))))



reply via email to

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