mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-27 08:49:40 -05:00
.
This commit is contained in:
@@ -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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -60,6 +60,18 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<artifactId>extension-collector</artifactId>
|
||||||
|
<version>1.0.14-Release</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<artifactId>extension-recorder</artifactId>
|
||||||
|
<version>1.0.14-Release</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
0
extension-collector/README.md
Normal file
0
extension-collector/README.md
Normal file
41
extension-collector/pom.xml
Normal file
41
extension-collector/pom.xml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
|
<version>1.0.14-Release</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
|
||||||
|
<artifactId>extension-collector</artifactId>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<artifactId>API</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.protobuf</groupId>
|
||||||
|
<artifactId>protobuf-java</artifactId>
|
||||||
|
<version>3.24.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mongodb</groupId>
|
||||||
|
<artifactId>mongodb-driver-sync</artifactId>
|
||||||
|
<version>4.4.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<artifactId>API</artifactId>
|
||||||
|
<version>1.0.17-Release</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -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<LiveDataCollectorSettings> consumer)
|
||||||
|
{
|
||||||
|
var settings = new LiveDataCollectorSettings();
|
||||||
|
consumer.accept(settings);
|
||||||
|
return new TikTokLiveDataCollector(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<String, Object> extraFields;
|
||||||
|
private Function<Document, Boolean> filter;
|
||||||
|
}
|
||||||
@@ -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<MongoDBConnectionStringBuilder> consumer) {
|
||||||
|
var builder = new MongoDBConnectionStringBuilder();
|
||||||
|
consumer.accept(builder);
|
||||||
|
connectionUrl = builder.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<Document> 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<String, Object> additionalFields) {
|
||||||
|
return newListener(additionalFields, (e)->true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TikTokLiveDataCollectorListener newListener(Map<String, Object> additionalFields,
|
||||||
|
Function<Document, Boolean> filter) {
|
||||||
|
var settings = new CollectorListenerSettings();
|
||||||
|
settings.setExtraFields(additionalFields);
|
||||||
|
settings.setFilter(filter);
|
||||||
|
return new TikTokLiveDataCollectorListener(collection, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<Document> collection;
|
||||||
|
private final CollectorListenerSettings settings;
|
||||||
|
private String sessionId;
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
public TikTokLiveDataCollectorListener(MongoCollection<Document> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
extension-recorder/README.md
Normal file
0
extension-recorder/README.md
Normal file
39
extension-recorder/pom.xml
Normal file
39
extension-recorder/pom.xml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<version>1.0.14-Release</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>extension-recorder</artifactId>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<artifactId>Client</artifactId>
|
||||||
|
<version>1.0.14-Release</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.bramp.ffmpeg</groupId>
|
||||||
|
<artifactId>ffmpeg</artifactId>
|
||||||
|
<version>0.8.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<artifactId>API</artifactId>
|
||||||
|
<version>1.0.17-Release</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>16</maven.compiler.source>
|
||||||
|
<maven.compiler.target>16</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -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<RecorderSettings> consumer)
|
||||||
|
{
|
||||||
|
return new RecorderListener(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LiveRecorder use()
|
||||||
|
{
|
||||||
|
return use(x ->{});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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<RecorderSettings> consumer;
|
||||||
|
private RecorderSettings settings;
|
||||||
|
private DownloadData downloadData;
|
||||||
|
private Thread liveDownloadThread;
|
||||||
|
|
||||||
|
public RecorderListener(Consumer<RecorderSettings> 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<String> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<String,DownloadData> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
3
pom.xml
3
pom.xml
@@ -16,6 +16,9 @@
|
|||||||
<module>Tools-EventsCollector</module>
|
<module>Tools-EventsCollector</module>
|
||||||
<module>Tools-ReadmeGenerator</module>
|
<module>Tools-ReadmeGenerator</module>
|
||||||
<module>Tools-EventsWebViewer</module>
|
<module>Tools-EventsWebViewer</module>
|
||||||
|
|
||||||
|
<module>extension-recorder</module>
|
||||||
|
<module>extension-collector</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
Reference in New Issue
Block a user