-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVideoTsDownloader.java
More file actions
202 lines (168 loc) · 7.13 KB
/
VideoTsDownloader.java
File metadata and controls
202 lines (168 loc) · 7.13 KB
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package com.learn.java;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* =========================================
* Download .ts video files for only Window.
* It needs FFmpeg to merge .ts files
* =========================================
* Default of `CompletableFuture` use ForkJoinPool
* It's a parallelism level and determined by your system settings or based on your current amount of processors.
* If core size = 1, a new Thread is created to run each task
* =========================================
* Custom pool-size by set execution context to runAsync(runnable, executor) or supplyAsync(runnable, executor)
* var executor = Executors.newFixedThreadPool(8)
*/
public class VideoTsDownloader {
public static final int DEFAULT_BUFFER_SIZE = 8192;
public static final String PART_FOLDER_PATH = "G:\\Projects\\ts\\out";
public static final String RESULT_FOLDER_PATH = "G:\\Projects\\ts\\result";
// Ts link is formatted: https://domain/path_1/file_index.ts
// -> firstURLPath = "https://domain/path_1/file_"
// -> lastURLPath = ".ts"
public static String firstURLPath = "";
public static String lastURLPath = "";
public static int LINK_IDX_START = 8;
public static int LINK_IDX_END = 1143;
public static int GROUP_SIZE = 200;
public static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) throws Exception {
var runner = new VideoTsDownloader();
runner.execute();
}
public void execute() throws Exception {
cleanResultFolder(PART_FOLDER_PATH);
cleanResultFolder(RESULT_FOLDER_PATH);
System.out.println("======[ Clean successfully ]==============");
System.out.println("=========[ Start Download, Store & Merge ]======================");
downloadAndStore(getUrlList());
runCmd(makeCommand(PART_FOLDER_PATH, ""), 0);
}
private void cleanResultFolder(String path) {
List.of(new File(path).listFiles()).forEach(file -> {
if (file.exists()) {
file.delete();
}
});
}
private List<String> makeCommand(String folder, String tag) {
var allFiles = Arrays.stream(new File(folder).listFiles()).sorted((f1, f2) -> {
var f1Name = f1.getName();
var f2Name = f2.getName();
var f1Idx = Integer.parseInt(f1Name.split("\\.")[0]);
var f2Idx = Integer.parseInt(f2Name.split("\\.")[0]);
return f1Idx - f2Idx;
}).collect(Collectors.toList());
StringBuilder allPath = new StringBuilder();
List<String> mergedPaths = new ArrayList<>();
int runner = 0;
for(int i = 0; i < allFiles.size(); i++) {
var filePath = allFiles.get(i).getPath();
allPath.append(filePath).append("|");
runner ++;
var isResetPath = (runner == GROUP_SIZE) || (i == allFiles.size() - 1);
if (isResetPath) {
mergedPaths.add(allPath.substring(0, allPath.length() - 1));
allPath = new StringBuilder();
runner = 0;
}
}
List<String> commands = new ArrayList<>();
for(int i = 0; i < mergedPaths.size(); i++) {
commands.add(
"ffmpeg -i \"concat:" + mergedPaths.get(i) + "\" -c copy \"" + RESULT_FOLDER_PATH + "\\" + i + tag +".ts\""
);
}
return commands;
}
private void runCmd(List<String> commands, int flag) {
System.out.println("===========[ Start to merge files ]=======================");
System.out.println("========[ Commands Size: " + commands.size());
commands.forEach(command -> {
try {
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", command);
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) break;
System.out.println(line);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
});
if (flag == 1) {
System.out.println("===========[ DONE ]=============================");
return;
}
System.out.println("==============[ Merge last time ]=====================");
runCmd(makeCommand(RESULT_FOLDER_PATH, "_LAST"), 1);
}
private void downloadAndStore(List<String> urls) throws Exception {
var futureList = new ArrayList<CompletableFuture<Void>>();
for(int i = 0; i < urls.size(); i++) {
int idx = i + 1;
String url = urls.get(i);
var result = CompletableFuture.runAsync(() -> {
try {
download(url, idx);
System.out.println("=====[ Counter: " + counter.getAndIncrement() + " ]=======================");;
} catch (Exception e) {
e.printStackTrace();
}
});
futureList.add(result);
}
var result = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]));
result.get();
System.out.println("======[ Finish to download ]=====================");
}
private void download(String url, int idx) throws Exception {
File file = new File(PART_FOLDER_PATH + "\\" + idx + ".ts");
URL tsUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) tsUrl.openConnection();
connection.connect();
InputStream input = connection.getInputStream();
try (FileOutputStream outputStream = new FileOutputStream(file, false)) {
int read;
byte[] bytes = new byte[DEFAULT_BUFFER_SIZE];
while ((read = input.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
}
}
// Using HttpClient In Java 11
private void downloadV2(String url, int idx) throws Exception {
File file = new File(PART_FOLDER_PATH + "/" + idx + ".ts");
var request = HttpRequest.newBuilder()
.uri(new URI(url))
.version(HttpClient.Version.HTTP_2)
.GET()
.build();
HttpClient.newBuilder()
.build()
.send(request, HttpResponse.BodyHandlers.ofFile(file.toPath()));
}
private List<String> getUrlList() {
var urls = new ArrayList<String>();
for(int i = LINK_IDX_START; i <= LINK_IDX_END; i++) {
var url = firstURLPath + i + lastURLPath;
urls.add(url);
}
return urls;
}
}