├── README.md
└── SubTitleReader
├── .classpath
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── bin
└── com
│ └── ver
│ └── subtitle
│ ├── Main.class
│ ├── PlayerSubTitleProxy.class
│ ├── loader
│ ├── PlayerSubTitleLoader$1.class
│ ├── PlayerSubTitleLoader$LoaderSubTitleListener.class
│ └── PlayerSubTitleLoader.class
│ ├── model
│ ├── SubTitleItem.class
│ ├── TuziSubTitleInfoTreeMap$KeyEntry.class
│ └── TuziSubTitleInfoTreeMap.class
│ ├── parser
│ ├── ISubTitleParser.class
│ ├── SrtSubTitleShop.class
│ ├── SubTitleParserFactory.class
│ └── srt
│ │ ├── InvalidSRTException.class
│ │ ├── SRTException.class
│ │ ├── SRTReader.class
│ │ ├── SRTReaderException.class
│ │ ├── SRTTimeFormat$SRTTime.class
│ │ ├── SRTTimeFormat$Type.class
│ │ └── SRTTimeFormat.class
│ └── utils
│ └── Log.class
├── libs
└── CharsetDetector.jar
└── src
└── com
└── ver
└── subtitle
├── Main.java
├── PlayerSubTitleProxy.java
├── loader
└── PlayerSubTitleLoader.java
├── model
├── SubTitleItem.java
└── TuziSubTitleInfoTreeMap.java
├── parser
├── ISubTitleParser.java
├── SrtSubTitleShop.java
├── SubTitleParserFactory.java
└── srt
│ ├── InvalidSRTException.java
│ ├── SRTException.java
│ ├── SRTReader.java
│ ├── SRTReaderException.java
│ └── SRTTimeFormat.java
└── utils
└── Log.java
/README.md:
--------------------------------------------------------------------------------
1 | # srt-reader-java
2 | Srt字幕文件的解析,支持多行解析,支持播放器是时间轴对应,读取的时间复杂度低
3 |
4 |
5 | ----
6 | # Srt字幕文件的解析
7 | * 支持所有的文件格式的解析
8 | * 支持Srt多行字幕的解析
9 | * 加载字幕方式:通过TreeMap的数据结构去读取字幕文件,时间复杂度O(1)
10 | * 可以结合播放器,去读取每一秒对应的字幕
11 |
12 | # 包结构
13 | * Main.java 为测试的调用类
14 | * PlayerSubTitleProxy 为代理类,注册一个监听器,如果加载成功则为字幕文件正确
15 | * TuziSubTitleInfoTreeMap 为核心数据结构
16 | * SRTReader 为读取类,用于去读取字幕文件
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/SubTitleReader/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SubTitleReader/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | SubTitleReader
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/SubTitleReader/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.6
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.6
12 |
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/Main.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/Main.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/PlayerSubTitleProxy.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/PlayerSubTitleProxy.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/loader/PlayerSubTitleLoader$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/loader/PlayerSubTitleLoader$1.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/loader/PlayerSubTitleLoader$LoaderSubTitleListener.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/loader/PlayerSubTitleLoader$LoaderSubTitleListener.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/loader/PlayerSubTitleLoader.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/loader/PlayerSubTitleLoader.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/model/SubTitleItem.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/model/SubTitleItem.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/model/TuziSubTitleInfoTreeMap$KeyEntry.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/model/TuziSubTitleInfoTreeMap$KeyEntry.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/model/TuziSubTitleInfoTreeMap.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/model/TuziSubTitleInfoTreeMap.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/parser/ISubTitleParser.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/parser/ISubTitleParser.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/parser/SrtSubTitleShop.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/parser/SrtSubTitleShop.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/parser/SubTitleParserFactory.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/parser/SubTitleParserFactory.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/parser/srt/InvalidSRTException.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/parser/srt/InvalidSRTException.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTException.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTException.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTReader.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTReader.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTReaderException.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTReaderException.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTTimeFormat$SRTTime.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTTimeFormat$SRTTime.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTTimeFormat$Type.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTTimeFormat$Type.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTTimeFormat.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/parser/srt/SRTTimeFormat.class
--------------------------------------------------------------------------------
/SubTitleReader/bin/com/ver/subtitle/utils/Log.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/bin/com/ver/subtitle/utils/Log.class
--------------------------------------------------------------------------------
/SubTitleReader/libs/CharsetDetector.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WangDingchun/srt-reader-java/138023210e136f0eaf0e5a1ba5a56817f7980ba5/SubTitleReader/libs/CharsetDetector.jar
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/Main.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle;
2 |
3 | /**
4 | *
5 | * @title 测试字幕加载类
6 | * @company 北京奔流网络信息技术有线公司
7 | * @email mail@wangdingchun.net
8 | * @author Vermouth
9 | * @version 1.0
10 | * @created 2015-2-27 下午3:16:22
11 | * @changeRecord [修改记录]
12 | */
13 | public class Main {
14 |
15 | public static void main(String[] args) {
16 | PlayerSubTitleProxy mPlayerSubTitleProxy = new PlayerSubTitleProxy();
17 | mPlayerSubTitleProxy.loaderSubTitle("/Users/Vermouth/Downloads/test.srt");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/PlayerSubTitleProxy.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle;
2 |
3 | import com.ver.subtitle.loader.PlayerSubTitleLoader;
4 | import com.ver.subtitle.loader.PlayerSubTitleLoader.LoaderSubTitleListener;
5 | import com.ver.subtitle.model.TuziSubTitleInfoTreeMap;
6 | import com.ver.subtitle.utils.Log;
7 |
8 | /**
9 | * 字幕的代理类 处理字幕展现和加载类的之间的逻辑
10 | *
11 | * @author Vermouth
12 | *
13 | */
14 | public class PlayerSubTitleProxy implements LoaderSubTitleListener {
15 | private PlayerSubTitleLoader mPlayerSubTitleLoader;
16 | private TuziSubTitleInfoTreeMap mTuziSubTitleInfoTreeMap = null;
17 |
18 | public PlayerSubTitleProxy() {
19 | mPlayerSubTitleLoader = new PlayerSubTitleLoader();
20 | mPlayerSubTitleLoader.setLoaderSubTitleListener(this);
21 | }
22 |
23 | public void updatCurrentSubTitle(long ms) {
24 | Log.d("zimu", formatTime((int) ms));
25 | if (mTuziSubTitleInfoTreeMap != null) {
26 | String subtitle = mTuziSubTitleInfoTreeMap.getByMins(ms);
27 | Log.d("zimu", "当前的字幕是:"+subtitle);
28 | }
29 | }
30 |
31 | public void loaderSubTitle(String filepath) {
32 | Log.d("zimu", filepath);
33 | mPlayerSubTitleLoader.loadSubTitle(filepath);
34 | }
35 |
36 | public void clearSubTitle() {
37 | if (mTuziSubTitleInfoTreeMap != null) {
38 | mTuziSubTitleInfoTreeMap.clear();
39 | mTuziSubTitleInfoTreeMap = null;
40 | }
41 | }
42 |
43 | @Override
44 | public void onLoadSuccess(TuziSubTitleInfoTreeMap mTuziSubTitleInfoTreeMap) {
45 | this.mTuziSubTitleInfoTreeMap = mTuziSubTitleInfoTreeMap;
46 | //如果加载成功了,测试读取2分钟时候的字幕
47 | updatCurrentSubTitle(1000*120);
48 | }
49 |
50 | @Override
51 | public void onLoadFail() {
52 |
53 | }
54 |
55 | @SuppressWarnings("all")
56 | public static String formatTime(int millisecond) {
57 | int totalSecond = millisecond / 1000;
58 | int minute = totalSecond / 60;
59 | int hour = minute / 60;
60 | int second = totalSecond % 60;
61 | minute %= 60;
62 | // p_txt_totaltime.setText(String.format("%02d:%02d:%02d", hour,minute,
63 | // second));
64 | return String.format("%02d:%02d:%02d", hour, minute, second);
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/loader/PlayerSubTitleLoader.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.loader;
2 |
3 | import java.io.File;
4 |
5 | import com.ver.subtitle.model.TuziSubTitleInfoTreeMap;
6 | import com.ver.subtitle.parser.SubTitleParserFactory;
7 |
8 | /**
9 | * 字幕的加载类
10 | *
11 | * @author Vermouth
12 | *
13 | */
14 | public class PlayerSubTitleLoader {
15 | private LoaderSubTitleListener mLoaderSubTitleListener;
16 | private SubTitleParserFactory mSubTitleParserFactory;
17 |
18 | public PlayerSubTitleLoader() {
19 | mSubTitleParserFactory = new SubTitleParserFactory();
20 | }
21 |
22 | public void setLoaderSubTitleListener(LoaderSubTitleListener mLoaderSubTitleListener) {
23 | this.mLoaderSubTitleListener = mLoaderSubTitleListener;
24 | }
25 |
26 | public interface LoaderSubTitleListener {
27 | public void onLoadSuccess(TuziSubTitleInfoTreeMap mTuziSubTitleInfoTreeMap);
28 |
29 | public void onLoadFail();
30 | }
31 |
32 | public void loadSubTitle(final String filePath) {
33 | if (!"".equals(filePath) && null != (filePath)) {
34 | new Thread(new Runnable() {
35 |
36 | @Override
37 | public void run() {
38 | try {
39 | File file = new File(filePath);
40 | if (!file.exists()) {
41 | if (mLoaderSubTitleListener != null) {
42 | mLoaderSubTitleListener.onLoadFail();
43 | }
44 | return;
45 | }
46 | final TuziSubTitleInfoTreeMap mTuziSubTitleInfoTreeMap = mSubTitleParserFactory.parserSubTitle("srt", file);
47 | if (mLoaderSubTitleListener != null) {
48 | mLoaderSubTitleListener.onLoadSuccess(mTuziSubTitleInfoTreeMap);
49 | }
50 | }catch (Exception e) {
51 | e.printStackTrace();
52 |
53 | if (mLoaderSubTitleListener != null) {
54 | mLoaderSubTitleListener.onLoadFail();
55 | }
56 | }
57 |
58 | }
59 | }).start();
60 | }
61 |
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/model/SubTitleItem.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.model;
2 |
3 | import java.util.ArrayList;
4 |
5 | public class SubTitleItem {
6 | private int count;
7 | private long start;
8 | private long end;
9 | private ArrayList mSubLists = new ArrayList();
10 |
11 | public int getCount() {
12 | return count;
13 | }
14 |
15 | public void setCount(int count) {
16 | this.count = count;
17 | }
18 |
19 | public long getStart() {
20 | return start;
21 | }
22 |
23 | public void setStart(long start) {
24 | this.start = start;
25 | }
26 |
27 | public long getEnd() {
28 | return end;
29 | }
30 |
31 | public void setEnd(long end) {
32 | this.end = end;
33 | }
34 |
35 | public ArrayList getSubLists() {
36 | return mSubLists;
37 | }
38 |
39 | public void setSubLists(ArrayList mSubLists) {
40 | this.mSubLists = mSubLists;
41 | }
42 |
43 | public String getSubTitle(){
44 | StringBuffer sb=new StringBuffer("");
45 | for(int i=0;i mSubMap = new TreeMap();
8 |
9 | public TuziSubTitleInfoTreeMap() {
10 |
11 | }
12 |
13 | public void insert(int index, long start, long end, ArrayList mSubTitles) {
14 | // System.out.println(index+" "+start+" "+end+" "+mSubTitles);
15 | mSubMap.put(new KeyEntry(start, end), genData(index, start, end, mSubTitles));
16 | }
17 |
18 | public void clear() {
19 | mSubMap.clear();
20 | }
21 |
22 | public String getByMins(long ms) {
23 | SubTitleItem data = mSubMap.get(new KeyEntry(ms, ms));
24 | if (data == null) {
25 | return "";
26 | } else {
27 | return data.getSubTitle();
28 | }
29 |
30 | }
31 |
32 | private class KeyEntry implements Comparable {
33 |
34 | final long start;
35 | final long end;
36 |
37 | public KeyEntry(long start, long end) {
38 | this.start = start;
39 | this.end = end;
40 | }
41 |
42 | public int compareTo(KeyEntry t) {
43 | long t1 = start - t.start;
44 | if (t1 < 0) {
45 | return -1;
46 | }
47 | long t2 = end - t.end;
48 | if (t1 >= 0 && t2 <= 0) {
49 | return 0;
50 | }
51 | return 1;
52 | }
53 |
54 | }
55 |
56 | private static SubTitleItem genData(int index, long start, long end, ArrayList mSubTitles) {
57 | SubTitleItem data = new SubTitleItem();
58 | data.setCount(index);
59 | data.setSubLists(mSubTitles);
60 | data.setStart(start);
61 | data.setEnd(end);
62 | return data;
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/parser/ISubTitleParser.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.parser;
2 |
3 | import java.io.File;
4 | import java.io.InputStream;
5 |
6 | import com.ver.subtitle.model.TuziSubTitleInfoTreeMap;
7 |
8 | public interface ISubTitleParser {
9 | public TuziSubTitleInfoTreeMap parser(InputStream is);
10 | public TuziSubTitleInfoTreeMap parser(File file);
11 | }
12 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/parser/SrtSubTitleShop.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.parser;
2 |
3 | import java.io.File;
4 | import java.io.InputStream;
5 |
6 | import com.ver.subtitle.model.TuziSubTitleInfoTreeMap;
7 | import com.ver.subtitle.parser.srt.SRTReader;
8 |
9 | /**
10 | * 加载srt字幕的车间
11 | *
12 | * @author Vermouth
13 | *
14 | */
15 | public class SrtSubTitleShop implements ISubTitleParser {
16 | @Override
17 | public TuziSubTitleInfoTreeMap parser(InputStream is) {
18 | TuziSubTitleInfoTreeMap mTuziSubTitleInfoTreeMap = SRTReader.read(is);
19 | return mTuziSubTitleInfoTreeMap;
20 | }
21 |
22 | @Override
23 | public TuziSubTitleInfoTreeMap parser(File file) {
24 | TuziSubTitleInfoTreeMap mTuziSubTitleInfoTreeMap = SRTReader.read(file);
25 | return mTuziSubTitleInfoTreeMap;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/parser/SubTitleParserFactory.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.parser;
2 |
3 | import java.io.File;
4 | import java.io.InputStream;
5 |
6 | import com.ver.subtitle.model.TuziSubTitleInfoTreeMap;
7 |
8 | public class SubTitleParserFactory {
9 | private ISubTitleParser mSubTitleParser;
10 |
11 | public TuziSubTitleInfoTreeMap parserSubTitle(String type, File file) {
12 | if ("srt".equals(type)) {
13 | mSubTitleParser = new SrtSubTitleShop();
14 | return mSubTitleParser.parser(file);
15 | } else {
16 | return null;
17 | }
18 | }
19 |
20 | public TuziSubTitleInfoTreeMap parserSubTitle(String type, InputStream is) {
21 | if ("srt".equals(type)) {
22 | mSubTitleParser = new SrtSubTitleShop();
23 | return mSubTitleParser.parser(is);
24 | } else {
25 | return null;
26 | }
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/parser/srt/InvalidSRTException.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.parser.srt;
2 |
3 | /**
4 | * An exception for an invalid SRT format.
5 | *
6 | * @author fredy
7 | */
8 | public class InvalidSRTException extends SRTException {
9 | private static final long serialVersionUID = 1L;
10 |
11 | /**
12 | * @param message the exception message
13 | * @param cause the cause
14 | */
15 | public InvalidSRTException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 |
19 | /**
20 | * @param message the exception message
21 | */
22 | public InvalidSRTException(String message) {
23 | super(message);
24 | }
25 |
26 | /**
27 | * @param cause the cause
28 | */
29 | public InvalidSRTException(Throwable cause) {
30 | super(cause);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/parser/srt/SRTException.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.parser.srt;
2 |
3 | /**
4 | * Any exceptions related to SRT.
5 | *
6 | * @author fredy
7 | */
8 | public class SRTException extends RuntimeException {
9 | private static final long serialVersionUID = 1L;
10 |
11 | /**
12 | * @param message the exception message
13 | * @param cause the cause
14 | */
15 | public SRTException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 |
19 | /**
20 | * @param message the exception message
21 | */
22 | public SRTException(String message) {
23 | super(message);
24 | }
25 |
26 | /**
27 | * @param cause the cause
28 | */
29 | public SRTException(Throwable cause) {
30 | super(cause);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/parser/srt/SRTReader.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.parser.srt;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.BufferedReader;
5 | import java.io.EOFException;
6 | import java.io.File;
7 | import java.io.FileInputStream;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.io.InputStreamReader;
11 | import java.text.ParseException;
12 | import java.util.ArrayList;
13 | import java.util.Date;
14 | import java.util.regex.Matcher;
15 | import java.util.regex.Pattern;
16 |
17 | import cn.xddai.chardet.CharsetDetector;
18 |
19 | import com.ver.subtitle.model.TuziSubTitleInfoTreeMap;
20 | import com.ver.subtitle.utils.Log;
21 |
22 | public class SRTReader {
23 |
24 | public SRTReader() {
25 | }
26 |
27 | /**
28 | * Reads an SRT file and transforming it into SRT object.
29 | *
30 | * @param srtFile
31 | * SRT file
32 | * @return the SRTInfo object
33 | * @throws InvalidSRTException
34 | * thrown when the SRT file is invalid
35 | * @throws SRTReaderException
36 | * thrown while reading SRT file
37 | */
38 | public static TuziSubTitleInfoTreeMap read(InputStream is) throws InvalidSRTException, SRTReaderException {
39 | if (is == null) {
40 | throw new SRTReaderException("is does not null");
41 | }
42 | TuziSubTitleInfoTreeMap mTuziSubTitleInfoTreeMap = new TuziSubTitleInfoTreeMap();
43 | try {
44 | BufferedReader br = new BufferedReader(new InputStreamReader(is));
45 | while (true) {
46 | parse(mTuziSubTitleInfoTreeMap, br);
47 | }
48 | } catch (EOFException e) {
49 | // Do nothing
50 | } catch (IOException e) {
51 | throw new SRTReaderException(e);
52 | }
53 |
54 | return mTuziSubTitleInfoTreeMap;
55 | }
56 |
57 | /**
58 | * Reads an SRT file and transforming it into SRT object.
59 | *
60 | * @param srtFile
61 | * SRT file
62 | * @return the SRTInfo object
63 | * @throws InvalidSRTException
64 | * thrown when the SRT file is invalid
65 | * @throws SRTReaderException
66 | * thrown while reading SRT file
67 | */
68 | public static TuziSubTitleInfoTreeMap read(File srtFile) throws InvalidSRTException, SRTReaderException {
69 | if (!srtFile.exists()) {
70 | throw new SRTReaderException(srtFile.getAbsolutePath() + " does not exist");
71 | }
72 | if (!srtFile.isFile()) {
73 | throw new SRTReaderException(srtFile.getAbsolutePath() + " is not a regular file");
74 | }
75 | TuziSubTitleInfoTreeMap mTuziSubTitleInfoTreeMap = new TuziSubTitleInfoTreeMap();
76 | InputStream in = null;
77 | InputStream inputStream = null;
78 |
79 | BufferedInputStream bin = null;
80 | try {
81 | in = new FileInputStream(srtFile);
82 | inputStream = new FileInputStream(srtFile);
83 | BufferedReader br = null;
84 | try {
85 | String code = codeString(in);
86 | br = new BufferedReader(new InputStreamReader(inputStream, code));
87 | } catch (Exception e) {
88 | // TODO Auto-generated catch block
89 | e.printStackTrace();
90 | }
91 | parse(mTuziSubTitleInfoTreeMap, br);
92 | } catch (EOFException e) {
93 |
94 | } catch (IOException e) {
95 | throw new SRTReaderException(e);
96 | } finally {
97 | if (in != null) {
98 | try {
99 | in.close();
100 | } catch (IOException e) {
101 | e.printStackTrace();
102 | }
103 | }
104 | if (inputStream != null) {
105 | try {
106 | inputStream.close();
107 | } catch (IOException e) {
108 | e.printStackTrace();
109 | }
110 | }
111 |
112 | if (bin != null) {
113 | try {
114 | bin.close();
115 | } catch (IOException e) {
116 | e.printStackTrace();
117 | }
118 |
119 | }
120 |
121 | }
122 |
123 | return mTuziSubTitleInfoTreeMap;
124 | }
125 |
126 | private static String codeString(InputStream bin) throws Exception {
127 | CharsetDetector charDect = new CharsetDetector();
128 | String[] probableSet = charDect.detectChineseCharset(bin);
129 | for (String charset : probableSet) {
130 | Log.e("lyric", "p=" + charset);
131 | }
132 | if (probableSet != null && probableSet.length > 0) {
133 | return probableSet[0];
134 | }
135 |
136 | return "";
137 | }
138 |
139 | private static void parse(TuziSubTitleInfoTreeMap mTreeMap, BufferedReader br) throws IOException, EOFException {
140 | String srtResult = bufferReader2String(br);
141 |
142 | if (srtResult == null) {
143 | throw new EOFException();
144 | }
145 |
146 | String dealSrt = dealSrt(srtResult);
147 |
148 | if (dealSrt == null) {
149 | throw new EOFException();
150 | }
151 |
152 | Pattern pat = Pattern.compile("^\\d{1,}\\s*\\r?\\n", Pattern.MULTILINE);
153 | Matcher mat = pat.matcher(dealSrt);
154 | String parseResult = mat.replaceAll("<1>\n");
155 | Pattern pattern = Pattern.compile("([^\\n-]*)\\s*-->\\s*([^\\n-]*)[\\r\\n]?([^<]*)", Pattern.MULTILINE);
156 | Matcher m = pattern.matcher(parseResult);
157 | int count = 0;
158 | while (m.find()) {
159 | count = count + 1;
160 | long startTimeLong = 0;
161 | long endTimeLong = 0;
162 | ArrayList subtitleLines = new ArrayList();
163 | for (int i = 1; i <= m.groupCount(); i++) {
164 | if (i == 1) {
165 | Date startTime = null;
166 | try {
167 | startTime = SRTTimeFormat.parse("1970-01-01 " + m.group(i).replaceAll("\r", "").replaceAll("\n", "").trim().replaceAll(",", "."));
168 | startTimeLong = startTime.getTime();
169 | } catch (ParseException e) {
170 | throw new InvalidSRTException(m.group(i) + " has an invalid time format");
171 | }
172 |
173 | }
174 | if (i == 2) {
175 | Date endTime = null;
176 | try {
177 | endTime = SRTTimeFormat.parse("1970-01-01 " + m.group(i).replaceAll("\r", "").replaceAll("\n", "").trim().replaceAll(",", "."));
178 | endTimeLong = endTime.getTime();
179 | } catch (ParseException e) {
180 | throw new InvalidSRTException(m.group(i) + " has an invalid time format");
181 | }
182 | }
183 |
184 | if (i == 3) {
185 | String[] results = m.group(i).split("[\\r\\n]");
186 | for (int j = 0; j < results.length; j++) {
187 | if (!"".equals(results[j].replaceAll("\r", "").replaceAll("\n", "").trim()) && (null != results[j].replaceAll("\r", "").replaceAll("\n", "").trim())) {
188 | subtitleLines.add(results[j].replaceAll("\r", "").replaceAll("\n", "").trim());
189 | }
190 | }
191 | }
192 | }
193 | mTreeMap.insert(count, startTimeLong, endTimeLong, subtitleLines);
194 | }
195 |
196 | // 识别字幕中的,时间,文字等
197 | // String pat = "(\\r\\n)+";
198 | // Pattern pattern = Pattern.compile(pat);
199 | // String[] models = pattern.split(dealSrt);
200 | // if (models.length > 0) {
201 | // for (int i = 0; i < models.length; i++) {
202 | // String[] zimuItems = models[i].split("[\\r\\n]");
203 | // if (zimuItems.length >= 2) {
204 | // // 读取字幕中的时间
205 | // String timeString = zimuItems[1];
206 | // String[] times = timeString.split(SRTTimeFormat.TIME_DELIMITER);
207 | // if (times.length != 2) {
208 | // throw new InvalidSRTException(timeString +
209 | // " needs to be seperated with " + SRTTimeFormat.TIME_DELIMITER);
210 | // }
211 | // Date startTime = null;
212 | // long startTimeLong = 0;
213 | // try {
214 | // startTime = SRTTimeFormat.parse("1970-01-01 " +
215 | // times[0].replaceAll(",", "."));
216 | // startTimeLong = startTime.getTime();
217 | // } catch (ParseException e) {
218 | // System.out.println(e);
219 | // throw new InvalidSRTException(times[0] +
220 | // " has an invalid time format");
221 | // }
222 | //
223 | // Date endTime = null;
224 | // long endTimeLong = 0;
225 | //
226 | // try {
227 | // endTime = SRTTimeFormat.parse("1970-01-01 " +
228 | // times[1].replaceAll(",", "."));
229 | // endTimeLong = endTime.getTime();
230 | //
231 | // } catch (ParseException e) {
232 | // throw new InvalidSRTException(times[1] +
233 | // " has an invalid time format");
234 | // }
235 | // // 读取字幕中的内容
236 | // ArrayList subtitleLines = new ArrayList();
237 | //
238 | // if (zimuItems.length > 2) {
239 | // for (int j = 2; j < zimuItems.length; j++)
240 | // subtitleLines.add(zimuItems[j]);
241 | // }
242 | // mTreeMap.insert(i + 1, startTimeLong, endTimeLong, subtitleLines);
243 | //
244 | // }
245 | // }
246 | // }
247 |
248 | // String nString = br.readLine();
249 | // if (nString == null) {
250 | // throw new EOFException();
251 | // }
252 | //
253 | // int subtitleNumber = -1;
254 | // try {
255 | // subtitleNumber = Integer.parseInt(nString.replaceAll("\\D+",
256 | // "").replaceAll("\r", "").replaceAll("\n", "").trim());
257 | // } catch (Exception e) {
258 | // throw new InvalidSRTException(nString +
259 | // " has an invalid subtitle number");
260 | // }
261 | //
262 | // String tString = br.readLine();
263 | // if (tString == null) {
264 | // throw new
265 | // InvalidSRTException("Start time and end time information is not present");
266 | // }
267 | // String timeString = tString.replaceAll("\\D+", "").replaceAll("\r",
268 | // "").replaceAll("\n", "").trim();
269 | // String[] times = timeString.split(SRTTimeFormat.TIME_DELIMITER);
270 | // if (times.length != 2) {
271 | // throw new InvalidSRTException(timeString +
272 | // " needs to be seperated with " + SRTTimeFormat.TIME_DELIMITER);
273 | // }
274 | // Date startTime = null;
275 | // long startTimeLong = 0;
276 | // try {
277 | // startTime = SRTTimeFormat.parse("1970-01-01 " +
278 | // times[0].replaceAll(",", "."));
279 | // startTimeLong = startTime.getTime();
280 | // } catch (ParseException e) {
281 | // System.out.println(e);
282 | //
283 | // throw new InvalidSRTException(times[0] +
284 | // " has an invalid time format");
285 | // }
286 | //
287 | // Date endTime = null;
288 | // long endTimeLong = 0;
289 | //
290 | // try {
291 | // endTime = SRTTimeFormat.parse("1970-01-01 " +
292 | // times[1].replaceAll(",", "."));
293 | // endTimeLong = endTime.getTime();
294 | //
295 | // } catch (ParseException e) {
296 | // throw new InvalidSRTException(times[1] +
297 | // " has an invalid time format");
298 | // }
299 | //
300 | // ArrayList subtitleLines = new ArrayList();
301 | // String line;
302 | //
303 | // while ((line = br.readLine()) != null) {
304 | // if (line.trim().isEmpty()) {
305 | // break;
306 | // }
307 | // // Spanned spanned=Html.fromHtml(line);
308 | // subtitleLines.add(line.replaceAll("\\D+", "").replaceAll("\r",
309 | // "").replaceAll("\n", "").trim());
310 | // }
311 | //
312 | // if (subtitleLines.size() == 0) {
313 | // br.readLine();
314 | // // throw new
315 | // // InvalidSRTException("Missing subtitle text information");
316 | // }
317 | //
318 | // mTreeMap.insert(subtitleNumber, startTimeLong, endTimeLong,
319 | // subtitleLines);
320 |
321 | }
322 |
323 | private static String bufferReader2String(BufferedReader br) throws IOException {
324 | StringBuffer out = new StringBuffer();
325 | String line = "";
326 | while ((line = br.readLine()) != null) {
327 | out.append(line + "\n");
328 | }
329 | return out.toString();
330 | }
331 |
332 | /**
333 | * 处理文件中的换行问题
334 | *
335 | * @param content
336 | * @return
337 | */
338 | private static String dealSrt(String content) {
339 | String p = "(\\s*\\n){2,}";
340 | Pattern pattern = Pattern.compile(p, Pattern.MULTILINE);
341 | Matcher matcher = pattern.matcher(content);
342 | String result = matcher.replaceAll("\r\n\r\n");
343 | return result;
344 | }
345 |
346 | }
347 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/parser/srt/SRTReaderException.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.parser.srt;
2 |
3 | /**
4 | * An exception while reading an SRT file.
5 | *
6 | * @author fredy
7 | */
8 | public class SRTReaderException extends SRTException {
9 | private static final long serialVersionUID = 1L;
10 |
11 | /**
12 | * @param message the exception message
13 | * @param cause the cause
14 | */
15 | public SRTReaderException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 |
19 | /**
20 | * @param message the exception message
21 | */
22 | public SRTReaderException(String message) {
23 | super(message);
24 | }
25 |
26 | /**
27 | * @param cause the cause
28 | */
29 | public SRTReaderException(Throwable cause) {
30 | super(cause);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/parser/srt/SRTTimeFormat.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.parser.srt;
2 |
3 | import java.text.ParseException;
4 | import java.text.SimpleDateFormat;
5 | import java.util.Calendar;
6 | import java.util.Date;
7 | import java.util.TimeZone;
8 |
9 | /**
10 | * This class contains utility methods for SRT time format related stuff.
11 | *
12 | * @author fredy
13 | */
14 | public class SRTTimeFormat {
15 | public static final String TIME_DELIMITER = " --> ";
16 | public static final String TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
17 | public static final String HOUR_FORMAT = "HH";
18 | public static final String MINUTE_FORMAT = "mm";
19 | public static final String SECOND_FORMAT = "ss";
20 | public static final String MILLISECOND_FORMAT = "SSS";
21 | private static final SimpleDateFormat sdf = new SimpleDateFormat(TIME_FORMAT);
22 |
23 | public enum Type {
24 | HOUR,
25 | MINUTE,
26 | SECOND,
27 | MILLISECOND
28 | }
29 |
30 | public static class SRTTime {
31 | public final int hour;
32 | public final int minute;
33 | public final int second;
34 | public final int millisecond;
35 |
36 |
37 | public SRTTime(int hour, int minute, int second, int millisecond) {
38 | this.hour = hour;
39 | this.minute = minute;
40 | this.second = second;
41 | this.millisecond = millisecond;
42 | }
43 | }
44 |
45 | private SRTTimeFormat() {
46 | }
47 |
48 | /**
49 | * Formats the date into SRT time format.
50 | * @param date the date
51 | * @return the SRT time format
52 | */
53 | public static String format(Date date) {
54 | return sdf.format(date);
55 | }
56 |
57 | /**
58 | * Parses the SRT time format into date.
59 | * @param srtTime the SRT time format
60 | * @return the date
61 | * @throws ParseException
62 | */
63 | public static Date parse(String srtTime) throws ParseException {
64 | sdf.setTimeZone(TimeZone.getTimeZone("GMT0"));
65 | Date date= sdf.parse(srtTime);
66 | return date;
67 | }
68 |
69 | /**
70 | * Converts Date to SRTTime.
71 | *
72 | * @param date the date
73 | * @return the SRTTime
74 | */
75 | public static SRTTime toSRTTime(Date date) {
76 | Calendar cal = Calendar.getInstance();
77 | cal.setTime(date);
78 | return new SRTTime(
79 | cal.get(Calendar.HOUR),
80 | cal.get(Calendar.MINUTE),
81 | cal.get(Calendar.SECOND),
82 | cal.get(Calendar.MILLISECOND));
83 | }
84 |
85 | /**
86 | * Converts SRTTime to Date.
87 | *
88 | * @param srtTime the SRTTime
89 | * @return the Date
90 | * @throws ParseException
91 | */
92 | public static Date fromSRTTime(SRTTime srtTime) throws ParseException {
93 | StringBuilder timeStr = new StringBuilder();
94 | if (srtTime.hour < 10) {
95 | timeStr.append("0");
96 | }
97 | timeStr.append(Integer.toString(srtTime.hour));
98 | timeStr.append(":");
99 | if (srtTime.minute < 10) {
100 | timeStr.append("0");
101 | }
102 | timeStr.append(Integer.toString(srtTime.minute));
103 | timeStr.append(":");
104 | if (srtTime.second < 10) {
105 | timeStr.append("0");
106 | }
107 | timeStr.append(Integer.toString(srtTime.second));
108 | timeStr.append(",");
109 | if (srtTime.second < 10) {
110 | timeStr.append("00");
111 | } else if (srtTime.second < 100) {
112 | timeStr.append("0");
113 | }
114 | timeStr.append(Integer.toString(srtTime.millisecond));
115 |
116 | return SRTTimeFormat.parse(timeStr.toString());
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/SubTitleReader/src/com/ver/subtitle/utils/Log.java:
--------------------------------------------------------------------------------
1 | package com.ver.subtitle.utils;
2 |
3 | public class Log {
4 | public static final boolean DEBUG = true;
5 |
6 | public static void v(String msg) {
7 | if (DEBUG) {
8 | if (msg == null)
9 | msg = "null";
10 | System.out.println(msg);
11 | }
12 | }
13 |
14 | public static void v(String TAG, String msg) {
15 | if (DEBUG) {
16 | if (msg == null)
17 | msg = "null";
18 | System.out.println(msg);
19 | }
20 | }
21 |
22 | public static void e(String msg) {
23 | if (DEBUG) {
24 | if (msg == null)
25 | msg = "null";
26 | System.out.println(msg);
27 | }
28 | }
29 |
30 | public static void e(String TAG, String msg) {
31 | if (DEBUG) {
32 | if (msg == null)
33 | msg = "null";
34 | System.out.println(msg);
35 | }
36 | }
37 |
38 | public static void e(String TAG, String msg, Throwable ex) {
39 | if (DEBUG) {
40 | if (msg == null)
41 | msg = "null";
42 | System.out.println(msg);
43 | }
44 | }
45 |
46 | public static void i(String msg) {
47 | if (DEBUG) {
48 | if (msg == null)
49 | msg = "null";
50 | System.out.println(msg);
51 | }
52 | }
53 |
54 | public static void i(String TAG, String msg) {
55 | if (DEBUG) {
56 | if (msg == null)
57 | msg = "null";
58 | System.out.println(msg);
59 | }
60 | }
61 |
62 | public static void i(String TAG, String msg, Throwable ex) {
63 | if (DEBUG) {
64 | if (msg == null)
65 | msg = "null";
66 | System.out.println(msg);
67 | }
68 | }
69 |
70 | public static void d(String msg) {
71 | if (DEBUG) {
72 | if (msg == null)
73 | msg = "null";
74 | System.out.println(msg);
75 | }
76 | }
77 |
78 | public static void d(String TAG, String msg) {
79 | if (DEBUG) {
80 | if (msg == null)
81 | msg = "null";
82 | System.out.println(msg);
83 | }
84 | }
85 |
86 | public static void d(String TAG, String msg, Throwable ex) {
87 | if (DEBUG) {
88 | if (msg == null)
89 | msg = "null";
90 | System.out.println(msg);
91 | }
92 | }
93 |
94 | public static void w(String msg) {
95 | if (DEBUG) {
96 | if (msg == null)
97 | msg = "null";
98 | System.out.println(msg);
99 | }
100 | }
101 |
102 | public static void w(String TAG, String msg) {
103 | if (DEBUG) {
104 | if (msg == null)
105 | msg = "null";
106 | System.out.println(msg);
107 | }
108 | }
109 |
110 | public static void w(String TAG, Throwable ex) {
111 | if (DEBUG) {
112 | System.out.println(ex.toString());
113 | }
114 | }
115 |
116 | public static void w(String TAG, String msg, Throwable ex) {
117 | if (DEBUG) {
118 | if (msg == null)
119 | msg = "null";
120 | System.out.println(msg);
121 | }
122 | }
123 |
124 | public static int VERBOSE = 2;
125 |
126 | public static boolean isLoggable(String str, int VERBOSE) {
127 | return DEBUG;
128 | }
129 | }
130 |
--------------------------------------------------------------------------------