From 7eac934c7feb3c5df2ffb5f32350032e7793ff70 Mon Sep 17 00:00:00 2001 From: 0xb00bface <0xboobface@gmail.com> Date: Sun, 11 Oct 2020 19:14:22 +0200 Subject: [PATCH] Remove getLength from download The length has to be determined just in time for certain pp functions to work properly. The length can no longer be retrieved from the recording, but has to be determined with the help of VideoLengthDetector --- common/src/main/java/ctbrec/Recording.java | 9 +++-- .../ctbrec/recorder/download/Download.java | 2 - .../recorder/download/dash/DashDownload.java | 17 --------- .../recorder/download/hls/FFmpegDownload.java | 6 --- .../recorder/download/hls/HlsDownload.java | 38 ------------------- .../download/hls/MergedFfmpegHlsDownload.java | 10 ----- .../postprocessing/DeleteTooShort.java | 12 ++++-- .../ctbrec/sites/showup/ShowupDownload.java | 7 ---- .../postprocessing/DeleteTooShortTest.java | 8 +++- 9 files changed, 21 insertions(+), 88 deletions(-) diff --git a/common/src/main/java/ctbrec/Recording.java b/common/src/main/java/ctbrec/Recording.java index 25cef8bd..6237baaa 100644 --- a/common/src/main/java/ctbrec/Recording.java +++ b/common/src/main/java/ctbrec/Recording.java @@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory; import ctbrec.event.EventBusHolder; import ctbrec.event.RecordingStateChangedEvent; import ctbrec.recorder.download.Download; +import ctbrec.recorder.download.VideoLengthDetector; public class Recording implements Serializable { private static final transient Logger LOG = LoggerFactory.getLogger(Recording.class); @@ -208,10 +209,12 @@ public class Recording implements Serializable { } public Duration getLength() { - if (getDownload() != null) { - return getDownload().getLength(); + File ppFile = getPostProcessedFile(); + if (ppFile.isDirectory()) { + File playlist = new File(ppFile, "playlist.m3u8a"); + return VideoLengthDetector.getLength(playlist); } else { - return Duration.ofSeconds(0); + return VideoLengthDetector.getLength(ppFile); } } diff --git a/common/src/main/java/ctbrec/recorder/download/Download.java b/common/src/main/java/ctbrec/recorder/download/Download.java index fc500a27..171a8d98 100644 --- a/common/src/main/java/ctbrec/recorder/download/Download.java +++ b/common/src/main/java/ctbrec/recorder/download/Download.java @@ -3,7 +3,6 @@ package ctbrec.recorder.download; import java.io.File; import java.io.IOException; import java.io.Serializable; -import java.time.Duration; import java.time.Instant; import ctbrec.Config; @@ -16,7 +15,6 @@ public interface Download extends Serializable { public void stop(); public Model getModel(); public Instant getStartTime(); - public Duration getLength(); public void postprocess(Recording recording); /** diff --git a/common/src/main/java/ctbrec/recorder/download/dash/DashDownload.java b/common/src/main/java/ctbrec/recorder/download/dash/DashDownload.java index e3f1a170..9f57d93a 100644 --- a/common/src/main/java/ctbrec/recorder/download/dash/DashDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/dash/DashDownload.java @@ -18,7 +18,6 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -29,8 +28,6 @@ import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; -import org.jcodec.containers.mp4.MP4Util; -import org.jcodec.containers.mp4.boxes.MovieBox; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,7 +59,6 @@ public class DashDownload extends AbstractDownload { private transient HttpClient httpClient; private transient Config config; private Model model; - private Instant endTime; private transient Path downloadDir; private String manifestUrl; private boolean running = false; @@ -272,7 +268,6 @@ public class DashDownload extends AbstractDownload { LOG.error("Error while downloading dash stream", e); } finally { running = false; - endTime = Instant.now(); downloadFinished.set(true); synchronized (downloadFinished) { downloadFinished.notifyAll(); @@ -374,18 +369,6 @@ public class DashDownload extends AbstractDownload { return model; } - @Override - public Duration getLength() { - try { - MovieBox movieBox = MP4Util.parseMovie(finalFile); - double lengthInSeconds = (double) movieBox.getDuration() / movieBox.getTimescale(); - return Duration.ofSeconds((long) Math.ceil(lengthInSeconds)); - } catch (IOException e) { - LOG.error("Couldn't determine length of MP4 file {}", getTarget(), e); - return Duration.between(startTime, Optional.ofNullable(endTime).orElse(Instant.now())); - } - } - @Override public void postprocess(Recording recording) { try { diff --git a/common/src/main/java/ctbrec/recorder/download/hls/FFmpegDownload.java b/common/src/main/java/ctbrec/recorder/download/hls/FFmpegDownload.java index a9eb03b3..1febf103 100644 --- a/common/src/main/java/ctbrec/recorder/download/hls/FFmpegDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/hls/FFmpegDownload.java @@ -6,7 +6,6 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.time.Duration; import java.time.Instant; import java.util.Arrays; import java.util.concurrent.ExecutionException; @@ -119,11 +118,6 @@ public class FFmpegDownload extends AbstractHlsDownload { return model; } - @Override - public Duration getLength() { - return Duration.between(startTime, Instant.now()); - } - @Override public void postprocess(Recording recording) { } diff --git a/common/src/main/java/ctbrec/recorder/download/hls/HlsDownload.java b/common/src/main/java/ctbrec/recorder/download/hls/HlsDownload.java index adca2dc2..8491971a 100644 --- a/common/src/main/java/ctbrec/recorder/download/hls/HlsDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/hls/HlsDownload.java @@ -2,7 +2,6 @@ package ctbrec.recorder.download.hls; import java.io.EOFException; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -31,15 +30,8 @@ import java.util.regex.Pattern; 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.data.MediaPlaylist; -import com.iheartradio.m3u8.data.Playlist; -import com.iheartradio.m3u8.data.TrackData; import ctbrec.Config; import ctbrec.Model; @@ -338,36 +330,6 @@ public class HlsDownload extends AbstractHlsDownload { return relativePath; } - @Override - public Duration getLength() { - try { - File playlist = new File(getTarget(), "playlist.m3u8"); - if (playlist.exists()) { - return Duration.ofSeconds((long) getPlaylistLength(playlist)); - } - } catch (IOException | ParseException | PlaylistException e) { - LOG.error("Couldn't determine recording length", e); - } - return Duration.ofSeconds(-1); - } - - private double getPlaylistLength(File playlist) throws IOException, ParseException, PlaylistException { - if (playlist.exists()) { - try (FileInputStream fin = new FileInputStream(playlist)) { - PlaylistParser playlistParser = new PlaylistParser(fin, Format.EXT_M3U, Encoding.UTF_8, ParsingMode.LENIENT); - Playlist m3u = playlistParser.parse(); - MediaPlaylist mediaPlaylist = m3u.getMediaPlaylist(); - double length = 0; - for (TrackData trackData : mediaPlaylist.getTracks()) { - length += trackData.getTrackInfo().duration; - } - return length; - } - } else { - throw new FileNotFoundException(playlist.getAbsolutePath() + " does not exist"); - } - } - @Override public boolean isSingleFile() { return false; diff --git a/common/src/main/java/ctbrec/recorder/download/hls/MergedFfmpegHlsDownload.java b/common/src/main/java/ctbrec/recorder/download/hls/MergedFfmpegHlsDownload.java index 7a2a114e..ed8f9d70 100644 --- a/common/src/main/java/ctbrec/recorder/download/hls/MergedFfmpegHlsDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/hls/MergedFfmpegHlsDownload.java @@ -44,7 +44,6 @@ import ctbrec.io.StreamRedirectThread; import ctbrec.recorder.ProgressListener; import ctbrec.recorder.download.HttpHeaderFactory; import ctbrec.recorder.download.ProcessExitedUncleanException; -import ctbrec.recorder.download.VideoLengthDetector; import okhttp3.Request; import okhttp3.Request.Builder; import okhttp3.Response; @@ -546,15 +545,6 @@ public class MergedFfmpegHlsDownload extends AbstractHlsDownload { return fileLoadedBytes; } - @Override - public Duration getLength() { - try { - return VideoLengthDetector.getLength(targetFile); - } catch (Exception e) { - return Duration.between(getStartTime(), Instant.now()); - } - } - @Override public boolean isSingleFile() { return true; diff --git a/common/src/main/java/ctbrec/recorder/postprocessing/DeleteTooShort.java b/common/src/main/java/ctbrec/recorder/postprocessing/DeleteTooShort.java index 7e5cab21..39b3691a 100644 --- a/common/src/main/java/ctbrec/recorder/postprocessing/DeleteTooShort.java +++ b/common/src/main/java/ctbrec/recorder/postprocessing/DeleteTooShort.java @@ -25,10 +25,14 @@ public class DeleteTooShort extends AbstractPostProcessor { Duration minimumLengthInSeconds = Duration.ofSeconds(Integer.parseInt(getConfig().getOrDefault(MIN_LEN_IN_SECS, "0"))); if (minimumLengthInSeconds.getSeconds() > 0) { Duration recordingLength = rec.getLength(); - if (!(recordingLength.isNegative() || recordingLength.isZero()) && recordingLength.compareTo(minimumLengthInSeconds) < 0) { - LOG.info("Deleting too short recording {} [{} < {}]", rec, recordingLength, minimumLengthInSeconds); - recordingManager.delete(rec); - return false; + if (recordingLength.isNegative()) { + LOG.info("Video length couldn't be determined. Keeping the file!"); + } else { + if (!recordingLength.isZero() && recordingLength.compareTo(minimumLengthInSeconds) < 0) { + LOG.info("Deleting too short recording {} [{} < {}]", rec, recordingLength, minimumLengthInSeconds); + recordingManager.delete(rec); + return false; + } } } return true; diff --git a/common/src/main/java/ctbrec/sites/showup/ShowupDownload.java b/common/src/main/java/ctbrec/sites/showup/ShowupDownload.java index 0245b7d3..951e5e59 100644 --- a/common/src/main/java/ctbrec/sites/showup/ShowupDownload.java +++ b/common/src/main/java/ctbrec/sites/showup/ShowupDownload.java @@ -2,8 +2,6 @@ package ctbrec.sites.showup; import java.io.File; import java.io.IOException; -import java.time.Duration; -import java.time.Instant; import com.iheartradio.m3u8.ParseException; import com.iheartradio.m3u8.PlaylistException; @@ -31,9 +29,4 @@ public class ShowupDownload extends HlsDownload { recording.setProgress(-1); return playlist; } - - @Override - public Duration getLength() { - return Duration.between(getStartTime(), Instant.now()); - } } diff --git a/common/src/test/java/ctbrec/recorder/postprocessing/DeleteTooShortTest.java b/common/src/test/java/ctbrec/recorder/postprocessing/DeleteTooShortTest.java index 6c3a5e08..e99cbada 100644 --- a/common/src/test/java/ctbrec/recorder/postprocessing/DeleteTooShortTest.java +++ b/common/src/test/java/ctbrec/recorder/postprocessing/DeleteTooShortTest.java @@ -1,6 +1,7 @@ package ctbrec.recorder.postprocessing; import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.io.File; @@ -9,11 +10,13 @@ import java.time.Duration; import java.util.Collections; import org.junit.Test; +import org.mockito.MockedStatic; import ctbrec.Config; import ctbrec.Recording; import ctbrec.recorder.RecordingManager; import ctbrec.recorder.download.Download; +import ctbrec.recorder.download.VideoLengthDetector; public class DeleteTooShortTest extends AbstractPpTest { @@ -30,6 +33,8 @@ public class DeleteTooShortTest extends AbstractPpTest { private void testProcess(File original) throws IOException { Recording rec = createRec(original); Config config = mockConfig(); + MockedStatic videoLengthDetectorMock = mockStatic(VideoLengthDetector.class); + when(VideoLengthDetector.getLength(any())).thenReturn(Duration.ofSeconds(5)); RecordingManager recordingManager = new RecordingManager(config, Collections.emptyList()); recordingManager.add(rec); @@ -42,6 +47,8 @@ public class DeleteTooShortTest extends AbstractPpTest { assertFalse(rec.getAbsoluteFile().exists()); assertFalse(original.exists()); assertEquals(0, recordingManager.getAll().size()); + + videoLengthDetectorMock.close(); } @Test @@ -85,7 +92,6 @@ public class DeleteTooShortTest extends AbstractPpTest { private Recording createRec(File original) { Download download = mock(Download.class); - when(download.getLength()).thenReturn(Duration.ofSeconds(5)); Recording rec = new Recording(); rec.setModel(mockModel()); rec.setAbsoluteFile(original);