Compare commits

...

33 Commits

Author SHA1 Message Date
David Kohler
498d34a90b Merge pull request #69 from jwdeveloper/develop-1.5.4
Changed isNotClosing to isOpen
2024-04-01 22:27:09 -04:00
kohlerpop1
103ed7e3ed Changed isNotClosing to isOpen because if isOpen is false inside of any of the using methods, it throws an exception. 2024-03-31 20:19:24 -04:00
GitHub Action
67e70c34bc Update version in pom.xml 2024-03-03 21:42:11 +00:00
JW
786c24d267 Merge remote-tracking branch 'origin/master' 2024-03-03 22:40:11 +01:00
JW
966d2f65d8 - improve recorder 2024-03-03 22:39:44 +01:00
GitHub Action
7ba7143f5a Update version in pom.xml 2024-03-02 09:57:33 +00:00
JW
92fde03f2b - improve collector 2024-03-02 10:55:44 +01:00
GitHub Action
e058290118 Update version in pom.xml 2024-03-01 23:17:33 +00:00
David Kohler
d25741b229 Merge pull request #67 from jwdeveloper/develop-1.5.1
Fix for mapping of HttpResponse & HttpRequest and more!
2024-03-01 18:15:41 -05:00
kohlerpop1
560a8d7c3b Added IllegalStateException to LiveUserDataMapper to catch getAsJsonObject exception.
Created HttpRequestJsonMapper and HttpResponseJsonMapper for ActionResult gson parser.
2024-03-01 16:08:05 -05:00
GitHub Action
6178bc25cf Update version in pom.xml 2024-03-01 01:54:49 +00:00
Jacek W
48d1138754 MINOR 2024-03-01 02:53:04 +01:00
Jacek W
a5320db820 Merge pull request #63 from jwdeveloper/develop-1.5.0
Develop 1.5.0
2024-03-01 02:51:35 +01:00
JW
4e1ab35a60 Merge branch 'master' into develop-1.5.0
# Conflicts:
#	Tools-EventsCollector/pom.xml
#	Tools-EventsWebViewer/pom.xml
2024-03-01 02:50:35 +01:00
David Kohler
cef4972f37 Merge pull request #64 from jwdeveloper/develop-1.5.0-live-user-data-fix
Develop 1.5.0 live user data fix
2024-02-29 20:42:36 -05:00
JW
713c90a271 . 2024-03-01 02:42:23 +01:00
kohlerpop1
71853db5cc Merge remote-tracking branch 'origin/develop-1.5.0' into develop-1.5.0-live-user-data-fix
# Conflicts:
#	Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClient.java
2024-02-29 20:38:53 -05:00
kohlerpop1
ef90d4cd58 Moved validation to TikTokLiveClientBuilder#validate! 2024-02-29 20:38:05 -05:00
Jacek W
dad4048bc0 Merge pull request #65 from jwdeveloper/develop-1.5.0-publishing-messages
- implementing publishing messages
2024-03-01 02:35:52 +01:00
kohlerpop1
9ba049d37a Fixed CollectorExample and removed useless @Setter in MongoDataCollectorSettings! 2024-02-29 20:27:41 -05:00
kohlerpop1
f7d657371b Merge remote-tracking branch 'origin/develop-1.5.0' into develop-1.5.0-live-user-data-fix
# Conflicts:
#	extension-collector/src/main/java/io/github/jwdeveloper/tiktok/extension/collector/api/settings/mongo/MongoDataCollectorSettings.java
2024-02-29 20:23:32 -05:00
JW
eea691a5aa - implementing publishing messages 2024-03-01 02:20:11 +01:00
Jacek W
a249ac0cdd Merge pull request #62 from jwdeveloper/develop-1.5.0-messages-to-file
Develop 1.5.0 messages to file
2024-03-01 01:53:21 +01:00
JW
b82c7184b3 Removed unused projects. 2024-03-01 01:52:54 +01:00
kohlerpop1
29631ac468 Fixed Live User Data Mapper throwing MalformedJsonException! 2024-02-29 19:19:23 -05:00
kohlerpop1
15c642297c Fixed Live User Data Mapper throwing MalformedJsonException! 2024-02-28 21:03:00 -05:00
kohlerpop1
d3004d76c1 Merge remote-tracking branch 'origin/develop-1.5.0' into develop-1.5.0/messages-to-file 2024-02-28 12:27:05 -05:00
kohlerpop1
3ae73072ff Working on collecting to files! 2024-02-28 12:24:34 -05:00
Jacek W
9c5f97157a Merge pull request #61 from jwdeveloper/develop-1.5.0-remove-old-stuff
Develop 1.5.0 remove old stuff
2024-02-28 16:45:49 +01:00
GitHub Action
ead954dd27 Update version in pom.xml 2024-02-26 15:26:34 +00:00
Jacek W
e37b30ff12 MINOR 2024-02-26 16:20:47 +01:00
GitHub Action
7a5c00d99a Update version in pom.xml 2024-02-26 15:17:09 +00:00
Jacek W
407f51fa73 Merge pull request #59 from jwdeveloper/develop-1.4.0
MINOR update
2024-02-26 16:15:37 +01:00
38 changed files with 529 additions and 318 deletions

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.3.0-Release</version> <version>1.5.3-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>API</artifactId> <artifactId>API</artifactId>

View File

