From eef9d43d01b570917cd30855e7704c50cc0d8785 Mon Sep 17 00:00:00 2001 From: kohlerpop1 Date: Thu, 17 Oct 2024 16:53:00 -0400 Subject: [PATCH] Added TikTokLiveRecorderEndedEvent and updated RecorderListener to use CompletableFuture and a cancellation token! --- .../recorder/impl/RecorderListener.java | 82 ++++++++++--------- .../event/TikTokLiveRecorderEndedEvent.java | 37 +++++++++ .../event/TikTokLiveRecorderStartedEvent.java | 3 +- 3 files changed, 80 insertions(+), 42 deletions(-) create mode 100644 extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/event/TikTokLiveRecorderEndedEvent.java diff --git a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/RecorderListener.java b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/RecorderListener.java index 516befe..cfb4230 100644 --- a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/RecorderListener.java +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/RecorderListener.java @@ -30,7 +30,7 @@ import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings; import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder; import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.*; import io.github.jwdeveloper.tiktok.extension.recorder.impl.enums.LiveQuality; -import io.github.jwdeveloper.tiktok.extension.recorder.impl.event.TikTokLiveRecorderStartedEvent; +import io.github.jwdeveloper.tiktok.extension.recorder.impl.event.*; import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.models.ConnectionState; @@ -38,14 +38,17 @@ import java.io.*; import java.net.URI; import java.net.http.*; import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiConsumer; public class RecorderListener implements LiveRecorder { private final BiConsumer consumer; private final RecorderSettings settings; + private final AtomicBoolean token = new AtomicBoolean(); private DownloadData downloadData; - private Thread liveDownloadThread; + private CompletableFuture future; public RecorderListener(BiConsumer consumer) { this.consumer = consumer; @@ -74,60 +77,59 @@ public class RecorderListener implements LiveRecorder { if (isConnected() || downloadData.getDownloadLiveUrl().isEmpty()) return; - liveDownloadThread = new Thread(() -> { - try { - liveClient.getLogger().info("Recording started "+liveClient.getRoomInfo().getHostName()); - - HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(URI.create(downloadData.getFullUrl())).GET(); - for (var entry : LiveClientSettings.DefaultRequestHeaders().entrySet()) - requestBuilder.header(entry.getKey(), entry.getValue()); - HttpResponse serverResponse = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL) - .connectTimeout(Duration.ofSeconds(10)).build().send(requestBuilder.build(), HttpResponse.BodyHandlers.ofInputStream()); - - var file = settings.getOutputFile(); - file.getParentFile().mkdirs(); - file.createNewFile(); - - try ( - var in = serverResponse.body(); - var fos = new FileOutputStream(file, true) - ) { - byte[] dataBuffer = new byte[1024]; - int bytesRead; - while ((!settings.isStopOnDisconnect() || liveClient.getRoomInfo().getConnectionState() == ConnectionState.CONNECTED) && (bytesRead = in.read(dataBuffer)) != -1) { - fos.write(dataBuffer, 0, bytesRead); - fos.flush(); - } - } catch (IOException ignored) { - } finally { - liveClient.getLogger().severe("Stopped recording " + liveClient.getRoomInfo().getHostName()); - } - } catch (Exception e) { - e.printStackTrace(); - } - }); - var recordingStartedEvent = new TikTokLiveRecorderStartedEvent(downloadData); liveClient.publishEvent(recordingStartedEvent); if (recordingStartedEvent.isCanceled()) liveClient.getLogger().info("Recording cancelled"); else - liveDownloadThread.start(); + future = CompletableFuture.runAsync(() -> { + try { + liveClient.getLogger().info("Recording started "+liveClient.getRoomInfo().getHostName()); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(URI.create(downloadData.getFullUrl())).GET(); + for (var entry : LiveClientSettings.DefaultRequestHeaders().entrySet()) + requestBuilder.header(entry.getKey(), entry.getValue()); + HttpResponse serverResponse = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL) + .connectTimeout(Duration.ofSeconds(10)).build().send(requestBuilder.build(), HttpResponse.BodyHandlers.ofInputStream()); + + var file = settings.getOutputFile(); + file.getParentFile().mkdirs(); + file.createNewFile(); + + try ( + var in = serverResponse.body(); + var fos = new FileOutputStream(file, true) + ) { + byte[] dataBuffer = new byte[1024]; + int bytesRead; + while (!token.get() && (!settings.isStopOnDisconnect() || liveClient.getRoomInfo().getConnectionState() == ConnectionState.CONNECTED) && (bytesRead = in.read(dataBuffer)) != -1) { + fos.write(dataBuffer, 0, bytesRead); + fos.flush(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + liveClient.getLogger().info("Stopped recording " + liveClient.getRoomInfo().getHostName()); + liveClient.publishEvent(new TikTokLiveRecorderEndedEvent(settings)); + } + } catch (Exception e) { + e.printStackTrace(); + } + }); } @TikTokEventObserver private void onDisconnected(LiveClient liveClient, TikTokDisconnectedEvent event) { if (isConnected() && settings.isStopOnDisconnect()) - liveDownloadThread.interrupt(); + token.set(true); } @TikTokEventObserver private void onLiveEnded(LiveClient liveClient, TikTokLiveEndedEvent event) { if (isConnected()) - liveDownloadThread.interrupt(); + token.set(true); } - private DownloadData mapToDownloadData(String json) { try { var parsedJson = JsonParser.parseString(json); @@ -164,6 +166,6 @@ public class RecorderListener implements LiveRecorder { } private boolean isConnected() { - return liveDownloadThread != null && liveDownloadThread.isAlive(); + return future != null && !future.isDone(); } } \ No newline at end of file diff --git a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/event/TikTokLiveRecorderEndedEvent.java b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/event/TikTokLiveRecorderEndedEvent.java new file mode 100644 index 0000000..c3dfa0e --- /dev/null +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/event/TikTokLiveRecorderEndedEvent.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package io.github.jwdeveloper.tiktok.extension.recorder.impl.event; + +import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; +import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.*; +import lombok.*; + +@Getter +public class TikTokLiveRecorderEndedEvent extends TikTokEvent { + + private final RecorderSettings settings; + + public TikTokLiveRecorderEndedEvent(RecorderSettings settings) { + this.settings = settings; + } +} \ No newline at end of file diff --git a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/event/TikTokLiveRecorderStartedEvent.java b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/event/TikTokLiveRecorderStartedEvent.java index c5b8959..bf7ca68 100644 --- a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/event/TikTokLiveRecorderStartedEvent.java +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/event/TikTokLiveRecorderStartedEvent.java @@ -25,7 +25,6 @@ package io.github.jwdeveloper.tiktok.extension.recorder.impl.event; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.DownloadData; import lombok.AllArgsConstructor; -import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -40,4 +39,4 @@ public class TikTokLiveRecorderStartedEvent extends TikTokEvent { public TikTokLiveRecorderStartedEvent(DownloadData downloadData) { this.downloadData = downloadData; } -} +} \ No newline at end of file