jafea7-ctbrec-v5.3.2-based/common/src/main/java/ctbrec/sites/amateurtv/AmateurTvDownload.java

172 lines
5.4 KiB
Java

package ctbrec.sites.amateurtv;
import ctbrec.Config;
import ctbrec.Model;
import ctbrec.Recording;
import ctbrec.io.BandwidthMeter;
import ctbrec.io.HttpClient;
import ctbrec.io.HttpException;
import ctbrec.recorder.download.AbstractDownload;
import ctbrec.recorder.download.RecordingProcess;
import ctbrec.recorder.download.StreamSource;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.regex.Pattern;
import static ctbrec.io.HttpConstants.*;
public class AmateurTvDownload extends AbstractDownload {
private static final Logger LOG = LoggerFactory.getLogger(AmateurTvDownload.class);
private static final int MAX_SECONDS_WITHOUT_TRANSFER = 20;
private final HttpClient httpClient;
private FileOutputStream fout;
private Instant timeOfLastTransfer = Instant.MAX;
private volatile boolean running;
private volatile boolean started;
private File targetFile;
public AmateurTvDownload(HttpClient httpClient) {
this.httpClient = httpClient;
}
@Override
public void init(Config config, Model model, Instant startTime, ExecutorService executorService) throws IOException {
this.config = config;
this.model = model;
this.startTime = startTime;
this.downloadExecutor = executorService;
splittingStrategy = initSplittingStrategy(config.getSettings());
targetFile = config.getFileForRecording(model, "mp4", startTime);
timeOfLastTransfer = Instant.now();
}
@Override
public void stop() {
running = false;
}
@Override
public void finalizeDownload() {
if (fout != null) {
try {
LOG.debug("Closing recording file {}", targetFile);
fout.close();
} catch (IOException e) {
LOG.error("Error while closing recording file {}", targetFile, e);
}
}
}
@Override
public boolean isRunning() {
return running;
}
@Override
public void postProcess(Recording recording) {
// nothing to do
}
@Override
public File getTarget() {
return targetFile;
}
@Override
public String getPath(Model model) {
String absolutePath = targetFile.getAbsolutePath();
String recordingsDir = Config.getInstance().getSettings().recordingsDir;
String relativePath = absolutePath.replaceFirst(Pattern.quote(recordingsDir), "");
return relativePath;
}
@Override
public boolean isSingleFile() {
return true;
}
@Override
public long getSizeInByte() {
return getTarget().length();
}
@Override
public RecordingProcess call() throws Exception {
if (!started) {
started = true;
startDownload();
}
if (splittingStrategy.splitNecessary(this)) {
stop();
rescheduleTime = Instant.now();
} else {
rescheduleTime = Instant.now().plusSeconds(5);
}
if (!model.isOnline(true)) {
stop();
}
if (Duration.between(timeOfLastTransfer, Instant.now()).getSeconds() > MAX_SECONDS_WITHOUT_TRANSFER) {
LOG.info("No video data received for {} seconds. Stopping recording for model {}", MAX_SECONDS_WITHOUT_TRANSFER, model);
stop();
}
return this;
}
private void startDownload() {
downloadExecutor.submit(() -> {
running = true;
try {
StreamSource src = model.getStreamSources().get(0);
LOG.debug("Loading video from {}", src.mediaPlaylistUrl);
Request request = new Request.Builder()
.url(src.mediaPlaylistUrl)
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.header(ACCEPT, "*/*")
.header(ACCEPT_LANGUAGE, "en")
.header(ORIGIN, AmateurTv.BASE_URL)
.build();
try (Response resp = httpClient.execute(request)) {
if (resp.isSuccessful()) {
LOG.debug("Recording video stream to {}", targetFile);
Files.createDirectories(targetFile.getParentFile().toPath());
fout = new FileOutputStream(targetFile);
InputStream in = Objects.requireNonNull(resp.body()).byteStream();
byte[] b = new byte[1024];
int len;
while (running && !Thread.currentThread().isInterrupted() && (len = in.read(b)) >= 0) {
fout.write(b, 0, len);
timeOfLastTransfer = Instant.now();
getDownloadedBytes().addAndGet(len);
BandwidthMeter.add(len);
}
} else {
throw new HttpException(resp.code(), resp.message());
}
}
} catch (Exception e) {
LOG.error("Error while downloading MP4", e);
}
running = false;
});
}
}