@@ -86,9 +86,15 @@ public class LiveClientSettings {
private HttpClientSettings httpSettings; private HttpClientSettings httpSettings;
/** /**
* Optional: Sometimes not every messages from chat are send to TikTokLiveJava to fix this issue you can set sessionId * Interval of time in milliseconds between pings to TikTok
* documentation how to obtain sessionId https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages * @apiNote Min: 250 (0.25 seconds), Default: 5000 (5 seconds)
*/ */
private long pingInterval = 5000;
/**
* Optional: Sometimes not every messages from chat are send to TikTokLiveJava to fix this issue you can set sessionId
* @see <a href="https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages">Documentation: How to obtain sessionId</a>
*/
private String sessionId; private String sessionId;
/** /**

View File

@@ -59,9 +59,16 @@ public interface LiveClient {
/** /**
* Use to manually invoke event * Use to manually invoke event
*/ */
void publishEvent(TikTokEvent event); void publishEvent(TikTokEvent event);
void publishMessage(String base64);
/**
* @param webcastMessageName name of TikTok protocol-buffer message
* @param payloadBase64 protocol-buffer message bytes payload
*/
void publishMessage(String webcastMessageName, String payloadBase64);
void publishMessage(String webcastMessageName, byte[] payload);
/** /**
* Get information about gifts * Get information about gifts

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.3.0-Release</version> <version>1.5.3-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -28,7 +28,6 @@ import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.live.GiftsManager; import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder; import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class TikTokLive { public class TikTokLive {
@@ -102,14 +101,9 @@ public class TikTokLive {
* @return GiftsManager * @return GiftsManager
*/ */
public static GiftsManager gifts() { public static GiftsManager gifts() {
if (giftsManager != null) { if (giftsManager == null) {
return giftsManager; synchronized (GiftsManager.class) {
} giftsManager = new TikTokGiftsManager(requests().fetchGiftsData().getGifts());
synchronized (GiftsManager.class)
{
if (giftsManager == null)
{
return new TikTokGiftsManager(requests().fetchGiftsData().getGifts());
} }
} }
return giftsManager; return giftsManager;

View File

@@ -22,6 +22,7 @@
*/ */
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent;
@@ -39,10 +40,12 @@ import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.live.GiftsManager; import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo; import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.models.ConnectionState; import io.github.jwdeveloper.tiktok.models.ConnectionState;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings; import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.websocket.SocketClient; import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import java.util.Base64;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -56,15 +59,19 @@ public class TikTokLiveClient implements LiveClient {
private final TikTokListenersManager listenersManager; private final TikTokListenersManager listenersManager;
private final Logger logger; private final Logger logger;
private final GiftsManager giftsManager; private final GiftsManager giftsManager;
private final TikTokLiveMessageHandler messageHandler;
public TikTokLiveClient(GiftsManager giftsManager, public TikTokLiveClient(
TikTokRoomInfo tikTokLiveMeta, TikTokLiveMessageHandler messageHandler,
LiveHttpClient tiktokHttpClient, GiftsManager giftsManager,
SocketClient webSocketClient, TikTokRoomInfo tikTokLiveMeta,
TikTokLiveEventHandler tikTokEventHandler, LiveHttpClient tiktokHttpClient,
LiveClientSettings clientSettings, SocketClient webSocketClient,
TikTokListenersManager listenersManager, TikTokLiveEventHandler tikTokEventHandler,
Logger logger) { LiveClientSettings clientSettings,
TikTokListenersManager listenersManager,
Logger logger) {
this.messageHandler = messageHandler;
this.giftsManager = giftsManager; this.giftsManager = giftsManager;
this.liveRoomInfo = tikTokLiveMeta; this.liveRoomInfo = tikTokLiveMeta;
this.httpClient = tiktokHttpClient; this.httpClient = tiktokHttpClient;
@@ -184,6 +191,20 @@ public class TikTokLiveClient implements LiveClient {
tikTokEventHandler.publish(this, event); tikTokEventHandler.publish(this, event);
} }
@Override
public void publishMessage(String webcastMessageName, String payloadBase64) {
this.publishMessage(webcastMessageName, Base64.getDecoder().decode(payloadBase64));
}
@Override
public void publishMessage(String webcastMessageName, byte[] payload) {
var builder = WebcastResponse.Message.newBuilder();
builder.setMethod(webcastMessageName);
builder.setPayload(ByteString.copyFrom(payload));
var message = builder.build();
messageHandler.handleSingleMessage(this, message);
}
@Override @Override
public GiftsManager getGiftManager() { public GiftsManager getGiftManager() {
return giftsManager; return giftsManager;

View File

@@ -96,6 +96,9 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
if (clientSettings.getHostName().startsWith("@")) if (clientSettings.getHostName().startsWith("@"))
clientSettings.setHostName(clientSettings.getHostName().substring(1)); clientSettings.setHostName(clientSettings.getHostName().substring(1));
if (clientSettings.getPingInterval() < 250)
throw new TikTokLiveException("Minimum allowed ping interval is 250 millseconds");
var httpSettings = clientSettings.getHttpSettings(); var httpSettings = clientSettings.getHttpSettings();
httpSettings.getParams().put("app_language", clientSettings.getClientLanguage()); httpSettings.getParams().put("app_language", clientSettings.getClientLanguage());
httpSettings.getParams().put("webcast_language", clientSettings.getClientLanguage()); httpSettings.getParams().put("webcast_language", clientSettings.getClientLanguage());
@@ -129,6 +132,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
eventHandler); eventHandler);
return new TikTokLiveClient( return new TikTokLiveClient(
messageHandler,
giftsManager, giftsManager,
tiktokRoomInfo, tiktokRoomInfo,
liveHttpClient, liveHttpClient,

View File

@@ -83,7 +83,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
.toJsonResponse(); .toJsonResponse();
if (result.isFailure()) if (result.isFailure())
throw new TikTokLiveRequestException("Unable to fetch gifts information's"+result.toStack()); throw new TikTokLiveRequestException("Unable to fetch gifts information's - "+result);
var json = result.getContent(); var json = result.getContent();
return giftsDataMapper.map(json); return giftsDataMapper.map(json);
@@ -111,10 +111,10 @@ public class TikTokLiveHttpClient implements LiveHttpClient
.toJsonResponse(); .toJsonResponse();
if (result.isFailure()) if (result.isFailure())
throw new TikTokLiveRequestException("Unable to get information's about user"+result.toStack()); throw new TikTokLiveRequestException("Unable to get information's about user - "+result);
var json = result.getContent(); var json = result.getContent();
return liveUserDataMapper.map(json); return liveUserDataMapper.map(json, logger);
} }
@Override @Override
@@ -138,7 +138,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
.toJsonResponse(); .toJsonResponse();
if (result.isFailure()) if (result.isFailure())
throw new TikTokLiveRequestException("Unable to get info about live room"+result.toStack()); throw new TikTokLiveRequestException("Unable to get info about live room - "+result);
var json = result.getContent(); var json = result.getContent();
return liveDataMapper.map(json); return liveDataMapper.map(json);
@@ -153,7 +153,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
var resultHeader = ActionResult.of(credentialsResponse.headers().firstValue("x-set-tt-cookie")); var resultHeader = ActionResult.of(credentialsResponse.headers().firstValue("x-set-tt-cookie"));
if (resultHeader.isFailure()) { if (resultHeader.isFailure()) {
logger.warning("SignServer Headers: "+request.getRoomId()+" - "+credentialsResponse.headers().map()); logger.warning("SignServer Headers: "+request.getRoomId()+" - "+credentialsResponse.headers().map());
throw new TikTokSignServerException("Sign server did not return the x-set-tt-cookie header"+result.toStack()); throw new TikTokSignServerException("Sign server did not return the x-set-tt-cookie header - "+result);
} }
var websocketCookie = resultHeader.getContent(); var websocketCookie = resultHeader.getContent();
var webcastResponse = WebcastResponse.parseFrom(credentialsResponse.body()); var webcastResponse = WebcastResponse.parseFrom(credentialsResponse.body());
@@ -169,7 +169,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
return new LiveConnectionData.Response(websocketCookie, webSocketUrl, webcastResponse); return new LiveConnectionData.Response(websocketCookie, webSocketUrl, webcastResponse);
} catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) {
throw new TikTokSignServerException("Unable to parse websocket credentials response to WebcastResponse"+result.toStack()); throw new TikTokSignServerException("Unable to parse websocket credentials response to WebcastResponse - "+result);
} }
} }
@@ -197,7 +197,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
var result = builder.build().toResponse(); var result = builder.build().toResponse();
if (result.isFailure()) if (result.isFailure())
throw new TikTokSignServerException("Unable to get websocket connection credentials"+result.toStack()); throw new TikTokSignServerException("Unable to get websocket connection credentials - "+result);
return result; return result;
} }

View File

