View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  package org.opencastproject.subtitleparser.webvttparser;
22  
23  import static java.util.Optional.ofNullable;
24  
25  import java.io.IOException;
26  import java.io.OutputStream;
27  import java.io.UnsupportedEncodingException;
28  import java.nio.charset.Charset;
29  import java.nio.charset.StandardCharsets;
30  import java.util.List;
31  
32  public class WebVTTWriter {
33    private Charset charset; // Charset used to encode file
34  
35    public WebVTTWriter() {
36      this.charset = StandardCharsets.UTF_8;
37    }
38  
39    public WebVTTWriter(Charset charset) {
40      this.charset = charset;
41    }
42  
43    public void write(WebVTTSubtitle subtitleObject, OutputStream os) throws IOException {
44      try {
45        // Write header
46        List<String> headerLines = subtitleObject.getHeaderLines();
47        for (int i = 0; i < headerLines.size() ; i++) {
48          // Ensure valid header
49          if (i == 0 && !headerLines.get(i).startsWith("WEBVTT")) {
50            os.write(("WEBVTT " +  headerLines.get(i) + "\n").getBytes(this.charset));
51            continue;
52          }
53          os.write((headerLines.get(i) + "\n").getBytes(this.charset));
54        }
55        // Ensure valid header
56        if (headerLines.size() == 0) {
57          os.write(("WEBVTT" + "\n").getBytes(this.charset));
58        }
59        os.write("\n".getBytes(this.charset));
60  
61        // Write region blocks
62        for (WebVTTSubtitleRegion region : subtitleObject.getRegions()) {
63          for (String regionLine : region.getLines()) {
64            os.write((regionLine + "\n").getBytes(this.charset));
65          }
66          os.write("\n".getBytes(this.charset));
67        }
68  
69        // Write style blocks
70        for (WebVTTSubtitleStyle style : subtitleObject.getStyle()) {
71          for (String styleLine : style.getLines()) {
72            os.write((styleLine + "\n").getBytes(this.charset));
73          }
74          os.write("\n".getBytes(this.charset));
75        }
76  
77        // Write cues
78        for (WebVTTSubtitleCue cue : subtitleObject.getCues()) {
79          if (cue.getId() != null) {
80            // Write id
81            String number = String.format("%s\n", cue.getId());
82            os.write(number.getBytes(this.charset));
83          }
84  
85          // Write start and end time
86          String startToEnd = String.format("%s --> %s %s\n",
87                  this.formatTimeCode(cue.getStartTime()),
88                  this.formatTimeCode(cue.getEndTime()),
89                  ofNullable(cue.getCueSettingsList()).orElse(""));
90          os.write(startToEnd.getBytes(this.charset));
91  
92          // Write text
93          String text = String.format("%s\n", cue.getText());
94          os.write(text.getBytes(this.charset));
95  
96          // Write empty line
97          os.write("\n".getBytes(this.charset));
98        }
99      } catch (UnsupportedEncodingException e) {
100       throw new IOException("Encoding error in input subtitle");
101     }
102   }
103 
104   private String formatTimeCode(long ms) {
105     long milliseconds = ms % 1000L;
106     long seconds = ms / 1000L % 60L;
107     long minutes = ms / (1000L * 60L) % 60L;
108     long hours = ms / (1000L * 60L * 60L);
109 
110     return String.format("%02d:%02d:%02d.%03d",
111             hours,
112             minutes,
113             seconds,
114             milliseconds);
115   }
116 }