summaryrefslogtreecommitdiff
path: root/srt2vtt/subrip.scm
blob: 0031db363eafd1a2b5b70774a0f73a4fc757a7f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
;;; srt2vtt --- SRT to WebVTT converter
;;; Copyright © 2015 David Thompson <davet@gnu.org>
;;;
;;; srt2vtt is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or
;;; (at your option) any later version.
;;;
;;; srt2vtt is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with srt2vtt.  If not, see <http://www.gnu.org/licenses/>.

(define-module (srt2vtt subrip)
  #:use-module (ice-9 match)
  #:use-module (ice-9 rdelim)
  #:use-module (ice-9 regex)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-11)
  #:use-module (srfi srfi-26)
  #:use-module (srt2vtt)
  #:export (read-subrip
            read-subrips))

(define parse-time
  (let ((regexp (make-regexp "^([0-9]+):([0-9]+):([0-9]+),([0-9]+)$")))
    (lambda (s)
      "Parse the SubRip formatted timestamp in the string S into a 4
element list.  Valid input looks like '00:00:03.417'."
      (let ((match (regexp-exec regexp s)))
        (if match
            (map (compose string->number (cut match:substring match <>))
                 '(1 2 3 4))
            (error "Invalid SubRip timestamp: " s))))))

(define parse-time-span
  (let ((regexp (make-regexp "^([0-9:,]+) --> ([0-9:,]+)$")))
    (lambda (s)
      "Parse the SubRip formatted time span in the string S and return
two values: the start time and the end time.  Valid input looks like
'00:00:03.417 --> 00:00:04.936'."
      (let ((match (regexp-exec regexp s)))
        (if match
            (values (parse-time (match:substring match 1))
                    (parse-time (match:substring match 2)))
            (error "Invalid SubRip time range: " s))))))

(define (read-subrip port)
  "Read a SubRip formatted subtitle from PORT."
  (let-values (((id) (string->number (read-line port)))
               ((start end) (parse-time-span (read-line port)))
               ((lines) (let loop ((lines '()))
                          (let ((line (read-line port)))
                            (if (or (eof-object? line)
                                    (and (string-null? line)
                                         ;; A subtitle may be a blank line!
                                         (not (null? lines))))
                                (reverse lines)
                                (loop (cons line lines)))))))
    (make-subtitle id start end lines)))

(define (read-subrips port)
  "Read all SubRip formatted subtitles from PORT."
  (reverse
   (let loop ((subs '()))
     (if (eof-object? (peek-char port))
         subs
         (loop (cons (read-subrip port) subs))))))