@@ -1,16 +1,27 @@
package io.github.jwdeveloper.tiktok.common; package io.github.jwdeveloper.tiktok.common;
import com.google.gson.*;
import io.github.jwdeveloper.tiktok.http.mappers.*;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors;
import java.net.http.*;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
@Data @Data
public class ActionResult<T> { public class ActionResult<T> {
private static final Gson gson = new Gson().newBuilder().disableHtmlEscaping()
.registerTypeHierarchyAdapter(HttpResponse.class, new HttpResponseJsonMapper())
.registerTypeHierarchyAdapter(HttpRequest.class, new HttpRequestJsonMapper())
.setPrettyPrinting().create();
private boolean success = true; private boolean success = true;
private T content; private T content;
private String message; private String message;
@Accessors(chain = true, fluent = true)
private ActionResult<?> previous;
protected ActionResult(T object) { protected ActionResult(T object) {
this.content = object; this.content = object;
@@ -41,8 +52,9 @@ public class ActionResult<T> {
public boolean hasMessage() { public boolean hasMessage() {
return message != null; return message != null;
} }
public String toStack() {
return hasMessage() ? " - "+message : ""; public boolean hasPrevious() {
return previous != null;
} }
public boolean hasContent() { public boolean hasContent() {
@@ -84,4 +96,18 @@ public class ActionResult<T> {
public static <T> ActionResult<T> failure() { public static <T> ActionResult<T> failure() {
return failure(null); return failure(null);
} }
public JsonObject toJson() {
JsonObject map = new JsonObject();
map.addProperty("success", success);
map.add("content", gson.toJsonTree(content));
map.addProperty("message", message);
map.add("previous", hasPrevious() ? previous.toJson() : null);
return map;
}
@Override
public String toString() {
return "ActionResult: "+gson.toJson(toJson());
}
} }

View File

@@ -1,5 +1,8 @@
package io.github.jwdeveloper.tiktok.common; package io.github.jwdeveloper.tiktok.common;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -7,6 +10,8 @@ public class ActionResultBuilder<T>
{ {
private final T content; private final T content;
private String message; private String message;
@Setter @Accessors(fluent = true, chain = true)
private ActionResult<?> previous;
public ActionResultBuilder(T content) { public ActionResultBuilder(T content) {
this.content = content; this.content = content;
@@ -18,10 +23,10 @@ public class ActionResultBuilder<T>
} }
public ActionResult<T> success() { public ActionResult<T> success() {
return ActionResult.success(content, message); return ActionResult.success(content, message).previous(previous);
} }
public ActionResult<T> failure() { public ActionResult<T> failure() {
return ActionResult.success(content, message); return ActionResult.success(content, message).previous(previous);
} }
} }

View File

@@ -0,0 +1,21 @@
package io.github.jwdeveloper.tiktok.http.mappers;
import com.google.gson.*;
import java.lang.reflect.Type;
import java.net.http.HttpRequest;
public class HttpRequestJsonMapper implements JsonSerializer<HttpRequest>
{
@Override
public JsonElement serialize(HttpRequest src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.addProperty("method", src.method());
object.add("timeout", context.serialize(src.timeout().toString()));
object.addProperty("expectContinue", src.expectContinue());
object.add("uri", context.serialize(src.uri()));
object.add("version", context.serialize(src.version().toString()));
object.add("headers", context.serialize(src.headers().map()));
return object;
}
}

View File

@@ -0,0 +1,21 @@
package io.github.jwdeveloper.tiktok.http.mappers;
import com.google.gson.*;
import java.lang.reflect.Type;
import java.net.http.HttpResponse;
public class HttpResponseJsonMapper implements JsonSerializer<HttpResponse>
{
@Override
public JsonElement serialize(HttpResponse src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.addProperty("statusCode", src.statusCode());
object.add("request", context.serialize(src.request()));
object.add("headers", context.serialize(src.headers().map()));
object.add("body", context.serialize(src.body()));
object.add("uri", context.serialize(src.uri().toString()));
object.add("version", context.serialize(src.version().toString()));
return object;
}
}

View File

@@ -22,45 +22,52 @@
*/ */
package io.github.jwdeveloper.tiktok.http.mappers; package io.github.jwdeveloper.tiktok.http.mappers;
import com.google.gson.JsonParser; import com.google.gson.*;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData; import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import java.util.logging.Logger;
public class LiveUserDataMapper public class LiveUserDataMapper
{ {
public LiveUserData.Response map(String json) { public LiveUserData.Response map(String json, Logger logger) {
var jsonObject = JsonParser.parseString(json).getAsJsonObject(); try {
var jsonObject = JsonParser.parseString(json).getAsJsonObject();
var message = jsonObject.get("message").getAsString(); var message = jsonObject.get("message").getAsString();
if (message.equals("params_error")) { if (message.equals("params_error")) {
throw new TikTokLiveRequestException("fetchRoomIdFromTiktokApi -> Unable to fetch roomID, contact the developer"); throw new TikTokLiveRequestException("fetchRoomIdFromTiktokApi -> Unable to fetch roomID, contact the developer");
} }
if (message.equals("user_not_found")) { if (message.equals("user_not_found")) {
return new LiveUserData.Response(json, LiveUserData.UserStatus.NotFound, "", -1);
}
//live -> status 2
//live paused -> 3
//not live -> status 4
var element = jsonObject.get("data");
if (element.isJsonNull()) {
return new LiveUserData.Response(json, LiveUserData.UserStatus.NotFound, "", -1);
}
var data = element.getAsJsonObject();
var user = data.getAsJsonObject("user");
var roomId = user.get("roomId").getAsString();
var status = user.get("status").getAsInt();
var liveRoom = data.getAsJsonObject("liveRoom");
long startTime = liveRoom.get("startTime").getAsLong();
var statusEnum = switch (status) {
case 2 -> LiveUserData.UserStatus.Live;
case 3 -> LiveUserData.UserStatus.LivePaused;
case 4 -> LiveUserData.UserStatus.Offline;
default -> LiveUserData.UserStatus.NotFound;
};
return new LiveUserData.Response(json, statusEnum, roomId, startTime);
} catch (JsonSyntaxException | IllegalStateException e) {
logger.warning("Malformed Json: '"+json+"' - Error Message: "+e.getMessage());
return new LiveUserData.Response(json, LiveUserData.UserStatus.NotFound, "", -1); return new LiveUserData.Response(json, LiveUserData.UserStatus.NotFound, "", -1);
} }
//live -> status 2
//live paused -> 3
//not live -> status 4
var element = jsonObject.get("data");
if (element.isJsonNull()) {
return new LiveUserData.Response(json, LiveUserData.UserStatus.NotFound, "", -1);
}
var data = element.getAsJsonObject();
var user = data.getAsJsonObject("user");
var roomId = user.get("roomId").getAsString();
var status = user.get("status").getAsInt();
var liveRoom = data.getAsJsonObject("liveRoom");
long startTime = liveRoom.get("startTime").getAsLong();
var statusEnum = switch (status) {
case 2 -> LiveUserData.UserStatus.Live;
case 3 -> LiveUserData.UserStatus.LivePaused;
case 4 -> LiveUserData.UserStatus.Offline;
default -> LiveUserData.UserStatus.NotFound;
};
return new LiveUserData.Response(json, statusEnum, roomId, startTime);
} }
} }

View File

@@ -82,7 +82,7 @@ public class TikTokWebSocketClient implements SocketClient {
private void connectDefault() { private void connectDefault() {
try { try {
webSocketClient.connect(); webSocketClient.connect();
pingingTask.run(webSocketClient); pingingTask.run(webSocketClient, clientSettings.getPingInterval());
isConnected = true; isConnected = true;
} catch (Exception e) { } catch (Exception e) {
isConnected = false; isConnected = false;
@@ -112,7 +112,7 @@ public class TikTokWebSocketClient implements SocketClient {
proxySettings.remove(); proxySettings.remove();
continue; continue;
} }
pingingTask.run(webSocketClient); pingingTask.run(webSocketClient, clientSettings.getPingInterval());
isConnected = true; isConnected = true;
break; break;
} }

View File

@@ -61,7 +61,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
} catch (Exception e) { } catch (Exception e) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e)); tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e));
} }
if (isNotClosing()) { if (isOpen()) {
sendPing(); sendPing();
} }
} }
@@ -79,8 +79,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
pushFrameBuilder.setPayloadType("ack"); pushFrameBuilder.setPayloadType("ack");
pushFrameBuilder.setLogId(websocketPushFrame.getLogId()); pushFrameBuilder.setLogId(websocketPushFrame.getLogId());
pushFrameBuilder.setPayload(webcastResponse.getInternalExtBytes()); pushFrameBuilder.setPayload(webcastResponse.getInternalExtBytes());
if (isNotClosing()) if (isOpen()) {
{
this.send(pushFrameBuilder.build().toByteArray()); this.send(pushFrameBuilder.build().toByteArray());
} }
} }
@@ -90,7 +89,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
@Override @Override
public void onOpen(ServerHandshake serverHandshake) { public void onOpen(ServerHandshake serverHandshake) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokConnectedEvent()); tikTokEventHandler.publish(tikTokLiveClient, new TikTokConnectedEvent());
if (isNotClosing()) { if (isOpen()) {
sendPing(); sendPing();
} }
} }
@@ -104,7 +103,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
@Override @Override
public void onError(Exception error) { public void onError(Exception error) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(error)); tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(error));
if (isNotClosing()) { if (isOpen()) {
sendPing(); sendPing();
} }
} }
@@ -129,10 +128,6 @@ public class TikTokWebSocketListener extends WebSocketClient {
} }
} }
private boolean isNotClosing() {
return !isClosed() && !isClosing();
}
@Override @Override
public void onMessage(String s) { public void onMessage(String s) {
// System.err.println(s); // System.err.println(s);

View File

@@ -8,13 +8,13 @@ public class TikTokWebSocketPingingTask
{ {
private Thread thread; private Thread thread;
private boolean isRunning = false; private boolean isRunning = false;
private final int MIN_TIMEOUT = 250; private final int MAX_TIMEOUT = 250;
private final int MAX_TIMEOUT = 500; private final int SLEEP_TIME = 500;
public void run(WebSocket webSocket) public void run(WebSocket webSocket, long pingTaskTime)
{ {
stop(); stop();
thread = new Thread(() -> pingTask(webSocket)); thread = new Thread(() -> pingTask(webSocket, pingTaskTime));
isRunning = true; isRunning = true;
thread.start(); thread.start();
} }
@@ -26,20 +26,18 @@ public class TikTokWebSocketPingingTask
isRunning = false; isRunning = false;
} }
private void pingTask(WebSocket webSocket, long pingTaskTime)
private void pingTask(WebSocket webSocket)
{ {
var random = new Random(); var random = new Random();
while (isRunning) { while (isRunning) {
try { try {
if (!webSocket.isOpen()) { if (!webSocket.isOpen()) {
Thread.sleep(100); Thread.sleep(SLEEP_TIME);
continue; continue;
} }
webSocket.sendPing(); webSocket.sendPing();
var timeout = random.nextInt(MAX_TIMEOUT)+MIN_TIMEOUT; Thread.sleep(pingTaskTime+random.nextInt(MAX_TIMEOUT));
Thread.sleep(timeout);
} }
catch (Exception e) { catch (Exception e) {
isRunning = false; isRunning = false;

View File

@@ -41,7 +41,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.3.0-Release</version> <version>1.5.3-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -75,7 +75,7 @@
<dependency> <dependency>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>extension-collector</artifactId> <artifactId>extension-collector</artifactId>
<version>1.3.0-Release</version> <version>1.5.3-Release</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -25,27 +25,20 @@ package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.extension.collector.TikTokLiveCollector; import io.github.jwdeveloper.tiktok.extension.collector.TikTokLiveCollector;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.*;
import java.util.Map;
public class CollectorExample { public class CollectorExample {
private static String mongoUser;
private static String mongoPassword;
private static String mongoDatabase;
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
var collector = TikTokLiveCollector.use(settings -> var path = "C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Examples\\src\\main\\resources";
var collector = TikTokLiveCollector.useFile(settings ->
{ {
settings.setConnectionUrl("mongodb+srv://" + mongoUser + ":" + mongoPassword + "@" + mongoDatabase + "/?retryWrites=true&w=majority"); settings.setParentFile(new File(path));
settings.setDatabaseName("tiktok");
}); });
collector.connectDatabase(); collector.connect();
var users = List.of("tehila_723", "dino123597", "domaxyzx", "dash4214", "obserwacje_live"); var users = List.of("tehila_723", "dino123597", "domaxyzx", "dash4214", "obserwacje_live");
Map<String, Object> additionalDataFields = Map.of("sessionTag", "ExampleTag"); Map<String, Object> additionalDataFields = Map.of("sessionTag", "ExampleTag");
@@ -59,18 +52,11 @@ public class CollectorExample {
{ {
event.getException().printStackTrace(); event.getException().printStackTrace();
}) })
.addListener(collector.newListener(additionalDataFields, document -> .addListener(collector.newListener(additionalDataFields))
{
//filtering document data before it is inserted to database
if (document.get("dataType") == "message") {
return false;
}
return true;
}))
.buildAndConnectAsync(); .buildAndConnectAsync();
} }
System.in.read(); System.in.read();
collector.disconnectDatabase(); collector.disconnect();
} }
} }

View File

@@ -1,7 +1,6 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.TikTokCommentEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokCommentEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokSubNotifyEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent; import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent; import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
@@ -11,7 +10,9 @@ import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftComboStateType; import io.github.jwdeveloper.tiktok.data.models.gifts.GiftComboStateType;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
public class Events_And_Gifts_Testing_Example { public class Events_And_Gifts_Testing_Example
{
public static void main(String[] args) { public static void main(String[] args) {
LiveClient client = TikTokLive.newClient(ConnectionExample.TIKTOK_HOSTNAME) LiveClient client = TikTokLive.newClient(ConnectionExample.TIKTOK_HOSTNAME)
.configure(liveClientSettings -> .configure(liveClientSettings ->
@@ -35,6 +36,10 @@ public class Events_And_Gifts_Testing_Example {
{ {
liveClient.getLogger().info("New fake Gift: " + event.getGift()); liveClient.getLogger().info("New fake Gift: " + event.getGift());
}) })
.onLike((liveClient, event) ->
{
liveClient.getLogger().info("New fake Like event: " + event.getLikes());
})
.build(); .build();
var gifts = TikTokLive.gifts(); var gifts = TikTokLive.gifts();
@@ -57,11 +62,13 @@ public class Events_And_Gifts_Testing_Example {
client.publishEvent(fakeMessage); client.publishEvent(fakeMessage);
client.publishEvent(fakeSubscriber); client.publishEvent(fakeSubscriber);
client.publishEvent(fakeFollow); client.publishEvent(fakeFollow);
client.publishEvent(fakeLike);
client.publishEvent(fakeJoin); client.publishEvent(fakeJoin);
client.publishEvent(fakeLike);
client.publishMessage("WebcastLikeMessage", webcastLikeMessageBase64);
client.disconnect(); client.disconnect();
} }
private static final String webcastLikeMessageBase64 = "SAFSBRABGKwCUgcIAhABGKwCCv8BUAFYAbABA7gBARCflqWWo8Ha72UgzoPZhd8xQrwBGg4gkAMKCSNmZmZmZmZmZiJ/qgF6CngIhYjjgPWJv7RgGhDwnZKm8J2TjvCdk47wk4WTsgIKa3lsbGVlaGFsbPICTE1TNHdMakFCQUFBQXUyX21LNEw4WGJYa3lNaUFvZzJUTnNmVjk5N09WM2tpQ3NCTkNjYWkwcWxIcUt0Q3B0UGU1N2RLYVhxb0xWSXoICwoQcG1fbXRfbXNnX3ZpZXdlchIXezA6dXNlcn0gbGlrZWQgdGhlIExJVkVIAQoSV2ViY2FzdExpa2VNZXNzYWdlGIaWvY+RhdjvZTABwAEBEA8Y+Voq7RCyAQYImwEQjwK6AQCCAgDyAkxNUzR3TGpBQkFBQUF1Ml9tSzRMOFhiWGt5TWlBb2cyVE5zZlY5OTdPVjNraUNzQk5DY2FpMHFsSHFLdENwdFBlNTdkS2FYcW9MVkl6ggTqCLoBnwUqBggBEAEYIFoNCgASCSNCMzQ3N0VGRoABDwgEEtgEEix3ZWJjYXN0LXZhL2dyYWRlX2JhZGdlX2ljb25fbGl0ZV9sdjE1X3YyLnBuZzrpAnNzbG9jYWw6Ly93ZWJjYXN0X2x5bnh2aWV3X3BvcHVwP3VzZV9zcGFyaz0xJnVybD1odHRwcyUzQSUyRiUyRmxmMTYtZ2Vja28tc291cmNlLnRpa3Rva2Nkbi5jb20lMkZvYmolMkZieXRlLWd1cmQtc291cmNlLXNnJTJGdGlrdG9rJTJGZmUlMkZsaXZlJTJGdGlrdG9rX2xpdmVfcmV2ZW51ZV91c2VyX2xldmVsX21haW4lMkZzcmMlMkZwYWdlcyUyRnByaXZpbGVnZSUyRnBhbmVsJTJGdGVtcGxhdGUuanMmaGlkZV9zdGF0dXNfYmFyPTAmaGlkZV9uYXZfYmFyPTEmY29udGFpbmVyX2JnX2NvbG9yPTAwMDAwMDAwJmhlaWdodD05MCUyNSZiZGhtX2JpZD10aWt0b2tfbGl2ZV9yZXZlbnVlX3VzZXJfbGV2ZWxfbWFpbiZ1c2VfZm9yZXN0PTEKXWh0dHBzOi8vcDE2LXdlYmNhc3QudGlrdG9rY2RuLmNvbS93ZWJjYXN0LXZhL2dyYWRlX2JhZGdlX2ljb25fbGl0ZV9sdjE1X3YyLnBuZ350cGx2LW9iai5pbWFnZQpdaHR0cHM6Ly9wMTktd2ViY2FzdC50aWt0b2tjZG4uY29tL3dlYmNhc3QtdmEvZ3JhZGVfYmFkZ2VfaWNvbl9saXRlX2x2MTVfdjIucG5nfnRwbHYtb2JqLmltYWdlIgIxNTIAOgYaAhIAIgBiDQoAEgkjQjM0NzdFRkZ4DqIBBggBEAEYIAgEEBQYCCABUukCc3Nsb2NhbDovL3dlYmNhc3RfbHlueHZpZXdfcG9wdXA/dXNlX3NwYXJrPTEmdXJsPWh0dHBzJTNBJTJGJTJGbGYxNi1nZWNrby1zb3VyY2UudGlrdG9rY2RuLmNvbSUyRm9iaiUyRmJ5dGUtZ3VyZC1zb3VyY2Utc2clMkZ0aWt0b2slMkZmZSUyRmxpdmUlMkZ0aWt0b2tfbGl2ZV9yZXZlbnVlX3VzZXJfbGV2ZWxfbWFpbiUyRnNyYyUyRnBhZ2VzJTJGcHJpdmlsZWdlJTJGcGFuZWwlMkZ0ZW1wbGF0ZS5qcyZoaWRlX3N0YXR1c19iYXI9MCZoaWRlX25hdl9iYXI9MSZjb250YWluZXJfYmdfY29sb3I9MDAwMDAwMDAmaGVpZ2h0PTkwJTI1JmJkaG1fYmlkPXRpa3Rva19saXZlX3JldmVudWVfdXNlcl9sZXZlbF9tYWluJnVzZV9mb3Jlc3Q9MVgBYk8qAjE1CgEyEhM3MTM4MzgxNzQ3MjkyNTQyNzU2GgEwIi5tb2NrX2ZpeF93aWR0aF90cmFuc3BhcmVudF83MTM4MzgxNzQ3MjkyNTQyNzU2CIWI44D1ib+0YBoQ8J2SpvCdk47wnZOO8JOFk0r1BhJBMTAweDEwMC90b3MtdXNlYXN0OC1hdnQtMDA2OC10eDIvNjY0NmM4NjZjMzI1MWEwOTY3NjhiYjY4OTUyODVjMzEK0gFodHRwczovL3AxOS1wdS1zaWduLXVzZWFzdDgudGlrdG9rY2RuLXVzLmNvbS90b3MtdXNlYXN0OC1hdnQtMDA2OC10eDIvNjY0NmM4NjZjMzI1MWEwOTY3NjhiYjY4OTUyODVjMzF+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/bGszcz1hNWQ0ODA3OCZ4LWV4cGlyZXM9MTcwOTMxMjQwMCZ4LXNpZ25hdHVyZT1VMlNEbUk3Z3R5RW9rMlBlWFdmeTNsM1F6NlElM0QKyAFodHRwczovL3AxNi1wdS1zaWduLXVzZWFzdDgudGlrdG9rY2RuLXVzLmNvbS90b3MtdXNlYXN0OC1hdnQtMDA2OC10eDIvNjY0NmM4NjZjMzI1MWEwOTY3NjhiYjY4OTUyODVjMzF+YzVfMTAweDEwMC53ZWJwP2xrM3M9YTVkNDgwNzgmeC1leHBpcmVzPTE3MDkzMTI0MDAmeC1zaWduYXR1cmU9aWNWZEVZa0FnWkYlMkZ2WU5OTSUyRlVNMzE2eG9HdyUzRArGAWh0dHBzOi8vcDE5LXB1LXNpZ24tdXNlYXN0OC50aWt0b2tjZG4tdXMuY29tL3Rvcy11c2Vhc3Q4LWF2dC0wMDY4LXR4Mi82NjQ2Yzg2NmMzMjUxYTA5Njc2OGJiNjg5NTI4NWMzMX5jNV8xMDB4MTAwLndlYnA/bGszcz1hNWQ0ODA3OCZ4LWV4cGlyZXM9MTcwOTMxMjQwMCZ4LXNpZ25hdHVyZT1PQzdBQ3htQUklMkJsYlp4RkVuWktJT1RyRExGUSUzRArGAWh0dHBzOi8vcDE2LXB1LXNpZ24tdXNlYXN0OC50aWt0b2tjZG4tdXMuY29tL3Rvcy11c2Vhc3Q4LWF2dC0wMDY4LXR4Mi82NjQ2Yzg2NmMzMjUxYTA5Njc2OGJiNjg5NTI4NWMzMX5jNV8xMDB4MTAwLmpwZWc/bGszcz1hNWQ0ODA3OCZ4LWV4cGlyZXM9MTcwOTMxMjQwMCZ4LXNpZ25hdHVyZT02YUwlMkZNZWtOeHg5NXlvVTVLOTZON0xwRUlNdyUzRLICCmt5bGxlZWhhbGxCyQEIgojG1pKb0clgErwBChBwbV9tdF9tc2dfdmlld2VyEhd7MDp1c2VyfSBsaWtlZCB0aGUgTElWRRoOCgkjZmZmZmZmZmYgkAMifwgLqgF6CngIhYjjgPWJv7RgGhDwnZKm8J2TjvCdk47wk4WTsgIKa3lsbGVlaGFsbPICTE1TNHdMakFCQUFBQXUyX21LNEw4WGJYa3lNaUFvZzJUTnNmVjk5N09WM2tpQ3NCTkNjYWkwcWxIcUt0Q3B0UGU1N2RLYVhxb0xWSXo=";
} }

View File

@@ -70,7 +70,7 @@ Maven
<dependency> <dependency>
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId> <groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
<artifactId>Client</artifactId> <artifactId>Client</artifactId>
<version>1.3.0-Release</version> <version>1.5.0-Release</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -87,7 +87,7 @@ dependencyResolutionManagement {
} }
dependencies { dependencies {
implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.1.0-Release' implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.5.0-Release'
} }
``` ```

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.3.0-Release</version> <version>1.5.3-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<version>1.3.0-Release</version> <version>1.5.3-Release</version>
</parent> </parent>
@@ -33,7 +33,7 @@
<dependency> <dependency>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>API</artifactId> <artifactId>API</artifactId>
<version>1.3.0-Release</version> <version>1.5.3-Release</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -22,19 +22,34 @@
*/ */
package io.github.jwdeveloper.tiktok.extension.collector; package io.github.jwdeveloper.tiktok.extension.collector;
import io.github.jwdeveloper.tiktok.extension.collector.api.LiveDataCollector; import io.github.jwdeveloper.tiktok.extension.collector.api.settings.FileDataCollectorSettings;
import io.github.jwdeveloper.tiktok.extension.collector.api.data.LiveDataCollectorSettings; import io.github.jwdeveloper.tiktok.extension.collector.api.settings.mongo.MongoDataCollectorSettings;
import io.github.jwdeveloper.tiktok.extension.collector.impl.TikTokLiveDataCollector; import io.github.jwdeveloper.tiktok.extension.collector.impl.*;
import io.github.jwdeveloper.tiktok.extension.collector.impl.storages.FileStorage;
import io.github.jwdeveloper.tiktok.extension.collector.impl.storages.MongoStorage;
import java.util.function.Consumer; import java.util.function.Consumer;
/**
*
*/
public class TikTokLiveCollector public class TikTokLiveCollector
{ {
public static TikTokLiveDataCollector use(Consumer<LiveDataCollectorSettings> consumer) public static DataCollector useMongo(Consumer<MongoDataCollectorSettings> consumer) {
{ var settings = new MongoDataCollectorSettings();
var settings = new LiveDataCollectorSettings();
consumer.accept(settings); consumer.accept(settings);
return new TikTokLiveDataCollector(settings);
var storage = new MongoStorage(settings);
return new DataCollector(storage);
} }
}
public static DataCollector useFile(Consumer<FileDataCollectorSettings> consumer) {
var settings = new FileDataCollectorSettings();
consumer.accept(settings);
var storage = new FileStorage(settings);
return new DataCollector(storage);
}
}

View File

@@ -0,0 +1,8 @@
package io.github.jwdeveloper.tiktok.extension.collector.api;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import org.bson.Document;
public interface CollectorEvent {
boolean execute(LiveClient client, Document document);
}

View File

@@ -0,0 +1,11 @@
package io.github.jwdeveloper.tiktok.extension.collector.api;
import org.bson.Document;
public interface Storage {
void connect();
void disconnect();
void insert(Document document);
}

View File

@@ -1,5 +1,6 @@
package io.github.jwdeveloper.tiktok.extension.collector.api.data; package io.github.jwdeveloper.tiktok.extension.collector.api.settings;
import io.github.jwdeveloper.tiktok.extension.collector.api.CollectorEvent;
import lombok.Data; import lombok.Data;
import org.bson.Document; import org.bson.Document;
@@ -9,5 +10,5 @@ import java.util.function.Function;
@Data @Data
public class CollectorListenerSettings { public class CollectorListenerSettings {
private Map<String, Object> extraFields; private Map<String, Object> extraFields;
private Function<Document, Boolean> filter; private CollectorEvent filter;
} }

View File

@@ -0,0 +1,33 @@
/*
* 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.settings;
import lombok.Data;
import java.io.File;
@Data
public class FileDataCollectorSettings {
private File parentFile;
}

View File

@@ -20,36 +20,21 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.extension.collector.api.data; package io.github.jwdeveloper.tiktok.extension.collector.api.settings.mongo;
import lombok.Setter;
import lombok.experimental.Accessors;
@Setter
@Accessors(chain = true)
public class MongoDBConnectionStringBuilder { public class MongoDBConnectionStringBuilder {
private String username; private String username;
private String password; private String password;
private String database; private String database;
private String cluster; 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() { public String build() {
return String.format("mongodb+srv://%s:%s@%s/%s?retryWrites=true&w=majority", return String.format("mongodb+srv://%s:%s@%s/%s?retryWrites=true&w=majority",
username, password, cluster, database); username, password, cluster, database);
} }
} }

View File

@@ -20,29 +20,24 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.extension.collector.api.data; package io.github.jwdeveloper.tiktok.extension.collector.api.settings.mongo;
import lombok.Data; import lombok.*;
import java.util.function.Consumer; import java.util.function.Consumer;
@Data @Data
public class LiveDataCollectorSettings { public class MongoDataCollectorSettings {
private String connectionUrl; private String connectionUrl;
private String databaseName; private String databaseName = "tiktok";
private String sessionTag; private String collectionName = "data";
public void connectionBuilder(Consumer<MongoDBConnectionStringBuilder> consumer) {
public void setConnectionUrl(String connectionUrl) {
this.connectionUrl = connectionUrl;
}
public void setConnectionUrl(Consumer<MongoDBConnectionStringBuilder> consumer) {
var builder = new MongoDBConnectionStringBuilder(); var builder = new MongoDBConnectionStringBuilder();
consumer.accept(builder); consumer.accept(builder);
connectionUrl = builder.build(); connectionUrl = builder.build();
} }
} }

View File

@@ -0,0 +1,64 @@
/*
* 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 io.github.jwdeveloper.tiktok.extension.collector.api.CollectorEvent;
import io.github.jwdeveloper.tiktok.extension.collector.api.Storage;
import io.github.jwdeveloper.tiktok.extension.collector.api.settings.CollectorListenerSettings;
import org.bson.Document;
import java.util.Map;
import java.util.function.Function;
public class DataCollector {
private final Storage storage;
public DataCollector(Storage storage) {
this.storage = storage;
}
public void connect() {
storage.connect();
}
public void disconnect() {
storage.disconnect();
}
public DataCollectorListener newListener() {
return newListener(Map.of());
}
public DataCollectorListener newListener(Map<String, Object> additionalFields) {
return newListener(additionalFields, (live, document) -> true);
}
public DataCollectorListener newListener(Map<String, Object> additionalFields,
CollectorEvent filter) {
var settings = new CollectorListenerSettings();
settings.setExtraFields(additionalFields);
settings.setFilter(filter);
return new DataCollectorListener(storage, settings);
}
}

View File

@@ -1,6 +1,5 @@
package io.github.jwdeveloper.tiktok.extension.collector.impl; 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.annotations.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
@@ -8,7 +7,8 @@ import io.github.jwdeveloper.tiktok.data.events.control.TikTokConnectingEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent; import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.extension.collector.api.LiveDataCollector; import io.github.jwdeveloper.tiktok.extension.collector.api.LiveDataCollector;
import io.github.jwdeveloper.tiktok.extension.collector.api.data.CollectorListenerSettings; import io.github.jwdeveloper.tiktok.extension.collector.api.Storage;
import io.github.jwdeveloper.tiktok.extension.collector.api.settings.CollectorListenerSettings;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.JsonUtil; import io.github.jwdeveloper.tiktok.utils.JsonUtil;
@@ -17,17 +17,17 @@ import org.bson.Document;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.Base64; import java.util.Base64;
import java.util.UUID; import java.util.Date;
public class TikTokLiveDataCollectorListener implements LiveDataCollector { public class DataCollectorListener implements LiveDataCollector {
private final MongoCollection<Document> collection; private final Storage storage;
private final CollectorListenerSettings settings; private final CollectorListenerSettings settings;
private String sessionId; private String roomId;
private String userName; private String userName;
public TikTokLiveDataCollectorListener(MongoCollection<Document> collection, CollectorListenerSettings settings) { public DataCollectorListener(Storage collection, CollectorListenerSettings settings) {
this.collection = collection; this.storage = collection;
this.settings = settings; this.settings = settings;
} }
@@ -35,53 +35,48 @@ public class TikTokLiveDataCollectorListener implements LiveDataCollector {
@TikTokEventObserver @TikTokEventObserver
private void onResponse(LiveClient liveClient, TikTokWebsocketResponseEvent event) { private void onResponse(LiveClient liveClient, TikTokWebsocketResponseEvent event) {
includeResponse(liveClient, event.getResponse()); includeResponse(liveClient, event.getResponse());
event.getResponse().getMessagesList().forEach(message -> event.getResponse().getMessagesList().forEach(message -> includeMessage(liveClient, message));
{
includeMessage(liveClient, message);
});
} }
@TikTokEventObserver @TikTokEventObserver
private void onEvent(LiveClient liveClient, TikTokEvent event) { private void onEvent(LiveClient liveClient, TikTokEvent event) {
if (event instanceof TikTokConnectingEvent) { if (event instanceof TikTokConnectingEvent) {
sessionId = UUID.randomUUID().toString();
userName = liveClient.getRoomInfo().getHostName(); userName = liveClient.getRoomInfo().getHostName();
roomId = liveClient.getRoomInfo().getRoomId();
} }
if (event instanceof TikTokErrorEvent) { if (event instanceof TikTokErrorEvent) {
return; return;
} }
includeEvent(event); includeEvent(liveClient, event);
} }
@TikTokEventObserver @TikTokEventObserver
private void onError(LiveClient liveClient, TikTokErrorEvent event) { private void onError(LiveClient liveClient, TikTokErrorEvent event) {
event.getException().printStackTrace(); event.getException().printStackTrace();
includeError(event); includeError(liveClient, event);
} }
private void includeResponse(LiveClient liveClient, WebcastResponse message) { private void includeResponse(LiveClient liveClient, WebcastResponse message) {
var messageContent = Base64.getEncoder().encodeToString(message.toByteArray()); var messageContent = Base64.getEncoder().encodeToString(message.toByteArray());
insertDocument(createDocument("response", "webcast", messageContent)); insertDocument(liveClient, createDocument("response", "webcast", messageContent));
} }
private void includeMessage(LiveClient liveClient, WebcastResponse.Message message) { private void includeMessage(LiveClient liveClient, WebcastResponse.Message message) {
var method = message.getMethod(); var method = message.getMethod();
var messageContent = Base64.getEncoder().encodeToString(message.getPayload().toByteArray()); var messageContent = Base64.getEncoder().encodeToString(message.getPayload().toByteArray());
insertDocument(liveClient, createDocument("message", method, messageContent));
insertDocument(createDocument("message", method, messageContent));
} }
private void includeEvent(TikTokEvent event) { private void includeEvent(LiveClient client, TikTokEvent event) {
var json = JsonUtil.toJson(event); var json = JsonUtil.toJson(event);
var content = Base64.getEncoder().encodeToString(json.getBytes()); var content = Base64.getEncoder().encodeToString(json.getBytes());
var name = event.getClass().getSimpleName(); var name = event.getClass().getSimpleName();
insertDocument(createDocument("event", name, content)); insertDocument(client, createDocument("event", name, content));
} }
private void includeError(TikTokErrorEvent event) { private void includeError(LiveClient client, TikTokErrorEvent event) {
var exception = event.getException(); var exception = event.getException();
var exceptionName = event.getException().getClass().getSimpleName(); var exceptionName = event.getException().getClass().getSimpleName();
@@ -89,27 +84,27 @@ public class TikTokLiveDataCollectorListener implements LiveDataCollector {
var pw = new PrintWriter(sw); var pw = new PrintWriter(sw);
event.getException().printStackTrace(pw); event.getException().printStackTrace(pw);
var content = sw.toString(); var content = sw.toString();
var contentBase64 = Base64.getEncoder().encodeToString(content.getBytes());
var doc = createDocument("error", exceptionName, content); var doc = createDocument("error", exceptionName, contentBase64);
if (exception instanceof TikTokLiveMessageException ex) { if (exception instanceof TikTokLiveMessageException ex) {
doc.append("message", ex.messageToBase64()) doc.append("message", ex.messageToBase64())
.append("response", ex.webcastResponseToBase64()); .append("response", ex.webcastResponseToBase64());
} }
insertDocument(doc); insertDocument(client, doc);
} }
private void insertDocument(Document document) { private void insertDocument(LiveClient client, Document document) {
if (!settings.getFilter().apply(document)) { if (!settings.getFilter().execute(client, document)) {
return; return;
} }
collection.insertOne(document); storage.insert(document);
} }
private Document createDocument(String dataType, String dataTypeName, String content) { private Document createDocument(String dataType, String dataTypeName, String content) {
var doc = new Document(); var doc = new Document();
doc.append("session", sessionId); doc.append("roomId", roomId);
for (var entry : settings.getExtraFields().entrySet()) { for (var entry : settings.getExtraFields().entrySet()) {
doc.append(entry.getKey(), entry.getValue()); doc.append(entry.getKey(), entry.getValue());
} }
@@ -117,6 +112,7 @@ public class TikTokLiveDataCollectorListener implements LiveDataCollector {
doc.append("dataType", dataType); doc.append("dataType", dataType);
doc.append("dataTypeName", dataTypeName); doc.append("dataTypeName", dataTypeName);
doc.append("content", content); doc.append("content", content);
doc.append("createdAt", new Date());
return doc; return doc;
} }
} }

View File

@@ -1,89 +0,0 @@
/*
* 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);
}
}

View File

@@ -0,0 +1,42 @@
package io.github.jwdeveloper.tiktok.extension.collector.impl.storages;
import io.github.jwdeveloper.tiktok.extension.collector.api.Storage;
import io.github.jwdeveloper.tiktok.extension.collector.api.settings.FileDataCollectorSettings;
import org.bson.Document;
import org.bson.json.JsonWriterSettings;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
public class FileStorage implements Storage {
private final FileDataCollectorSettings settings;
public FileStorage(FileDataCollectorSettings fileDataCollectorSettings) {
this.settings = fileDataCollectorSettings;
}
@Override
public void connect() {
}
@Override
public void disconnect() {
}
@Override
public void insert(Document document) {
var fileName = document.get("dataType") + "_" + document.get("dataTypeName") + ".json";
try {
var file = new File(settings.getParentFile(), fileName);
file.createNewFile();
Files.writeString(file.toPath(), document.toJson(JsonWriterSettings.builder().indent(true).build()), StandardOpenOption.APPEND);
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,58 @@
package io.github.jwdeveloper.tiktok.extension.collector.impl.storages;
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.Storage;
import io.github.jwdeveloper.tiktok.extension.collector.api.settings.mongo.MongoDataCollectorSettings;
import org.bson.Document;
public class MongoStorage implements Storage {
private MongoClient mongoClient;
private MongoDatabase database;
private MongoCollection<Document> collection;
private final MongoDataCollectorSettings settings;
public MongoStorage(MongoDataCollectorSettings settings) {
this.settings = settings;
}
@Override
public void connect() {
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(settings.getCollectionName());
collection.createIndex(Indexes.hashed("session"));
collection.createIndex(Indexes.hashed("dataType"));
}
@Override
public void disconnect() {
if (mongoClient == null) {
return;
}
mongoClient.close();
}
@Override
public void insert(Document document) {
collection.insertOne(document);
}
}

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.3.0-Release</version> <version>1.5.3-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>extension-recorder</artifactId> <artifactId>extension-recorder</artifactId>

View File

@@ -30,6 +30,7 @@ import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder; import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.*; import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.*;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.enums.LiveQuality; import io.github.jwdeveloper.tiktok.extension.recorder.impl.enums.LiveQuality;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.event.TikTokLiveRecorderStartedEvent;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.models.ConnectionState; import io.github.jwdeveloper.tiktok.models.ConnectionState;
@@ -60,7 +61,9 @@ public class RecorderListener implements LiveRecorder {
var json = event.getLiveData().getJson(); var json = event.getLiveData().getJson();
liveClient.getLogger().info("Searching for live download url"); liveClient.getLogger().info("Searching for live download url");
downloadData = settings.getPrepareDownloadData() != null ? settings.getPrepareDownloadData().apply(json) : mapToDownloadData(json); downloadData = settings.getPrepareDownloadData() != null ?
settings.getPrepareDownloadData().apply(json) :
mapToDownloadData(json);
if (downloadData.getDownloadLiveUrl().isEmpty()) if (downloadData.getDownloadLiveUrl().isEmpty())
liveClient.getLogger().warning("Unable to find download live url!"); liveClient.getLogger().warning("Unable to find download live url!");
@@ -72,8 +75,11 @@ public class RecorderListener implements LiveRecorder {
private void onConnected(LiveClient liveClient, TikTokConnectedEvent event) { private void onConnected(LiveClient liveClient, TikTokConnectedEvent event) {
if (isConnected()) if (isConnected())
return; return;
liveDownloadThread = new Thread(() -> { liveDownloadThread = new Thread(() -> {
try { try {
liveClient.getLogger().info("Recording started");
var url = new URL(downloadData.getFullUrl()); var url = new URL(downloadData.getFullUrl());
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
var headers = LiveClientSettings.DefaultRequestHeaders(); var headers = LiveClientSettings.DefaultRequestHeaders();
@@ -87,8 +93,8 @@ public class RecorderListener implements LiveRecorder {
file.createNewFile(); file.createNewFile();
try ( try (
var in = connection.getInputStream(); var in = connection.getInputStream();
var fos = new FileOutputStream(file) var fos = new FileOutputStream(file)
) { ) {
byte[] dataBuffer = new byte[1024]; byte[] dataBuffer = new byte[1024];
int bytesRead; int bytesRead;
@@ -98,13 +104,19 @@ public class RecorderListener implements LiveRecorder {
} }
} catch (IOException ignored) { } catch (IOException ignored) {
} finally { } finally {
liveClient.getLogger().severe("Stopped recording "+liveClient.getRoomInfo().getHostName()); liveClient.getLogger().severe("Stopped recording " + liveClient.getRoomInfo().getHostName());
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
}); });
var recordingStartedEvent = new TikTokLiveRecorderStartedEvent(downloadData);
liveClient.publishEvent(recordingStartedEvent);
if (recordingStartedEvent.isCanceled()) {
liveClient.getLogger().info("Recording cancelled");
return;
}
liveDownloadThread.start(); liveDownloadThread.start();
} }
@@ -120,32 +132,6 @@ public class RecorderListener implements LiveRecorder {
liveDownloadThread.interrupt(); 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 (InterruptedException ie) {
System.out.println("Interrupted");
ie.printStackTrace();
Thread.currentThread().interrupt();
return -1;
}
}
private DownloadData mapToDownloadData(String json) { private DownloadData mapToDownloadData(String json) {

View File

@@ -26,10 +26,18 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.DownloadData; import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.DownloadData;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@AllArgsConstructor @AllArgsConstructor
@Data @Getter
public class TikTokLiveRecorderStartedEvent extends TikTokEvent public class TikTokLiveRecorderStartedEvent extends TikTokEvent {
{
DownloadData downloadData; DownloadData downloadData;
@Setter
boolean canceled;
public TikTokLiveRecorderStartedEvent(DownloadData downloadData) {
this.downloadData = downloadData;
}
} }

View File

@@ -7,7 +7,7 @@
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>1.3.0-Release</version> <version>1.5.3-Release</version>
<modules> <modules>
<module>API</module> <module>API</module>
<module>Client</module> <module>Client</module>