0031db363eafd1a2b5b70774a0f73a4fc757a7f9
[srt2vtt.git] / srt2vtt / subrip.scm
1 ;;; srt2vtt --- SRT to WebVTT converter
2 ;;; Copyright © 2015 David Thompson <davet@gnu.org>
3 ;;;
4 ;;; srt2vtt is free software; you can redistribute it and/or modify it
5 ;;; under the terms of the GNU General Public License as published by
6 ;;; the Free Software Foundation; either version 3 of the License, or
7 ;;; (at your option) any later version.
8 ;;;
9 ;;; srt2vtt is distributed in the hope that it will be useful, but
10 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 ;;; General Public License for more details.
13 ;;;
14 ;;; You should have received a copy of the GNU General Public License
15 ;;; along with srt2vtt.  If not, see <http://www.gnu.org/licenses/>.
16
17 (define-module (srt2vtt subrip)
18   #:use-module (ice-9 match)
19   #:use-module (ice-9 rdelim)
20   #:use-module (ice-9 regex)
21   #:use-module (srfi srfi-1)
22   #:use-module (srfi srfi-11)
23   #:use-module (srfi srfi-26)
24   #:use-module (srt2vtt)
25   #:export (read-subrip
26             read-subrips))
27
28 (define parse-time
29   (let ((regexp (make-regexp "^([0-9]+):([0-9]+):([0-9]+),([0-9]+)$")))
30     (lambda (s)
31       "Parse the SubRip formatted timestamp in the string S into a 4
32 element list.  Valid input looks like '00:00:03.417'."
33       (let ((match (regexp-exec regexp s)))
34         (if match
35             (map (compose string->number (cut match:substring match <>))
36                  '(1 2 3 4))
37             (error "Invalid SubRip timestamp: " s))))))
38
39 (define parse-time-span
40   (let ((regexp (make-regexp "^([0-9:,]+) --> ([0-9:,]+)$")))
41     (lambda (s)
42       "Parse the SubRip formatted time span in the string S and return
43 two values: the start time and the end time.  Valid input looks like
44 '00:00:03.417 --> 00:00:04.936'."
45       (let ((match (regexp-exec regexp s)))
46         (if match
47             (values (parse-time (match:substring match 1))
48                     (parse-time (match:substring match 2)))
49             (error "Invalid SubRip time range: " s))))))
50
51 (define (read-subrip port)
52   "Read a SubRip formatted subtitle from PORT."
53   (let-values (((id) (string->number (read-line port)))
54                ((start end) (parse-time-span (read-line port)))
55                ((lines) (let loop ((lines '()))
56                           (let ((line (read-line port)))
57                             (if (or (eof-object? line)
58                                     (and (string-null? line)
59                                          ;; A subtitle may be a blank line!
60                                          (not (null? lines))))
61                                 (reverse lines)
62                                 (loop (cons line lines)))))))
63     (make-subtitle id start end lines)))
64
65 (define (read-subrips port)
66   "Read all SubRip formatted subtitles from PORT."
67   (reverse
68    (let loop ((subs '()))
69      (if (eof-object? (peek-char port))
70          subs
71          (loop (cons (read-subrip port) subs))))))