From 913d473442f19bc5df2e7a21c40e7452bd1c93ee Mon Sep 17 00:00:00 2001 From: JW Date: Sun, 14 Jan 2024 22:55:05 +0100 Subject: [PATCH 01/10] . --- .../events/control/TikTokConnectingEvent.java | 37 +++ .../http/TikTokRoomDataResponseEvent.java | 38 +++ Examples/pom.xml | 12 + .../jwdeveloper/tiktok/CollectorExample.java | 68 +++++ .../jwdeveloper/tiktok/RecorderExample.java | 55 ++++ extension-collector/README.md | 0 extension-collector/pom.xml | 41 +++ .../collector/TikTokLiveCollector.java | 40 +++ .../collector/api/LiveDataCollector.java | 30 +++ .../api/data/CollectorListenerSettings.java | 13 + .../api/data/LiveDataCollectorSettings.java | 48 ++++ .../data/MongoDBConnectionStringBuilder.java | 55 ++++ .../impl/TikTokLiveDataCollector.java | 90 +++++++ .../impl/TikTokLiveDataCollectorListener.java | 122 +++++++++ extension-recorder/README.md | 0 extension-recorder/pom.xml | 39 +++ .../recorder/TikTokLiveRecorder.java | 43 +++ .../extension/recorder/api/LiveRecorder.java | 31 +++ .../recorder/impl/RecorderListener.java | 251 ++++++++++++++++++ .../recorder/impl/data/DownloadData.java | 39 +++ .../recorder/impl/data/RecorderSettings.java | 82 ++++++ .../recorder/impl/enums/LiveFormat.java | 28 ++ .../recorder/impl/enums/LiveQuality.java | 27 ++ .../event/TikTokLiveRecorderStartedEvent.java | 35 +++ pom.xml | 3 + 25 files changed, 1227 insertions(+) create mode 100644 API/src/main/java/io/github/jwdeveloper/tiktok/data/events/control/TikTokConnectingEvent.java create mode 100644 API/src/main/java/io/github/jwdeveloper/tiktok/data/events/http/TikTokRoomDataResponseEvent.java create mode 100644 Examples/src/main/java/io/github/jwdeveloper/tiktok/CollectorExample.java create mode 100644 Examples/src/main/java/io/github/jwdeveloper/tiktok/RecorderExample.java create mode 100644 extension-collector/README.md create mode 100644 extension-collector/pom.xml create mode 100644 extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/TikTokLiveCollector.java create mode 100644 extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/LiveDataCollector.java create mode 100644 extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/CollectorListenerSettings.java create mode 100644 extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/LiveDataCollectorSettings.java create mode 100644 extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/MongoDBConnectionStringBuilder.java create mode 100644 extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/impl/TikTokLiveDataCollector.java create mode 100644 extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/impl/TikTokLiveDataCollectorListener.java create mode 100644 extension-recorder/README.md create mode 100644 extension-recorder/pom.xml create mode 100644 extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/TikTokLiveRecorder.java create mode 100644 extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/api/LiveRecorder.java create mode 100644 extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/RecorderListener.java create mode 100644 extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/data/DownloadData.java create mode 100644 extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/data/RecorderSettings.java create mode 100644 extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/enums/LiveFormat.java create mode 100644 extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/enums/LiveQuality.java create mode 100644 extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/event/TikTokLiveRecorderStartedEvent.java diff --git a/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/control/TikTokConnectingEvent.java b/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/control/TikTokConnectingEvent.java new file mode 100644 index 00000000..86536a81 --- /dev/null +++ b/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/control/TikTokConnectingEvent.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.data.events.control; + +import io.github.jwdeveloper.tiktok.annotations.EventMeta; +import io.github.jwdeveloper.tiktok.annotations.EventType; +import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent; + + +/** + * Triggered when client is connecting to live is successfully established. + */ +@EventMeta(eventType = EventType.Control) +public class TikTokConnectingEvent extends TikTokLiveClientEvent +{ + +} diff --git a/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/http/TikTokRoomDataResponseEvent.java b/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/http/TikTokRoomDataResponseEvent.java new file mode 100644 index 00000000..8195973c --- /dev/null +++ b/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/http/TikTokRoomDataResponseEvent.java @@ -0,0 +1,38 @@ +/* + * 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.data.events.http; + +import io.github.jwdeveloper.tiktok.annotations.EventMeta; +import io.github.jwdeveloper.tiktok.annotations.EventType; +import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; +import io.github.jwdeveloper.tiktok.data.requests.LiveData; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +@EventMeta(eventType = EventType.Debug) +public class TikTokRoomDataResponseEvent extends TikTokEvent +{ + private final LiveData.Response liveData; +} diff --git a/Examples/pom.xml b/Examples/pom.xml index 33d117a0..7b41c54d 100644 --- a/Examples/pom.xml +++ b/Examples/pom.xml @@ -60,6 +60,18 @@ ${project.version} compile + + io.github.jwdeveloper.tiktok + extension-collector + 1.0.14-Release + compile + + + io.github.jwdeveloper.tiktok + extension-recorder + 1.0.14-Release + compile + diff --git a/Examples/src/main/java/io/github/jwdeveloper/tiktok/CollectorExample.java b/Examples/src/main/java/io/github/jwdeveloper/tiktok/CollectorExample.java new file mode 100644 index 00000000..e4a1e0fe --- /dev/null +++ b/Examples/src/main/java/io/github/jwdeveloper/tiktok/CollectorExample.java @@ -0,0 +1,68 @@ +/* + * 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; + +import io.github.jwdeveloper.tiktok.extension.collector.TikTokLiveCollector; + + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class CollectorExample { + public static void main(String[] args) throws IOException { + + var collector = TikTokLiveCollector.use(settings -> + { + settings.setConnectionUrl("mongodb+srv://jwoln:qaz123456@jwdatabase.a15gw.mongodb.net/?retryWrites=true&w=majority"); + settings.setDatabaseName("tiktok"); + }); + collector.connectDatabase(); + + var users = List.of("tehila_723", "dino123597", "domaxyzx", "dash4214","obserwacje_live"); + var sessionTag = "Dupa"; + for (var user : users) { + TikTokLive.newClient(user) + .configure(liveClientSettings -> + { + liveClientSettings.setPrintToConsole(true); + }) + .onError((liveClient, event) -> + { + event.getException().printStackTrace(); + }) + .addListener(collector.newListener(Map.of("sessionTag", sessionTag),document -> + { + if(document.get("dataType") == "message") + { + return false; + } + return true; + })) + .buildAndConnectAsync(); + } + + System.in.read(); + collector.disconnectDatabase(); + } +} diff --git a/Examples/src/main/java/io/github/jwdeveloper/tiktok/RecorderExample.java b/Examples/src/main/java/io/github/jwdeveloper/tiktok/RecorderExample.java new file mode 100644 index 00000000..050e3df5 --- /dev/null +++ b/Examples/src/main/java/io/github/jwdeveloper/tiktok/RecorderExample.java @@ -0,0 +1,55 @@ +/* + * 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; + + +import io.github.jwdeveloper.tiktok.extension.recorder.TikTokLiveRecorder; +import io.github.jwdeveloper.tiktok.extension.recorder.impl.event.TikTokLiveRecorderStartedEvent; + +public class RecorderExample { + + public static void main(String[] args) { + + TikTokLive.newClient("dash4214") + .configure(liveClientSettings -> + { + liveClientSettings.setPrintToConsole(true); + }) + .onError((liveClient, event) -> + { + event.getException().printStackTrace(); + }) + .addListener(TikTokLiveRecorder.use(recorderSettings -> + { + recorderSettings.setFfmpegPath("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\extension-recorder\\libs\\ffmpeg.exe"); + recorderSettings.setOutputPath("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\extension-recorder\\out"); + recorderSettings.setOutputFileName("test.mp4"); + })) + .onEvent(TikTokLiveRecorderStartedEvent.class, (liveClient, event) -> + { + System.out.println(event.getDownloadData().getFullUrl()); + }) + .buildAndConnect(); + + } +} diff --git a/extension-collector/README.md b/extension-collector/README.md new file mode 100644 index 00000000..e69de29b diff --git a/extension-collector/pom.xml b/extension-collector/pom.xml new file mode 100644 index 00000000..c5031d53 --- /dev/null +++ b/extension-collector/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + io.github.jwdeveloper.tiktok + TikTokLiveJava + 1.0.14-Release + + + + extension-collector + + + + + io.github.jwdeveloper.tiktok + API + ${project.version} + compile + + + com.google.protobuf + protobuf-java + 3.24.1 + + + org.mongodb + mongodb-driver-sync + 4.4.0 + + + io.github.jwdeveloper.tiktok + API + 1.0.17-Release + compile + + + + \ No newline at end of file diff --git a/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/TikTokLiveCollector.java b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/TikTokLiveCollector.java new file mode 100644 index 00000000..0ba18942 --- /dev/null +++ b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/TikTokLiveCollector.java @@ -0,0 +1,40 @@ +/* + * 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.collector; + +import io.github.jwdeveloper.tiktok.extension.collector.api.LiveDataCollector; +import io.github.jwdeveloper.tiktok.extension.collector.api.data.LiveDataCollectorSettings; +import io.github.jwdeveloper.tiktok.extension.collector.impl.TikTokLiveDataCollector; + +import java.util.function.Consumer; + +public class TikTokLiveCollector +{ + + public static TikTokLiveDataCollector use(Consumer consumer) + { + var settings = new LiveDataCollectorSettings(); + consumer.accept(settings); + return new TikTokLiveDataCollector(settings); + } +} diff --git a/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/LiveDataCollector.java b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/LiveDataCollector.java new file mode 100644 index 00000000..0532f244 --- /dev/null +++ b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/LiveDataCollector.java @@ -0,0 +1,30 @@ +/* + * 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.collector.api; + +import io.github.jwdeveloper.tiktok.listener.TikTokEventListener; + +public interface LiveDataCollector extends TikTokEventListener +{ + +} diff --git a/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/CollectorListenerSettings.java b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/CollectorListenerSettings.java new file mode 100644 index 00000000..8399a05a --- /dev/null +++ b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/CollectorListenerSettings.java @@ -0,0 +1,13 @@ +package io.github.jwdeveloper.tiktok.extension.collector.api.data; + +import lombok.Data; +import org.bson.Document; + +import java.util.Map; +import java.util.function.Function; + +@Data +public class CollectorListenerSettings { + private Map extraFields; + private Function filter; +} diff --git a/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/LiveDataCollectorSettings.java b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/LiveDataCollectorSettings.java new file mode 100644 index 00000000..4597c5cc --- /dev/null +++ b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/LiveDataCollectorSettings.java @@ -0,0 +1,48 @@ +/* + * 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.collector.api.data; + +import lombok.Data; + +import java.util.function.Consumer; + +@Data +public class LiveDataCollectorSettings { + + private String connectionUrl; + + private String databaseName; + + private String sessionTag; + + + public void setConnectionUrl(String connectionUrl) { + this.connectionUrl = connectionUrl; + } + + public void setConnectionUrl(Consumer consumer) { + var builder = new MongoDBConnectionStringBuilder(); + consumer.accept(builder); + connectionUrl = builder.build(); + } +} diff --git a/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/MongoDBConnectionStringBuilder.java b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/MongoDBConnectionStringBuilder.java new file mode 100644 index 00000000..556a0cd2 --- /dev/null +++ b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/data/MongoDBConnectionStringBuilder.java @@ -0,0 +1,55 @@ +/* + * 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.collector.api.data; + +public class MongoDBConnectionStringBuilder { + private String username; + private String password; + private String database; + private String cluster; + + public MongoDBConnectionStringBuilder setUsername(String username) { + this.username = username; + return this; + } + + public MongoDBConnectionStringBuilder setPassword(String password) { + this.password = password; + return this; + } + + public MongoDBConnectionStringBuilder setDatabase(String database) { + this.database = database; + return this; + } + + public MongoDBConnectionStringBuilder setCluster(String cluster) { + this.cluster = cluster; + return this; + } + + public String build() { + return String.format("mongodb+srv://%s:%s@%s/%s?retryWrites=true&w=majority", + username, password, cluster, database); + } +} diff --git a/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/impl/TikTokLiveDataCollector.java b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/impl/TikTokLiveDataCollector.java new file mode 100644 index 00000000..d9899b72 --- /dev/null +++ b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/impl/TikTokLiveDataCollector.java @@ -0,0 +1,90 @@ +/* + * 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.collector.impl; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.ServerApi; +import com.mongodb.ServerApiVersion; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Indexes; +import io.github.jwdeveloper.tiktok.extension.collector.api.data.CollectorListenerSettings; +import io.github.jwdeveloper.tiktok.extension.collector.api.data.LiveDataCollectorSettings; +import org.bson.Document; + +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Function; + +public class TikTokLiveDataCollector { + + private final LiveDataCollectorSettings settings; + private MongoClient mongoClient; + private MongoDatabase database; + private MongoCollection collection; + + public TikTokLiveDataCollector(LiveDataCollectorSettings settings) { + this.settings = settings; + } + + + public void connectDatabase() { + var serverApi = ServerApi.builder() + .version(ServerApiVersion.V1) + .build(); + var mongoSettings = MongoClientSettings.builder() + .applyConnectionString(new ConnectionString(settings.getConnectionUrl())) + .serverApi(serverApi) + .build(); + + mongoClient = MongoClients.create(mongoSettings); + database = mongoClient.getDatabase(settings.getDatabaseName()); + collection = database.getCollection("data"); + collection.createIndex(Indexes.hashed("session")); + collection.createIndex(Indexes.hashed("dataType")); + } + + + public void disconnectDatabase() { + mongoClient.close(); + } + + public TikTokLiveDataCollectorListener newListener() { + return newListener(Map.of()); + } + + public TikTokLiveDataCollectorListener newListener(Map additionalFields) { + return newListener(additionalFields, (e)->true); + } + + public TikTokLiveDataCollectorListener newListener(Map additionalFields, + Function filter) { + var settings = new CollectorListenerSettings(); + settings.setExtraFields(additionalFields); + settings.setFilter(filter); + return new TikTokLiveDataCollectorListener(collection, settings); + } +} diff --git a/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/impl/TikTokLiveDataCollectorListener.java b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/impl/TikTokLiveDataCollectorListener.java new file mode 100644 index 00000000..17d9578d --- /dev/null +++ b/extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/impl/TikTokLiveDataCollectorListener.java @@ -0,0 +1,122 @@ +package io.github.jwdeveloper.tiktok.extension.collector.impl; + +import com.mongodb.client.MongoCollection; +import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver; +import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent; +import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; +import io.github.jwdeveloper.tiktok.data.events.control.TikTokConnectingEvent; +import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent; +import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException; +import io.github.jwdeveloper.tiktok.extension.collector.api.LiveDataCollector; +import io.github.jwdeveloper.tiktok.extension.collector.api.data.CollectorListenerSettings; +import io.github.jwdeveloper.tiktok.live.LiveClient; +import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; +import io.github.jwdeveloper.tiktok.utils.JsonUtil; +import org.bson.Document; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Base64; +import java.util.UUID; + +public class TikTokLiveDataCollectorListener implements LiveDataCollector { + + private final MongoCollection collection; + private final CollectorListenerSettings settings; + private String sessionId; + private String userName; + + public TikTokLiveDataCollectorListener(MongoCollection collection, CollectorListenerSettings settings) { + this.collection = collection; + this.settings = settings; + } + + + @TikTokEventObserver + private void onResponse(LiveClient liveClient, TikTokWebsocketResponseEvent event) { + includeResponse(liveClient, event.getResponse()); + event.getResponse().getMessagesList().forEach(message -> + { + includeMessage(liveClient, message); + }); + } + + @TikTokEventObserver + private void onEvent(LiveClient liveClient, TikTokEvent event) { + if (event instanceof TikTokConnectingEvent) { + sessionId = UUID.randomUUID().toString(); + userName = liveClient.getRoomInfo().getHostName(); + } + + if (event instanceof TikTokErrorEvent) { + return; + } + + includeEvent(event); + } + + @TikTokEventObserver + private void onError(LiveClient liveClient, TikTokErrorEvent event) { + event.getException().printStackTrace(); + includeError(event); + } + + + private void includeResponse(LiveClient liveClient, WebcastResponse message) { + var messageContent = Base64.getEncoder().encodeToString(message.toByteArray()); + insertDocument(createDocument("response", "webcast", messageContent)); + } + + private void includeMessage(LiveClient liveClient, WebcastResponse.Message message) { + var method = message.getMethod(); + var messageContent = Base64.getEncoder().encodeToString(message.getPayload().toByteArray()); + + insertDocument(createDocument("message", method, messageContent)); + } + + private void includeEvent(TikTokEvent event) { + var json = JsonUtil.toJson(event); + var content = Base64.getEncoder().encodeToString(json.getBytes()); + var name = event.getClass().getSimpleName(); + insertDocument(createDocument("event", name, content)); + } + + private void includeError(TikTokErrorEvent event) { + var exception = event.getException(); + var exceptionName = event.getException().getClass().getSimpleName(); + + var sw = new StringWriter(); + var pw = new PrintWriter(sw); + event.getException().printStackTrace(pw); + var content = sw.toString(); + + var doc = createDocument("error", exceptionName, content); + if (exception instanceof TikTokLiveMessageException ex) { + doc.append("message", ex.messageToBase64()) + .append("response", ex.webcastResponseToBase64()); + } + insertDocument(doc); + } + + + private void insertDocument(Document document) { + if (!settings.getFilter().apply(document)) { + return; + } + collection.insertOne(document); + } + + + private Document createDocument(String dataType, String dataTypeName, String content) { + var doc = new Document(); + doc.append("session", sessionId); + for (var entry : settings.getExtraFields().entrySet()) { + doc.append(entry.getKey(), entry.getValue()); + } + doc.append("tiktokUser", userName); + doc.append("dataType", dataType); + doc.append("dataTypeName", dataTypeName); + doc.append("content", content); + return doc; + } +} diff --git a/extension-recorder/README.md b/extension-recorder/README.md new file mode 100644 index 00000000..e69de29b diff --git a/extension-recorder/pom.xml b/extension-recorder/pom.xml new file mode 100644 index 00000000..6a9dd469 --- /dev/null +++ b/extension-recorder/pom.xml @@ -0,0 +1,39 @@ + + + + TikTokLiveJava + io.github.jwdeveloper.tiktok + 1.0.14-Release + + 4.0.0 + extension-recorder + + + io.github.jwdeveloper.tiktok + Client + 1.0.14-Release + compile + + + net.bramp.ffmpeg + ffmpeg + 0.8.0 + compile + + + io.github.jwdeveloper.tiktok + API + 1.0.17-Release + compile + + + + + 16 + 16 + UTF-8 + + + \ No newline at end of file diff --git a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/TikTokLiveRecorder.java b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/TikTokLiveRecorder.java new file mode 100644 index 00000000..ca0ad623 --- /dev/null +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/TikTokLiveRecorder.java @@ -0,0 +1,43 @@ +/* + * 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; + +import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder; +import io.github.jwdeveloper.tiktok.extension.recorder.impl.RecorderListener; +import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.RecorderSettings; + +import java.util.function.Consumer; + +public class TikTokLiveRecorder +{ + + public static LiveRecorder use(Consumer consumer) + { + return new RecorderListener(consumer); + } + + public static LiveRecorder use() + { + return use(x ->{}); + } +} diff --git a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/api/LiveRecorder.java b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/api/LiveRecorder.java new file mode 100644 index 00000000..3aa4328a --- /dev/null +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/api/LiveRecorder.java @@ -0,0 +1,31 @@ +/* + * 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.api; + +import io.github.jwdeveloper.tiktok.listener.TikTokEventListener; + +public interface LiveRecorder extends TikTokEventListener { + + void pause(); + void unpause(); +} 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 new file mode 100644 index 00000000..7956da60 --- /dev/null +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/RecorderListener.java @@ -0,0 +1,251 @@ +/* + * 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; + +import com.google.gson.JsonParser; +import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver; +import io.github.jwdeveloper.tiktok.data.events.TikTokLiveEndedEvent; +import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings; +import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder; +import io.github.jwdeveloper.tiktok.data.events.TikTokConnectedEvent; +import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent; +import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; +import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.DownloadData; +import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.RecorderSettings; +import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent; +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.http.HttpClientFactory; +import io.github.jwdeveloper.tiktok.live.LiveClient; +import net.bramp.ffmpeg.FFmpeg; +import net.bramp.ffmpeg.FFmpegExecutor; +import net.bramp.ffmpeg.RunProcessFunction; +import net.bramp.ffmpeg.builder.FFmpegBuilder; + +import java.io.*; +import java.net.URL; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class RecorderListener implements LiveRecorder { + + private final Consumer consumer; + private RecorderSettings settings; + private DownloadData downloadData; + private Thread liveDownloadThread; + + public RecorderListener(Consumer consumer) { + this.consumer = consumer; + } + + @Override + public void pause() { + + } + + @Override + public void unpause() { + + } + + @TikTokEventObserver + private void onResponse(LiveClient liveClient, TikTokRoomDataResponseEvent event) { + settings = RecorderSettings.DEFAULT(); + consumer.accept(settings); + + var json = event.getLiveData().getJson(); + + liveClient.getLogger().info("Searching for live download url"); + if (settings.getPrepareDownloadData() != null) { + downloadData = settings.getPrepareDownloadData().apply(json); + } else { + downloadData = mapToDownloadData(json); + } + + if (downloadData.getDownloadLiveUrl().isEmpty()) { + throw new TikTokLiveException("Unable to find download live url!"); + } + liveClient.getLogger().info("Live download url found!"); + + } + + @TikTokEventObserver + private void onConnected(LiveClient liveClient, TikTokConnectedEvent event) { + /* liveDownloadThread = new Thread(() -> + { + try { + var ffmpeg = new FFmpeg(settings.getFfmpegPath(), new RunProcessFunction() { + @Override + public Process run(final List args) throws IOException { + var process = super.run(args); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + terminateFfmpeg(process); + }, "FFmpeg process destroyer")); + return process; + } + }); + + var builder = new FFmpegBuilder() + .setInput(downloadData.getFullUrl()) + .addOutput(settings.getOutputPath() + File.separator + settings.getOutputFileName()) // Set the output file path + .setFormat("mp4") + .done(); + + var executor = new FFmpegExecutor(ffmpeg); + var ffmpegProcess = executor.createJob(builder, (progress)-> { + liveClient.getLogger().info("Downloading stream: " +progress.total_size); + }); + ffmpegProcess.run(); + liveClient.publishEvent(new TikTokLiveRecorderStartedEvent(downloadData)); + + } catch (Exception e) { + throw new TikTokLiveException("Unable to run ffmpeg drivers",e); + } + }); +*/ + var factory = new HttpClientFactory(LiveClientSettings.createDefault()); + var builder = factory.client(downloadData.getFullUrl()); + + /* + var path = settings.getOutputPath() + File.separator + settings.getOutputFileName(); + var file = new File(path); + file.getParentFile().mkdirs(); + */ + + liveDownloadThread = new Thread(() -> + { + var bufferSize = 1024; + try (var in = new BufferedInputStream(new URL(downloadData.getFullUrl()).openStream(), bufferSize)) { + var path = settings.getOutputPath() + File.separator + settings.getOutputFileName(); + var file = new File(path); + file.getParentFile().mkdirs(); + var fileOutputStream = new FileOutputStream(file); + byte dataBuffer[] = new byte[bufferSize]; + int bytesRead; + while ((bytesRead = in.read(dataBuffer, 0, bufferSize)) != -1) { + fileOutputStream.write(dataBuffer, 0, bytesRead); + } + } catch (IOException e) { + e.printStackTrace(); + } + }); + + + liveDownloadThread.start(); + } + + + private static void downloadUsingStream(String urlStr, String file) throws IOException { + URL url = new URL(urlStr); + BufferedInputStream bis = new BufferedInputStream(url.openStream()); + FileOutputStream fis = new FileOutputStream(file); + byte[] buffer = new byte[1024]; + int count = 0; + while ((count = bis.read(buffer, 0, 1024)) != -1) { + fis.write(buffer, 0, count); + } + fis.close(); + bis.close(); + } + + + @TikTokEventObserver + private void onDisconnected(LiveClient liveClient, TikTokDisconnectedEvent event) { + liveDownloadThread.interrupt(); + } + + @TikTokEventObserver + private void onDisconnected(LiveClient liveClient, TikTokLiveEndedEvent event) { + liveDownloadThread.interrupt(); + } + + private int terminateFfmpeg(final Process process) { + if (!process.isAlive()) { + /* + * ffmpeg -version, do nothing + */ + return process.exitValue(); + } + + /* + * ffmpeg -f x11grab + */ + System.out.println("About to destroy the child process..."); + try (final OutputStreamWriter out = new OutputStreamWriter(process.getOutputStream(), UTF_8)) { + out.write('q'); + } catch (final IOException ioe) { + ioe.printStackTrace(); + } + try { + if (!process.waitFor(5L, TimeUnit.SECONDS)) { + process.destroy(); + process.waitFor(); + } + return process.exitValue(); + } catch (final InterruptedException ie) { + System.out.println("Interrupted"); + ie.printStackTrace(); + Thread.currentThread().interrupt(); + return -1; + } + } + + private DownloadData mapToDownloadData(String json) { + + var parsedJson = JsonParser.parseString(json); + var jsonObject = parsedJson.getAsJsonObject(); + var streamDataJson = jsonObject.getAsJsonObject("data") + .getAsJsonObject("stream_url") + .getAsJsonObject("live_core_sdk_data") + .getAsJsonObject("pull_data") + .get("stream_data") + .getAsString(); + + var streamDataJsonObject = JsonParser.parseString(streamDataJson).getAsJsonObject(); + + var urlLink = streamDataJsonObject.getAsJsonObject("data") + .getAsJsonObject(LiveQuality.origin.name()) + .getAsJsonObject("main") + .get("flv") + .getAsString(); + + + var sessionId = streamDataJsonObject.getAsJsonObject("common") + .get("session_id") + .getAsString(); + + + //main + //https://pull-f5-tt03.fcdn.eu.tiktokcdn.com/stage/stream-3284937501738533765.flv?session_id=136-20240109000954BF818F1B3A8E5E39E238&_webnoredir=1 + //Working + //https://pull-f5-tt03.fcdn.eu.tiktokcdn.com/game/stream-3284937501738533765_sd5.flv?_session_id=136-20240109001052D91FDBC00143211020C8.1704759052997&_webnoredir=1 + //https://pull-f5-tt02.fcdn.eu.tiktokcdn.com/stage/stream-3861399216374940610_uhd5.flv?_session_id=136-20240109000223D0BAA1A83974490EE630.1704758544391&_webnoredir=1 + + return new DownloadData(urlLink, sessionId); + } + + +} diff --git a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/data/DownloadData.java b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/data/DownloadData.java new file mode 100644 index 00000000..0bc02601 --- /dev/null +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/data/DownloadData.java @@ -0,0 +1,39 @@ +/* + * 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.data; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class DownloadData { + + private String downloadLiveUrl; + + private String sessionId; + + public String getFullUrl() { + return downloadLiveUrl + "?_webnoredir=1&session_id=" + sessionId; + } +} diff --git a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/data/RecorderSettings.java b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/data/RecorderSettings.java new file mode 100644 index 00000000..ea4a8ec4 --- /dev/null +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/data/RecorderSettings.java @@ -0,0 +1,82 @@ +/* + * 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.data; + +import io.github.jwdeveloper.tiktok.extension.recorder.impl.enums.LiveQuality; +import io.github.jwdeveloper.tiktok.extension.recorder.impl.enums.LiveFormat; +import lombok.Getter; +import lombok.Setter; + +import java.util.function.Function; + +/** + * self, + * path: str, + * duration: Optional[int] = None, + * quality: Optional[VideoQuality] = None, + * verbose: bool = True, + * loglevel: str = "error", + * global_options: Set[str] = set(), + * inputs: Dict[str, str] = dict(), + * outputs: Dict[str, str] = dict() + * :param loglevel: Set the FFmpeg log level + * :param outputs: Pass custom params to FFmpeg outputs + * :param inputs: Pass custom params to FFmpeg inputs + * :param global_options: Pass custom params to FFmpeg global options + * :param path: The path to download the livestream video to + * :param duration: If duration is None or less than 1, download will go forever + * :param quality: If quality is None, download quality will auto + * :param verbose: Whether to log info about the download in console + */ +@Getter +@Setter +public class RecorderSettings { + private String ffmpegPath; + private String quality; + private String format; + private String outputPath; + private String outputFileName; + private Function prepareDownloadData; + private boolean startOnConnected; + + public static RecorderSettings DEFAULT() { + return new RecorderSettings(); + } + + public void setQuality(String format) { + this.format = format; + } + + public void setQuality(LiveQuality quality) { + this.quality = quality.name(); + } + + + public void setFormat(String format) { + this.format = format; + } + + public void setFormat(LiveFormat format) { + this.format = format.name(); + } +} diff --git a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/enums/LiveFormat.java b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/enums/LiveFormat.java new file mode 100644 index 00000000..e48c83c0 --- /dev/null +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/enums/LiveFormat.java @@ -0,0 +1,28 @@ +/* + * 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.enums; + +public enum LiveFormat +{ + MP4 +} diff --git a/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/enums/LiveQuality.java b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/enums/LiveQuality.java new file mode 100644 index 00000000..9171a75e --- /dev/null +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/enums/LiveQuality.java @@ -0,0 +1,27 @@ +/* + * 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.enums; + +public enum LiveQuality { + origin, hd_60, ao, hd, sd, ld,uhd_60 +} 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 new file mode 100644 index 00000000..99914a8a --- /dev/null +++ b/extension-recorder/src/main/java/io/github/jwdeveloper/tiktok/extension/recorder/impl/event/TikTokLiveRecorderStartedEvent.java @@ -0,0 +1,35 @@ +/* + * 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.DownloadData; +import lombok.AllArgsConstructor; +import lombok.Data; + +@AllArgsConstructor +@Data +public class TikTokLiveRecorderStartedEvent extends TikTokEvent +{ + DownloadData downloadData; +} diff --git a/pom.xml b/pom.xml index 74df4121..9a96d50a 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,9 @@ Tools-EventsCollector Tools-ReadmeGenerator Tools-EventsWebViewer + + extension-recorder + extension-collector From cf9b8823918093b274683c157554fbb6296d3fe4 Mon Sep 17 00:00:00 2001 From: JW Date: Sun, 14 Jan 2024 23:16:35 +0100 Subject: [PATCH 02/10] . --- .../jwdeveloper/tiktok/TikTokLiveClient.java | 5 ++- .../tiktok/http/mappers/LiveDataMapper.java | 1 + .../listener/TikTokListenersManager.java | 1 + .../jwdeveloper/tiktok/RecorderExample.java | 4 +- .../recorder/impl/RecorderListener.java | 45 +++++++++++-------- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java index 81709a07..591be517 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java @@ -26,6 +26,8 @@ import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; +import io.github.jwdeveloper.tiktok.data.events.control.TikTokConnectingEvent; +import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent; import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent; import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData; import io.github.jwdeveloper.tiktok.data.requests.LiveData; @@ -120,7 +122,7 @@ public void tryConnect() { } setState(ConnectionState.CONNECTING); - + tikTokEventHandler.publish(this,new TikTokConnectingEvent()); var userDataRequest = new LiveUserData.Request(liveRoomInfo.getHostName()); var userData = httpClient.fetchLiveUserData(userDataRequest); liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp()); @@ -134,6 +136,7 @@ public void tryConnect() { var liveDataRequest = new LiveData.Request(userData.getRoomId()); var liveData = httpClient.fetchLiveData(liveDataRequest); + tikTokEventHandler.publish(this, new TikTokRoomDataResponseEvent(liveData)); if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound) { throw new TikTokLiveOfflineHostException("LiveStream for Host name could not be found."); } diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/mappers/LiveDataMapper.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/mappers/LiveDataMapper.java index 1a9108bc..34041b44 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/mappers/LiveDataMapper.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/mappers/LiveDataMapper.java @@ -43,6 +43,7 @@ public class LiveDataMapper { public LiveData.Response map(String json) { var response = new LiveData.Response(); + response.setJson(json); var parsedJson = JsonParser.parseString(json); var jsonObject = parsedJson.getAsJsonObject(); diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/listener/TikTokListenersManager.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/listener/TikTokListenersManager.java index 16c1d968..27310637 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/listener/TikTokListenersManager.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/listener/TikTokListenersManager.java @@ -111,6 +111,7 @@ private ListenerBindingModel bindToEvents(TikTokEventListener listener) { EventConsumer eventMethodRef = (liveClient, event) -> { try { + method.setAccessible(true); method.invoke(listener, liveClient, event); } catch (Exception e) { throw new TikTokEventListenerMethodException(e); diff --git a/Examples/src/main/java/io/github/jwdeveloper/tiktok/RecorderExample.java b/Examples/src/main/java/io/github/jwdeveloper/tiktok/RecorderExample.java index 050e3df5..50b05de6 100644 --- a/Examples/src/main/java/io/github/jwdeveloper/tiktok/RecorderExample.java +++ b/Examples/src/main/java/io/github/jwdeveloper/tiktok/RecorderExample.java @@ -30,7 +30,7 @@ public class RecorderExample { public static void main(String[] args) { - TikTokLive.newClient("dash4214") + TikTokLive.newClient("bangbetmenygy") .configure(liveClientSettings -> { liveClientSettings.setPrintToConsole(true); @@ -43,7 +43,7 @@ public static void main(String[] args) { { recorderSettings.setFfmpegPath("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\extension-recorder\\libs\\ffmpeg.exe"); recorderSettings.setOutputPath("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\extension-recorder\\out"); - recorderSettings.setOutputFileName("test.mp4"); + recorderSettings.setOutputFileName("test.flv"); })) .onEvent(TikTokLiveRecorderStartedEvent.class, (liveClient, event) -> { 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 7956da60..d283c480 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 @@ -42,6 +42,7 @@ import net.bramp.ffmpeg.RunProcessFunction; import net.bramp.ffmpeg.builder.FFmpegBuilder; +import javax.net.ssl.HttpsURLConnection; import java.io.*; import java.net.URL; import java.util.List; @@ -126,31 +127,37 @@ public Process run(final List args) throws IOException { } }); */ - var factory = new HttpClientFactory(LiveClientSettings.createDefault()); - var builder = factory.client(downloadData.getFullUrl()); - - /* - var path = settings.getOutputPath() + File.separator + settings.getOutputFileName(); - var file = new File(path); - file.getParentFile().mkdirs(); - */ liveDownloadThread = new Thread(() -> { - var bufferSize = 1024; - try (var in = new BufferedInputStream(new URL(downloadData.getFullUrl()).openStream(), bufferSize)) { - var path = settings.getOutputPath() + File.separator + settings.getOutputFileName(); - var file = new File(path); - file.getParentFile().mkdirs(); - var fileOutputStream = new FileOutputStream(file); - byte dataBuffer[] = new byte[bufferSize]; - int bytesRead; - while ((bytesRead = in.read(dataBuffer, 0, bufferSize)) != -1) { - fileOutputStream.write(dataBuffer, 0, bytesRead); + try { + var bufferSize = 1024; + var url = new URL(downloadData.getFullUrl()); + HttpsURLConnection socksConnection = (HttpsURLConnection) url.openConnection(); + var headers = LiveClientSettings.DefaultRequestHeaders(); + for (var entry : headers.entrySet()) { + socksConnection.setRequestProperty(entry.getKey(), entry.getValue()); } - } catch (IOException e) { + + System.out.println(socksConnection.getResponseCode()); + try (var in = new BufferedInputStream(socksConnection.getInputStream())) { + var path = settings.getOutputPath() + File.separator + settings.getOutputFileName(); + var file = new File(path); + file.getParentFile().mkdirs(); + var fileOutputStream = new FileOutputStream(file); + byte dataBuffer[] = new byte[bufferSize]; + int bytesRead; + while ((bytesRead = in.read(dataBuffer, 0, bufferSize)) != -1) { + fileOutputStream.write(dataBuffer, 0, bytesRead); + } + } catch (IOException e) { + throw e; + } + } catch (Exception e) { e.printStackTrace(); + ; } + }); From 6bfa0b77456b883312a65431dc6a58361ff1653e Mon Sep 17 00:00:00 2001 From: kohlerpop1 Date: Sun, 14 Jan 2024 20:46:58 -0500 Subject: [PATCH 03/10] Fixed stack overflow error! --- .../src/main/java/io/github/jwdeveloper/tiktok/TikTokLive.java | 1 - .../java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLive.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLive.java index d2243195..2d67e890 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLive.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLive.java @@ -50,7 +50,6 @@ public static boolean isLiveOnline(String hostName) return requests().fetchLiveUserData(hostName).isLiveOnline(); } - /** * * @param hostName profile name of Tiktok user could be found in profile link diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java index 81709a07..34282237 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java @@ -159,8 +159,8 @@ public void disconnect() { if (liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) { return; } - webSocketClient.stop(); setState(ConnectionState.DISCONNECTED); + webSocketClient.stop(); } private void setState(ConnectionState connectionState) { From 12cf9e641b6f215cac8311e5102d27e7832807b8 Mon Sep 17 00:00:00 2001 From: kohlerpop1 Date: Sun, 14 Jan 2024 20:46:58 -0500 Subject: [PATCH 04/10] Fixed stack overflow error! --- .../src/main/java/io/github/jwdeveloper/tiktok/TikTokLive.java | 1 - .../java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLive.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLive.java index d2243195..2d67e890 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLive.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLive.java @@ -50,7 +50,6 @@ public static boolean isLiveOnline(String hostName) return requests().fetchLiveUserData(hostName).isLiveOnline(); } - /** * * @param hostName profile name of Tiktok user could be found in profile link diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java index 591be517..f0741449 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java @@ -162,8 +162,8 @@ public void disconnect() { if (liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) { return; } - webSocketClient.stop(); setState(ConnectionState.DISCONNECTED); + webSocketClient.stop(); } private void setState(ConnectionState connectionState) { From 9da96b4417c2e7dbe43501a14421afe3bc7c675b Mon Sep 17 00:00:00 2001 From: kohlerpop1 Date: Mon, 15 Jan 2024 12:32:31 -0500 Subject: [PATCH 05/10] Missed one print statement! --- .../java/io/github/jwdeveloper/tiktok/http/HttpProxyClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/HttpProxyClient.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/HttpProxyClient.java index 88b523c5..d17c4129 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/HttpProxyClient.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/HttpProxyClient.java @@ -99,7 +99,6 @@ public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {} try { Proxy proxy = new Proxy(Proxy.Type.SOCKS, proxySettings.next().toSocketAddress()); - System.err.println("Connecting to "+ url); HttpsURLConnection socksConnection = (HttpsURLConnection) url.openConnection(proxy); socksConnection.setSSLSocketFactory(sc.getSocketFactory()); socksConnection.setConnectTimeout(httpClientSettings.getTimeout().toMillisPart()); From a80584452297ff252a420502cabce9e95307cd96 Mon Sep 17 00:00:00 2001 From: kohlerpop1 Date: Mon, 15 Jan 2024 12:32:31 -0500 Subject: [PATCH 06/10] Missed one print statement! --- .../java/io/github/jwdeveloper/tiktok/http/HttpProxyClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/HttpProxyClient.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/HttpProxyClient.java index 88b523c5..d17c4129 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/HttpProxyClient.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/HttpProxyClient.java @@ -99,7 +99,6 @@ public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {} try { Proxy proxy = new Proxy(Proxy.Type.SOCKS, proxySettings.next().toSocketAddress()); - System.err.println("Connecting to "+ url); HttpsURLConnection socksConnection = (HttpsURLConnection) url.openConnection(proxy); socksConnection.setSSLSocketFactory(sc.getSocketFactory()); socksConnection.setConnectTimeout(httpClientSettings.getTimeout().toMillisPart()); From 2555edd86f42e9106beb88c7d4d7343840ffe8ba Mon Sep 17 00:00:00 2001 From: kohlerpop1 Date: Tue, 16 Jan 2024 22:09:56 -0500 Subject: [PATCH 07/10] Moved proxy declaration to inside of try, updated websocket version to 1.5.5 from 1.5.4, and cleared up ProxyExample! --- Client/pom.xml | 2 +- .../jwdeveloper/tiktok/websocket/TikTokWebSocketClient.java | 3 +-- .../main/java/io/github/jwdeveloper/tiktok/ProxyExample.java | 4 +++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Client/pom.xml b/Client/pom.xml index ec21e033..f4ba06c3 100644 --- a/Client/pom.xml +++ b/Client/pom.xml @@ -39,7 +39,7 @@ org.java-websocket Java-WebSocket - 1.5.4 + 1.5.5 org.testng diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketClient.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketClient.java index 5b32b765..60742a57 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketClient.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketClient.java @@ -22,7 +22,6 @@ */ package io.github.jwdeveloper.tiktok.websocket; - import io.github.jwdeveloper.tiktok.*; import io.github.jwdeveloper.tiktok.data.dto.ProxyData; import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData; @@ -105,7 +104,6 @@ public void connectProxy(ProxyClientSettings proxySettings) { } public boolean tryProxyConnection(ProxyClientSettings proxySettings, ProxyData proxyData) { - webSocketClient.setProxy(new Proxy(proxySettings.getType(), proxyData.toSocketAddress())); try { if (proxySettings.getType() == Proxy.Type.SOCKS) { SSLContext sc = SSLContext.getInstance("SSL"); @@ -116,6 +114,7 @@ public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {} }}, null); webSocketClient.setSocketFactory(sc.getSocketFactory()); } + webSocketClient.setProxy(new Proxy(proxySettings.getType(), proxyData.toSocketAddress())); webSocketClient.connect(); return true; } catch (Exception e) diff --git a/Examples/src/main/java/io/github/jwdeveloper/tiktok/ProxyExample.java b/Examples/src/main/java/io/github/jwdeveloper/tiktok/ProxyExample.java index 3746bf43..a70ce60d 100644 --- a/Examples/src/main/java/io/github/jwdeveloper/tiktok/ProxyExample.java +++ b/Examples/src/main/java/io/github/jwdeveloper/tiktok/ProxyExample.java @@ -38,10 +38,12 @@ public static void main(String[] args) throws Exception { }) .onConnected((liveClient, event) -> liveClient.getLogger().info("Connected "+liveClient.getRoomInfo().getHostName())) + .onComment((liveClient, event) -> liveClient.getLogger().info(event.getUser().getName()+": "+event.getText())) + .onLike((liveClient, event) -> liveClient.getLogger().info(event.getUser().getName()+" sent "+event.getLikes()+"x likes!")) .onDisconnected((liveClient, event) -> liveClient.getLogger().info("Disconnect reason: "+event.getReason())) .onLiveEnded((liveClient, event) -> - liveClient.getLogger().info("Live Ended")) + liveClient.getLogger().info("Live Ended: "+liveClient.getRoomInfo().getHostName())) .onError((liveClient, event) -> event.getException().printStackTrace()) .buildAndConnect(); From 7b4590d0a1348216294882f4a464b5e209da5236 Mon Sep 17 00:00:00 2001 From: kohlerpop1 Date: Thu, 18 Jan 2024 10:51:03 -0500 Subject: [PATCH 08/10] Fixed SimpleExample! --- .../main/java/io/github/jwdeveloper/tiktok/SimpleExample.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Examples/src/main/java/io/github/jwdeveloper/tiktok/SimpleExample.java b/Examples/src/main/java/io/github/jwdeveloper/tiktok/SimpleExample.java index e1df391a..e36586ec 100644 --- a/Examples/src/main/java/io/github/jwdeveloper/tiktok/SimpleExample.java +++ b/Examples/src/main/java/io/github/jwdeveloper/tiktok/SimpleExample.java @@ -41,7 +41,7 @@ import java.util.logging.Level; public class SimpleExample { - public static String TIKTOK_HOSTNAME = "dash4214"; + public static String TIKTOK_HOSTNAME = "dash4114"; public static void main(String[] args) throws IOException, InterruptedException { @@ -160,4 +160,4 @@ private static void showLogo() { """); } -} +} \ No newline at end of file From 8a7b9e801bd323d4733230c6848b4a312f862bac Mon Sep 17 00:00:00 2001 From: kohlerpop1 Date: Thu, 18 Jan 2024 10:58:33 -0500 Subject: [PATCH 09/10] Removed not used SimpleExample imports! --- .../io/github/jwdeveloper/tiktok/SimpleExample.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Examples/src/main/java/io/github/jwdeveloper/tiktok/SimpleExample.java b/Examples/src/main/java/io/github/jwdeveloper/tiktok/SimpleExample.java index e36586ec..858ff8f5 100644 --- a/Examples/src/main/java/io/github/jwdeveloper/tiktok/SimpleExample.java +++ b/Examples/src/main/java/io/github/jwdeveloper/tiktok/SimpleExample.java @@ -23,27 +23,18 @@ package io.github.jwdeveloper.tiktok; import io.github.jwdeveloper.tiktok.data.events.TikTokSubNotifyEvent; -import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent; import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent; import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent; -import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException; -import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage; import io.github.jwdeveloper.tiktok.utils.ConsoleColors; -import io.github.jwdeveloper.tiktok.utils.JsonUtil; import java.io.IOException; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; import java.time.Duration; -import java.util.HashMap; import java.util.logging.Level; public class SimpleExample { public static String TIKTOK_HOSTNAME = "dash4114"; - public static void main(String[] args) throws IOException, InterruptedException { + public static void main(String[] args) throws IOException { showLogo(); From 9ddec4574025db5400b961d6fc04e17495615d35 Mon Sep 17 00:00:00 2001 From: JW Date: Thu, 18 Jan 2024 17:03:50 +0100 Subject: [PATCH 10/10] Including Pinging Task --- .../websocket/TikTokWebSocketClient.java | 30 ++++++---- .../websocket/TikTokWebSocketPingingTask.java | 60 +++++++++++++++++++ .../jwdeveloper/tiktok/CollectorExample.java | 17 ++++-- .../jwdeveloper/tiktok/ListenerExample.java | 2 +- .../jwdeveloper/tiktok/ProxyExample.java | 45 ++++++++------ README.md | 8 +-- 6 files changed, 122 insertions(+), 40 deletions(-) create mode 100644 Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketPingingTask.java diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketClient.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketClient.java index 5b32b765..8e655479 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketClient.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketClient.java @@ -41,6 +41,8 @@ public class TikTokWebSocketClient implements SocketClient { private final TikTokLiveMessageHandler messageHandler; private final TikTokLiveEventHandler tikTokEventHandler; private WebSocketClient webSocketClient; + + private TikTokWebSocketPingingTask pingingTask; private boolean isConnected; public TikTokWebSocketClient( @@ -51,11 +53,11 @@ public TikTokWebSocketClient( this.messageHandler = messageHandler; this.tikTokEventHandler = tikTokEventHandler; isConnected = false; + pingingTask = new TikTokWebSocketPingingTask(); } @Override - public void start(LiveConnectionData.Response connectionData, LiveClient liveClient) - { + public void start(LiveConnectionData.Response connectionData, LiveClient liveClient) { if (isConnected) { stop(); } @@ -74,16 +76,16 @@ public void start(LiveConnectionData.Response connectionData, LiveClient liveCli // ProxyClientSettings proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings(); // if (proxyClientSettings.isEnabled()) // connectProxy(proxyClientSettings); - // else - connectDefault(); + // else + connectDefault(); } private void connectDefault() { try { webSocketClient.connect(); + pingingTask.run(webSocketClient); isConnected = true; - } catch (Exception e) - { + } catch (Exception e) { isConnected = false; throw new TikTokLiveException("Failed to connect to the websocket", e); } @@ -110,16 +112,21 @@ public boolean tryProxyConnection(ProxyClientSettings proxySettings, ProxyData p if (proxySettings.getType() == Proxy.Type.SOCKS) { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, new TrustManager[]{new X509TrustManager() { - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {} - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {} - public X509Certificate[] getAcceptedIssuers() { return null; } + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) { + } + + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) { + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } }}, null); webSocketClient.setSocketFactory(sc.getSocketFactory()); } webSocketClient.connect(); return true; - } catch (Exception e) - { + } catch (Exception e) { return false; } } @@ -127,6 +134,7 @@ public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {} public void stop() { if (isConnected && webSocketClient != null && webSocketClient.isOpen()) { webSocketClient.closeConnection(0, ""); + pingingTask.stop(); } webSocketClient = null; isConnected = false; diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketPingingTask.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketPingingTask.java new file mode 100644 index 00000000..be104067 --- /dev/null +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketPingingTask.java @@ -0,0 +1,60 @@ +package io.github.jwdeveloper.tiktok.websocket; + +import org.java_websocket.WebSocket; + +import java.util.Random; + +public class TikTokWebSocketPingingTask +{ + private Thread thread; + private boolean isRunning = false; + private final int MIN_TIMEOUT = 250; + private final int MAX_TIMEOUT = 500; + + + public void run(WebSocket webSocket) + { + stop(); + thread = new Thread(() -> + { + pingTask(webSocket); + }); + isRunning =true; + thread.start(); + } + + public void stop() + { + if(thread != null) + { + thread.interrupt(); + } + isRunning = false; + } + + + private void pingTask(WebSocket webSocket) + { + var random = new Random(); + while (isRunning) + { + try + { + if(!webSocket.isOpen()) + { + Thread.sleep(100); + continue; + } + webSocket.sendPing(); + + var timeout = random.nextInt(MAX_TIMEOUT)+MIN_TIMEOUT; + Thread.sleep(timeout); + } + catch (Exception e) + { + isRunning = false; + } + } + + } +} diff --git a/Examples/src/main/java/io/github/jwdeveloper/tiktok/CollectorExample.java b/Examples/src/main/java/io/github/jwdeveloper/tiktok/CollectorExample.java index e4a1e0fe..e00f6cd3 100644 --- a/Examples/src/main/java/io/github/jwdeveloper/tiktok/CollectorExample.java +++ b/Examples/src/main/java/io/github/jwdeveloper/tiktok/CollectorExample.java @@ -30,16 +30,24 @@ import java.util.Map; public class CollectorExample { + + + private static String mongoUser; + + private static String mongoPassword; + + private static String mongoDatabase; + public static void main(String[] args) throws IOException { var collector = TikTokLiveCollector.use(settings -> { - settings.setConnectionUrl("mongodb+srv://jwoln:qaz123456@jwdatabase.a15gw.mongodb.net/?retryWrites=true&w=majority"); + settings.setConnectionUrl("mongodb+srv://" + mongoUser + ":" + mongoPassword + "@" + mongoDatabase + "/?retryWrites=true&w=majority"); settings.setDatabaseName("tiktok"); }); collector.connectDatabase(); - var users = List.of("tehila_723", "dino123597", "domaxyzx", "dash4214","obserwacje_live"); + var users = List.of("tehila_723", "dino123597", "domaxyzx", "dash4214", "obserwacje_live"); var sessionTag = "Dupa"; for (var user : users) { TikTokLive.newClient(user) @@ -51,10 +59,9 @@ public static void main(String[] args) throws IOException { { event.getException().printStackTrace(); }) - .addListener(collector.newListener(Map.of("sessionTag", sessionTag),document -> + .addListener(collector.newListener(Map.of("sessionTag", sessionTag), document -> { - if(document.get("dataType") == "message") - { + if (document.get("dataType") == "message") { return false; } return true; diff --git a/Examples/src/main/java/io/github/jwdeveloper/tiktok/ListenerExample.java b/Examples/src/main/java/io/github/jwdeveloper/tiktok/ListenerExample.java index a9aa3dd1..f4cde537 100644 --- a/Examples/src/main/java/io/github/jwdeveloper/tiktok/ListenerExample.java +++ b/Examples/src/main/java/io/github/jwdeveloper/tiktok/ListenerExample.java @@ -57,7 +57,7 @@ public static void main(String[] args) throws IOException { /** * * Method in TikTokEventListener should meet 4 requirements to be detected - * - must have @TikTokEventHandler annotation + * - must have @TikTokEventObserver annotation * - must have 2 parameters * - first parameter must be LiveClient * - second must be class that extending TikTokEvent diff --git a/Examples/src/main/java/io/github/jwdeveloper/tiktok/ProxyExample.java b/Examples/src/main/java/io/github/jwdeveloper/tiktok/ProxyExample.java index 3746bf43..9c140cc0 100644 --- a/Examples/src/main/java/io/github/jwdeveloper/tiktok/ProxyExample.java +++ b/Examples/src/main/java/io/github/jwdeveloper/tiktok/ProxyExample.java @@ -24,27 +24,34 @@ import java.net.Proxy; -public class ProxyExample -{ +public class ProxyExample { public static void main(String[] args) throws Exception { TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME) - .configure(clientSettings -> { - clientSettings.setPrintToConsole(true); - clientSettings.getHttpSettings().configureProxy(proxySettings -> { - proxySettings.setOnProxyUpdated(proxyData -> System.err.println("Next proxy: " + proxyData.toString())); - proxySettings.setType(Proxy.Type.SOCKS); - proxySettings.addProxy("localhost", 8080); - }); - }) - .onConnected((liveClient, event) -> - liveClient.getLogger().info("Connected "+liveClient.getRoomInfo().getHostName())) - .onDisconnected((liveClient, event) -> - liveClient.getLogger().info("Disconnect reason: "+event.getReason())) - .onLiveEnded((liveClient, event) -> - liveClient.getLogger().info("Live Ended")) - .onError((liveClient, event) -> - event.getException().printStackTrace()) - .buildAndConnect(); + .configure(clientSettings -> { + clientSettings.setPrintToConsole(true); + clientSettings.getHttpSettings().configureProxy(proxySettings -> { + proxySettings.setOnProxyUpdated(proxyData -> System.err.println("Next proxy: " + proxyData.toString())); + proxySettings.setType(Proxy.Type.SOCKS); + proxySettings.addProxy("localhost", 8080); + }); + }) + .onConnected((liveClient, event) -> + { + liveClient.getLogger().info("Connected " + liveClient.getRoomInfo().getHostName()); + }) + .onDisconnected((liveClient, event) -> + { + liveClient.getLogger().info("Disconnect reason: " + event.getReason()); + }) + .onLiveEnded((liveClient, event) -> + { + liveClient.getLogger().info("Live Ended"); + }) + .onError((liveClient, event) -> + { + event.getException().printStackTrace(); + }) + .buildAndConnect(); System.in.read(); } } \ No newline at end of file diff --git a/README.md b/README.md index f5ba958a..a0d7ac72 100644 --- a/README.md +++ b/README.md @@ -652,24 +652,24 @@ public static void main(String[] args) throws IOException { public static class CustomListener implements TikTokEventListener { - @TikTokEventHandler + @TikTokEventObserver public void onLike(LiveClient liveClient, TikTokLikeEvent event) { System.out.println(event.toString()); } - @TikTokEventHandler + @TikTokEventObserver public void onError(LiveClient liveClient, TikTokErrorEvent event) { // event.getException().printStackTrace(); } - @TikTokEventHandler + @TikTokEventObserver public void onComment(LiveClient liveClient, TikTokCommentEvent event) { var userName = event.getUser().getName(); var text = event.getText(); liveClient.getLogger().info(userName + ": " + text); } - @TikTokEventHandler + @TikTokEventObserver public void onGift(LiveClient liveClient, TikTokGiftEvent event) { var message = switch (event.getGift()) { case ROSE -> "Thanks :)";