Fix bug in stalled recording detection
This commit is contained in:
parent
21fa71c901
commit
e0426d7c86
|
@ -1,52 +1,10 @@
|
|||
package ctbrec.recorder.download.hls;
|
||||
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
import static ctbrec.recorder.download.StreamSource.*;
|
||||
import static java.nio.charset.StandardCharsets.*;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.iheartradio.m3u8.Encoding;
|
||||
import com.iheartradio.m3u8.Format;
|
||||
import com.iheartradio.m3u8.ParseException;
|
||||
import com.iheartradio.m3u8.ParsingMode;
|
||||
import com.iheartradio.m3u8.PlaylistException;
|
||||
import com.iheartradio.m3u8.PlaylistParser;
|
||||
import com.iheartradio.m3u8.*;
|
||||
import com.iheartradio.m3u8.data.EncryptionData;
|
||||
import com.iheartradio.m3u8.data.MediaPlaylist;
|
||||
import com.iheartradio.m3u8.data.Playlist;
|
||||
import com.iheartradio.m3u8.data.TrackData;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.Model.State;
|
||||
|
@ -64,6 +22,32 @@ import ctbrec.sites.Site;
|
|||
import okhttp3.Request;
|
||||
import okhttp3.Request.Builder;
|
||||
import okhttp3.Response;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.io.*;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
import static ctbrec.recorder.download.StreamSource.UNKNOWN;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
public abstract class AbstractHlsDownload extends AbstractDownload {
|
||||
|
||||
|
@ -85,7 +69,7 @@ public abstract class AbstractHlsDownload extends AbstractDownload {
|
|||
private Instant beforeLastPlaylistRequest= Instant.EPOCH;
|
||||
private int consecutivePlaylistTimeouts = 0;
|
||||
private int consecutivePlaylistErrors = 0;
|
||||
private Instant lastSegmentDownload = Instant.MAX;
|
||||
private Instant lastSegmentDownload = Instant.MIN;
|
||||
private int selectedResolution = UNKNOWN;
|
||||
|
||||
private final List<RecordingEvent> recordingEvents = new LinkedList<>();
|
||||
|
@ -99,6 +83,7 @@ public abstract class AbstractHlsDownload extends AbstractDownload {
|
|||
public void init(Config config, Model model, Instant startTime, ExecutorService executorService) throws IOException {
|
||||
super.init(config, model, startTime, executorService);
|
||||
segmentDownloadService = new ExecutorCompletionService<>(downloadExecutor);
|
||||
lastSegmentDownload = Instant.now();
|
||||
}
|
||||
|
||||
protected abstract OutputStream getSegmentOutputStream(Segment segment) throws IOException;
|
||||
|
@ -245,7 +230,7 @@ public abstract class AbstractHlsDownload extends AbstractDownload {
|
|||
List<StreamSource> filteredStreamSources = streamSources.stream()
|
||||
.filter(src -> src.height == 0 || src.height == UNKNOWN || minRes <= src.height)
|
||||
.filter(src -> src.height == 0 || src.height == UNKNOWN || maxRes >= src.height)
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
|
||||
if (filteredStreamSources.isEmpty()) {
|
||||
throw new ExecutionException(new NoStreamFoundException("No stream left in playlist"));
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.security.InvalidAlgorithmParameterException;
|
|||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
|
@ -34,12 +35,12 @@ import okhttp3.Response;
|
|||
public class SegmentDownload implements Callable<SegmentDownload> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SegmentDownload.class);
|
||||
|
||||
private URL url;
|
||||
private HttpClient client;
|
||||
private SegmentPlaylist playlist;
|
||||
private Segment segment;
|
||||
private Model model;
|
||||
private OutputStream out;
|
||||
private final URL url;
|
||||
private final HttpClient client;
|
||||
private final SegmentPlaylist playlist;
|
||||
private final Segment segment;
|
||||
private final Model model;
|
||||
private final OutputStream out;
|
||||
|
||||
public SegmentDownload(Model model, SegmentPlaylist playlist, Segment segment, HttpClient client, OutputStream out) throws MalformedURLException {
|
||||
this.model = model;
|
||||
|
@ -52,7 +53,7 @@ public class SegmentDownload implements Callable<SegmentDownload> {
|
|||
|
||||
@Override
|
||||
public SegmentDownload call() {
|
||||
for (int tries = 1; tries <= 3 && !Thread.currentThread().isInterrupted(); tries++) {
|
||||
for (int tries = 1; tries <= 3 && !Thread.currentThread().isInterrupted(); tries++) { // NOSONAR
|
||||
Request request = createRequest();
|
||||
try (Response response = client.execute(request)) {
|
||||
handleResponse(response);
|
||||
|
@ -73,20 +74,19 @@ public class SegmentDownload implements Callable<SegmentDownload> {
|
|||
return this;
|
||||
}
|
||||
|
||||
private boolean handleResponse(Response response) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IOException {
|
||||
private void handleResponse(Response response) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IOException {
|
||||
if (response.isSuccessful()) {
|
||||
InputStream in = response.body().byteStream();
|
||||
InputStream in = Objects.requireNonNull(response.body(), "HTTP response body is null").byteStream();
|
||||
if (playlist.encrypted) {
|
||||
in = new Crypto(playlist.encryptionKeyUrl, client).wrap(in);
|
||||
}
|
||||
byte[] b = new byte[1024 * 100];
|
||||
int length = -1;
|
||||
int length;
|
||||
while ((length = in.read(b)) >= 0 && !Thread.currentThread().isInterrupted()) {
|
||||
out.write(b, 0, length);
|
||||
BandwidthMeter.add(length);
|
||||
}
|
||||
out.flush();
|
||||
return true;
|
||||
} else {
|
||||
throw new HttpException(response.code(), response.message());
|
||||
}
|
||||
|
@ -105,4 +105,4 @@ public class SegmentDownload implements Callable<SegmentDownload> {
|
|||
public Segment getSegment() {
|
||||
return segment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue