From 71be9b3665a6b98ba91779fafff1da65bcd4eeee Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Sat, 22 Feb 2020 17:40:22 +0100 Subject: [PATCH] Improve support for server-side single files --- .../main/java/ctbrec/ui/JavaFxRecording.java | 5 +++++ client/src/main/java/ctbrec/ui/Player.java | 2 +- .../java/ctbrec/ui/tabs/RecordingsTab.java | 18 +++++++++--------- common/src/main/java/ctbrec/AbstractModel.java | 2 +- common/src/main/java/ctbrec/Recording.java | 14 +++++++++----- common/src/main/java/ctbrec/Settings.java | 1 + .../ctbrec/recorder/NextGenLocalRecorder.java | 1 + .../ctbrec/recorder/download/Download.java | 6 ++++++ .../recorder/download/dash/DashDownload.java | 5 +++++ .../recorder/download/hls/FFmpegDownload.java | 5 +++++ .../recorder/download/hls/HlsDownload.java | 5 +++++ .../download/hls/MergedFfmpegHlsDownload.java | 5 +++++ .../java/ctbrec/sites/fc2live/Fc2Model.java | 2 +- .../ctbrec/sites/jasmin/LiveJasminModel.java | 2 +- .../src/main/resources/html/static/index.html | 15 ++++++++++----- 15 files changed, 65 insertions(+), 23 deletions(-) diff --git a/client/src/main/java/ctbrec/ui/JavaFxRecording.java b/client/src/main/java/ctbrec/ui/JavaFxRecording.java index 76508b28..aa696760 100644 --- a/client/src/main/java/ctbrec/ui/JavaFxRecording.java +++ b/client/src/main/java/ctbrec/ui/JavaFxRecording.java @@ -179,6 +179,11 @@ public class JavaFxRecording extends Recording { return delegate.getMetaDataFile(); } + @Override + public boolean isSingleFile() { + return delegate.isSingleFile(); + } + public boolean valueChanged() { boolean changed = getSizeInByte() != lastValue; lastValue = getSizeInByte(); diff --git a/client/src/main/java/ctbrec/ui/Player.java b/client/src/main/java/ctbrec/ui/Player.java index bc1c5522..47c1accc 100644 --- a/client/src/main/java/ctbrec/ui/Player.java +++ b/client/src/main/java/ctbrec/ui/Player.java @@ -162,7 +162,7 @@ public class Player { private String getRemoteRecordingUrl(Recording rec, Config cfg) throws MalformedURLException, InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { String hlsBase = Config.getInstance().getServerUrl() + "/hls"; - String recUrl = hlsBase + rec.getPath() + (rec.isSegmented() ? "/playlist.m3u8" : ""); + String recUrl = hlsBase + rec.getPath() + (rec.isSingleFile() ? "" : "/playlist.m3u8"); if (cfg.getSettings().requireAuthentication) { URL u = new URL(recUrl); String path = u.getPath(); diff --git a/client/src/main/java/ctbrec/ui/tabs/RecordingsTab.java b/client/src/main/java/ctbrec/ui/tabs/RecordingsTab.java index fcc18db2..7c023338 100644 --- a/client/src/main/java/ctbrec/ui/tabs/RecordingsTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/RecordingsTab.java @@ -404,7 +404,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener { MenuItem rerunPostProcessing = new MenuItem("Rerun Post-Processing"); rerunPostProcessing.setOnAction(e -> triggerPostProcessing(first)); if (first.getStatus() == FAILED || first.getStatus() == WAITING || first.getStatus() == FINISHED) { - if (first.isSegmented() || !first.isSegmented() && first.getPath().endsWith(".part")) { + if (!first.isSingleFile() || first.isSingleFile() && first.getPath().endsWith(".part")) { contextMenu.getItems().add(rerunPostProcessing); } } @@ -488,12 +488,12 @@ public class RecordingsTab extends Tab implements TabSelectionListener { private String proposeTargetFilename(Recording recording) { String path = recording.getPath().substring(1); - if(recording.isSegmented()) { + if(recording.isSingleFile()) { + return new File(path).getName(); + } else { String fileSuffix = config.getSettings().ffmpegFileSuffix; String filename = path.replace("/", "-").replace(".mp4", "") + '.' + fileSuffix; return filename; - } else { - return new File(path).getName(); } } @@ -501,16 +501,16 @@ public class RecordingsTab extends Tab implements TabSelectionListener { Thread t = new Thread(() -> { try { String hlsBase = config.getServerUrl() + "/hls"; - if (recording.isSegmented()) { + if (recording.isSingleFile()) { + URL url = new URL(hlsBase + recording.getPath()); + FileDownload download = new FileDownload(CamrecApplication.httpClient, createDownloadListener(recording)); + download.start(url, target); + } else { URL url = new URL(hlsBase + recording.getPath() + "/playlist.m3u8"); MergedFfmpegHlsDownload download = new MergedFfmpegHlsDownload(CamrecApplication.httpClient); download.init(config, recording.getModel(), Instant.now()); LOG.info("Downloading {}", url); download.downloadFinishedRecording(url.toString(), target, createDownloadListener(recording)); - } else { - URL url = new URL(hlsBase + recording.getPath()); - FileDownload download = new FileDownload(CamrecApplication.httpClient, createDownloadListener(recording)); - download.start(url, target); } } catch (FileNotFoundException e) { showErrorDialog(ERROR_WHILE_DOWNLOADING_RECORDING, "The target file couldn't be created", e); diff --git a/common/src/main/java/ctbrec/AbstractModel.java b/common/src/main/java/ctbrec/AbstractModel.java index 179c9393..46ef3627 100644 --- a/common/src/main/java/ctbrec/AbstractModel.java +++ b/common/src/main/java/ctbrec/AbstractModel.java @@ -230,7 +230,7 @@ public abstract class AbstractModel implements Model { @Override public Download createDownload() { - if (Config.isServerMode()) { + if (Config.isServerMode() && !Config.getInstance().getSettings().recordSingleFile) { return new HlsDownload(getSite().getHttpClient()); } else { return new MergedFfmpegHlsDownload(getSite().getHttpClient()); diff --git a/common/src/main/java/ctbrec/Recording.java b/common/src/main/java/ctbrec/Recording.java index b003799c..0e85db4d 100644 --- a/common/src/main/java/ctbrec/Recording.java +++ b/common/src/main/java/ctbrec/Recording.java @@ -7,7 +7,6 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.Optional; import ctbrec.event.EventBusHolder; import ctbrec.event.RecordingStateChangedEvent; @@ -22,6 +21,7 @@ public class Recording implements Serializable { private int progress = -1; private long sizeInByte = -1; private String metaDataFile; + private boolean singleFile = false; public enum State { RECORDING("recording"), @@ -123,6 +123,14 @@ public class Recording implements Serializable { this.download = download; } + public boolean isSingleFile() { + return singleFile; + } + + public void setSingleFile(boolean singleFile) { + this.singleFile = singleFile; + } + public String getMetaDataFile() { return metaDataFile; } @@ -224,8 +232,4 @@ public class Recording implements Serializable { public void refresh() { sizeInByte = getSize(); } - - public boolean isSegmented() { - return !Optional.ofNullable(getPath()).orElse("").endsWith(".mp4"); - } } diff --git a/common/src/main/java/ctbrec/Settings.java b/common/src/main/java/ctbrec/Settings.java index d67d93a6..20159a21 100644 --- a/common/src/main/java/ctbrec/Settings.java +++ b/common/src/main/java/ctbrec/Settings.java @@ -103,6 +103,7 @@ public class Settings { public DirectoryStructure recordingsDirStructure = DirectoryStructure.FLAT; public String recordingsSortColumn = ""; public String recordingsSortType = ""; + public boolean recordSingleFile = false; public boolean requireAuthentication = false; public String servletContext = ""; public boolean showPlayerStarting = false; diff --git a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java index 24a7df71..ae106dbd 100644 --- a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java +++ b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java @@ -268,6 +268,7 @@ public class NextGenLocalRecorder implements Recorder { rec.setPath(download.getPath(model).replaceAll("\\\\", "/")); rec.setModel(model); rec.setStartDate(download.getStartTime()); + rec.setSingleFile(download.isSingleFile()); recordingProcesses.put(model, rec); recordingManager.add(rec); completionService.submit(() -> { diff --git a/common/src/main/java/ctbrec/recorder/download/Download.java b/common/src/main/java/ctbrec/recorder/download/Download.java index 42c3b6f5..fc500a27 100644 --- a/common/src/main/java/ctbrec/recorder/download/Download.java +++ b/common/src/main/java/ctbrec/recorder/download/Download.java @@ -34,4 +34,10 @@ public interface Download extends Serializable { * @see #getTarget() */ public String getPath(Model model); + + /** + * Specifies, if the final result of this recording is a single file or consists of segments + playlist + * @return true, if the recording is only a single file + */ + public boolean isSingleFile(); } 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 f7ed3ba8..35a0111e 100644 --- a/common/src/main/java/ctbrec/recorder/download/dash/DashDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/dash/DashDownload.java @@ -425,4 +425,9 @@ public class DashDownload extends AbstractDownload { } } + @Override + public boolean isSingleFile() { + return false; + } + } 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 4100a3a5..2e25a9f9 100644 --- a/common/src/main/java/ctbrec/recorder/download/hls/FFmpegDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/hls/FFmpegDownload.java @@ -151,4 +151,9 @@ public class FFmpegDownload extends AbstractHlsDownload { stop(); } + @Override + public boolean isSingleFile() { + return true; + } + } 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 dc962242..3bd6c144 100644 --- a/common/src/main/java/ctbrec/recorder/download/hls/HlsDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/hls/HlsDownload.java @@ -366,4 +366,9 @@ public class HlsDownload extends AbstractHlsDownload { 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 f31cd1fb..4851c844 100644 --- a/common/src/main/java/ctbrec/recorder/download/hls/MergedFfmpegHlsDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/hls/MergedFfmpegHlsDownload.java @@ -489,4 +489,9 @@ public class MergedFfmpegHlsDownload extends AbstractHlsDownload { public Duration getLength() { return Duration.between(getStartTime(), Instant.now()); } + + @Override + public boolean isSingleFile() { + return true; + } } diff --git a/common/src/main/java/ctbrec/sites/fc2live/Fc2Model.java b/common/src/main/java/ctbrec/sites/fc2live/Fc2Model.java index be2bf391..a686d0eb 100644 --- a/common/src/main/java/ctbrec/sites/fc2live/Fc2Model.java +++ b/common/src/main/java/ctbrec/sites/fc2live/Fc2Model.java @@ -381,7 +381,7 @@ public class Fc2Model extends AbstractModel { @Override public Download createDownload() { - if(Config.isServerMode()) { + if(Config.isServerMode() && !Config.getInstance().getSettings().recordSingleFile) { return new Fc2HlsDownload(getSite().getHttpClient()); } else { return new Fc2MergedHlsDownload(getSite().getHttpClient()); diff --git a/common/src/main/java/ctbrec/sites/jasmin/LiveJasminModel.java b/common/src/main/java/ctbrec/sites/jasmin/LiveJasminModel.java index de6c047c..c7aa3d18 100644 --- a/common/src/main/java/ctbrec/sites/jasmin/LiveJasminModel.java +++ b/common/src/main/java/ctbrec/sites/jasmin/LiveJasminModel.java @@ -297,7 +297,7 @@ public class LiveJasminModel extends AbstractModel { @Override public Download createDownload() { - if(Config.isServerMode()) { + if(Config.isServerMode() && !Config.getInstance().getSettings().recordSingleFile) { return new LiveJasminHlsDownload(getSite().getHttpClient()); } else { return new LiveJasminMergedHlsDownload(getSite().getHttpClient()); diff --git a/server/src/main/resources/html/static/index.html b/server/src/main/resources/html/static/index.html index 25f2ab36..d8139478 100644 --- a/server/src/main/resources/html/static/index.html +++ b/server/src/main/resources/html/static/index.html @@ -158,7 +158,7 @@ - + @@ -389,9 +389,10 @@ }; function play(recording) { - let src = recording.playlist; + let src = recording.singleFile ? '/hls' + recording.path : recording.playlist; + console.log("####################", src); let hmacOfPath = CryptoJS.HmacSHA256(src, hmac); - src = '..' + src; + src = '..' + src; if(console) console.log("Path", src, "HMAC", hmacOfPath); if (hmac.length > 0) { src += "?hmac=" + hmacOfPath; @@ -399,15 +400,19 @@ if(console) console.log('Playing video from', src); - if(src.indexOf('.mp4') > 0) { + if(recording.singleFile) { var video = document.getElementById('player'); video.src = src; video.load(); + console.log(video); video.oncanplay = function() { video.height = window.innerHeight * 0.85; $('#player-window').css('display', 'block'); video.play(); - } + }; + video.onerror = function() { + $.notify(video.error.message, 'error'); + }; } else { if (Hls.isSupported()) { var video = document.getElementById('player');