mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-28 01:09:40 -05:00
Compare commits
30 Commits
develop-1.
...
1.5.3-Rele
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
786c24d267 | ||
|
|
966d2f65d8 | ||
|
|
7ba7143f5a | ||
|
|
92fde03f2b | ||
|
|
e058290118 | ||
|
|
d25741b229 | ||
|
|
560a8d7c3b | ||
|
|
6178bc25cf | ||
|
|
48d1138754 | ||
|
|
a5320db820 | ||
|
|
4e1ab35a60 | ||
|
|
cef4972f37 | ||
|
|
713c90a271 | ||
|
|
71853db5cc | ||
|
|
ef90d4cd58 | ||
|
|
dad4048bc0 | ||
|
|
9ba049d37a | ||
|
|
f7d657371b | ||
|
|
eea691a5aa | ||
|
|
a249ac0cdd | ||
|
|
b82c7184b3 | ||
|
|
29631ac468 | ||
|
|
15c642297c | ||
|
|
d3004d76c1 | ||
|
|
3ae73072ff | ||
|
|
9c5f97157a | ||
|
|
ead954dd27 | ||
|
|
e37b30ff12 | ||
|
|
7a5c00d99a | ||
|
|
407f51fa73 |
@@ -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.2-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>API</artifactId>
|
<artifactId>API</artifactId>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.2-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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.2-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.2-Release</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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=";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -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.2-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -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.2-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.2-Release</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.2-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>extension-recorder</artifactId>
|
<artifactId>extension-recorder</artifactId>
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@@ -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.2-Release</version>
|
||||||
<modules>
|
<modules>
|
||||||
<module>API</module>
|
<module>API</module>
|
||||||
<module>Client</module>
|
<module>Client</module>
|
||||||
|
|||||||
Reference in New Issue
Block a user