mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-27 16:59:39 -05:00
Compare commits
11 Commits
1.0.8-Rele
...
develop-1-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1733102aff | ||
|
|
89f54d5976 | ||
|
|
39055b5f3a | ||
|
|
cd9e9ead85 | ||
|
|
5a2d2d23f0 | ||
|
|
3eed982d6b | ||
|
|
385560de3a | ||
|
|
2e37b6627b | ||
|
|
c4f0d63b43 | ||
|
|
15550ed703 | ||
|
|
c7d84218f2 |
@@ -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.0.7-Release</version>
|
<version>1.0.9-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>API</artifactId>
|
<artifactId>API</artifactId>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class ClientSettings {
|
|||||||
* Whether to print Logs to Console
|
* Whether to print Logs to Console
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private boolean printToConsole;
|
private boolean printToConsole = true;
|
||||||
/**
|
/**
|
||||||
* LoggingLevel for Logs
|
* LoggingLevel for Logs
|
||||||
*/
|
*/
|
||||||
@@ -64,7 +64,7 @@ public class ClientSettings {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional: Use it if you need to change TikTok live hostname in builder
|
* Optional: Use it if you need to change TikTok live hostname in builder
|
||||||
*/
|
*/
|
||||||
private String hostName;
|
private String hostName;
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface TikTokEventHandler
|
public @interface TikTokEventObserver
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -47,11 +47,11 @@ public class TikTokCommentEvent extends TikTokHeaderEvent {
|
|||||||
|
|
||||||
public TikTokCommentEvent(WebcastChatMessage msg) {
|
public TikTokCommentEvent(WebcastChatMessage msg) {
|
||||||
super(msg.getCommon());
|
super(msg.getCommon());
|
||||||
user = User.map(msg.getUser());
|
user = User.map(msg.getUser(),msg.getUserIdentity());
|
||||||
text = msg.getContent();
|
text = msg.getContent();
|
||||||
visibleToSender = msg.getVisibleToSender();
|
visibleToSender = msg.getVisibleToSender();
|
||||||
getUserLanguage = msg.getContentLanguage();
|
getUserLanguage = msg.getContentLanguage();
|
||||||
mentionedUser = User.map(msg.getAtUser(),msg.getUserIdentity());
|
mentionedUser = User.map(msg.getAtUser());
|
||||||
pictures = msg.getEmotesListList().stream().map(e -> Picture.map(e.getEmote().getImage())).toList();
|
pictures = msg.getEmotesListList().stream().map(e -> Picture.map(e.getEmote().getImage())).toList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,28 +26,34 @@ package io.github.jwdeveloper.tiktok.data.events.gift;
|
|||||||
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
|
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
|
||||||
import io.github.jwdeveloper.tiktok.annotations.EventType;
|
import io.github.jwdeveloper.tiktok.annotations.EventType;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
|
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/*
|
|
||||||
|
/**
|
||||||
* Triggered when user sends gifts that has
|
* Triggered when user sends gifts that has
|
||||||
* no combo (most of expensive gifts)
|
* no combo (most of expensive gifts)
|
||||||
* or if combo has finished
|
* or if combo has finished
|
||||||
*/
|
*/
|
||||||
@EventMeta(eventType = EventType.Message)
|
@EventMeta(eventType = EventType.Message)
|
||||||
@Getter
|
@Getter
|
||||||
public class TikTokGiftEvent extends TikTokHeaderEvent {
|
public class TikTokGiftEvent extends TikTokHeaderEvent {
|
||||||
private final Gift gift;
|
private final Gift gift;
|
||||||
private final User user;
|
private final User user;
|
||||||
|
private final User toUser;
|
||||||
private final int combo;
|
private final int combo;
|
||||||
|
|
||||||
public TikTokGiftEvent(Gift gift, WebcastGiftMessage msg) {
|
public TikTokGiftEvent(Gift gift, WebcastGiftMessage msg) {
|
||||||
super(msg.getCommon());
|
super(msg.getCommon());
|
||||||
this.gift = gift;
|
this.gift = gift;
|
||||||
user = User.map(msg.getUser(), msg.getUserIdentity());
|
user = User.map(msg.getUser(), msg.getUserIdentity());
|
||||||
|
toUser = new User(msg.getUserGiftReciever().getUserId(), "", "", new Picture(""), 0, 0, new ArrayList<>());
|
||||||
combo = msg.getComboCount();
|
combo = msg.getComboCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.data.events.http;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
|
||||||
|
import io.github.jwdeveloper.tiktok.annotations.EventType;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.http.HttpData;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
@EventMeta(eventType = EventType.Debug)
|
||||||
|
public class TikTokHttpResponseEvent extends TikTokEvent
|
||||||
|
{
|
||||||
|
String url;
|
||||||
|
|
||||||
|
HttpData response;
|
||||||
|
|
||||||
|
HttpData request;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.data.models.http;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class HttpData {
|
||||||
|
String url;
|
||||||
|
String method;
|
||||||
|
Map<String, List<String>> headers = new TreeMap<>();
|
||||||
|
Map<String, String> parameters = new TreeMap<>();
|
||||||
|
int status;
|
||||||
|
String body = "";
|
||||||
|
|
||||||
|
|
||||||
|
public static HttpData map(HttpRequest request) {
|
||||||
|
var data = new HttpData();
|
||||||
|
data.setUrl(request.uri().getPath());
|
||||||
|
data.setMethod(request.method());
|
||||||
|
data.setParameters(extractQueryParams(request.uri()));
|
||||||
|
data.setStatus(200);
|
||||||
|
if (request.bodyPublisher().isPresent()) {
|
||||||
|
data.setBody(request.bodyPublisher().get().toString());
|
||||||
|
}
|
||||||
|
data.setHeaders(Collections.unmodifiableMap(request.headers().map()));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpData map(HttpResponse<String> response) {
|
||||||
|
var data = new HttpData();
|
||||||
|
data.setUrl(response.uri().getPath());
|
||||||
|
data.setMethod(response.request().method());
|
||||||
|
data.setParameters(extractQueryParams(response.uri()));
|
||||||
|
data.setStatus(200);
|
||||||
|
data.setBody(response.body());
|
||||||
|
data.setHeaders(Collections.unmodifiableMap(response.headers().map()));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Map<String, String> extractQueryParams(URI uri) {
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
String query = uri.getQuery();
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
for (String param : query.split("&")) {
|
||||||
|
String[] keyValue = param.split("=");
|
||||||
|
if (keyValue.length > 1) {
|
||||||
|
params.put(keyValue[0], keyValue[1]);
|
||||||
|
} else {
|
||||||
|
params.put(keyValue[0], ""); // Empty value for parameter without explicit value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.live;
|
package io.github.jwdeveloper.tiktok.live;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
|
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
|
||||||
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
|
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
|
||||||
|
|
||||||
@@ -55,6 +56,11 @@ public interface LiveClient {
|
|||||||
void disconnect();
|
void disconnect();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You to manually trigger event
|
||||||
|
*/
|
||||||
|
void publishEvent(TikTokEvent event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about gifts
|
* Get information about gifts
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
|||||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||||
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;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
||||||
@@ -39,61 +40,140 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandl
|
|||||||
public interface EventsBuilder<T> {
|
public interface EventsBuilder<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method used to register own custom events
|
* Invoked whenever specified event is triggered
|
||||||
* @param eventClazz event class
|
*
|
||||||
* @param event action
|
* @param eventClass event class
|
||||||
|
* @param action action
|
||||||
*/
|
*/
|
||||||
<E extends TikTokEvent> T onCustomEvent(Class<E> eventClazz, EventConsumer<E> event);
|
<E extends TikTokEvent> T onEvent(Class<E> eventClass, EventConsumer<E> action);
|
||||||
|
|
||||||
T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event);
|
|
||||||
|
|
||||||
T onComment(EventConsumer<TikTokCommentEvent> event);
|
|
||||||
|
|
||||||
T onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> event);
|
|
||||||
|
|
||||||
T onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> event);
|
|
||||||
|
|
||||||
T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> event);
|
|
||||||
|
|
||||||
|
|
||||||
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> event);
|
/**
|
||||||
|
* Invoked whenever any event is triggered
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onEvent(EventConsumer<TikTokEvent> action);
|
||||||
|
|
||||||
T onGift(EventConsumer<TikTokGiftEvent> event);
|
/**
|
||||||
|
* Invoked when information about room (live) got updated such as viewer count, etc..
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> action);
|
||||||
|
|
||||||
T onQuestion(EventConsumer<TikTokQuestionEvent> event);
|
/**
|
||||||
|
* Invoked when someone send message to chat
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onComment(EventConsumer<TikTokCommentEvent> action);
|
||||||
|
|
||||||
T onSubscribe(EventConsumer<TikTokSubscribeEvent> event);
|
|
||||||
|
|
||||||
T onFollow(EventConsumer<TikTokFollowEvent> event);
|
/**
|
||||||
|
* Invoked when TikTokLiveJava makes http request and getting response
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action);
|
||||||
|
|
||||||
T onLike(EventConsumer<TikTokLikeEvent> event);
|
/**
|
||||||
|
* Invoked when TikTok protocolBuffer data "message" was successfully mapped to event
|
||||||
|
* events contains protocol-buffer "Message" and TikTokLiveJava "Event"
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> action);
|
||||||
|
|
||||||
T onEmote(EventConsumer<TikTokEmoteEvent> event);
|
/**
|
||||||
|
* Invoked when there was not found event mapper for TikTok protocolBuffer data "message"
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> action);
|
||||||
|
|
||||||
T onJoin(EventConsumer<TikTokJoinEvent> event);
|
/**
|
||||||
|
* Invoked every time TikTok sends protocolBuffer data to websocket
|
||||||
|
* Response contains list of messages that are later mapped to events
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> action);
|
||||||
|
|
||||||
T onShare(EventConsumer<TikTokShareEvent> event);
|
|
||||||
|
|
||||||
// T onChest(EventConsumer<TikTokChestEvent> event);
|
/**
|
||||||
|
* Invoked for gifts that has no combo, or when combo finishes
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onGift(EventConsumer<TikTokGiftEvent> action);
|
||||||
|
|
||||||
T onLivePaused(EventConsumer<TikTokLivePausedEvent> event);
|
/**
|
||||||
|
* Invoked for gifts that has combo options such as roses
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> action);
|
||||||
|
|
||||||
T onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event);
|
|
||||||
|
|
||||||
T onLiveEnded(EventConsumer<TikTokLiveEndedEvent> event);
|
T onQuestion(EventConsumer<TikTokQuestionEvent> action);
|
||||||
|
|
||||||
T onConnected(EventConsumer<TikTokConnectedEvent> event);
|
T onSubscribe(EventConsumer<TikTokSubscribeEvent> action);
|
||||||
|
|
||||||
T onReconnecting(EventConsumer<TikTokReconnectingEvent> event);
|
T onFollow(EventConsumer<TikTokFollowEvent> action);
|
||||||
|
|
||||||
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> event);
|
T onLike(EventConsumer<TikTokLikeEvent> action);
|
||||||
|
|
||||||
T onError(EventConsumer<TikTokErrorEvent> event);
|
T onEmote(EventConsumer<TikTokEmoteEvent> action);
|
||||||
|
|
||||||
T onEvent(EventConsumer<TikTokEvent> event);
|
T onJoin(EventConsumer<TikTokJoinEvent> action);
|
||||||
|
|
||||||
|
T onShare(EventConsumer<TikTokShareEvent> action);
|
||||||
|
|
||||||
|
T onLivePaused(EventConsumer<TikTokLivePausedEvent> action);
|
||||||
|
|
||||||
|
T onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> action);
|
||||||
|
|
||||||
|
T onLiveEnded(EventConsumer<TikTokLiveEndedEvent> action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when client has been successfully connected to live
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onConnected(EventConsumer<TikTokConnectedEvent> action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when client tries to reconnect
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onReconnecting(EventConsumer<TikTokReconnectingEvent> action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when client disconnected
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when exception was throed inside client or event handler
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onError(EventConsumer<TikTokErrorEvent> action);
|
||||||
|
|
||||||
|
|
||||||
// TODO Figure out how those events works
|
// TODO Figure out how those events works
|
||||||
|
// T onChest(EventConsumer<TikTokChestEvent> event);
|
||||||
|
|
||||||
//T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);
|
//T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);
|
||||||
|
|
||||||
//T onEnvelope(TikTokEventConsumer<TikTokEnvelopeEvent> event);
|
//T onEnvelope(TikTokEventConsumer<TikTokEnvelopeEvent> event);
|
||||||
|
|||||||
@@ -24,72 +24,32 @@ package io.github.jwdeveloper.tiktok.mappers;
|
|||||||
|
|
||||||
import com.google.protobuf.GeneratedMessageV3;
|
import com.google.protobuf.GeneratedMessageV3;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingAction;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public interface TikTokMapper {
|
public interface TikTokMapper {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggered when `sourceClass` is mapped,
|
* * if mapper is not found for messageName, TikTokLiveException is thrown
|
||||||
* input is bytes that are coming from TikTok in `sourceClass` packet
|
|
||||||
* output is TikTok event we want to create
|
|
||||||
* <p>
|
|
||||||
* bytesToEvent(WebcastGiftMessage.class, bytes ->
|
|
||||||
* {
|
|
||||||
* var giftMessage = WebcastGiftMessage.parseFrom(bytes);
|
|
||||||
* var giftName = giftMessage.getGift().getName();
|
|
||||||
* return new TikTokEvent(Gift.ROSE, giftMessage);
|
|
||||||
* })
|
|
||||||
*
|
*
|
||||||
* @param sourceClass protocol buffer webcast class
|
* @param messageName
|
||||||
* @param onMapping lambda function that is triggered on mapping. takes as input ProtocolBuffer object and as output TikTokEvent
|
* @return TikTokMapperModel
|
||||||
*/
|
*/
|
||||||
void bytesToEvent(Class<? extends GeneratedMessageV3> sourceClass, Function<byte[], TikTokEvent> onMapping);
|
TikTokMapperModel forMessage(String messageName);
|
||||||
|
|
||||||
void bytesToEvents(Class<? extends GeneratedMessageV3> sourceClass, Function<byte[], List<TikTokEvent>> onMapping);
|
TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName);
|
||||||
|
|
||||||
|
TikTokMapperModel forMessage(String mapperName, MappingAction<MappingResult> onMapping);
|
||||||
|
|
||||||
/**
|
TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName, MappingAction<MappingResult> onMapping);
|
||||||
* In case you found some TikTok message that has not Webcast class use this method
|
|
||||||
*
|
|
||||||
* @param messageName Name of TikTok data event
|
|
||||||
* @param onMapping lambda function that is triggered on mapping. takes as input ProtocolBuffer object and as output TikTokEvent
|
|
||||||
*/
|
|
||||||
void bytesToEvent(String messageName, Function<byte[], TikTokEvent> onMapping);
|
|
||||||
|
|
||||||
void bytesToEvents(String messageName, Function<byte[], List<TikTokEvent>> onMapping);
|
TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName, Function<byte[], TikTokEvent> onMapping);
|
||||||
|
|
||||||
|
boolean isRegistered(String mapperName);
|
||||||
|
|
||||||
/**
|
<T extends GeneratedMessageV3> boolean isRegistered(Class<T> mapperName);
|
||||||
* This method can be used to override default mapping for
|
|
||||||
* certain TikTok incoming data message. For this example
|
|
||||||
* we are overriding WebcastGiftMessage and retuning CustomGiftEvent
|
|
||||||
* instead of TikTokGiftEvent
|
|
||||||
* <p>
|
|
||||||
* webcastObjectToEvent(WebcastGiftMessage.class, webcastGiftMessage ->
|
|
||||||
* {
|
|
||||||
* var giftName = webcastGiftMessage.getGift().getName();
|
|
||||||
* var user = webcastGiftMessage.getUser().getNickname();
|
|
||||||
* return new CustomGiftEvent(giftName, user);
|
|
||||||
* })
|
|
||||||
*
|
|
||||||
* @param sourceClass ProtocolBuffer class that represent incoming custom data, hint class should starts with Webcast prefix
|
|
||||||
* @param onMapping lambda function that is triggered on mapping. takes as input ProtocolBuffer object and as output TikTokEvent
|
|
||||||
*/
|
|
||||||
<T extends GeneratedMessageV3> void webcastObjectToEvent(Class<T> sourceClass, Function<T, TikTokEvent> onMapping);
|
|
||||||
|
|
||||||
<T extends GeneratedMessageV3> void webcastObjectToEvents(Class<T> sourceClass, Function<T, List<TikTokEvent>> onMapping);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggered when `sourceClass` is mapped,
|
|
||||||
* looking for constructor in `outputClass` with one parameter that is of type `sourceClass`
|
|
||||||
* and created instance of object from this constructor
|
|
||||||
*
|
|
||||||
* @param sourceClass protocol buffer webcast class
|
|
||||||
* @param outputClass TikTok event class
|
|
||||||
*/
|
|
||||||
void webcastObjectToConstructor(Class<? extends GeneratedMessageV3> sourceClass, Class<? extends TikTokEvent> outputClass);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.mappers;
|
||||||
|
|
||||||
|
import com.google.protobuf.GeneratedMessageV3;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
|
||||||
|
import io.github.jwdeveloper.tiktok.utils.ProtoBufferObject;
|
||||||
|
|
||||||
|
public interface TikTokMapperHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bytes protocol buffer data bytes
|
||||||
|
* @param messageClass class that we want to serialize bytes to
|
||||||
|
* @param <T> @messageClass must be class that is made by protocol buffer
|
||||||
|
* @return object of type @messageClass
|
||||||
|
*/
|
||||||
|
<T extends GeneratedMessageV3> T bytesToWebcastObject(byte[] bytes, Class<T> messageClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bytes protocol buffer data bytes
|
||||||
|
* @param messageName class that we want to serialize bytes to
|
||||||
|
* @return protocol buffer objects if class for @messageName has been found
|
||||||
|
* @throws TikTokMessageMappingException if there is no suitable class for messageName
|
||||||
|
*/
|
||||||
|
Object bytesToWebcastObject(byte[] bytes, String messageName);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param messageName checks wheaten TikTokLiveJava has class representation for certain protocol-buffer message name
|
||||||
|
* @return false if class is not found
|
||||||
|
*/
|
||||||
|
boolean isMessageHasProtoClass(String messageName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bytes protocol buffer data bytes
|
||||||
|
* @return tree structure of protocol buffer object
|
||||||
|
* @see ProtoBufferObject
|
||||||
|
*/
|
||||||
|
ProtoBufferObject bytesToProtoBufferStructure(byte[] bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts object to json
|
||||||
|
*
|
||||||
|
* @param obj any object
|
||||||
|
* @return pretty formatted json
|
||||||
|
*/
|
||||||
|
String toJson(Object obj);
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.mappers;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.AfterMappingAction;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingAction;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public interface TikTokMapperModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return name of websocket message that this mapper is mapping from
|
||||||
|
*/
|
||||||
|
|
||||||
|
String getSourceMessageName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param action Input bytes from websocket, you can modify it and returns different bytes
|
||||||
|
*/
|
||||||
|
TikTokMapperModel onBeforeMapping(MappingAction<byte[]> action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param action Input bytes from websocket. As output returns list of tiktok live events
|
||||||
|
*/
|
||||||
|
TikTokMapperModel onMapping(MappingAction<MappingResult> action);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param action You can modify output list of TikTokLive events
|
||||||
|
* @see AfterMappingAction
|
||||||
|
*/
|
||||||
|
TikTokMapperModel onAfterMapping(Function<MappingResult, List<TikTokEvent>> action);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.mappers.data;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface AfterMappingAction {
|
||||||
|
/**
|
||||||
|
* @param source object that was used as source to create events
|
||||||
|
* @param events list of events prepared before, could be modified or changed
|
||||||
|
* @return list of events that will be invoked
|
||||||
|
*/
|
||||||
|
List<TikTokEvent> onAfterMapping(Object source, List<TikTokEvent> events);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.mappers.data;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.TikTokMapperHelper;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface MappingAction<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param inputBytes incoming bytes from TikTok server. The represents protocol buffer message that was send to client
|
||||||
|
* @param messageName name of protocol buffer message
|
||||||
|
* @param mapperHelper utils and helper methods that can be use to debbug/display/deserialize protocol buffer data
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onMapping(byte[] inputBytes, String messageName, TikTokMapperHelper mapperHelper);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.mappers.data;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public class MappingResult
|
||||||
|
{
|
||||||
|
|
||||||
|
Object source;
|
||||||
|
|
||||||
|
List<TikTokEvent> events;
|
||||||
|
|
||||||
|
String message;
|
||||||
|
|
||||||
|
public static MappingResult of(Object source) {
|
||||||
|
return new MappingResult(source, List.of(),"");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MappingResult of(Object source, List<TikTokEvent> events) {
|
||||||
|
return new MappingResult(source, events,"");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MappingResult of(Object source,TikTokEvent events) {
|
||||||
|
return new MappingResult(source, List.of(events),"");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,8 +64,8 @@ message Text {
|
|||||||
string stringValue = 11;
|
string stringValue = 11;
|
||||||
oneof textPieceType
|
oneof textPieceType
|
||||||
{
|
{
|
||||||
TextPieceUser userValue = 21;
|
TextPieceUser userValue = 21;
|
||||||
TextPieceGift giftValue = 22;
|
TextPieceGift giftValue = 22;
|
||||||
}
|
}
|
||||||
TextPiecePatternRef patternRefValue = 24;
|
TextPiecePatternRef patternRefValue = 24;
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ message BadgeStruct {
|
|||||||
|
|
||||||
message ProfileCardPanel {
|
message ProfileCardPanel {
|
||||||
bool useNewProfileCardStyle = 1;
|
bool useNewProfileCardStyle = 1;
|
||||||
// BadgeTextPosition badgeTextPosition = 2; // Enum
|
// BadgeTextPosition badgeTextPosition = 2; // Enum
|
||||||
ProjectionConfig projectionConfig = 3;
|
ProjectionConfig projectionConfig = 3;
|
||||||
ProfileContent profileContent = 4;
|
ProfileContent profileContent = 4;
|
||||||
}
|
}
|
||||||
@@ -1000,8 +1000,8 @@ message LinkerCreateContent {
|
|||||||
|
|
||||||
message LinkerEnterContent {
|
message LinkerEnterContent {
|
||||||
repeated User LinkedUsersList = 1;
|
repeated User LinkedUsersList = 1;
|
||||||
// LinkmicMultiLiveEnum AnchorMultiLiveEnum = 2;
|
// LinkmicMultiLiveEnum AnchorMultiLiveEnum = 2;
|
||||||
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 3;
|
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LinkerInviteContent {
|
message LinkerInviteContent {
|
||||||
@@ -1018,15 +1018,15 @@ message LinkerInviteContent {
|
|||||||
//Data.LinkmicMultiLiveEnum AnchorMultiLiveEnum = 11;
|
//Data.LinkmicMultiLiveEnum AnchorMultiLiveEnum = 11;
|
||||||
//Data.LinkmicUserSettingInfo AnchorSettingInfo = 12;
|
//Data.LinkmicUserSettingInfo AnchorSettingInfo = 12;
|
||||||
string InviterLinkmicIdStr = 13;
|
string InviterLinkmicIdStr = 13;
|
||||||
// InviteTopHostInfo FromTopHostInfo = 16;
|
// InviteTopHostInfo FromTopHostInfo = 16;
|
||||||
int64 ActionId = 17;
|
int64 ActionId = 17;
|
||||||
// repeated LinkmicUserInfo LinkedUsersList = 18;
|
// repeated LinkmicUserInfo LinkedUsersList = 18;
|
||||||
// Data.PerceptionDialogInfo Dialog = 19;
|
// Data.PerceptionDialogInfo Dialog = 19;
|
||||||
// Data.PunishEventInfo PunishInfo = 20;
|
// Data.PunishEventInfo PunishInfo = 20;
|
||||||
int32 FromRoomAgeRestricted = 21;
|
int32 FromRoomAgeRestricted = 21;
|
||||||
// Data.Tag FromTag = 22;
|
// Data.Tag FromTag = 22;
|
||||||
// repeated Data.CohostABTestSetting AbTestSettingList = 23;
|
// repeated Data.CohostABTestSetting AbTestSettingList = 23;
|
||||||
// Data.LinkerInviteMessageExtra LinkerInviteMsgExtra = 101;
|
// Data.LinkerInviteMessageExtra LinkerInviteMsgExtra = 101;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LinkerKickOutContent {
|
message LinkerKickOutContent {
|
||||||
@@ -1046,17 +1046,17 @@ message LinkerLinkedListChangeContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message LinkerListChangeContent {
|
message LinkerListChangeContent {
|
||||||
repeated User LinkedUsersList = 1;
|
repeated LinkLayerListUser LinkedUsersList = 1;
|
||||||
repeated User AppliedUsersList = 2;
|
repeated LinkLayerListUser AppliedUsersList = 2;
|
||||||
repeated User ConnectingUsersList = 3;
|
repeated LinkLayerListUser ConnectingUsersList = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LinkerMediaChangeContent {
|
message LinkerMediaChangeContent {
|
||||||
// MicIdxOperation Op = 1;
|
// MicIdxOperation Op = 1;
|
||||||
int64 ToUserId = 2;
|
int64 ToUserId = 2;
|
||||||
int64 AnchorId = 3;
|
int64 AnchorId = 3;
|
||||||
int64 RoomId = 4;
|
int64 RoomId = 4;
|
||||||
// LinkerSceneType ChangeScene = 5;
|
// LinkerSceneType ChangeScene = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LinkerMicIdxUpdateContent {
|
message LinkerMicIdxUpdateContent {
|
||||||
@@ -1064,14 +1064,14 @@ message LinkerMicIdxUpdateContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message LinkerMicIdxUpdateInfo {
|
message LinkerMicIdxUpdateInfo {
|
||||||
// MicIdxOperation Op = 1;
|
// MicIdxOperation Op = 1;
|
||||||
int64 UserId = 2;
|
int64 UserId = 2;
|
||||||
int64 MicIdx = 3;
|
int64 MicIdx = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LinkerMuteContent {
|
message LinkerMuteContent {
|
||||||
int64 UserId = 1;
|
int64 UserId = 1;
|
||||||
// Data.MuteStatus Status = 2;
|
// Data.MuteStatus Status = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LinkerRandomMatchContent {
|
message LinkerRandomMatchContent {
|
||||||
@@ -1085,9 +1085,9 @@ message LinkerRandomMatchContent {
|
|||||||
message LinkerReplyContent {
|
message LinkerReplyContent {
|
||||||
int64 FromUserId = 1;
|
int64 FromUserId = 1;
|
||||||
int64 FromRoomId = 2;
|
int64 FromRoomId = 2;
|
||||||
// LinkmicInfo FromUserLinkmicInfo = 3;
|
// LinkmicInfo FromUserLinkmicInfo = 3;
|
||||||
int64 ToUserId = 4;
|
int64 ToUserId = 4;
|
||||||
// LinkmicInfo ToUserLinkmicInfo = 5;
|
// LinkmicInfo ToUserLinkmicInfo = 5;
|
||||||
int64 LinkType = 6;
|
int64 LinkType = 6;
|
||||||
int64 ReplyStatus = 7;
|
int64 ReplyStatus = 7;
|
||||||
LinkerSetting LinkerSetting = 8;
|
LinkerSetting LinkerSetting = 8;
|
||||||
@@ -1096,10 +1096,10 @@ message LinkerReplyContent {
|
|||||||
map<int64, string> RtcExtInfoMap = 11;
|
map<int64, string> RtcExtInfoMap = 11;
|
||||||
LinkerMicIdxUpdateInfo InviteeMicIdxUpdateInfo = 12;
|
LinkerMicIdxUpdateInfo InviteeMicIdxUpdateInfo = 12;
|
||||||
map<int64, int64> ApplierMicIdxInfoMap = 13;
|
map<int64, int64> ApplierMicIdxInfoMap = 13;
|
||||||
// Data.LinkmicMultiLiveEnum AnchorMultiLiveEnum = 14;
|
// Data.LinkmicMultiLiveEnum AnchorMultiLiveEnum = 14;
|
||||||
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 15;
|
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 15;
|
||||||
int64 ActionId = 16;
|
int64 ActionId = 16;
|
||||||
// repeated LinkmicUserInfo LinkedUsersList = 17;
|
// repeated LinkmicUserInfo LinkedUsersList = 17;
|
||||||
int64 SourceType = 18;
|
int64 SourceType = 18;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1124,7 +1124,7 @@ message LinkerUpdateUserContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message LinkerUpdateUserSettingContent {
|
message LinkerUpdateUserSettingContent {
|
||||||
// Data.LinkmicUserSettingInfo UpdateUserSettingInfo = 1;
|
// Data.LinkmicUserSettingInfo UpdateUserSettingInfo = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LinkerWaitingListChangeContent {
|
message LinkerWaitingListChangeContent {
|
||||||
@@ -1156,10 +1156,11 @@ message AllListUser {
|
|||||||
|
|
||||||
message LinkLayerListUser {
|
message LinkLayerListUser {
|
||||||
User user = 1;
|
User user = 1;
|
||||||
string linkmicId = 2;
|
int64 linkmicId = 2;
|
||||||
Position pos = 3;
|
Position pos = 3;
|
||||||
int64 linkedTimeNano = 4;
|
int64 linkedTimeNano = 4;
|
||||||
string appVersion = 5;
|
string appVersion = 5;
|
||||||
|
int64 magicNumber1 = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Position {
|
message Position {
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ message WebcastGiftMessage {
|
|||||||
int32 repeatCount = 5;
|
int32 repeatCount = 5;
|
||||||
int32 comboCount = 6;
|
int32 comboCount = 6;
|
||||||
User user = 7;
|
User user = 7;
|
||||||
User toUser = 8;
|
|
||||||
int32 repeatEnd = 9;
|
int32 repeatEnd = 9;
|
||||||
int64 groupId = 11;
|
int64 groupId = 11;
|
||||||
int64 incomeTaskgifts = 12;
|
int64 incomeTaskgifts = 12;
|
||||||
@@ -81,6 +80,13 @@ message WebcastGiftMessage {
|
|||||||
bool isFirstSent = 25;
|
bool isFirstSent = 25;
|
||||||
string orderId = 28;
|
string orderId = 28;
|
||||||
UserIdentity userIdentity = 32;
|
UserIdentity userIdentity = 32;
|
||||||
|
UserGiftReciever userGiftReciever = 23;
|
||||||
|
|
||||||
|
message UserGiftReciever
|
||||||
|
{
|
||||||
|
int64 userId =1;
|
||||||
|
string deviceName = 10;
|
||||||
|
}
|
||||||
|
|
||||||
message GiftIMPriority {
|
message GiftIMPriority {
|
||||||
repeated int64 queueSizesList = 1;
|
repeated int64 queueSizesList = 1;
|
||||||
@@ -507,6 +513,9 @@ message WebcastHourlyRankMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//<Battles>
|
||||||
|
|
||||||
//@WebcastLinkMicArmies
|
//@WebcastLinkMicArmies
|
||||||
message WebcastLinkMicArmies {
|
message WebcastLinkMicArmies {
|
||||||
Common common = 1;
|
Common common = 1;
|
||||||
@@ -523,6 +532,45 @@ message WebcastLinkMicArmies {
|
|||||||
uint32 data4 = 12;
|
uint32 data4 = 12;
|
||||||
uint32 data5 = 13;
|
uint32 data5 = 13;
|
||||||
}
|
}
|
||||||
|
//@WebcastLinkMicBattlePunishFinish
|
||||||
|
message WebcastLinkMicBattlePunishFinish {
|
||||||
|
Common Header = 1;
|
||||||
|
uint64 Id1 = 2;
|
||||||
|
uint64 Timestamp = 3;
|
||||||
|
uint32 Data4 = 4;
|
||||||
|
uint64 Id2 = 5;
|
||||||
|
LinkMicBattlePunishFinishData Data6 = 6;
|
||||||
|
|
||||||
|
message LinkMicBattlePunishFinishData {
|
||||||
|
uint64 Id2 = 1; // Same as Id2 in outer object (loser?)
|
||||||
|
uint64 Timestamp = 2;
|
||||||
|
uint32 Data3 = 3;
|
||||||
|
uint64 Id1 = 4; // Same as Id1 in outer object (winner?)
|
||||||
|
uint32 Data5 = 5;
|
||||||
|
uint32 Data6 = 6;
|
||||||
|
uint32 Data8 = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//@WebcastLinkmicBattleTaskMessage
|
||||||
|
message WebcastLinkmicBattleTaskMessage {
|
||||||
|
Common Header = 1;
|
||||||
|
uint32 Data2 = 2;
|
||||||
|
LinkmicBattleTaskData Data3 = 3;
|
||||||
|
LinkmicBattleTaskData2 Data5 = 5;
|
||||||
|
|
||||||
|
message LinkmicBattleTaskData {
|
||||||
|
BattleTaskData Data1 = 1;
|
||||||
|
}
|
||||||
|
message BattleTaskData {
|
||||||
|
uint32 Data1 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LinkmicBattleTaskData2 {
|
||||||
|
uint32 Data1 = 1;
|
||||||
|
uint32 Data2 = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//@WebcastLinkMicBattle
|
//@WebcastLinkMicBattle
|
||||||
message WebcastLinkMicBattle {
|
message WebcastLinkMicBattle {
|
||||||
@@ -572,7 +620,6 @@ message WebcastLinkMicFanTicketMethod {
|
|||||||
Common common = 1;
|
Common common = 1;
|
||||||
FanTicketRoomNoticeContent FanTicketRoomNotice = 2;
|
FanTicketRoomNoticeContent FanTicketRoomNotice = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//@WebcastLinkMicMethod
|
//@WebcastLinkMicMethod
|
||||||
message WebcastLinkMicMethod {
|
message WebcastLinkMicMethod {
|
||||||
Common common = 1;
|
Common common = 1;
|
||||||
@@ -590,6 +637,8 @@ message WebcastLinkMicMethod {
|
|||||||
int64 inviteUid = 13;
|
int64 inviteUid = 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//<Battles>
|
||||||
|
|
||||||
//@WebcastLiveIntroMessage
|
//@WebcastLiveIntroMessage
|
||||||
message WebcastLiveIntroMessage {
|
message WebcastLiveIntroMessage {
|
||||||
Common common = 1;
|
Common common = 1;
|
||||||
|
|||||||
@@ -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.0.7-Release</version>
|
<version>1.0.9-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -87,4 +87,5 @@ public class TikTokLive
|
|||||||
{
|
{
|
||||||
return new TikTokDataChecker().isHostNameValidAsync(hostName);
|
return new TikTokDataChecker().isHostNameValidAsync(hostName);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ package io.github.jwdeveloper.tiktok;
|
|||||||
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;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
|
||||||
@@ -189,4 +190,8 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
liveRoomInfo.setConnectionState(connectionState);
|
liveRoomInfo.setConnectionState(connectionState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void publishEvent(TikTokEvent event)
|
||||||
|
{
|
||||||
|
tikTokEventHandler.publish(this, event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
|||||||
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
|
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
|
||||||
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;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
|
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
|
||||||
@@ -41,23 +42,25 @@ import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
|||||||
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
|
||||||
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
|
||||||
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper;
|
|
||||||
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
|
|
||||||
import io.github.jwdeveloper.tiktok.mappers.events.TikTokCommonEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.mappers.events.TikTokGiftEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.mappers.events.TikTokRoomInfoEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.mappers.events.TikTokSocialMediaEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||||
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
|
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
|
||||||
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
|
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
|
||||||
|
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
|
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
|
||||||
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||||
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
|
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapperHelper;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokCommonEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokGiftEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokRoomInfoEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokSocialMediaEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.*;
|
import io.github.jwdeveloper.tiktok.messages.webcast.*;
|
||||||
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
||||||
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
|
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
|
||||||
@@ -88,12 +91,12 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings) {
|
public LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings) {
|
||||||
this.onCustomMappings = onCustomMappings;
|
this.onCustomMappings = onCustomMappings;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> onConfigure) {
|
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> onConfigure) {
|
||||||
onConfigure.accept(clientSettings);
|
onConfigure.accept(clientSettings);
|
||||||
return this;
|
return this;
|
||||||
@@ -159,7 +162,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
|
|
||||||
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
|
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
|
||||||
var cookieJar = new TikTokCookieJar();
|
var cookieJar = new TikTokCookieJar();
|
||||||
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
|
var requestFactory = new TikTokHttpRequestFactory(cookieJar, tikTokEventHandler);
|
||||||
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
|
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
|
||||||
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
|
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
|
||||||
var giftManager = new TikTokGiftManager(logger);
|
var giftManager = new TikTokGiftManager(logger);
|
||||||
@@ -167,7 +170,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
var messageHandler = new TikTokMessageHandler(tikTokEventHandler, eventsMapper);
|
var messageHandler = new TikTokMessageHandler(tikTokEventHandler, eventsMapper);
|
||||||
|
|
||||||
|
|
||||||
var webSocketClient = new TikTokWebSocketClient(logger,
|
var webSocketClient = new TikTokWebSocketClient(
|
||||||
cookieJar,
|
cookieJar,
|
||||||
clientSettings,
|
clientSettings,
|
||||||
messageHandler,
|
messageHandler,
|
||||||
@@ -185,7 +188,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
|
|
||||||
public TikTokLiveMapper createMapper(GiftManager giftManager, TikTokRoomInfo roomInfo) {
|
public TikTokLiveMapper createMapper(GiftManager giftManager, TikTokRoomInfo roomInfo) {
|
||||||
var eventMapper = new TikTokGenericEventMapper();
|
var eventMapper = new TikTokGenericEventMapper();
|
||||||
var mapper = new TikTokLiveMapper(eventMapper);
|
var mapper = new TikTokLiveMapper(new TikTokLiveMapperHelper(eventMapper));
|
||||||
|
|
||||||
//ConnectionEvents events
|
//ConnectionEvents events
|
||||||
var commonHandler = new TikTokCommonEventHandler();
|
var commonHandler = new TikTokCommonEventHandler();
|
||||||
@@ -193,48 +196,77 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
var roomInfoHandler = new TikTokRoomInfoEventHandler(roomInfo);
|
var roomInfoHandler = new TikTokRoomInfoEventHandler(roomInfo);
|
||||||
var socialHandler = new TikTokSocialMediaEventHandler(roomInfo);
|
var socialHandler = new TikTokSocialMediaEventHandler(roomInfo);
|
||||||
|
|
||||||
mapper.bytesToEvent(WebcastControlMessage.class, commonHandler::handleWebcastControlMessage);
|
|
||||||
|
mapper.forMessage(WebcastControlMessage.class, commonHandler::handleWebcastControlMessage);
|
||||||
|
|
||||||
//Room status events
|
//Room status events
|
||||||
mapper.bytesToEvent(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
|
mapper.forMessage(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
|
||||||
mapper.bytesToEvent(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
|
mapper.forMessage(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
|
||||||
|
mapper.forMessage(WebcastCaptionMessage.class, (inputBytes, messageName, mapperHelper) ->
|
||||||
|
{
|
||||||
|
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastCaptionMessage.class);
|
||||||
|
return MappingResult.of(messageObject, new TikTokCaptionEvent(messageObject));
|
||||||
|
});
|
||||||
|
|
||||||
mapper.webcastObjectToConstructor(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
|
|
||||||
|
|
||||||
//User Interactions events
|
//User Interactions events
|
||||||
mapper.webcastObjectToConstructor(WebcastChatMessage.class, TikTokCommentEvent.class);
|
mapper.forMessage(WebcastChatMessage.class, (inputBytes, messageName, mapperHelper) ->
|
||||||
mapper.bytesToEvents(WebcastLikeMessage.class, roomInfoHandler::handleLike);
|
{
|
||||||
mapper.bytesToEvents(WebcastGiftMessage.class, giftHandler::handleGift);
|
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
|
||||||
mapper.bytesToEvent(WebcastSocialMessage.class, socialHandler::handle);
|
return MappingResult.of(messageObject, new TikTokCommentEvent(messageObject));
|
||||||
mapper.bytesToEvents(WebcastMemberMessage.class, roomInfoHandler::handleMemberMessage);
|
});
|
||||||
|
mapper.forMessage(WebcastSubNotifyMessage.class, (inputBytes, messageName, mapperHelper) ->
|
||||||
|
{
|
||||||
|
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastSubNotifyMessage.class);
|
||||||
|
return MappingResult.of(messageObject, new TikTokSubscribeEvent(messageObject));
|
||||||
|
});
|
||||||
|
mapper.forMessage(WebcastEmoteChatMessage.class, (inputBytes, messageName, mapperHelper) ->
|
||||||
|
{
|
||||||
|
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastEmoteChatMessage.class);
|
||||||
|
return MappingResult.of(messageObject, new TikTokEmoteEvent(messageObject));
|
||||||
|
});
|
||||||
|
mapper.forMessage(WebcastQuestionNewMessage.class, (inputBytes, messageName, mapperHelper) ->
|
||||||
|
{
|
||||||
|
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastQuestionNewMessage.class);
|
||||||
|
return MappingResult.of(messageObject, new TikTokQuestionEvent(messageObject));
|
||||||
|
});
|
||||||
|
|
||||||
|
mapper.forMessage(WebcastLikeMessage.class, roomInfoHandler::handleLike);
|
||||||
|
mapper.forMessage(WebcastGiftMessage.class, giftHandler::handleGifts);
|
||||||
|
mapper.forMessage(WebcastSocialMessage.class, socialHandler::handle);
|
||||||
|
mapper.forMessage(WebcastMemberMessage.class, roomInfoHandler::handleMemberMessage);
|
||||||
|
|
||||||
|
|
||||||
//Host Interaction events
|
//Host Interaction events
|
||||||
mapper.bytesToEvent(WebcastPollMessage.class, commonHandler::handlePollEvent);
|
mapper.forMessage(WebcastPollMessage.class, commonHandler::handlePollEvent);
|
||||||
mapper.bytesToEvent(WebcastRoomPinMessage.class, commonHandler::handlePinMessage);
|
mapper.forMessage(WebcastRoomPinMessage.class, commonHandler::handlePinMessage);
|
||||||
mapper.webcastObjectToConstructor(WebcastGoalUpdateMessage.class, TikTokGoalUpdateEvent.class);
|
mapper.forMessage(WebcastChatMessage.class, (inputBytes, messageName, mapperHelper) ->
|
||||||
|
{
|
||||||
|
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
|
||||||
|
return MappingResult.of(messageObject, new TikTokCommentEvent(messageObject));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
//LinkMic events
|
//LinkMic events
|
||||||
mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
|
||||||
|
|
||||||
//Rank events
|
//Rank events
|
||||||
mapper.webcastObjectToConstructor(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
|
||||||
|
|
||||||
//Others events
|
//Others events
|
||||||
mapper.webcastObjectToConstructor(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
|
// mapper.webcastObjectToConstructor(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
|
||||||
mapper.webcastObjectToConstructor(WebcastQuestionNewMessage.class, TikTokQuestionEvent.class);
|
// mapper.bytesToEvents(WebcastEnvelopeMessage.class, commonHandler::handleEnvelop);
|
||||||
mapper.bytesToEvents(WebcastEnvelopeMessage.class, commonHandler::handleEnvelop);
|
|
||||||
mapper.webcastObjectToConstructor(WebcastSubNotifyMessage.class, TikTokSubscribeEvent.class);
|
|
||||||
mapper.webcastObjectToConstructor(WebcastEmoteChatMessage.class, TikTokEmoteEvent.class);
|
|
||||||
|
|
||||||
onCustomMappings.accept(mapper);
|
onCustomMappings.accept(mapper);
|
||||||
return mapper;
|
return mapper;
|
||||||
@@ -315,8 +347,8 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <E extends TikTokEvent> LiveClientBuilder onCustomEvent(Class<E> eventClazz, EventConsumer<E> event) {
|
public <E extends TikTokEvent> LiveClientBuilder onEvent(Class<E> eventClass, EventConsumer<E> event) {
|
||||||
tikTokEventHandler.subscribe(eventClazz, event);
|
tikTokEventHandler.subscribe(eventClass, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,6 +448,12 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LiveClientBuilder onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokHttpResponseEvent.class, action);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onGoalUpdate(EventConsumer<TikTokGoalUpdateEvent> event) {
|
public TikTokLiveClientBuilder onGoalUpdate(EventConsumer<TikTokGoalUpdateEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokGoalUpdateEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokGoalUpdateEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class TikTokRoomInfo implements LiveRoomInfo {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User getHostUser() {
|
public User getHostUser() {
|
||||||
return null;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateRanking(List<RankingUser> rankingUsers) {
|
public void updateRanking(List<RankingUser> rankingUsers) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import io.github.jwdeveloper.tiktok.ClientSettings;
|
|||||||
import io.github.jwdeveloper.tiktok.Constants;
|
import io.github.jwdeveloper.tiktok.Constants;
|
||||||
import io.github.jwdeveloper.tiktok.data.dto.TikTokUserInfo;
|
import io.github.jwdeveloper.tiktok.data.dto.TikTokUserInfo;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -54,7 +55,7 @@ public class TikTokDataChecker {
|
|||||||
|
|
||||||
public TikTokApiService getApiService() {
|
public TikTokApiService getApiService() {
|
||||||
var jar = new TikTokCookieJar();
|
var jar = new TikTokCookieJar();
|
||||||
var factory = new TikTokHttpRequestFactory(jar);
|
var factory = new TikTokHttpRequestFactory(jar,new TikTokEventObserver());
|
||||||
var client = new TikTokHttpClient(jar, factory);
|
var client = new TikTokHttpClient(jar, factory);
|
||||||
var settings = new ClientSettings();
|
var settings = new ClientSettings();
|
||||||
settings.setClientParameters(Constants.DefaultClientParams());
|
settings.setClientParameters(Constants.DefaultClientParams());
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ public class TikTokHttpClient {
|
|||||||
if (parameters == null) {
|
if (parameters == null) {
|
||||||
parameters = new HashMap<>();
|
parameters = new HashMap<>();
|
||||||
}
|
}
|
||||||
System.out.println("RomMID: "+parameters.get("room_id"));
|
|
||||||
var request = requestFactory.setQueries(parameters);
|
var request = requestFactory.setQueries(parameters);
|
||||||
return request.post(url);
|
return request.post(url);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,10 @@ package io.github.jwdeveloper.tiktok.http;
|
|||||||
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.Constants;
|
import io.github.jwdeveloper.tiktok.Constants;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.http.HttpData;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import java.net.CookieManager;
|
import java.net.CookieManager;
|
||||||
@@ -45,26 +48,27 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
|||||||
private final Map<String, String> defaultHeaders;
|
private final Map<String, String> defaultHeaders;
|
||||||
private final TikTokCookieJar tikTokCookieJar;
|
private final TikTokCookieJar tikTokCookieJar;
|
||||||
private final HttpClient client;
|
private final HttpClient client;
|
||||||
|
private final TikTokEventObserver eventHandler;
|
||||||
private String query;
|
private String query;
|
||||||
|
|
||||||
public TikTokHttpRequestFactory(TikTokCookieJar tikTokCookieJar) {
|
public TikTokHttpRequestFactory(TikTokCookieJar tikTokCookieJar, TikTokEventObserver eventHandler) {
|
||||||
this.tikTokCookieJar = tikTokCookieJar;
|
this.tikTokCookieJar = tikTokCookieJar;
|
||||||
this.cookieManager = new CookieManager();
|
this.cookieManager = new CookieManager();
|
||||||
|
this.eventHandler = eventHandler;
|
||||||
defaultHeaders = Constants.DefaultRequestHeaders();
|
defaultHeaders = Constants.DefaultRequestHeaders();
|
||||||
client = HttpClient.newBuilder()
|
client = HttpClient.newBuilder()
|
||||||
.cookieHandler(cookieManager)
|
.cookieHandler(cookieManager)
|
||||||
.connectTimeout(Duration.ofSeconds(2))
|
.connectTimeout(Duration.ofSeconds(2))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String get(String url) {
|
public String get(String url) {
|
||||||
var uri = URI.create(url);
|
var uri = URI.create(url);
|
||||||
var requestBuilder = HttpRequest.newBuilder().GET();
|
var requestBuilder = HttpRequest.newBuilder().GET();
|
||||||
|
|
||||||
for (var header : defaultHeaders.entrySet())
|
for (var header : defaultHeaders.entrySet()) {
|
||||||
{
|
if (header.getKey().equals("Connection") || header.getKey().equals("Accept-Encoding")) {
|
||||||
if(header.getKey().equals("Connection") || header.getKey().equals("Accept-Encoding"))
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
requestBuilder.setHeader(header.getKey(), header.getValue());
|
requestBuilder.setHeader(header.getKey(), header.getValue());
|
||||||
@@ -73,9 +77,7 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
|||||||
var baseUri = uri.toString();
|
var baseUri = uri.toString();
|
||||||
var requestUri = URI.create(baseUri + "?" + query);
|
var requestUri = URI.create(baseUri + "?" + query);
|
||||||
requestBuilder.uri(requestUri);
|
requestBuilder.uri(requestUri);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
requestBuilder.uri(uri);
|
requestBuilder.uri(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,15 +90,13 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
|||||||
public String post(String url) {
|
public String post(String url) {
|
||||||
var uri = URI.create(url);
|
var uri = URI.create(url);
|
||||||
var request = HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(""));
|
var request = HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(""));
|
||||||
for (var header : defaultHeaders.entrySet())
|
for (var header : defaultHeaders.entrySet()) {
|
||||||
{
|
if (header.getKey().equals("Connection")) {
|
||||||
if(header.getKey().equals("Connection"))
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
request.setHeader(header.getKey(), header.getValue());
|
request.setHeader(header.getKey(), header.getValue());
|
||||||
}
|
}
|
||||||
request.setHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8");
|
request.setHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||||
request.setHeader("Cookie", tikTokCookieJar.parseCookies());
|
request.setHeader("Cookie", tikTokCookieJar.parseCookies());
|
||||||
|
|
||||||
|
|
||||||
@@ -104,11 +104,8 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
|||||||
var baseUri = uri.toString();
|
var baseUri = uri.toString();
|
||||||
var requestUri = URI.create(baseUri + "?" + query);
|
var requestUri = URI.create(baseUri + "?" + query);
|
||||||
request.uri(requestUri);
|
request.uri(requestUri);
|
||||||
System.out.println(requestUri.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return getContent(request.build());
|
return getContent(request.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +122,7 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
|||||||
public TikTokHttpRequest setQueries(Map<String, Object> queries) {
|
public TikTokHttpRequest setQueries(Map<String, Object> queries) {
|
||||||
if (queries == null)
|
if (queries == null)
|
||||||
return this;
|
return this;
|
||||||
var testMap = new TreeMap<String,Object>(queries);
|
var testMap = new TreeMap<String, Object>(queries);
|
||||||
query = String.join("&", testMap.entrySet().stream().map(x ->
|
query = String.join("&", testMap.entrySet().stream().map(x ->
|
||||||
{
|
{
|
||||||
var key = x.getKey();
|
var key = x.getKey();
|
||||||
@@ -143,6 +140,9 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
|||||||
|
|
||||||
private String getContent(HttpRequest request) throws Exception {
|
private String getContent(HttpRequest request) throws Exception {
|
||||||
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
var event = new TikTokHttpResponseEvent(response.uri().toString(), HttpData.map(request), HttpData.map(response));
|
||||||
|
eventHandler.publish(null, event);
|
||||||
if (response.statusCode() == 404) {
|
if (response.statusCode() == 404) {
|
||||||
throw new TikTokLiveRequestException("Request responded with 404 NOT_FOUND");
|
throw new TikTokLiveRequestException("Request responded with 404 NOT_FOUND");
|
||||||
}
|
}
|
||||||
@@ -155,8 +155,6 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
|||||||
for (var cookie : cookies) {
|
for (var cookie : cookies) {
|
||||||
var split = cookie.split(";")[0].split("=");
|
var split = cookie.split(";")[0].split("=");
|
||||||
var uri = request.uri();
|
var uri = request.uri();
|
||||||
|
|
||||||
|
|
||||||
var key = split[0];
|
var key = split[0];
|
||||||
var value = split[1];
|
var value = split[1];
|
||||||
tikTokCookieJar.set(key, value);
|
tikTokCookieJar.set(key, value);
|
||||||
|
|||||||
@@ -23,11 +23,10 @@
|
|||||||
package io.github.jwdeveloper.tiktok.listener;
|
package io.github.jwdeveloper.tiktok.listener;
|
||||||
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.annotations.TikTokEventHandler;
|
import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokEventListenerMethodException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokEventListenerMethodException;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
|
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
|
||||||
|
|
||||||
@@ -37,10 +36,10 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TikTokListenersManager implements ListenersManager {
|
public class TikTokListenersManager implements ListenersManager {
|
||||||
private final TikTokEventObserver eventObserver;
|
private final io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver eventObserver;
|
||||||
private final List<ListenerBindingModel> bindingModels;
|
private final List<ListenerBindingModel> bindingModels;
|
||||||
|
|
||||||
public TikTokListenersManager(List<TikTokEventListener> listeners, TikTokEventObserver tikTokEventHandler) {
|
public TikTokListenersManager(List<TikTokEventListener> listeners, io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver tikTokEventHandler) {
|
||||||
this.eventObserver = tikTokEventHandler;
|
this.eventObserver = tikTokEventHandler;
|
||||||
this.bindingModels = new ArrayList<>(listeners.size());
|
this.bindingModels = new ArrayList<>(listeners.size());
|
||||||
for (var listener : listeners) {
|
for (var listener : listeners) {
|
||||||
@@ -93,7 +92,7 @@ public class TikTokListenersManager implements ListenersManager {
|
|||||||
var clazz = listener.getClass();
|
var clazz = listener.getClass();
|
||||||
var methods = Arrays.stream(clazz.getDeclaredMethods()).filter(m ->
|
var methods = Arrays.stream(clazz.getDeclaredMethods()).filter(m ->
|
||||||
m.getParameterCount() == 2 &&
|
m.getParameterCount() == 2 &&
|
||||||
m.isAnnotationPresent(TikTokEventHandler.class)).toList();
|
m.isAnnotationPresent(TikTokEventObserver.class)).toList();
|
||||||
var eventsMap = new HashMap<Class<?>, List<EventConsumer<?>>>();
|
var eventsMap = new HashMap<Class<?>, List<EventConsumer<?>>>();
|
||||||
for (var method : methods) {
|
for (var method : methods) {
|
||||||
var eventClazz = method.getParameterTypes()[1];
|
var eventClazz = method.getParameterTypes()[1];
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ package io.github.jwdeveloper.tiktok.mappers;
|
|||||||
|
|
||||||
import com.google.protobuf.GeneratedMessageV3;
|
import com.google.protobuf.GeneratedMessageV3;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingAction;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -32,79 +33,68 @@ import java.util.Map;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class TikTokLiveMapper implements TikTokMapper {
|
public class TikTokLiveMapper implements TikTokMapper {
|
||||||
private final Map<String, Function<byte[], List<TikTokEvent>>> mappers;
|
|
||||||
private final TikTokGenericEventMapper genericMapper;
|
|
||||||
|
|
||||||
public TikTokLiveMapper(TikTokGenericEventMapper genericMapper) {
|
private final Map<String, TikTokLiveMapperModel> mappers;
|
||||||
|
private final TikTokMapperHelper mapperUtils;
|
||||||
|
|
||||||
|
public TikTokLiveMapper(TikTokMapperHelper mapperUtils) {
|
||||||
this.mappers = new HashMap<>();
|
this.mappers = new HashMap<>();
|
||||||
this.genericMapper = genericMapper;
|
this.mapperUtils = mapperUtils;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bytesToEvent(String messageName, Function<byte[], TikTokEvent> onMapping) {
|
public TikTokMapperModel forMessage(String messageName) {
|
||||||
mappers.put(messageName, messagePayload -> List.of(onMapping.apply(messagePayload)));
|
if (!isRegistered(messageName)) {
|
||||||
|
var model = new TikTokLiveMapperModel(messageName);
|
||||||
|
mappers.put(messageName, model);
|
||||||
|
}
|
||||||
|
return mappers.get(messageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bytesToEvents(String messageName, Function<byte[], List<TikTokEvent>> onMapping) {
|
public TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName) {
|
||||||
mappers.put(messageName, onMapping::apply);
|
return forMessage(mapperName.getSimpleName());
|
||||||
}
|
|
||||||
|
|
||||||
public void bytesToEvent(Class<? extends GeneratedMessageV3> clazz, Function<byte[], TikTokEvent> onMapping) {
|
|
||||||
mappers.put(clazz.getSimpleName(), messagePayload -> List.of(onMapping.apply(messagePayload)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void bytesToEvents(Class<? extends GeneratedMessageV3> clazz, Function<byte[], List<TikTokEvent>> onMapping) {
|
|
||||||
mappers.put(clazz.getSimpleName(), onMapping::apply);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void webcastObjectToConstructor(Class<? extends GeneratedMessageV3> sourceClass, Class<? extends TikTokEvent> outputClass) {
|
public TikTokMapperModel forMessage(String mapperName, MappingAction<MappingResult> onMapping) {
|
||||||
bytesToEvent(sourceClass, (e) -> genericMapper.mapToEvent(sourceClass, outputClass, e));
|
var model = forMessage(mapperName);
|
||||||
|
model.onMapping(onMapping);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName, MappingAction<MappingResult> onMapping) {
|
||||||
|
var model = forMessage(mapperName);
|
||||||
|
model.onMapping(onMapping);
|
||||||
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends GeneratedMessageV3> void webcastObjectToEvent(Class<T> source, Function<T, TikTokEvent> onMapping) {
|
public TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName, Function<byte[], TikTokEvent> onMapping) {
|
||||||
bytesToEvent(source, (bytes) ->
|
return forMessage(mapperName, (inputBytes, messageName, mapperHelper) -> MappingResult.of(inputBytes, onMapping.apply(inputBytes)));
|
||||||
{
|
|
||||||
try {
|
|
||||||
var parsingMethod = genericMapper.getParsingMethod(source);
|
|
||||||
var sourceObject = parsingMethod.invoke(null, bytes);
|
|
||||||
var event = onMapping.apply((T) sourceObject);
|
|
||||||
return event;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new TikTokMessageMappingException(source, "can't find parsing method", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T extends GeneratedMessageV3> void webcastObjectToEvents(Class<T> source, Function<T, List<TikTokEvent>> onMapping) {
|
public boolean isRegistered(String mapperName) {
|
||||||
bytesToEvents(source, (bytes) ->
|
return mappers.containsKey(mapperName);
|
||||||
{
|
|
||||||
try {
|
|
||||||
var parsingMethod = genericMapper.getParsingMethod(source);
|
|
||||||
var sourceObject = parsingMethod.invoke(null, bytes);
|
|
||||||
var event = onMapping.apply((T) sourceObject);
|
|
||||||
return event;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new TikTokMessageMappingException(source, "can't find parsing method", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRegistered(String input) {
|
public <T extends GeneratedMessageV3> boolean isRegistered(Class<T> mapperName) {
|
||||||
return mappers.containsKey(input);
|
return mappers.containsKey(mapperName.getSimpleName());
|
||||||
}
|
}
|
||||||
|
public List<TikTokEvent> handleMapping(String messageName, byte[] bytes) {
|
||||||
public List<TikTokEvent> handleMapping(String input, byte[] bytes) {
|
if (!isRegistered(messageName)) {
|
||||||
if (!isRegistered(input)) {
|
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
var mapper = mappers.get(input);
|
var mapperModel = mappers.get(messageName);
|
||||||
var events = mapper.apply(bytes);
|
|
||||||
return events;
|
var inputBytes = mapperModel.getOnBeforeMapping().onMapping(bytes, messageName, mapperUtils);
|
||||||
|
|
||||||
|
var mappingResult = mapperModel.getOnMapping().onMapping(inputBytes, messageName, mapperUtils);
|
||||||
|
|
||||||
|
var afterMappingResult = mapperModel.getOnAfterMapping().apply(mappingResult);
|
||||||
|
return afterMappingResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.mappers;
|
||||||
|
|
||||||
|
import com.google.protobuf.GeneratedMessageV3;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
|
||||||
|
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
|
||||||
|
import io.github.jwdeveloper.tiktok.utils.ProtoBufferObject;
|
||||||
|
import io.github.jwdeveloper.tiktok.utils.ProtocolUtils;
|
||||||
|
|
||||||
|
public class TikTokLiveMapperHelper implements TikTokMapperHelper {
|
||||||
|
private final TikTokGenericEventMapper genericMapper;
|
||||||
|
|
||||||
|
public TikTokLiveMapperHelper(TikTokGenericEventMapper genericMapper) {
|
||||||
|
this.genericMapper = genericMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends GeneratedMessageV3> T bytesToWebcastObject(byte[] bytes, Class<T> messageClass) {
|
||||||
|
try {
|
||||||
|
var parsingMethod = genericMapper.getParsingMethod(messageClass);
|
||||||
|
var sourceObject = parsingMethod.invoke(null, bytes);
|
||||||
|
return (T) sourceObject;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new TikTokMessageMappingException(messageClass, "can't find parsing method", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object bytesToWebcastObject(byte[] bytes, String messageName) {
|
||||||
|
try {
|
||||||
|
var packageName = "io.github.jwdeveloper.tiktok.messages.webcast." + messageName;
|
||||||
|
var clazz = Class.forName(packageName);
|
||||||
|
return bytesToWebcastObject(bytes, (Class<? extends GeneratedMessageV3>) clazz);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new TikTokMessageMappingException(messageName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMessageHasProtoClass(String messageName) {
|
||||||
|
try {
|
||||||
|
var packageName = "io.github.jwdeveloper.tiktok.messages.webcast." + messageName;
|
||||||
|
Class.forName(packageName);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProtoBufferObject bytesToProtoBufferStructure(byte[] bytes) {
|
||||||
|
return ProtocolUtils.getProtocolBufferStructure(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toJson(Object obj) {
|
||||||
|
return JsonUtil.toJson(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.mappers;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingAction;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class TikTokLiveMapperModel implements TikTokMapperModel {
|
||||||
|
@Getter
|
||||||
|
private String sourceMessageName;
|
||||||
|
|
||||||
|
private MappingAction<byte[]> onBeforeMapping;
|
||||||
|
|
||||||
|
private MappingAction<MappingResult> onMapping;
|
||||||
|
|
||||||
|
private Function<MappingResult, List<TikTokEvent>> onAfterMapping;
|
||||||
|
|
||||||
|
public TikTokLiveMapperModel(String sourceMessageName, MappingAction onMapping) {
|
||||||
|
this.sourceMessageName = sourceMessageName;
|
||||||
|
this.onBeforeMapping = (inputBytes, mesasgeName, mapperHelper) -> inputBytes;
|
||||||
|
this.onMapping = onMapping;
|
||||||
|
this.onAfterMapping = MappingResult::getEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TikTokLiveMapperModel(String sourceMessageName) {
|
||||||
|
this.sourceMessageName = sourceMessageName;
|
||||||
|
this.onBeforeMapping = (inputBytes, mesasgeName, mapperHelper) -> inputBytes;
|
||||||
|
this.onMapping = (inputBytes, mesasgeName, mapperHelper) -> MappingResult.of(inputBytes, List.of());
|
||||||
|
this.onAfterMapping = MappingResult::getEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TikTokMapperModel onBeforeMapping(MappingAction<byte[]> action) {
|
||||||
|
this.onBeforeMapping = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TikTokMapperModel onMapping(MappingAction<MappingResult> action) {
|
||||||
|
this.onMapping = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TikTokMapperModel onAfterMapping(Function<MappingResult, List<TikTokEvent>> action) {
|
||||||
|
this.onAfterMapping = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* 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.mappers.events;
|
package io.github.jwdeveloper.tiktok.mappers.handlers;
|
||||||
|
|
||||||
public class TikTokChestEventHandler {
|
public class TikTokChestEventHandler {
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* 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.mappers.events;
|
package io.github.jwdeveloper.tiktok.mappers.handlers;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* 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.mappers.events;
|
package io.github.jwdeveloper.tiktok.mappers.handlers;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
||||||
@@ -30,6 +30,8 @@ import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
|
|||||||
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.TikTokMapperHelper;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import sun.misc.Unsafe;
|
import sun.misc.Unsafe;
|
||||||
@@ -48,9 +50,10 @@ public class TikTokGiftEventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public List<TikTokEvent> handleGift(byte[] msg) {
|
public MappingResult handleGifts(byte[] msg, String name, TikTokMapperHelper helper) {
|
||||||
var currentMessage = WebcastGiftMessage.parseFrom(msg);
|
var currentMessage = WebcastGiftMessage.parseFrom(msg);
|
||||||
return handleGift(currentMessage);
|
var gifts = handleGift(currentMessage);
|
||||||
|
return MappingResult.of(currentMessage,gifts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TikTokEvent> handleGift(WebcastGiftMessage currentMessage) {
|
public List<TikTokEvent> handleGift(WebcastGiftMessage currentMessage) {
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* 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.mappers.events;
|
package io.github.jwdeveloper.tiktok.mappers.handlers;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
|
||||||
@@ -31,6 +31,8 @@ import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
|||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.RankingUser;
|
import io.github.jwdeveloper.tiktok.data.models.RankingUser;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.TikTokMapperHelper;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLikeMessage;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLikeMessage;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
|
||||||
@@ -76,8 +78,7 @@ public class TikTokRoomInfoEventHandler {
|
|||||||
|
|
||||||
return handleRoomInfo(tikTokRoomInfo ->
|
return handleRoomInfo(tikTokRoomInfo ->
|
||||||
{
|
{
|
||||||
if(tikTokRoomInfo.getHost() == null)
|
if (tikTokRoomInfo.getHost() == null) {
|
||||||
{
|
|
||||||
tikTokRoomInfo.setHost(hostUser);
|
tikTokRoomInfo.setHost(hostUser);
|
||||||
}
|
}
|
||||||
tikTokRoomInfo.setLanguage(language);
|
tikTokRoomInfo.setLanguage(language);
|
||||||
@@ -85,7 +86,7 @@ public class TikTokRoomInfoEventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public List<TikTokEvent> handleMemberMessage(byte[] msg) {
|
public MappingResult handleMemberMessage(byte[] msg, String name, TikTokMapperHelper helper) {
|
||||||
var message = WebcastMemberMessage.parseFrom(msg);
|
var message = WebcastMemberMessage.parseFrom(msg);
|
||||||
|
|
||||||
var event = switch (message.getAction()) {
|
var event = switch (message.getAction()) {
|
||||||
@@ -98,18 +99,17 @@ public class TikTokRoomInfoEventHandler {
|
|||||||
{
|
{
|
||||||
tikTokRoomInfo.setViewersCount(message.getMemberCount());
|
tikTokRoomInfo.setViewersCount(message.getMemberCount());
|
||||||
});
|
});
|
||||||
|
return MappingResult.of(message, List.of(event, roomInfoEvent));
|
||||||
return List.of(event, roomInfoEvent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public List<TikTokEvent> handleLike(byte[] msg)
|
public MappingResult handleLike(byte[] msg, String name, TikTokMapperHelper helper) {
|
||||||
{
|
|
||||||
var message = WebcastLikeMessage.parseFrom(msg);
|
var message = WebcastLikeMessage.parseFrom(msg);
|
||||||
var event = new TikTokLikeEvent(message);
|
var event = new TikTokLikeEvent(message);
|
||||||
var roomInfoEvent = this.handleRoomInfo(tikTokRoomInfo ->
|
var roomInfoEvent = this.handleRoomInfo(tikTokRoomInfo ->
|
||||||
{
|
{
|
||||||
tikTokRoomInfo.setLikesCount(event.getTotalLikes());
|
tikTokRoomInfo.setLikesCount(event.getTotalLikes());
|
||||||
});
|
});
|
||||||
return List.of(event, roomInfoEvent);
|
return MappingResult.of(message, List.of(event, roomInfoEvent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* 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.mappers.events;
|
package io.github.jwdeveloper.tiktok.mappers.handlers;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.TikTokUnhandledSocialEvent;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokUnhandledSocialEvent;
|
||||||
@@ -39,7 +39,6 @@ import java.util.TreeMap;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class TikTokWebSocketClient implements SocketClient {
|
public class TikTokWebSocketClient implements SocketClient {
|
||||||
private final Logger logger;
|
|
||||||
private final ClientSettings clientSettings;
|
private final ClientSettings clientSettings;
|
||||||
private final TikTokCookieJar tikTokCookieJar;
|
private final TikTokCookieJar tikTokCookieJar;
|
||||||
private final TikTokMessageHandler messageHandler;
|
private final TikTokMessageHandler messageHandler;
|
||||||
@@ -48,12 +47,11 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
private TikTokWebSocketPingingTask pingingTask;
|
private TikTokWebSocketPingingTask pingingTask;
|
||||||
private boolean isConnected;
|
private boolean isConnected;
|
||||||
|
|
||||||
public TikTokWebSocketClient(Logger logger,
|
public TikTokWebSocketClient(
|
||||||
TikTokCookieJar tikTokCookieJar,
|
TikTokCookieJar tikTokCookieJar,
|
||||||
ClientSettings clientSettings,
|
ClientSettings clientSettings,
|
||||||
TikTokMessageHandler messageHandler,
|
TikTokMessageHandler messageHandler,
|
||||||
TikTokEventObserver tikTokEventHandler) {
|
TikTokEventObserver tikTokEventHandler) {
|
||||||
this.logger = logger;
|
|
||||||
this.tikTokCookieJar = tikTokCookieJar;
|
this.tikTokCookieJar = tikTokCookieJar;
|
||||||
this.clientSettings = clientSettings;
|
this.clientSettings = clientSettings;
|
||||||
this.messageHandler = messageHandler;
|
this.messageHandler = messageHandler;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
|||||||
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
||||||
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
||||||
import io.github.jwdeveloper.tiktok.mappers.events.TikTokGiftEventHandler;
|
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokGiftEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.messages.data.GiftStruct;
|
import io.github.jwdeveloper.tiktok.messages.data.GiftStruct;
|
||||||
import io.github.jwdeveloper.tiktok.messages.data.Image;
|
import io.github.jwdeveloper.tiktok.messages.data.Image;
|
||||||
import io.github.jwdeveloper.tiktok.messages.data.User;
|
import io.github.jwdeveloper.tiktok.messages.data.User;
|
||||||
|
|||||||
@@ -22,12 +22,11 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.listener;
|
package io.github.jwdeveloper.tiktok.listener;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.annotations.TikTokEventHandler;
|
import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -42,12 +41,12 @@ import static org.mockito.Mockito.verify;
|
|||||||
|
|
||||||
class TikTokListenersManagerTest {
|
class TikTokListenersManagerTest {
|
||||||
|
|
||||||
private TikTokEventObserver eventObserver;
|
private io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver eventObserver;
|
||||||
private TikTokListenersManager tikTokListenersManager;
|
private TikTokListenersManager tikTokListenersManager;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
eventObserver = Mockito.mock(TikTokEventObserver.class);
|
eventObserver = Mockito.mock(io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver.class);
|
||||||
List<TikTokEventListener> listeners = new ArrayList<>();
|
List<TikTokEventListener> listeners = new ArrayList<>();
|
||||||
tikTokListenersManager = new TikTokListenersManager(listeners, eventObserver);
|
tikTokListenersManager = new TikTokListenersManager(listeners, eventObserver);
|
||||||
}
|
}
|
||||||
@@ -93,19 +92,19 @@ class TikTokListenersManagerTest {
|
|||||||
|
|
||||||
public static class TikTokEventListenerTest implements TikTokEventListener
|
public static class TikTokEventListenerTest implements TikTokEventListener
|
||||||
{
|
{
|
||||||
@TikTokEventHandler
|
@TikTokEventObserver
|
||||||
public void onJoin(LiveClient client, TikTokJoinEvent joinEvent)
|
public void onJoin(LiveClient client, TikTokJoinEvent joinEvent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TikTokEventHandler
|
@TikTokEventObserver
|
||||||
public void onGift(LiveClient client, TikTokGiftEvent giftMessageEvent)
|
public void onGift(LiveClient client, TikTokGiftEvent giftMessageEvent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TikTokEventHandler
|
@TikTokEventObserver
|
||||||
public void onEvent(LiveClient client, TikTokEvent event)
|
public void onEvent(LiveClient client, TikTokEvent event)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -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.0.7-Release</version>
|
<version>1.0.9-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
@@ -22,55 +22,64 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok;
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
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;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
|
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastChatMessage;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastChatMessage;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
|
||||||
import io.github.jwdeveloper.tiktok.utils.ProtocolUtils;
|
|
||||||
|
|
||||||
public class CustomMappingExample {
|
public class CustomMappingExample {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
TikTokLive.newClient("vadimpyrography")
|
TikTokLive.newClient("saszareznikow")
|
||||||
.onCustomEvent(CustomChatEvent.class, (liveClient, event) ->
|
.onMapping(mapper ->
|
||||||
{
|
{
|
||||||
System.out.println("hello world!");
|
mapper.forMessage(WebcastChatMessage.class)
|
||||||
|
.onBeforeMapping((inputBytes, messageName, mapperHelper) ->
|
||||||
|
{
|
||||||
|
System.out.println("===============================");
|
||||||
|
System.out.println("OnBefore mapping: " + messageName);
|
||||||
|
return inputBytes;
|
||||||
|
})
|
||||||
|
.onMapping((inputBytes, messageName, mapperHelper) ->
|
||||||
|
{
|
||||||
|
System.out.println("onMapping mapping: " + messageName);
|
||||||
|
var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
|
||||||
|
var language = message.getContentLanguage();
|
||||||
|
var userName = message.getUser().getNickname();
|
||||||
|
var content = message.getContent();
|
||||||
|
var event = new CustomChatEvent(language, userName, content);
|
||||||
|
return MappingResult.of(message, event);
|
||||||
|
})
|
||||||
|
.onAfterMapping(mappingResult ->
|
||||||
|
{
|
||||||
|
var source = mappingResult.getSource();
|
||||||
|
var events = mappingResult.getEvents();
|
||||||
|
System.out.println("onAfter mapping, " + source.getClass().getSimpleName() + " was mapped to " + events.size() + " events");
|
||||||
|
return events;
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
There might be cast that we don't have Webcast class for incoming message from TikTok
|
||||||
|
`mapperHelper.bytesToProtoBufferStructure` but you can still investigate message structure
|
||||||
|
by using helper methods
|
||||||
|
*/
|
||||||
|
mapper.forMessage("WebcastMemberMessage")
|
||||||
|
.onBeforeMapping((inputBytes, messageName, mapperHelper) ->
|
||||||
|
{
|
||||||
|
if (mapperHelper.isMessageHasProtoClass(messageName)) {
|
||||||
|
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, messageName);
|
||||||
|
// System.out.println(mapperHelper.toJson(messageObject));
|
||||||
|
} else {
|
||||||
|
var structure = mapperHelper.bytesToProtoBufferStructure(inputBytes);
|
||||||
|
// System.out.println(structure.toJson());
|
||||||
|
}
|
||||||
|
return inputBytes;
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.onError((liveClient, event) ->
|
.onError((liveClient, event) ->
|
||||||
{
|
{
|
||||||
event.getException().printStackTrace();
|
event.getException().printStackTrace();
|
||||||
})
|
})
|
||||||
.onMapping(mapper ->
|
.buildAndConnect();
|
||||||
{
|
|
||||||
mapper.webcastObjectToEvent(WebcastChatMessage.class, chatMessage ->
|
|
||||||
{
|
|
||||||
var language = chatMessage.getContentLanguage();
|
|
||||||
var userName = chatMessage.getUser().getNickname();
|
|
||||||
var message = chatMessage.getContent();
|
|
||||||
return new CustomChatEvent(language, userName, message);
|
|
||||||
});
|
|
||||||
mapper.bytesToEvent("WebcastGiftMessage", bytes ->
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var event = WebcastGiftMessage.parseFrom(bytes);
|
|
||||||
return new TikTokGiftEvent(Gift.ROSA, event);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new TikTokMessageMappingException("unable to map gift message!", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mapper.bytesToEvent("WebcastMemberMessage",bytes ->
|
|
||||||
{
|
|
||||||
//displaying unknown messages from tiktok
|
|
||||||
var structure = ProtocolUtils.getProtocolBufferStructure(bytes);
|
|
||||||
System.out.println(structure.toJson());
|
|
||||||
return new TikTokErrorEvent(new RuntimeException("Message not implemented"));
|
|
||||||
});
|
|
||||||
}).buildAndConnect();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +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;
|
|
||||||
|
|
||||||
public class Examplee
|
|
||||||
{
|
|
||||||
public static void main(String[] args)
|
|
||||||
{
|
|
||||||
TikTokLive.newClient("skullchefasmr")
|
|
||||||
.onGift((liveClient, event) ->
|
|
||||||
{
|
|
||||||
System.out.println("Dzięki za gifta "+event.getGift().getName());
|
|
||||||
}).buildAndConnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok;
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.annotations.TikTokEventHandler;
|
import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.TikTokCommentEvent;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokCommentEvent;
|
||||||
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;
|
||||||
@@ -65,24 +65,24 @@ public class ListenerExample
|
|||||||
|
|
||||||
public static class CustomListener implements TikTokEventListener {
|
public static class CustomListener implements TikTokEventListener {
|
||||||
|
|
||||||
@TikTokEventHandler
|
@TikTokEventObserver
|
||||||
public void onLike(LiveClient liveClient, TikTokLikeEvent event) {
|
public void onLike(LiveClient liveClient, TikTokLikeEvent event) {
|
||||||
System.out.println(event.toString());
|
System.out.println(event.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@TikTokEventHandler
|
@TikTokEventObserver
|
||||||
public void onError(LiveClient liveClient, TikTokErrorEvent event) {
|
public void onError(LiveClient liveClient, TikTokErrorEvent event) {
|
||||||
// event.getException().printStackTrace();
|
// event.getException().printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@TikTokEventHandler
|
@TikTokEventObserver
|
||||||
public void onComment(LiveClient liveClient, TikTokCommentEvent event) {
|
public void onComment(LiveClient liveClient, TikTokCommentEvent event) {
|
||||||
var userName = event.getUser().getName();
|
var userName = event.getUser().getName();
|
||||||
var text = event.getText();
|
var text = event.getText();
|
||||||
liveClient.getLogger().info(userName + ": " + text);
|
liveClient.getLogger().info(userName + ": " + text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TikTokEventHandler
|
@TikTokEventObserver
|
||||||
public void onGift(LiveClient liveClient, TikTokGiftEvent event) {
|
public void onGift(LiveClient liveClient, TikTokGiftEvent event) {
|
||||||
var message = switch (event.getGift()) {
|
var message = switch (event.getGift()) {
|
||||||
case ROSE -> "Thanks :)";
|
case ROSE -> "Thanks :)";
|
||||||
@@ -95,7 +95,7 @@ public class ListenerExample
|
|||||||
liveClient.getLogger().info(message);
|
liveClient.getLogger().info(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TikTokEventHandler
|
@TikTokEventObserver
|
||||||
public void onAnyEvent(LiveClient liveClient, TikTokEvent event) {
|
public void onAnyEvent(LiveClient liveClient, TikTokEvent event) {
|
||||||
liveClient.getLogger().info(event.getClass().getSimpleName());
|
liveClient.getLogger().info(event.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -1,7 +1,6 @@
|
|||||||
<div align="center" >
|
<div align="center" >
|
||||||
<a target="blank" >
|
<a target="blank" >
|
||||||
<img src="https://raw.githubusercontent.com/jwdeveloper/TikTokLiveJava/develop-1_0_0/Tools-ReadmeGenerator/src/main/resources/logo.svg" width="15%" >
|
<img src="https://raw.githubusercontent.com/jwdeveloper/TikTokLiveJava/develop-1_0_0/Tools-ReadmeGenerator/src/main/resources/logo.svg" width="15%" >
|
||||||
</img>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div align="center" >
|
<div align="center" >
|
||||||
@@ -12,18 +11,15 @@
|
|||||||
<div align="center" >
|
<div align="center" >
|
||||||
<a href="https://jitpack.io/#jwdeveloper/TikTok-Live-Java" target="blank" >
|
<a href="https://jitpack.io/#jwdeveloper/TikTok-Live-Java" target="blank" >
|
||||||
<img src="https://jitpack.io/v/jwdeveloper/TikTok-Live-Java.svg" width="20%" >
|
<img src="https://jitpack.io/v/jwdeveloper/TikTok-Live-Java.svg" width="20%" >
|
||||||
</img>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
<a href="https://discord.gg/e2XwPNTBBr" target="blank" >
|
<a href="https://discord.gg/e2XwPNTBBr" target="blank" >
|
||||||
<img src="https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white" >
|
<img src="https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white" >
|
||||||
</img>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a target="blank" >
|
<a target="blank" >
|
||||||
<img src="https://img.shields.io/badge/java-%23ED8B00.svg?style=for-the-badge&logo=openjdk&logoColor=white" >
|
<img src="https://img.shields.io/badge/java-%23ED8B00.svg?style=for-the-badge&logo=openjdk&logoColor=white" >
|
||||||
</img>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,7 +29,7 @@ A Java library inspired by [TikTokLive](https://github.com/isaackogan/TikTokLive
|
|||||||
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
|
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
|
||||||
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
|
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
|
||||||
|
|
||||||
# Contributors
|
# Contributors
|
||||||
[Library documentation for contributors](https://github.com/jwdeveloper/TikTokLiveJava/wiki)
|
[Library documentation for contributors](https://github.com/jwdeveloper/TikTokLiveJava/wiki)
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@@ -58,7 +54,7 @@ Do you prefer other programming languages?
|
|||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
1. Install the package
|
1. Install the package
|
||||||
|
|
||||||
Maven
|
Maven
|
||||||
```xml
|
```xml
|
||||||
@@ -73,7 +69,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.0.7-Release</version>
|
<version>1.0.8-Release</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -90,7 +86,7 @@ dependencyResolutionManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.0.7-Release'
|
implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.0.8-Release'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -438,9 +434,9 @@ Triggered every time gift is sent
|
|||||||
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
|
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
|
||||||
<p>Combo: 4 -> comboState = GiftSendType.Active</p>
|
<p>Combo: 4 -> comboState = GiftSendType.Active</p>
|
||||||
<p>Combo: 8 -> comboState = GiftSendType.Active</p>
|
<p>Combo: 8 -> comboState = GiftSendType.Active</p>
|
||||||
<p>Combo: 12 -> comboState = GiftSendType.Finsihed</p>
|
<p>Combo: 12 -> comboState = GiftSendType.Finished</p>
|
||||||
|
|
||||||
Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
|
Remember if comboState is Finished both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
|
||||||
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@@ -697,4 +693,4 @@ public static class CustomListener implements TikTokEventListener {
|
|||||||
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Your improvements are welcome! Feel free to open an <a href="https://github.com/jwdeveloper/TikTok-Live-Java/issues">issue</a> or <a href="https://github.com/jwdeveloper/TikTok-Live-Java/pulls">pull request</a>.
|
Your improvements are welcome! Feel free to open an <a href="https://github.com/jwdeveloper/TikTok-Live-Java/issues">issue</a> or <a href="https://github.com/jwdeveloper/TikTok-Live-Java/pulls">pull request</a>.
|
||||||
@@ -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.0.7-Release</version>
|
<version>1.0.9-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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.tools;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.client.TikTokDataCollectorBuilder;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.api.DataCollectorBuilder;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.tester.TikTokDataTesterBuilder;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTesterBuilder;
|
||||||
|
|
||||||
|
public class TikTokLiveTools
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param databaseName dataCollector use sql-lite database to store message
|
||||||
|
* if database not exits it creates new one
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static DataCollectorBuilder createCollector(String databaseName)
|
||||||
|
{
|
||||||
|
return new TikTokDataCollectorBuilder(databaseName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param databaseName dataTester will read messages for database
|
||||||
|
* before using dataTester, use dataCollector to create database
|
||||||
|
* if database not exits exception will be thrown
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static DataTesterBuilder createTester(String databaseName)
|
||||||
|
{
|
||||||
|
return new TikTokDataTesterBuilder(databaseName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Returns browser application that collects and display Events, Messages, WebcastResponses
|
||||||
|
* in online web editor so it's easier to read and analyze data structures
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static void createWebViewer()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,93 +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.tools.collector;
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokLive;
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.client.TikTokMessageCollectorClient;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class RunCollector {
|
|
||||||
|
|
||||||
//https://protobuf-decoder.netlify.app/
|
|
||||||
//https://streamdps.com/tiktok-widgets/gifts/
|
|
||||||
|
|
||||||
//WebcastLinkMicBattleItemCard does streamer win battle?
|
|
||||||
|
|
||||||
public static void main(String[] args) throws SQLException, IOException {
|
|
||||||
|
|
||||||
TikTokMessageCollectorClient.create("giftsCollector")
|
|
||||||
//.addUser("crece.sara")
|
|
||||||
//.addUser("moniczkka")
|
|
||||||
.addUser("valeria.viral")
|
|
||||||
// .addUser("cbcgod")
|
|
||||||
// .addUser("psychotropnazywo")
|
|
||||||
// .addUser("accordionistka")
|
|
||||||
//.addEventFilter(WebcastGiftMessage.class)
|
|
||||||
.addOnBuilder(liveClientBuilder ->
|
|
||||||
{
|
|
||||||
liveClientBuilder.onGiftCombo((liveClient, event) ->
|
|
||||||
{
|
|
||||||
liveClient.getLogger().setLevel(Level.OFF);
|
|
||||||
var gifts = liveClient.getGiftManager().getGifts();
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.append("GIFT COMBO User: " + event.getUser().getProfileName()+" ");
|
|
||||||
sb.append("Name: " + event.getGift().getName() + " ");
|
|
||||||
sb.append("Combo: " + event.getCombo() + " ");
|
|
||||||
sb.append("COST: " + event.getGift().getDiamondCost() + " ");
|
|
||||||
sb.append("STATE: " + event.getComboState() + " ");
|
|
||||||
System.out.println(sb.toString());
|
|
||||||
});
|
|
||||||
|
|
||||||
liveClientBuilder.onGift((liveClient, event) ->
|
|
||||||
{
|
|
||||||
liveClient.getLogger().setLevel(Level.OFF);
|
|
||||||
var gifts = liveClient.getGiftManager().getGifts();
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.append("GIFT User: " + event.getUser().getProfileName()+" ");
|
|
||||||
sb.append("Name: " + event.getGift().getName() + " ");
|
|
||||||
sb.append("COST: " + event.getGift().getDiamondCost() + " ");
|
|
||||||
sb.append("Combo: " + event.getCombo() + " ");
|
|
||||||
System.out.println(sb.toString());
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.buildAndRun();
|
|
||||||
|
|
||||||
System.in.read();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -20,18 +20,14 @@
|
|||||||
* 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.tools.collector.tables;
|
package io.github.jwdeveloper.tiktok.tools.collector.api;
|
||||||
|
|
||||||
import lombok.Data;
|
public interface DataCollector {
|
||||||
|
|
||||||
@Data
|
void connect();
|
||||||
public class TikTokResponseModel
|
|
||||||
{
|
|
||||||
private Integer id;
|
|
||||||
|
|
||||||
private String hostName;
|
|
||||||
|
|
||||||
private String response;
|
void disconnect();
|
||||||
|
|
||||||
private String createdAt;
|
void disconnect(boolean keepDatabase);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.tools.collector.api;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public interface DataCollectorBuilder extends DataFilters<DataCollectorBuilder> {
|
||||||
|
DataCollectorBuilder setOutputPath(String path);
|
||||||
|
DataCollectorBuilder setSessionTag(String sessionTimestamp);
|
||||||
|
|
||||||
|
DataCollectorBuilder setDatabase(TikTokDatabase database);
|
||||||
|
|
||||||
|
DataCollectorBuilder configureLiveClient(Consumer<LiveClientBuilder> consumer);
|
||||||
|
|
||||||
|
DataCollectorBuilder addUser(String user);
|
||||||
|
|
||||||
|
DataCollector buildAndRun();
|
||||||
|
|
||||||
|
DataCollector build();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.github.jwdeveloper.tiktok.tools.collector.api;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
|
||||||
|
public interface DataFilters<T> {
|
||||||
|
T addMessageFilter(Class<? extends com.google.protobuf.GeneratedMessageV3> message);
|
||||||
|
|
||||||
|
T addMessageFilter(String message);
|
||||||
|
|
||||||
|
T addEventFilter(Class<? extends TikTokEvent> event);
|
||||||
|
|
||||||
|
T addEventFilter(String event);
|
||||||
|
}
|
||||||
@@ -20,17 +20,22 @@
|
|||||||
* 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.tools.collector.client;
|
package io.github.jwdeveloper.tiktok.tools.collector.api;
|
||||||
|
|
||||||
public class TikTokMessageCollectorClient
|
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||||
{
|
import lombok.Data;
|
||||||
public static TikTokMessagessCollectorBuilder create(String outputName)
|
|
||||||
{
|
|
||||||
return new TikTokMessagessCollectorBuilder(outputName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TikTokMessagessCollectorBuilder create(MessageCollector messageCollector, String outputName)
|
import java.util.List;
|
||||||
{
|
import java.util.Set;
|
||||||
return new TikTokMessagessCollectorBuilder(messageCollector,outputName);
|
import java.util.function.Consumer;
|
||||||
}
|
|
||||||
|
@Data
|
||||||
|
public class TikTokDataCollectorModel {
|
||||||
|
private List<String> users;
|
||||||
|
private String outputPath;
|
||||||
|
private String outputName;
|
||||||
|
private Set<String> eventsFilter;
|
||||||
|
private Set<String> messagesFilter;
|
||||||
|
private String sessionTag ="";
|
||||||
|
private Consumer<LiveClientBuilder> onConfigureLiveClient;
|
||||||
}
|
}
|
||||||
@@ -37,14 +37,14 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class MessageCollector {
|
public class MessagesManager {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
Map<String, Queue<MessageData>> messages;
|
Map<String, Queue<MessageData>> messages;
|
||||||
String outputName;
|
String outputName;
|
||||||
|
|
||||||
int limit = 20;
|
int limit = 20;
|
||||||
public MessageCollector(String outputName) {
|
public MessagesManager(String outputName) {
|
||||||
this.messages = new TreeMap<>();
|
this.messages = new TreeMap<>();
|
||||||
this.outputName = outputName;
|
this.outputName = outputName;
|
||||||
load();
|
load();
|
||||||
@@ -22,104 +22,16 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.tools.collector.client;
|
package io.github.jwdeveloper.tiktok.tools.collector.client;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokLive;
|
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
|
||||||
import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
|
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
|
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
|
||||||
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.db.TikTokDatabase;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.ExceptionInfoModel;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
|
|
||||||
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class TikTokClientFactory {
|
public class TikTokClientFactory {
|
||||||
private final MessageCollector messageCollector;
|
private final MessagesManager messageCollector;
|
||||||
private final TikTokDatabase tikTokDatabase;
|
private final TikTokDatabase tikTokDatabase;
|
||||||
|
|
||||||
public TikTokClientFactory(MessageCollector messageCollector, TikTokDatabase tikTokDatabase) {
|
public TikTokClientFactory(MessagesManager messageCollector, TikTokDatabase tikTokDatabase) {
|
||||||
this.messageCollector = messageCollector;
|
this.messageCollector = messageCollector;
|
||||||
this.tikTokDatabase = tikTokDatabase;
|
this.tikTokDatabase = tikTokDatabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<LiveClient> runClientAsync(String tiktokUser, List<Class<?>> filters, Consumer<LiveClientBuilder> onBuilder) {
|
|
||||||
var builder = TikTokLive.newClient(tiktokUser);
|
|
||||||
var msgFilter = filters.stream().map(Class::getSimpleName).toList();
|
|
||||||
onBuilder.accept(builder);
|
|
||||||
return builder.onConnected((liveClient, event) ->
|
|
||||||
{
|
|
||||||
liveClient.getLogger().info("CONNECTED TO " + liveClient.getRoomInfo().getHostName());
|
|
||||||
})
|
|
||||||
.onWebsocketResponse((liveClient, event) ->
|
|
||||||
{
|
|
||||||
var response = Base64.getEncoder().encodeToString(event.getResponse().toByteArray());
|
|
||||||
|
|
||||||
var responseModel = new TikTokResponseModel();
|
|
||||||
responseModel.setResponse(response);
|
|
||||||
responseModel.setHostName(liveClient.getRoomInfo().getHostName());
|
|
||||||
tikTokDatabase.insertResponse(responseModel);
|
|
||||||
liveClient.getLogger().info("Response");
|
|
||||||
for (var message : event.getResponse().getMessagesList())
|
|
||||||
{
|
|
||||||
if(msgFilter.size() > 0 && !msgFilter.contains(message.getMethod()))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
messageCollector.addMessage(liveClient.getLogger(), liveClient.getRoomInfo().getHostName(), message);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.onWebsocketMessage((liveClient, event) ->
|
|
||||||
{
|
|
||||||
var eventName = event.getEvent().getClass().getSimpleName();
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (msgFilter.size() != 0 && !msgFilter.contains(event.getEvent().getClass())) {
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
var messageBinary = Base64.getEncoder().encodeToString(event.getMessage().toByteArray());
|
|
||||||
var model = new TikTokMessageModel();
|
|
||||||
model.setType("messsage");
|
|
||||||
model.setHostName(tiktokUser);
|
|
||||||
model.setEventName(eventName);
|
|
||||||
model.setMessage(messageBinary);
|
|
||||||
|
|
||||||
// tikTokDatabase.insertMessage(model);
|
|
||||||
// liveClient.getLogger().info("EVENT: [" + tiktokUser + "] " + eventName);
|
|
||||||
})
|
|
||||||
.onError((liveClient, event) ->
|
|
||||||
{
|
|
||||||
event.getException().printStackTrace();
|
|
||||||
var exception = event.getException();
|
|
||||||
var exceptionContent = ExceptionInfoModel.getStackTraceAsString(exception);
|
|
||||||
var errorModel = new TikTokErrorModel();
|
|
||||||
if (exception instanceof TikTokLiveMessageException ex) {
|
|
||||||
errorModel.setHostName(tiktokUser);
|
|
||||||
errorModel.setErrorName(ex.messageMethod());
|
|
||||||
errorModel.setErrorType("error-message");
|
|
||||||
errorModel.setExceptionContent(exceptionContent);
|
|
||||||
errorModel.setMessage(ex.messageToBase64());
|
|
||||||
errorModel.setResponse(ex.webcastResponseToBase64());
|
|
||||||
} else {
|
|
||||||
errorModel.setHostName(tiktokUser);
|
|
||||||
errorModel.setErrorName(exception.getClass().getSimpleName());
|
|
||||||
errorModel.setErrorType("error-system");
|
|
||||||
errorModel.setExceptionContent(exceptionContent);
|
|
||||||
errorModel.setMessage("");
|
|
||||||
errorModel.setResponse("");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
tikTokDatabase.insertError(errorModel);
|
|
||||||
liveClient.getLogger().info("ERROR: " + errorModel.getErrorName());
|
|
||||||
exception.printStackTrace();
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnectAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* 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.tools.collector.client;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLive;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
|
||||||
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.api.DataCollector;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.api.TikTokDataCollectorModel;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.tables.ExceptionInfoModel;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokDataTable;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokErrorModel;
|
||||||
|
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TikTokDataCollector implements DataCollector {
|
||||||
|
private final TikTokDataCollectorModel dataCollectorModel;
|
||||||
|
private final TikTokDatabase tikTokDatabase;
|
||||||
|
private final List<LiveClient> tiktokClients;
|
||||||
|
|
||||||
|
public TikTokDataCollector(TikTokDataCollectorModel dataCollectorModel, TikTokDatabase tikTokDatabase) {
|
||||||
|
this.dataCollectorModel = dataCollectorModel;
|
||||||
|
this.tikTokDatabase = tikTokDatabase;
|
||||||
|
this.tiktokClients = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect() {
|
||||||
|
try {
|
||||||
|
if (!tikTokDatabase.isConnected()) {
|
||||||
|
tikTokDatabase.connect();
|
||||||
|
}
|
||||||
|
for (var user : dataCollectorModel.getUsers()) {
|
||||||
|
var client = createLiveClient(user);
|
||||||
|
tiktokClients.add(client);
|
||||||
|
client.connectAsync();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Unable to start tiktok connector", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void disconnect() {
|
||||||
|
disconnect(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect(boolean keepDatabase) {
|
||||||
|
try {
|
||||||
|
for (var client : tiktokClients) {
|
||||||
|
client.disconnect();
|
||||||
|
}
|
||||||
|
if (!keepDatabase) {
|
||||||
|
tikTokDatabase.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Unable to stop tiktok connector", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveClient createLiveClient(String tiktokUser) {
|
||||||
|
var builder = TikTokLive.newClient(tiktokUser);
|
||||||
|
builder.onConnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
liveClient.getLogger().info("Connected to " + liveClient.getRoomInfo().getHostName());
|
||||||
|
})
|
||||||
|
.onDisconnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
liveClient.getLogger().info("Disconnected " + liveClient.getRoomInfo().getHostName());
|
||||||
|
})
|
||||||
|
.onWebsocketResponse(this::handleResponseAndMessages)
|
||||||
|
.onWebsocketMessage(this::handleMappedEvent)
|
||||||
|
.onHttpResponse((liveClient, event) ->
|
||||||
|
{
|
||||||
|
var data = createHttpResponseData(event, tiktokUser);
|
||||||
|
tikTokDatabase.insertData(data);
|
||||||
|
})
|
||||||
|
.onError(this::handleError);
|
||||||
|
dataCollectorModel.getOnConfigureLiveClient().accept(builder);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleResponseAndMessages(LiveClient client, TikTokWebsocketResponseEvent event) {
|
||||||
|
var responseData = createResponseData(event.getResponse(), client.getRoomInfo().getHostName());
|
||||||
|
tikTokDatabase.insertData(responseData);
|
||||||
|
|
||||||
|
var filter = dataCollectorModel.getMessagesFilter();
|
||||||
|
for (var message : event.getResponse().getMessagesList()) {
|
||||||
|
if (filter.isEmpty()) {
|
||||||
|
var data = createMessageData(message, client.getRoomInfo().getHostName());
|
||||||
|
tikTokDatabase.insertData(data);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!filter.contains(message.getMethod())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var data = createMessageData(message, client.getRoomInfo().getHostName());
|
||||||
|
tikTokDatabase.insertData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMappedEvent(LiveClient client, TikTokWebsocketMessageEvent messageEvent) {
|
||||||
|
var event = messageEvent.getEvent();
|
||||||
|
var eventName = event.getClass().getSimpleName();
|
||||||
|
|
||||||
|
var filter = dataCollectorModel.getEventsFilter();
|
||||||
|
|
||||||
|
if (filter.isEmpty()) {
|
||||||
|
var data = createEventData(event, client.getRoomInfo().getHostName());
|
||||||
|
tikTokDatabase.insertData(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filter.contains(eventName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var data = createEventData(event, client.getRoomInfo().getHostName());
|
||||||
|
tikTokDatabase.insertData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleError(LiveClient client, TikTokErrorEvent event) {
|
||||||
|
var exception = event.getException();
|
||||||
|
var userName = client.getRoomInfo().getHostName();
|
||||||
|
var exceptionContent = ExceptionInfoModel.getStackTraceAsString(exception);
|
||||||
|
var errorModel = new TikTokErrorModel();
|
||||||
|
if (exception instanceof TikTokLiveMessageException ex) {
|
||||||
|
errorModel.setHostName(userName);
|
||||||
|
errorModel.setErrorName(ex.messageMethod());
|
||||||
|
errorModel.setErrorType("error-message");
|
||||||
|
errorModel.setExceptionContent(exceptionContent);
|
||||||
|
errorModel.setMessage(ex.messageToBase64());
|
||||||
|
errorModel.setResponse(ex.webcastResponseToBase64());
|
||||||
|
} else {
|
||||||
|
errorModel.setHostName(userName);
|
||||||
|
errorModel.setErrorName(exception.getClass().getSimpleName());
|
||||||
|
errorModel.setErrorType("error-system");
|
||||||
|
errorModel.setExceptionContent(exceptionContent);
|
||||||
|
errorModel.setMessage("");
|
||||||
|
errorModel.setResponse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tikTokDatabase.insertError(errorModel);
|
||||||
|
client.getLogger().info("ERROR: " + errorModel.getErrorName());
|
||||||
|
exception.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TikTokDataTable createHttpResponseData(TikTokHttpResponseEvent response, String tiktokUser) {
|
||||||
|
var base64 = JsonUtil.toJson(response);
|
||||||
|
var data = new TikTokDataTable();
|
||||||
|
data.setSessionTag(dataCollectorModel.getSessionTag());
|
||||||
|
data.setTiktokUser(tiktokUser);
|
||||||
|
data.setDataType("response");
|
||||||
|
data.setDataTypeName("Http");
|
||||||
|
data.setContent(base64);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private TikTokDataTable createResponseData(WebcastResponse response, String tiktokUser) {
|
||||||
|
var base64 = Base64.getEncoder().encodeToString(response.toByteArray());
|
||||||
|
var data = new TikTokDataTable();
|
||||||
|
data.setSessionTag(dataCollectorModel.getSessionTag());
|
||||||
|
data.setTiktokUser(tiktokUser);
|
||||||
|
data.setDataType("response");
|
||||||
|
data.setDataTypeName("WebcastResponse");
|
||||||
|
data.setContent(base64);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TikTokDataTable createMessageData(WebcastResponse.Message message, String tiktokUser) {
|
||||||
|
var base64 = Base64.getEncoder().encodeToString(message.getPayload().toByteArray());
|
||||||
|
var data = new TikTokDataTable();
|
||||||
|
data.setSessionTag(dataCollectorModel.getSessionTag());
|
||||||
|
data.setTiktokUser(tiktokUser);
|
||||||
|
data.setDataType("message");
|
||||||
|
data.setDataTypeName(message.getMethod());
|
||||||
|
data.setContent(base64);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TikTokDataTable createEventData(TikTokEvent event, String tiktokUser) {
|
||||||
|
var base64 = JsonUtil.toJson(event);
|
||||||
|
var data = new TikTokDataTable();
|
||||||
|
data.setSessionTag(dataCollectorModel.getSessionTag());
|
||||||
|
data.setTiktokUser(tiktokUser);
|
||||||
|
data.setDataType("event");
|
||||||
|
data.setDataTypeName(event.getClass().getSimpleName());
|
||||||
|
data.setContent(base64);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* 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.tools.collector.client;
|
||||||
|
|
||||||
|
import com.google.protobuf.GeneratedMessageV3;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.api.DataCollectorBuilder;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.api.DataCollector;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.api.TikTokDataCollectorModel;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class TikTokDataCollectorBuilder implements DataCollectorBuilder {
|
||||||
|
|
||||||
|
|
||||||
|
TikTokDataCollectorModel dataModel;
|
||||||
|
|
||||||
|
TikTokDatabase database;
|
||||||
|
|
||||||
|
public TikTokDataCollectorBuilder(String outputName) {
|
||||||
|
|
||||||
|
dataModel = new TikTokDataCollectorModel();
|
||||||
|
dataModel.setOutputName(outputName);
|
||||||
|
dataModel.setUsers(new ArrayList<>());
|
||||||
|
dataModel.setEventsFilter(new HashSet<>());
|
||||||
|
dataModel.setMessagesFilter(new HashSet<>());
|
||||||
|
dataModel.setOutputPath("...");
|
||||||
|
dataModel.setOnConfigureLiveClient((e) -> {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataCollectorBuilder addUser(String user) {
|
||||||
|
dataModel.getUsers().add(user);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TikTokDataCollectorBuilder addMessageFilter(Class<? extends GeneratedMessageV3> message) {
|
||||||
|
dataModel.getMessagesFilter().add(message.getSimpleName());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TikTokDataCollectorBuilder addMessageFilter(String message) {
|
||||||
|
dataModel.getMessagesFilter().add(message);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TikTokDataCollectorBuilder addEventFilter(Class<? extends TikTokEvent> event) {
|
||||||
|
dataModel.getEventsFilter().add(event.getSimpleName());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TikTokDataCollectorBuilder addEventFilter(String event) {
|
||||||
|
dataModel.getEventsFilter().add(event);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataCollectorBuilder setOutputPath(String path) {
|
||||||
|
dataModel.setOutputPath(path);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataCollectorBuilder setSessionTag(String sessionTimestamp) {
|
||||||
|
dataModel.setSessionTag(sessionTimestamp);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataCollectorBuilder setDatabase(TikTokDatabase database)
|
||||||
|
{
|
||||||
|
this.database =database;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataCollectorBuilder configureLiveClient(Consumer<LiveClientBuilder> consumer) {
|
||||||
|
dataModel.setOnConfigureLiveClient(consumer);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataCollector buildAndRun() {
|
||||||
|
|
||||||
|
var collector = build();
|
||||||
|
collector.connect();
|
||||||
|
return collector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataCollector build() {
|
||||||
|
|
||||||
|
if (dataModel.getSessionTag().isEmpty()) {
|
||||||
|
dataModel.setSessionTag(UUID.randomUUID().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(database == null)
|
||||||
|
{
|
||||||
|
database = new TikTokDatabase(dataModel.getOutputName());
|
||||||
|
}
|
||||||
|
var dataCollector = new TikTokDataCollector(dataModel, database);
|
||||||
|
return dataCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,99 +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.tools.collector.client;
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
|
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
|
||||||
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.db.TikTokDatabase;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class TikTokMessagessCollectorBuilder {
|
|
||||||
List<String> users;
|
|
||||||
String outputFileName;
|
|
||||||
List<Class<?>> filters;
|
|
||||||
Consumer<LiveClientBuilder> onBuilder;
|
|
||||||
List<LiveClient> tiktokclients;
|
|
||||||
|
|
||||||
MessageCollector messageCollector;
|
|
||||||
|
|
||||||
public TikTokMessagessCollectorBuilder(String outputName) {
|
|
||||||
users = new ArrayList<>();
|
|
||||||
outputFileName = outputName;
|
|
||||||
filters = new ArrayList<>();
|
|
||||||
onBuilder = (e) -> {
|
|
||||||
};
|
|
||||||
tiktokclients = new ArrayList<>();
|
|
||||||
messageCollector = new MessageCollector(outputName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokMessagessCollectorBuilder(MessageCollector messageCollector, String outputFileName) {
|
|
||||||
this(outputFileName);
|
|
||||||
this.messageCollector = messageCollector;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokMessagessCollectorBuilder setOutputName(String name) {
|
|
||||||
outputFileName = name;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TikTokMessagessCollectorBuilder addOnBuilder(Consumer<LiveClientBuilder> consumer) {
|
|
||||||
onBuilder = consumer;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokMessagessCollectorBuilder addUser(String user) {
|
|
||||||
users.add(user);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokMessagessCollectorBuilder addEventFilter(Class<?> event) {
|
|
||||||
filters.add(event);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageCollector buildAndRun() throws SQLException {
|
|
||||||
var db = new TikTokDatabase(outputFileName);
|
|
||||||
db.init();
|
|
||||||
var factory = new TikTokClientFactory(messageCollector, db);
|
|
||||||
for (var user : users) {
|
|
||||||
var client = factory.runClientAsync(user,filters, onBuilder);
|
|
||||||
client.thenAccept(liveClient ->
|
|
||||||
{
|
|
||||||
tiktokclients.add(liveClient);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return messageCollector;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
for (var client : tiktokclients) {
|
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,92 +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.tools.collector.db;
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
|
|
||||||
import org.jdbi.v3.core.Jdbi;
|
|
||||||
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
|
|
||||||
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class TikTokDatabase {
|
|
||||||
private final String database;
|
|
||||||
private TikTokMessageModelDAO messagesTable;
|
|
||||||
private TikTokErrorModelDAO errorTable;
|
|
||||||
private TikTokResponseModelDAO responseTable;
|
|
||||||
|
|
||||||
public TikTokDatabase(String database) {
|
|
||||||
this.database = database;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() throws SQLException {
|
|
||||||
var jdbcUrl = "jdbc:sqlite:" + database + ".db";
|
|
||||||
DriverManager.getConnection(jdbcUrl);
|
|
||||||
var jdbi = Jdbi.create(jdbcUrl)
|
|
||||||
.installPlugin(new SqlObjectPlugin());
|
|
||||||
jdbi.useHandle(handle -> {
|
|
||||||
handle.execute(SqlConsts.CREATE_MESSAGES_TABLE);
|
|
||||||
handle.execute(SqlConsts.CREATE_ERROR_TABLE);
|
|
||||||
handle.execute(SqlConsts.CREATE_RESPONSE_MODEL);
|
|
||||||
});
|
|
||||||
messagesTable = jdbi.onDemand(TikTokMessageModelDAO.class);
|
|
||||||
errorTable = jdbi.onDemand(TikTokErrorModelDAO.class);
|
|
||||||
responseTable = jdbi.onDemand(TikTokResponseModelDAO.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insertMessage(TikTokMessageModel message) {
|
|
||||||
message.setCreatedAt(getTime());
|
|
||||||
messagesTable.insertTikTokMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insertError(TikTokErrorModel message) {
|
|
||||||
message.setCreatedAt(getTime());
|
|
||||||
errorTable.insertTikTokMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insertResponse(TikTokResponseModel message) {
|
|
||||||
message.setCreatedAt(getTime());
|
|
||||||
responseTable.insert(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TikTokErrorModel> selectErrors() {
|
|
||||||
return errorTable.selectErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TikTokMessageModel> selectMessages() {
|
|
||||||
return messagesTable.select();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TikTokResponseModel> selectResponces() {
|
|
||||||
return responseTable.select();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTime() {
|
|
||||||
return new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS").format(new Date());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +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.tools.collector.db;
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
|
|
||||||
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
|
|
||||||
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
|
||||||
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
|
||||||
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@RegisterBeanMapper(TikTokMessageModel.class)
|
|
||||||
public interface TikTokMessageModelDAO
|
|
||||||
{
|
|
||||||
@SqlUpdate("INSERT INTO TikTokMessageModel (hostName, eventName,type, eventContent, createdAt) " +
|
|
||||||
"VALUES (:hostName, :eventName, :type, :eventContent, :createdAt)")
|
|
||||||
void insertTikTokMessage(@BindBean TikTokMessageModel message);
|
|
||||||
|
|
||||||
@SqlQuery("SELECT * FROM TikTokMessageModel")
|
|
||||||
List<TikTokMessageModel> select();
|
|
||||||
}
|
|
||||||
@@ -1,43 +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.tools.collector.db;
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
|
|
||||||
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
|
|
||||||
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
|
||||||
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
|
||||||
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@RegisterBeanMapper(TikTokResponseModel.class)
|
|
||||||
public interface TikTokResponseModelDAO
|
|
||||||
{
|
|
||||||
@SqlUpdate("INSERT INTO TikTokResponseModel (hostName, response, createdAt) " +
|
|
||||||
"VALUES (:hostName, :response, :createdAt)")
|
|
||||||
void insert(@BindBean TikTokResponseModel message);
|
|
||||||
|
|
||||||
@SqlQuery("SELECT * FROM TikTokResponseModel")
|
|
||||||
List<TikTokResponseModel> select();
|
|
||||||
}
|
|
||||||
@@ -20,17 +20,19 @@
|
|||||||
* 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.tools.collector.db;
|
package io.github.jwdeveloper.tiktok.tools.db;
|
||||||
|
|
||||||
public class SqlConsts
|
public class SqlConsts
|
||||||
{
|
{
|
||||||
public static String CREATE_MESSAGES_TABLE = """
|
|
||||||
CREATE TABLE IF NOT EXISTS TikTokMessageModel (
|
public static String CREATE_DATA_TABLE = """
|
||||||
|
CREATE TABLE IF NOT EXISTS TikTokData (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
hostName TEXT,
|
sessionTag TEXT,
|
||||||
type TEXT,
|
tiktokUser TEXT,
|
||||||
eventName TEXT,
|
dataType TEXT,
|
||||||
eventContent TEXT,
|
dataTypeName TEXT,
|
||||||
|
content TEXT,
|
||||||
createdAt TEXT
|
createdAt TEXT
|
||||||
);
|
);
|
||||||
""";
|
""";
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* 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.tools.db;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokDataTable;
|
||||||
|
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
|
||||||
|
import org.jdbi.v3.sqlobject.customizer.Bind;
|
||||||
|
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
||||||
|
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
||||||
|
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RegisterBeanMapper(TikTokDataTable.class)
|
||||||
|
public interface TikTokDataTableDAO {
|
||||||
|
String query = """
|
||||||
|
INSERT INTO TikTokData (sessionTag, tiktokUser, dataType, dataTypeName, content, createdAt) VALUES (:sessionTag, :tiktokUser, :dataType, :dataTypeName, :content, :createdAt)
|
||||||
|
""";
|
||||||
|
|
||||||
|
@SqlUpdate(query)
|
||||||
|
void insertData(@BindBean TikTokDataTable data);
|
||||||
|
|
||||||
|
@SqlQuery("SELECT * FROM TikTokData WHERE sessionTag = :sessionTag")
|
||||||
|
List<TikTokDataTable> selectBySession(@Bind("sessionTag") String sessionTag);
|
||||||
|
|
||||||
|
@SqlQuery("SELECT * FROM TikTokData WHERE dataType = :dataType AND sessionTag = :sessionTag AND tiktokUser = :tiktokUser")
|
||||||
|
List<TikTokDataTable> selectSessionData(@Bind("dataType") String dataType,
|
||||||
|
@Bind("sessionTag") String sessionTag,
|
||||||
|
@Bind("tiktokUser") String user);
|
||||||
|
|
||||||
|
@SqlQuery("SELECT * FROM TikTokData WHERE sessionTag = :sessionTag AND tiktokUser = :tiktokUser AND dataType = \"response\"")
|
||||||
|
List<TikTokDataTable> selectResponces(@Bind("sessionTag") String sessionTag, @Bind("tiktokUser") String user);
|
||||||
|
|
||||||
|
@SqlQuery("SELECT * FROM TikTokData WHERE sessionTag = :sessionTag AND tiktokUser = :tiktokUser AND dataType = \"event\"")
|
||||||
|
List<TikTokDataTable> selectBySessionEvents(@Bind("sessionTag") String sessionTag, @Bind("tiktokUser") String userName);
|
||||||
|
|
||||||
|
@SqlQuery("SELECT * FROM TikTokData WHERE sessionTag = :sessionTag AND tiktokUser = :tiktokUser AND dataType = \"message\"")
|
||||||
|
List<TikTokDataTable> selectBySessionMessages(@Bind("sessionTag") String sessionTag, @Bind("tiktokUser") String userName);
|
||||||
|
|
||||||
|
|
||||||
|
@SqlQuery("SELECT tiktokUser FROM TikTokData GROUP BY tiktokUser")
|
||||||
|
List<String> getUsers();
|
||||||
|
|
||||||
|
|
||||||
|
@SqlQuery("SELECT sessionTag FROM TikTokData WHERE tiktokUser = :tiktokUser GROUP BY sessionTag")
|
||||||
|
List<String> getSessionTagByUser(@Bind("tiktokUser") String tiktokUser);
|
||||||
|
|
||||||
|
String groupByDataTypeNameQuery = """
|
||||||
|
SELECT dataTypeName, COUNT(*) as count
|
||||||
|
FROM TikTokData
|
||||||
|
WHERE dataType = 'message' AND sessionTag = :sessionTag AND tiktokUser = :userName
|
||||||
|
GROUP BY dataTypeName
|
||||||
|
""";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* 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.tools.db;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokDataTable;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokErrorModel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.jdbi.v3.core.Jdbi;
|
||||||
|
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
|
||||||
|
import org.sqlite.SQLiteConfig;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TikTokDatabase {
|
||||||
|
private final String database;
|
||||||
|
|
||||||
|
private TikTokErrorModelDAO errorTable;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private TikTokDataTableDAO dataTableDAO;
|
||||||
|
|
||||||
|
private Connection connection;
|
||||||
|
|
||||||
|
|
||||||
|
public TikTokDatabase(String database) {
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected()
|
||||||
|
{
|
||||||
|
return connection != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect() throws SQLException {
|
||||||
|
var jdbcUrl = "jdbc:sqlite:" + database + ".db";
|
||||||
|
var config = new SQLiteConfig();
|
||||||
|
config.setEncoding(SQLiteConfig.Encoding.UTF8);
|
||||||
|
connection = DriverManager.getConnection(jdbcUrl, config.toProperties());
|
||||||
|
var jdbi = Jdbi.create(jdbcUrl).installPlugin(new SqlObjectPlugin());
|
||||||
|
jdbi.useHandle(handle -> {
|
||||||
|
handle.execute(SqlConsts.CREATE_DATA_TABLE);
|
||||||
|
handle.execute(SqlConsts.CREATE_ERROR_TABLE);
|
||||||
|
});
|
||||||
|
dataTableDAO = jdbi.onDemand(TikTokDataTableDAO.class);
|
||||||
|
errorTable = jdbi.onDemand(TikTokErrorModelDAO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws SQLException {
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertData(TikTokDataTable tikTokDataTable) {
|
||||||
|
tikTokDataTable.setCreatedAt(getTime());
|
||||||
|
dataTableDAO.insertData(tikTokDataTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TikTokDataTable> getSessionResponces(String sessionTag, String userName) {
|
||||||
|
return dataTableDAO.selectResponces(sessionTag, userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getDataNames(String dataType, String sessionTag, String userName) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.append("""
|
||||||
|
SELECT dataTypeName, COUNT(*) as count
|
||||||
|
FROM TikTokData
|
||||||
|
""");
|
||||||
|
sb.append(" WHERE dataType = \""+dataType+"\" ");
|
||||||
|
sb.append(" AND tiktokUser = \"" + userName + "\" ");
|
||||||
|
sb.append(" AND sessionTag = \"" + sessionTag + "\" ");
|
||||||
|
sb.append("GROUP BY dataTypeName");
|
||||||
|
var statement = connection.prepareStatement(sb.toString());
|
||||||
|
var resultSet = statement.executeQuery();
|
||||||
|
List<String> dataTypeCounts = new ArrayList<>();
|
||||||
|
while (resultSet.next()) {
|
||||||
|
var dataTypeName = resultSet.getString("dataTypeName");
|
||||||
|
dataTypeCounts.add(dataTypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSet.close();
|
||||||
|
statement.close();
|
||||||
|
|
||||||
|
return dataTypeCounts;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return List.of("error");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public List<TikTokDataTable> getSessionMessages(String sessionTag, String userName, int count) {
|
||||||
|
return dataTableDAO.selectBySessionMessages(sessionTag, userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertError(TikTokErrorModel message) {
|
||||||
|
message.setCreatedAt(getTime());
|
||||||
|
errorTable.insertTikTokMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<TikTokErrorModel> selectErrors() {
|
||||||
|
return errorTable.selectErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTime() {
|
||||||
|
return new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS").format(new Date());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,9 +20,9 @@
|
|||||||
* 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.tools.collector.db;
|
package io.github.jwdeveloper.tiktok.tools.db;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
|
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokErrorModel;
|
||||||
|
|
||||||
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
|
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
|
||||||
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* 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.tools.collector.tables;
|
package io.github.jwdeveloper.tiktok.tools.db.tables;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
@@ -20,23 +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.tools.collector.tables;
|
package io.github.jwdeveloper.tiktok.tools.db.tables;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TikTokMessageModel
|
public class TikTokDataTable
|
||||||
{
|
{
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
private String hostName;
|
private String sessionTag;
|
||||||
|
|
||||||
private String eventName;
|
private String tiktokUser;
|
||||||
|
|
||||||
private String type;
|
private String dataType;
|
||||||
|
|
||||||
private String message;
|
private String dataTypeName;
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
|
||||||
private String createdAt;
|
private String createdAt;
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* 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.tools.collector.tables;
|
package io.github.jwdeveloper.tiktok.tools.db.tables;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -1,77 +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.tools.tester;
|
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
|
||||||
import io.github.jwdeveloper.tiktok.mockClient.TikTokClientMock;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.db.TikTokDatabase;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.util.MessageUtil;
|
|
||||||
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
|
||||||
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
|
|
||||||
|
|
||||||
import java.util.logging.ConsoleHandler;
|
|
||||||
import java.util.logging.Formatter;
|
|
||||||
import java.util.logging.LogRecord;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
|
|
||||||
public class RunDbTester {
|
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
var db = new TikTokDatabase("test");
|
|
||||||
db.init();
|
|
||||||
|
|
||||||
var responses = db.selectResponces().stream().map(TikTokResponseModel::getResponse).toList();
|
|
||||||
var client = TikTokClientMock
|
|
||||||
.create()
|
|
||||||
.addResponses(responses)
|
|
||||||
.onWebsocketUnhandledMessage((liveClient, event) ->
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.append("Unhandled Message! " );
|
|
||||||
sb.append(event.getData().getMethod());
|
|
||||||
sb.append(MessageUtil.getContent(event.getData()));
|
|
||||||
|
|
||||||
liveClient.getLogger().info(sb.toString());
|
|
||||||
})
|
|
||||||
.onWebsocketMessage((liveClient, event) ->
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.append(event.getEvent().getClass().getSimpleName());
|
|
||||||
sb.append(event.getEvent().toJson());
|
|
||||||
liveClient.getLogger().fine(sb.toString());
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
|
|
||||||
|
|
||||||
client.connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
package io.github.jwdeveloper.tiktok.tools.tester;
|
package io.github.jwdeveloper.tiktok.tools.tester;
|
||||||
|
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import io.github.jwdeveloper.tiktok.mockClient.TikTokClientMock;
|
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.TikTokLiveMock;
|
||||||
import io.github.jwdeveloper.tiktok.mockClient.mocks.LiveClientMock;
|
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.LiveClientMock;
|
||||||
import io.github.jwdeveloper.tiktok.tools.util.MessageUtil;
|
import io.github.jwdeveloper.tiktok.tools.util.MessageUtil;
|
||||||
|
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
@@ -37,7 +37,7 @@ public class RunJsonTester {
|
|||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
var messages = getMessages();
|
var messages = getMessages();
|
||||||
var client =(LiveClientMock) TikTokClientMock.create()
|
var client =(LiveClientMock) TikTokLiveMock.create()
|
||||||
.onWebsocketUnhandledMessage((liveClient, event) ->
|
.onWebsocketUnhandledMessage((liveClient, event) ->
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.github.jwdeveloper.tiktok.tools.tester;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokDataTable;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTester;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTesterModel;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.TikTokLiveMock;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.LiveClientMock;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
public class TikTokDataTester implements DataTester {
|
||||||
|
private DataTesterModel model;
|
||||||
|
|
||||||
|
private LiveClientMock client;
|
||||||
|
|
||||||
|
private Queue<TikTokDataTable> data;
|
||||||
|
|
||||||
|
private TikTokDatabase database;
|
||||||
|
|
||||||
|
public TikTokDataTester(DataTesterModel model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
database = new TikTokDatabase(model.getDatabaseName());
|
||||||
|
database.connect();
|
||||||
|
var mockBuilder = TikTokLiveMock.create();
|
||||||
|
model.getBuilderConsumer().accept(mockBuilder);
|
||||||
|
client = mockBuilder.build();
|
||||||
|
var respocnes = database.getSessionResponces(model.getSessionTag(), model.getUser());
|
||||||
|
data = new LinkedList<>(respocnes);
|
||||||
|
client.connect();
|
||||||
|
while (!data.isEmpty()) {
|
||||||
|
nextResponse();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Error while running tester", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nextResponse() {
|
||||||
|
try {
|
||||||
|
var responce = data.poll();
|
||||||
|
client.publishResponse(responce.getContent());
|
||||||
|
Thread.sleep(1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Unable to run response!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
client.disconnect();
|
||||||
|
database.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.tools.tester;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTester;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTesterBuilder;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTesterModel;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class TikTokDataTesterBuilder implements DataTesterBuilder {
|
||||||
|
private final DataTesterModel model;
|
||||||
|
|
||||||
|
public TikTokDataTesterBuilder(String databaseName) {
|
||||||
|
this.model = new DataTesterModel();
|
||||||
|
this.model.setDatabaseName(databaseName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTesterBuilder setSessionTag(String sessionTag) {
|
||||||
|
model.setSessionTag(sessionTag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTesterBuilder setUser(String user) {
|
||||||
|
model.setUser(user);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTesterBuilder configureLiveClient(Consumer<LiveClientBuilder> builderConsumer) {
|
||||||
|
model.setBuilderConsumer(builderConsumer);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTester build() {
|
||||||
|
return new TikTokDataTester(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTester buildAndRun()
|
||||||
|
{
|
||||||
|
var tester = build();
|
||||||
|
tester.connect();
|
||||||
|
return tester;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.tools.tester.api;
|
||||||
|
|
||||||
|
public interface DataTester
|
||||||
|
{
|
||||||
|
void connect();
|
||||||
|
|
||||||
|
void nextResponse();
|
||||||
|
|
||||||
|
void disconnect();
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.tools.tester.api;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public interface DataTesterBuilder {
|
||||||
|
|
||||||
|
DataTesterBuilder setSessionTag(String sessionTag);
|
||||||
|
|
||||||
|
DataTesterBuilder setUser(String user);
|
||||||
|
|
||||||
|
DataTesterBuilder configureLiveClient(Consumer<LiveClientBuilder> builderConsumer);
|
||||||
|
|
||||||
|
DataTester build();
|
||||||
|
|
||||||
|
DataTester buildAndRun();
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.github.jwdeveloper.tiktok.tools.tester.api;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DataTesterModel {
|
||||||
|
|
||||||
|
|
||||||
|
String databaseName;
|
||||||
|
String sessionTag;
|
||||||
|
String user;
|
||||||
|
Consumer<LiveClientBuilder> builderConsumer = (a) -> {
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -20,9 +20,9 @@
|
|||||||
* 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.mockClient;
|
package io.github.jwdeveloper.tiktok.tools.tester.mockClient;
|
||||||
|
|
||||||
public class TikTokClientMock
|
public class TikTokLiveMock
|
||||||
{
|
{
|
||||||
public static TikTokMockBuilder create(String host)
|
public static TikTokMockBuilder create(String host)
|
||||||
{
|
{
|
||||||
@@ -20,25 +20,22 @@
|
|||||||
* 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.mockClient;
|
package io.github.jwdeveloper.tiktok.tools.tester.mockClient;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
|
import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
|
||||||
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
|
||||||
import io.github.jwdeveloper.tiktok.mappers.events.TikTokGiftEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.mappers.events.TikTokRoomInfoEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.mappers.events.TikTokSocialMediaEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||||
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
|
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
|
||||||
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
import io.github.jwdeveloper.tiktok.mockClient.mocks.ApiServiceMock;
|
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.ApiServiceMock;
|
||||||
import io.github.jwdeveloper.tiktok.mockClient.mocks.LiveClientMock;
|
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.LiveClientMock;
|
||||||
import io.github.jwdeveloper.tiktok.mockClient.mocks.WebsocketClientMock;
|
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.WebsocketClientMock;
|
||||||
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -96,7 +93,7 @@ public class TikTokMockBuilder extends TikTokLiveClientBuilder {
|
|||||||
|
|
||||||
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
|
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
|
||||||
var giftManager = new TikTokGiftManager(logger);
|
var giftManager = new TikTokGiftManager(logger);
|
||||||
var requestFactory = new TikTokHttpRequestFactory(cookie);
|
var requestFactory = new TikTokHttpRequestFactory(cookie, new TikTokEventObserver());
|
||||||
var apiClient = new TikTokHttpClient(cookie, requestFactory);
|
var apiClient = new TikTokHttpClient(cookie, requestFactory);
|
||||||
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
|
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
|
||||||
var mapper = createMapper(giftManager, tiktokRoomInfo);
|
var mapper = createMapper(giftManager, tiktokRoomInfo);
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* 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.mockClient.mocks;
|
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.ClientSettings;
|
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* 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.mockClient.mocks;
|
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.ClientSettings;
|
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||||
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
|
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
|
||||||
@@ -54,8 +54,11 @@ public class LiveClientMock extends TikTokLiveClient {
|
|||||||
listenersManager,
|
listenersManager,
|
||||||
logger);
|
logger);
|
||||||
this.websocketClientMock = webSocketClient;
|
this.websocketClientMock = webSocketClient;
|
||||||
|
websocketClientMock.setClient(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void publishMessage(String type, String base64) {
|
public void publishMessage(String type, String base64) {
|
||||||
websocketClientMock.addMessage(type, base64);
|
websocketClientMock.addMessage(type, base64);
|
||||||
}
|
}
|
||||||
@@ -75,5 +78,4 @@ public class LiveClientMock extends TikTokLiveClient {
|
|||||||
public void publishResponse(WebcastResponse message) {
|
public void publishResponse(WebcastResponse message) {
|
||||||
websocketClientMock.addResponse(message);
|
websocketClientMock.addResponse(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* 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.mockClient.mocks;
|
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
@@ -39,12 +39,19 @@ import java.util.logging.Logger;
|
|||||||
public class WebsocketClientMock implements SocketClient {
|
public class WebsocketClientMock implements SocketClient {
|
||||||
Logger logger;
|
Logger logger;
|
||||||
Stack<WebcastResponse> responses;
|
Stack<WebcastResponse> responses;
|
||||||
|
|
||||||
Stack<MsgStruct> messages;
|
Stack<MsgStruct> messages;
|
||||||
TikTokMessageHandler messageHandler;
|
TikTokMessageHandler messageHandler;
|
||||||
|
|
||||||
|
LiveClient client;
|
||||||
|
|
||||||
|
Thread thread;
|
||||||
|
|
||||||
private boolean isRunning;
|
private boolean isRunning;
|
||||||
|
|
||||||
|
public void setClient(LiveClientMock liveClientMock) {
|
||||||
|
this.client = liveClientMock;
|
||||||
|
}
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
public static class MsgStruct {
|
public static class MsgStruct {
|
||||||
String messageType;
|
String messageType;
|
||||||
@@ -87,38 +94,28 @@ public class WebsocketClientMock implements SocketClient {
|
|||||||
@Override
|
@Override
|
||||||
public void start(WebcastResponse webcastResponse, LiveClient tikTokLiveClient) {
|
public void start(WebcastResponse webcastResponse, LiveClient tikTokLiveClient) {
|
||||||
logger.info("Running message: " + responses.size());
|
logger.info("Running message: " + responses.size());
|
||||||
|
|
||||||
|
|
||||||
|
thread = new Thread(() ->
|
||||||
|
{
|
||||||
|
|
||||||
|
while (isRunning)
|
||||||
|
{
|
||||||
|
while (!responses.isEmpty()) {
|
||||||
|
var response = responses.pop();
|
||||||
|
messageHandler.handle(client, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
while (!responses.isEmpty() || !messages.isEmpty()) {
|
thread.start();
|
||||||
if (!responses.isEmpty()) {
|
|
||||||
var response = responses.pop();
|
|
||||||
for (var message : response.getMessagesList()) {
|
|
||||||
try {
|
|
||||||
messageHandler.handleSingleMessage(tikTokLiveClient, message);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.info("Unable to parse message for response " + response.getCursor());
|
|
||||||
throw new TikTokLiveMessageException(message, response, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!messages.isEmpty()) {
|
|
||||||
var messageStr = messages.pop();
|
|
||||||
try {
|
|
||||||
var msg = WebcastResponse.Message.newBuilder()
|
|
||||||
.setMethod(messageStr.messageType)
|
|
||||||
.setPayload(ByteString.copyFrom(messageStr.getMessageValue()))
|
|
||||||
.build();
|
|
||||||
messageHandler.handleSingleMessage(tikTokLiveClient, msg);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.info("Unable to parse message for response " + messageStr.getMessageType());
|
|
||||||
throw new TikTokLiveException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
isRunning = true;
|
isRunning = false;
|
||||||
|
thread.interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,16 +42,16 @@ public class MessageUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getContent(String methodName, byte[] bytes) {
|
public static String getContent(String messageName, byte[] bytes) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
var inputClazz = Class.forName("io.github.jwdeveloper.tiktok.messages.webcast." + methodName);
|
var inputClazz = Class.forName("io.github.jwdeveloper.tiktok.messages.webcast." + messageName);
|
||||||
var parseMethod = inputClazz.getDeclaredMethod("parseFrom", byte[].class);
|
var parseMethod = inputClazz.getDeclaredMethod("parseFrom", byte[].class);
|
||||||
var deserialized = parseMethod.invoke(null, bytes);
|
var deserialized = parseMethod.invoke(null, bytes);
|
||||||
return JsonUtil.messageToJson(deserialized);
|
return JsonUtil.messageToJson(deserialized);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.append("Can not find protocolbuffer file message representation for " + methodName);
|
sb.append("Can not find protocol-buffer file message representation for " + messageName);
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
var structure = ProtocolUtils.getProtocolBufferStructure(bytes);
|
var structure = ProtocolUtils.getProtocolBufferStructure(bytes);
|
||||||
var json =structure.toJson();
|
var json =structure.toJson();
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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.0.7-Release</version>
|
<version>1.0.9-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>Tools-EventsWebViewer</artifactId>
|
<artifactId>Tools-EventsWebViewer</artifactId>
|
||||||
|
|||||||
@@ -22,13 +22,35 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.webviewer;
|
package io.github.jwdeveloper.tiktok.webviewer;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
|
||||||
import io.github.jwdeveloper.tiktok.webviewer.handlers.TikTokHandler;
|
import io.github.jwdeveloper.tiktok.webviewer.handlers.TikTokHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.webviewer.services.TikTokCollectorService;
|
||||||
|
import io.github.jwdeveloper.tiktok.webviewer.services.TikTokDatabaseService;
|
||||||
import io.javalin.Javalin;
|
import io.javalin.Javalin;
|
||||||
|
|
||||||
public class Main {
|
import java.io.IOException;
|
||||||
public static void main(String[] args) {
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
var manager = new TikTokManager();
|
public class Main {
|
||||||
|
public static void main(String[] args) throws SQLException, ExecutionException, InterruptedException, IOException {
|
||||||
|
var settings = new Settings();
|
||||||
|
settings.setUserName("szalonamoniaxx");
|
||||||
|
settings.setSessionTag("battle");
|
||||||
|
settings.setDbName("db-battle");
|
||||||
|
settings.setPort(8002);
|
||||||
|
|
||||||
|
var db = new TikTokDatabase(settings.getDbName());
|
||||||
|
db.connect();
|
||||||
|
|
||||||
|
var service = new TikTokDatabaseService(db);
|
||||||
|
var collectorService = new TikTokCollectorService(settings, db);
|
||||||
|
var handler = new TikTokHandler(service, settings, collectorService);
|
||||||
|
// var manager = new TikTokManager(service);
|
||||||
var app = Javalin.create(config ->
|
var app = Javalin.create(config ->
|
||||||
{
|
{
|
||||||
config.plugins.enableCors(corsContainer ->
|
config.plugins.enableCors(corsContainer ->
|
||||||
@@ -39,13 +61,19 @@ public class Main {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
config.staticFiles.add("/public");
|
config.staticFiles.add("/public");
|
||||||
}).start(8001);
|
}).start(settings.getPort());
|
||||||
|
|
||||||
var handler = new TikTokHandler(manager);
|
app.get("/tiktok/status", handler::connectionStatus);
|
||||||
app.get("/tiktok/connect", handler::connect);
|
app.get("/tiktok/connect", handler::connect);
|
||||||
app.get("/tiktok/disconnect", handler::disconnect);
|
app.get("/tiktok/disconnect", handler::disconnect);
|
||||||
app.get("/tiktok/events", handler::events);
|
|
||||||
app.get("/tiktok/events/pages", handler::eventPages);
|
app.get("/tiktok/data/pages", handler::getDataPages);
|
||||||
app.get("/tiktok/events/message", handler::eventMessage);
|
app.get("/tiktok/data/names", handler::getDataNames);
|
||||||
|
app.get("/tiktok/data", handler::getData);
|
||||||
|
|
||||||
|
app.get("/tiktok/update", handler::updateSearch);
|
||||||
|
app.get("/tiktok/sessions", handler::getUserSessionTags);
|
||||||
|
app.get("/tiktok/users", handler::getUsers);
|
||||||
|
app.get("/tiktok/data-types", handler::getDataTypes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.webviewer;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Settings
|
||||||
|
{
|
||||||
|
|
||||||
|
private int port;
|
||||||
|
private String dbName;
|
||||||
|
private String userName;
|
||||||
|
private String sessionTag;
|
||||||
|
}
|
||||||
@@ -1,137 +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.webviewer;
|
|
||||||
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.client.MessageCollector;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.client.TikTokMessageCollectorClient;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.collector.client.TikTokMessagessCollectorBuilder;
|
|
||||||
import io.github.jwdeveloper.tiktok.tools.util.MessageUtil;
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
public class TikTokManager {
|
|
||||||
TikTokMessagessCollectorBuilder client;
|
|
||||||
MessageCollector msgCollector;
|
|
||||||
|
|
||||||
public static String dbName= "log";
|
|
||||||
|
|
||||||
public TikTokManager() {
|
|
||||||
msgCollector = new MessageCollector(dbName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void connect(String name) throws SQLException {
|
|
||||||
disconnect();
|
|
||||||
client = TikTokMessageCollectorClient.create(msgCollector, dbName)
|
|
||||||
.addOnBuilder(liveClientBuilder ->
|
|
||||||
{
|
|
||||||
liveClientBuilder.onRoomInfo((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
});
|
|
||||||
liveClientBuilder.onGift((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
});
|
|
||||||
liveClientBuilder.onWebsocketUnhandledMessage((liveClient, event) ->
|
|
||||||
{
|
|
||||||
System.out.println("UNHANDLED MESSAGE! "+event.getMessage().getMethod());
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
.addUser(name);
|
|
||||||
client.buildAndRun();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getEventsNames() {
|
|
||||||
return msgCollector.getMessages().keySet().stream().toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getEventMessages(String eventName) {
|
|
||||||
return msgCollector.getMessages().get(eventName).stream().map(MessageCollector.MessageData::getEventData).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public MessageDto getMessage(String event, String index) throws InvalidProtocolBufferException {
|
|
||||||
var eventData = msgCollector.getMessages().get(event);
|
|
||||||
var messages = eventData.stream().toList();
|
|
||||||
var random = new Random();
|
|
||||||
|
|
||||||
var msgIndex = 0;
|
|
||||||
if (index != null && !index.isEmpty()) {
|
|
||||||
msgIndex = Integer.parseInt(index);
|
|
||||||
msgIndex = Math.min(msgIndex, messages.size() - 1);
|
|
||||||
msgIndex = Math.max(msgIndex, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var msg = messages.get(msgIndex);
|
|
||||||
|
|
||||||
|
|
||||||
var bytes = Base64.getDecoder().decode(msg.getEventData());
|
|
||||||
var content = MessageUtil.getContent(event, bytes);
|
|
||||||
return new MessageDto(content, msg.getEventData(), event);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public PagesDto getPages(String event) throws InvalidProtocolBufferException {
|
|
||||||
var eventData = msgCollector.getMessages().get(event);
|
|
||||||
var messages = eventData.stream().toList();
|
|
||||||
|
|
||||||
var counter = new AtomicInteger(-1);
|
|
||||||
var pages = messages.stream().map(e ->
|
|
||||||
{
|
|
||||||
return "http://localhost:8001/tiktok/events/message?eventName=" + event + "&page=" + counter.incrementAndGet();
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
return new PagesDto(event, messages.size(), pages);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Value
|
|
||||||
public class PagesDto {
|
|
||||||
String eventName;
|
|
||||||
int pages;
|
|
||||||
List<String> links;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Value
|
|
||||||
public class MessageDto {
|
|
||||||
String content;
|
|
||||||
String base64;
|
|
||||||
String eventName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnect() {
|
|
||||||
if (client == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
client.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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.webviewer;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkLayerMessage;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.TikTokLiveTools;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class ToolsExamples {
|
||||||
|
|
||||||
|
private static final String tiktokUser = "debb.cl";
|
||||||
|
|
||||||
|
private static final String db = "db-battle";
|
||||||
|
|
||||||
|
private static final String sessionTag = "gifts";
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
// runCollector();
|
||||||
|
runCollector();
|
||||||
|
//runTester();
|
||||||
|
System.in.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
WebcastLinkMicArmies
|
||||||
|
WebcastLinkMicBattle
|
||||||
|
*/
|
||||||
|
//WebcastLinkMicArmies battle data?
|
||||||
|
//WebcastLinkMicBattlePunishFinish end of battle?
|
||||||
|
//WebcastLinkLayerMessage send after end of battle
|
||||||
|
// send after LinkLayer -> WebcastLinkMessage
|
||||||
|
private static void runCollector() {
|
||||||
|
TikTokLiveTools.createCollector(db)
|
||||||
|
.addUser(tiktokUser)
|
||||||
|
.setSessionTag(sessionTag)
|
||||||
|
.configureLiveClient(liveClientBuilder ->
|
||||||
|
{
|
||||||
|
liveClientBuilder.configure(clientSettings ->
|
||||||
|
{
|
||||||
|
clientSettings.setPrintToConsole(true);
|
||||||
|
});
|
||||||
|
liveClientBuilder.onWebsocketResponse((liveClient, event) ->
|
||||||
|
{
|
||||||
|
for (var msg : event.getResponse().getMessagesList()) {
|
||||||
|
System.out.println(msg.getMethod());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
liveClientBuilder.onConnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
liveClient.getLogger().info("Connected");
|
||||||
|
});
|
||||||
|
}).buildAndRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void runTester() {
|
||||||
|
TikTokLiveTools.createTester(db)
|
||||||
|
.setSessionTag(sessionTag)
|
||||||
|
.setUser(tiktokUser)
|
||||||
|
.configureLiveClient(liveClientBuilder ->
|
||||||
|
{
|
||||||
|
liveClientBuilder.onError((liveClient, event) ->
|
||||||
|
{
|
||||||
|
event.getException().printStackTrace();
|
||||||
|
;
|
||||||
|
});
|
||||||
|
|
||||||
|
liveClientBuilder.onWebsocketResponse((liveClient, event) ->
|
||||||
|
{
|
||||||
|
System.out.println("Response =====================================");
|
||||||
|
for (var msg : event.getResponse().getMessagesList()) {
|
||||||
|
System.out.println("Message -> " + msg.getMethod());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
liveClientBuilder.onEvent((liveClient, event) ->
|
||||||
|
{
|
||||||
|
System.out.println("Event -> " + event.getClass().getSimpleName());
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.buildAndRun();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,61 +25,153 @@ package io.github.jwdeveloper.tiktok.webviewer.handlers;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
import io.github.jwdeveloper.tiktok.webviewer.TikTokManager;
|
import io.github.jwdeveloper.tiktok.webviewer.Settings;
|
||||||
|
import io.github.jwdeveloper.tiktok.webviewer.services.TikTokCollectorService;
|
||||||
|
import io.github.jwdeveloper.tiktok.webviewer.services.TikTokDatabaseService;
|
||||||
import io.javalin.http.Context;
|
import io.javalin.http.Context;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class TikTokHandler {
|
public class TikTokHandler {
|
||||||
private final TikTokManager tikTokManager;
|
private final TikTokDatabaseService databaseService;
|
||||||
|
private final Settings settings;
|
||||||
|
private final TikTokCollectorService collectorService;
|
||||||
|
|
||||||
public TikTokHandler(TikTokManager tikTokManager) {
|
public TikTokHandler(TikTokDatabaseService databaseService,
|
||||||
this.tikTokManager = tikTokManager;
|
Settings settings,
|
||||||
|
TikTokCollectorService collectorService) {
|
||||||
|
this.databaseService = databaseService;
|
||||||
|
this.settings = settings;
|
||||||
|
this.collectorService = collectorService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void connect(Context context) throws SQLException {
|
public void connect(Context context) {
|
||||||
String name = context.queryParam("name");
|
var name = context.queryParam("name");
|
||||||
if (name.equals(" ")) {
|
var sessionTag = context.queryParam("session");
|
||||||
context.result("Name can not be empty");
|
System.out.println("Session tag" + sessionTag);
|
||||||
context.status(400);
|
collectorService.start(name, sessionTag);
|
||||||
return;
|
settings.setUserName(name);
|
||||||
}
|
|
||||||
tikTokManager.connect(name);
|
|
||||||
context.status(200);
|
context.status(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect(Context context){
|
public void connectionStatus(Context context) {
|
||||||
tikTokManager.disconnect();
|
var isWorking = collectorService.isRunning();
|
||||||
context.status(200);
|
var result = getGson().toJson(isWorking);
|
||||||
}
|
|
||||||
|
|
||||||
public void events(Context context) {
|
|
||||||
var events = tikTokManager.getEventsNames();
|
|
||||||
var gson = getGson();
|
|
||||||
var result = gson.toJson(events);
|
|
||||||
context.result(result);
|
context.result(result);
|
||||||
context.status(200);
|
context.status(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void eventMessage(Context context) throws InvalidProtocolBufferException {
|
public void disconnect(Context context) {
|
||||||
String name = context.queryParam("eventName");
|
|
||||||
String page = context.queryParam("page");
|
|
||||||
|
|
||||||
var result = tikTokManager.getMessage(name, page);
|
collectorService.stop();
|
||||||
var gson = getGson();
|
context.status(200);
|
||||||
context.result(gson.toJson(result));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void eventPages(Context context) throws InvalidProtocolBufferException {
|
|
||||||
String name = context.queryParam("eventName");
|
public void getUsers(Context context) {
|
||||||
var result = tikTokManager.getPages(name);
|
var users = databaseService.getUsers();
|
||||||
|
var result = getGson().toJson(users);
|
||||||
|
context.result(result);
|
||||||
|
context.status(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getUserSessionTags(Context context) {
|
||||||
|
var dataType = context.queryParam("user");
|
||||||
|
var sessionsTags = databaseService.getSessionTag(dataType);
|
||||||
|
|
||||||
|
var result = getGson().toJson(sessionsTags);
|
||||||
|
context.result(result);
|
||||||
|
context.status(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getDataTypes(Context context) {
|
||||||
|
var result = getGson().toJson(List.of("event", "message", "response"));
|
||||||
|
context.result(result);
|
||||||
|
context.status(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void updateSearch(Context context) {
|
||||||
|
var userName = context.queryParam("user");
|
||||||
|
var sessionTag = context.queryParam("session");
|
||||||
|
|
||||||
|
settings.setUserName(userName);
|
||||||
|
settings.setSessionTag(sessionTag);
|
||||||
|
context.status(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void getDataNames(Context context) {
|
||||||
|
var dataType = context.queryParam("type");
|
||||||
|
var dataNames = databaseService.getDataNames(dataType, settings.getUserName(), settings.getSessionTag());
|
||||||
var gson = getGson();
|
var gson = getGson();
|
||||||
context.result(gson.toJson(result));
|
|
||||||
|
|
||||||
|
var result = gson.toJson(dataNames);
|
||||||
|
context.result(result);
|
||||||
|
context.status(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getData(Context context) {
|
||||||
|
var page = context.queryParam("page");
|
||||||
|
var dataType = context.queryParam("type");
|
||||||
|
var dataName = context.queryParam("name");
|
||||||
|
if (page == null) {
|
||||||
|
page = "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var asProto = context.queryParam("asProto");
|
||||||
|
var asJson = asProto == null;
|
||||||
|
var dto = new TikTokDatabaseService.DatabaseDataDto(dataType, dataName, settings.getUserName(), settings.getSessionTag(), asJson);
|
||||||
|
var result = databaseService.getData(dto);
|
||||||
|
var content = result.get(Integer.parseInt(page));
|
||||||
|
|
||||||
|
var response = new MessageDto(content, "", dataName);
|
||||||
|
var gson = getGson();
|
||||||
|
context.result(gson.toJson(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getDataPages(Context context) throws InvalidProtocolBufferException {
|
||||||
|
var dataType = context.queryParam("type");
|
||||||
|
var dataName = context.queryParam("name");
|
||||||
|
|
||||||
|
var asJson = true;
|
||||||
|
var dto = new TikTokDatabaseService.DatabaseDataDto(dataType, dataName, settings.getUserName(), settings.getSessionTag(), asJson);
|
||||||
|
var result = databaseService.getData(dto);
|
||||||
|
var counter = new AtomicInteger(-1);
|
||||||
|
var pages = result.stream().map(e ->
|
||||||
|
{
|
||||||
|
return "http://localhost:" + settings.getPort() + "/tiktok/data?type=" + dataType + "&page=" + counter.incrementAndGet() + "&name=" + dataName;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
var response = new PagesDto(dataName, counter.get(), pages);
|
||||||
|
var gson = getGson();
|
||||||
|
context.result(gson.toJson(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Gson getGson() {
|
public Gson getGson() {
|
||||||
return new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
|
return new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class PagesDto {
|
||||||
|
String eventName;
|
||||||
|
int pages;
|
||||||
|
List<String> links;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class MessageDto {
|
||||||
|
String content;
|
||||||
|
String base64;
|
||||||
|
String eventName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.webviewer.services;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.TikTokLiveTools;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.api.DataCollector;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
|
||||||
|
import io.github.jwdeveloper.tiktok.webviewer.Settings;
|
||||||
|
|
||||||
|
public class TikTokCollectorService {
|
||||||
|
private final Settings settings;
|
||||||
|
private final TikTokDatabase database;
|
||||||
|
|
||||||
|
private boolean isConnected = false;
|
||||||
|
|
||||||
|
private DataCollector collector;
|
||||||
|
|
||||||
|
public TikTokCollectorService(Settings settings, TikTokDatabase database) {
|
||||||
|
this.settings = settings;
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(String user, String sessionTag) {
|
||||||
|
stop();
|
||||||
|
collector = createClient(user, sessionTag);
|
||||||
|
|
||||||
|
collector.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning()
|
||||||
|
{
|
||||||
|
if(collector == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (collector != null) {
|
||||||
|
collector.disconnect(true);
|
||||||
|
}
|
||||||
|
isConnected =false;
|
||||||
|
collector = null;
|
||||||
|
try {
|
||||||
|
database.close();
|
||||||
|
database.connect();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private DataCollector createClient(String user, String sessionTag) {
|
||||||
|
return TikTokLiveTools.createCollector("dupa")
|
||||||
|
.addUser(user)
|
||||||
|
.setSessionTag(sessionTag)
|
||||||
|
.setDatabase(database)
|
||||||
|
.configureLiveClient(liveClientBuilder ->
|
||||||
|
{
|
||||||
|
liveClientBuilder.configure(clientSettings ->
|
||||||
|
{
|
||||||
|
clientSettings.setPrintToConsole(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
liveClientBuilder.onWebsocketResponse((liveClient, event) ->
|
||||||
|
{
|
||||||
|
for (var msg : event.getResponse().getMessagesList()) {
|
||||||
|
System.out.println(msg.getMethod());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
liveClientBuilder.onDisconnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
liveClient.getLogger().info("Disconnected");
|
||||||
|
isConnected = false;
|
||||||
|
});
|
||||||
|
liveClientBuilder.onError((liveClient, event) ->
|
||||||
|
{
|
||||||
|
event.getException().printStackTrace();
|
||||||
|
});
|
||||||
|
liveClientBuilder.onConnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
liveClient.getLogger().info("Connected");
|
||||||
|
isConnected = true;
|
||||||
|
});
|
||||||
|
}).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.webviewer.services;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.TikTokDataTableDAO;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokDataTable;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.util.MessageUtil;
|
||||||
|
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
|
||||||
|
import io.github.jwdeveloper.tiktok.utils.ProtocolUtils;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TikTokDatabaseService {
|
||||||
|
public TikTokDatabase tikTokDatabase;
|
||||||
|
private TikTokDataTableDAO table;
|
||||||
|
|
||||||
|
|
||||||
|
public record DatabaseDataDto(String dataType, String dataName, String user, String sessionTag, boolean asJson) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public TikTokDatabaseService(TikTokDatabase databaseName) {
|
||||||
|
tikTokDatabase = databaseName;
|
||||||
|
table = tikTokDatabase.getDataTableDAO();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getUsers() {
|
||||||
|
return table.getUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getSessionTag(String user) {
|
||||||
|
return table.getSessionTagByUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getDataNames(String dataType, String user, String sessionTag) {
|
||||||
|
|
||||||
|
return tikTokDatabase.getDataNames(dataType, sessionTag, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getData(DatabaseDataDto dataDto) {
|
||||||
|
var data = tikTokDatabase.getDataTableDAO().selectSessionData(dataDto.dataType(), dataDto.sessionTag(), dataDto.user());
|
||||||
|
switch (dataDto.dataType()) {
|
||||||
|
case "message" -> {
|
||||||
|
return getMessages(dataDto.dataName(), data, dataDto.asJson);
|
||||||
|
}
|
||||||
|
case "event" -> {
|
||||||
|
return getEvents(dataDto.dataName(), data);
|
||||||
|
}
|
||||||
|
case "response" -> {
|
||||||
|
return getResponse(data,dataDto.dataName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return List.of("unknown dataType");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private List<String> getMessages(String messageName, List<TikTokDataTable> data, boolean asJson) {
|
||||||
|
|
||||||
|
var messages = data.stream()
|
||||||
|
.filter(e -> e.getDataTypeName().equals(messageName))
|
||||||
|
.map(e ->
|
||||||
|
{
|
||||||
|
|
||||||
|
try {
|
||||||
|
var bytes = Base64.getDecoder().decode(e.getContent());
|
||||||
|
if (asJson == false) {
|
||||||
|
return ProtocolUtils.getProtocolBufferStructure(bytes).toJson();
|
||||||
|
}
|
||||||
|
var parsedMessage = MessageUtil.getContent(messageName, bytes);
|
||||||
|
return parsedMessage;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getResponse(List<TikTokDataTable> data,String dataTypeName)
|
||||||
|
{
|
||||||
|
var messages = data.stream()
|
||||||
|
.filter(e -> e.getDataTypeName().equals(dataTypeName))
|
||||||
|
.map(e ->
|
||||||
|
{
|
||||||
|
if(e.getDataTypeName().equals("Http"))
|
||||||
|
{
|
||||||
|
return e.getContent();
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var bytes = Base64.getDecoder().decode(e.getContent());
|
||||||
|
var parsedMessage = WebcastResponse.parseFrom(bytes);
|
||||||
|
var json = JsonUtil.toJson(parsedMessage);
|
||||||
|
return json;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return "error";
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getEvents(String dataName, List<TikTokDataTable> data) {
|
||||||
|
var messages = data.stream()
|
||||||
|
.filter(e -> e.getDataTypeName().equals(dataName))
|
||||||
|
.map(TikTokDataTable::getContent)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
}
|
||||||
135
Tools-EventsWebViewer/src/main/resources/public/index.css
Normal file
135
Tools-EventsWebViewer/src/main/resources/public/index.css
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
body, html {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connect-btn
|
||||||
|
{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.dropdown
|
||||||
|
{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.dropdown-toggle
|
||||||
|
{
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
border-color: #2c2c2c;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary
|
||||||
|
{
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
border-color: #2c2c2c;
|
||||||
|
}
|
||||||
|
.btn-primary:hover
|
||||||
|
{
|
||||||
|
background-color: #474747;
|
||||||
|
border-color: #474747;
|
||||||
|
}
|
||||||
|
.margin
|
||||||
|
{
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
.form
|
||||||
|
{
|
||||||
|
|
||||||
|
padding: 1em;
|
||||||
|
|
||||||
|
border-bottom: 2px solid #676767
|
||||||
|
}
|
||||||
|
.form-label
|
||||||
|
{
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
.editor-parent
|
||||||
|
{
|
||||||
|
height: 2000px;
|
||||||
|
}
|
||||||
|
.editor-container
|
||||||
|
{
|
||||||
|
resize: vertical;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.list-group-item:hover
|
||||||
|
{
|
||||||
|
background-color: #474747;
|
||||||
|
color: azure;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.list-group-item
|
||||||
|
{
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
color: azure;
|
||||||
|
border-color: #252424;
|
||||||
|
}
|
||||||
|
.margin-left
|
||||||
|
{
|
||||||
|
margin-right: 0.2em;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
flex-grow: 1; /* Takes up the remaining space */
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.col-md-10, .col-md-2 {
|
||||||
|
padding: 0; /* Remove default padding */
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.scrollable-element {
|
||||||
|
|
||||||
|
overflow-y: scroll; /* Enable vertical scrollbar */
|
||||||
|
/* Other styles as needed */
|
||||||
|
scrollbar-width: thin;
|
||||||
|
height: 800px;
|
||||||
|
scrollbar-color: #275c9c #000000; /* thumb and track color */
|
||||||
|
}
|
||||||
|
.dropdown-menu
|
||||||
|
{
|
||||||
|
width: 100%;
|
||||||
|
background-color: #414040;
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
.dropdown-item
|
||||||
|
{
|
||||||
|
-webkit-user-select: none; /* For webkit browsers */
|
||||||
|
-moz-user-select: none; /* For Firefox */
|
||||||
|
-ms-user-select: none; /* For Microsoft browsers */
|
||||||
|
user-select: none; /* Standard syntax */
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item:hover
|
||||||
|
{
|
||||||
|
background-color: #696868;
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item:hover
|
||||||
|
{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 10px; /* Set width of the scrollbar */
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: #1e1e23; /* Track color */
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #123054; /* Thumb color */
|
||||||
|
border-radius: 5px; /* Rounded corners */
|
||||||
|
}
|
||||||
@@ -3,252 +3,132 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"></script>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
||||||
|
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"
|
||||||
|
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<title>Bootstrap Styled Javalin App</title>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
|
||||||
|
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" type="text/javascript"
|
||||||
|
charset="utf-8"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet"
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/editor/editor.main.css">
|
href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/editor/editor.main.css">
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/loader.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/loader.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/editor/editor.main.css">
|
||||||
<style>
|
<link rel="stylesheet" , href="index.css">
|
||||||
body, html {
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/loader.min.js"></script>
|
||||||
height: 100%;
|
<script>
|
||||||
margin: 0;
|
require.config({
|
||||||
display: flex;
|
paths: {'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs'}
|
||||||
flex-direction: column;
|
});
|
||||||
background-color: #121212; /* Dark background */
|
</script>
|
||||||
}
|
<script>
|
||||||
#app {
|
var editor;
|
||||||
height: 100vh; /* 100% of the viewport height */
|
var editor2;
|
||||||
display: flex;
|
require(['vs/editor/editor.main'], function () {
|
||||||
flex-direction: column;
|
editor = monaco.editor.create(document.getElementById('editor'), {
|
||||||
}
|
value: [
|
||||||
.header {
|
'Hello world!',
|
||||||
margin-bottom: 20px;
|
].join('\n'),
|
||||||
}
|
language: 'json',
|
||||||
.btn-primary
|
theme: 'vs-dark',
|
||||||
{
|
automaticLayout: true
|
||||||
background-color: #2c2c2c;
|
});
|
||||||
border-color: #2c2c2c;
|
|
||||||
}
|
|
||||||
.btn-primary:hover
|
|
||||||
{
|
|
||||||
background-color: #474747;
|
|
||||||
border-color: #474747;
|
|
||||||
}
|
|
||||||
|
|
||||||
#editor {
|
|
||||||
overflow-y: auto;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
.editor-container
|
|
||||||
{
|
|
||||||
|
|
||||||
padding: 10em;
|
|
||||||
}
|
|
||||||
.list-group-item:hover
|
|
||||||
{
|
|
||||||
background-color: #474747;
|
|
||||||
color: azure;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.list-group-item
|
|
||||||
{
|
|
||||||
background-color: #2c2c2c;
|
|
||||||
color: azure;
|
|
||||||
border-color: #252424;
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
flex-grow: 1; /* Takes up the remaining space */
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.col-md-10, .col-md-2 {
|
|
||||||
padding: 0; /* Remove default padding */
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/editor/editor.main.css">
|
|
||||||
|
|
||||||
<!-- Load Monaco Editor's main loader script -->
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/loader.min.js"></script>
|
|
||||||
|
|
||||||
<!-- Configure the loader -->
|
|
||||||
<script>
|
|
||||||
require.config({
|
|
||||||
paths: {'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs'}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Load the editor -->
|
|
||||||
<script>
|
|
||||||
var editor;
|
|
||||||
require(['vs/editor/editor.main'], function() {
|
|
||||||
editor = monaco.editor.create(document.getElementById('editor'), {
|
|
||||||
value: [
|
|
||||||
'function x() {',
|
|
||||||
'\tconsole.log("Hello world!");',
|
|
||||||
'}'
|
|
||||||
].join('\n'),
|
|
||||||
language: 'json',
|
|
||||||
theme: 'vs-dark'
|
|
||||||
});
|
|
||||||
editor.onDidChangeModelContent(function () {
|
|
||||||
console.log("hello")
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
editor2 = monaco.editor.create(document.getElementById('editor2'), {
|
||||||
|
value: [
|
||||||
|
'Hello world!',
|
||||||
|
].join('\n'),
|
||||||
|
language: 'json',
|
||||||
|
theme: 'vs-dark',
|
||||||
|
automaticLayout: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-dark">
|
<body class="container-fluid bg-dark">
|
||||||
|
|
||||||
<div id="app" class="container-fluid mt-5">
|
|
||||||
<div >
|
<div class="row ">
|
||||||
<div class="mb-3">
|
<div class="col-2 ">
|
||||||
<label for="name" class="form-label">Name:</label>
|
<div class="form margin">
|
||||||
<input type="text" id="name" name="name" class="form-control">
|
<h5 >Data collector</h5>
|
||||||
|
<div class="form-group ">
|
||||||
|
<label for="name" class="form-label">TikTok username</label>
|
||||||
|
<input type="text" id="name" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<button type="button" onclick="connect()" class="btn btn-primary">Connect</button>
|
<div class="form-group ">
|
||||||
<button type="button" onclick="disconnect()" class="btn btn-primary">Disconnect</button>
|
<label class="form-label">SessionTag</label>
|
||||||
<button onclick="showEvents()" class="btn btn-primary">Show Events</button>
|
<input type="text" id="sessionTag" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
|
<button id="connectionButton" type="button" class="btn btn-primary mt-3 connect-btn">Connect </button>
|
||||||
<div class="content row mt-5">
|
|
||||||
|
</div>
|
||||||
<div class="col-md-2 ">
|
|
||||||
<ul id="eventList" class="list-group" style="max-height: 100%; overflow-y: auto;">
|
<div>
|
||||||
<!-- List items will be added dynamically -->
|
<div class="dropdown mt-3" id="usersDropDown">
|
||||||
|
<button class="btn btn-secondary dropdown-toggle" type="button" id="usersDropDownButton"
|
||||||
|
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
User
|
||||||
|
</button>
|
||||||
|
<div id="userDropdownContent" class="dropdown-menu" aria-labelledby="usersDropDownButton">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dropdown mt-3" id="sessionTagDropDown">
|
||||||
|
<button class="btn btn-secondary dropdown-toggle" type="button" id="sessionTagDropDownButton"
|
||||||
|
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
SessionTag
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="sessionTagDropDownButton">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dropdown mt-3" id="dataTypeDropDown">
|
||||||
|
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton"
|
||||||
|
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
Data Type
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-5">
|
||||||
|
<ul id="dataList" class="list-group scrollable-element">
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-10 editor-container ">
|
|
||||||
<nav aria-label="Page navigation example">
|
|
||||||
<ul id="pages" class="pagination">
|
|
||||||
<li class="page-item btn-primary"><a class="page-link" href="#">Previous</a></li>
|
|
||||||
<li class="page-item"><a class="page-link" href="#">Next</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
<div id="editor"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="col-10 margin">
|
||||||
<div class="container mt-5">
|
<nav aria-label="Page navigation example">
|
||||||
<div class="row justify-content-center">
|
<ul id="pages" class="pagination">
|
||||||
<div class="col-md-6">
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<div class="row editor-parent">
|
||||||
|
<div class="col-6 editor-container" id="editor"></div>
|
||||||
|
<div class="col-6 editor-container" id="editor2"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="index.js"></script>
|
||||||
<script>
|
|
||||||
async function connect() {
|
|
||||||
let name = document.getElementById('name').value;
|
|
||||||
// name = "bangbetmenygy"
|
|
||||||
let response = await fetch(`http://localhost:8001/tiktok/connect?name=${name}`);
|
|
||||||
let greeting = await response.text();
|
|
||||||
console.log("connect",greeting);
|
|
||||||
connected = true;
|
|
||||||
}
|
|
||||||
async function disconnect() {
|
|
||||||
let response = await fetch(`http://localhost:8001/tiktok/disconnect`);
|
|
||||||
let greeting = await response.text();
|
|
||||||
console.log("disconnect",greeting);
|
|
||||||
connected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadMessage(event)
|
|
||||||
{
|
|
||||||
let response = await fetch(`http://localhost:8001/tiktok/events/message?eventName=${event}`);
|
|
||||||
let json = await response.text();
|
|
||||||
let root= JSON.parse(json);
|
|
||||||
editor.setValue(root.content);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadMessageLink(link)
|
|
||||||
{
|
|
||||||
let response = await fetch(link);
|
|
||||||
let json = await response.text();
|
|
||||||
let root= JSON.parse(json);
|
|
||||||
editor.setValue(root.content);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadPagination(event)
|
|
||||||
{
|
|
||||||
let response = await fetch(`http://localhost:8001/tiktok/events/pages?eventName=${event}`);
|
|
||||||
let json = await response.text();
|
|
||||||
let object = JSON.parse(json);
|
|
||||||
let pages = object.links;
|
|
||||||
console.log("PAGES: ",pages)
|
|
||||||
$("#pages").empty();
|
|
||||||
$.each(pages, function(index, element) {
|
|
||||||
let content = $('<button>',{
|
|
||||||
class: 'btn btn-primary',
|
|
||||||
text: index
|
|
||||||
}).click(async function()
|
|
||||||
{
|
|
||||||
await loadMessageLink(element);
|
|
||||||
console.log(editor)
|
|
||||||
});
|
|
||||||
$("#pages").append(content);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showEvents() {
|
|
||||||
let response = await fetch(`http://localhost:8001/tiktok/events`);
|
|
||||||
let json = await response.text();
|
|
||||||
console.log("events:",json);
|
|
||||||
let events= JSON.parse(json);
|
|
||||||
|
|
||||||
$("#eventList").empty();
|
|
||||||
$.each(events, function(index, event) {
|
|
||||||
let listItem = $('<li>', {
|
|
||||||
class: 'list-group-item',
|
|
||||||
text: event
|
|
||||||
}).click(async function()
|
|
||||||
{
|
|
||||||
await loadMessage(event);
|
|
||||||
await loadPagination(event);
|
|
||||||
});
|
|
||||||
$("#eventList").append(listItem);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loop()
|
|
||||||
{
|
|
||||||
if(!connected)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("updating");
|
|
||||||
await showEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
var connected = false;
|
|
||||||
var paginationIndex = 0;
|
|
||||||
var maxPages = 10;
|
|
||||||
var pages = [];
|
|
||||||
setInterval(loop, 1000)
|
|
||||||
showEvents()
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.3/dist/umd/popper.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.3/dist/umd/popper.min.js"></script>
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||||
|
|||||||
210
Tools-EventsWebViewer/src/main/resources/public/index.js
Normal file
210
Tools-EventsWebViewer/src/main/resources/public/index.js
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
var dataType = "messages"
|
||||||
|
var connected = false;
|
||||||
|
var paginationIndex = 0;
|
||||||
|
var maxPages = 10;
|
||||||
|
var pages = [];
|
||||||
|
var userName = "";
|
||||||
|
|
||||||
|
var port = 8002;
|
||||||
|
var baseUrl = `http://localhost:${port}`
|
||||||
|
|
||||||
|
var data =
|
||||||
|
{
|
||||||
|
dataType: "event",
|
||||||
|
dataName: "",
|
||||||
|
user: "",
|
||||||
|
sessionTag: "",
|
||||||
|
page: 0,
|
||||||
|
|
||||||
|
collector:
|
||||||
|
{
|
||||||
|
connected: false,
|
||||||
|
user: "",
|
||||||
|
sessionTag: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
dropDown("usersDropDown", () => `${baseUrl}/tiktok/users`, async (e) => {
|
||||||
|
data.user = e;
|
||||||
|
update();
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
dropDown("dataTypeDropDown", () => `${baseUrl}/tiktok/data-types`, async (e) => {
|
||||||
|
data.dataType = e;
|
||||||
|
update();
|
||||||
|
})
|
||||||
|
|
||||||
|
dropDown("sessionTagDropDown", () => `${baseUrl}/tiktok/sessions?user=${data.user}`, async (e) => {
|
||||||
|
data.sessionTag = e;
|
||||||
|
update();
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
new Promise(async function (resolve, reject) {
|
||||||
|
await updateAsync();
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateAsync() {
|
||||||
|
console.log(data);
|
||||||
|
await updateConnectionButton()
|
||||||
|
await updateDataNamesList(async (dataName) => {
|
||||||
|
data.dataName = dataName;
|
||||||
|
data.page = 0;
|
||||||
|
await updateContent();
|
||||||
|
await updatePagination(async (page, link) => {
|
||||||
|
data.page = page;
|
||||||
|
let response = await fetch(link);
|
||||||
|
let json = await response.text();
|
||||||
|
console.log(link)
|
||||||
|
let root = JSON.parse(json);
|
||||||
|
editor.setValue(root.content);
|
||||||
|
|
||||||
|
if(data.dataType === 'message')
|
||||||
|
{
|
||||||
|
console.log("sending proto version")
|
||||||
|
let response2 = await fetch(`${link}&asProto=true`);
|
||||||
|
let json2 = await response2.text();
|
||||||
|
let root2 = JSON.parse(json2);
|
||||||
|
editor2.setValue(root2.content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
await fetch(`${baseUrl}/tiktok/update?user=${data.user}&session=${data.sessionTag}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updatePagination(onSelect) {
|
||||||
|
let response = await fetch(`${baseUrl}/tiktok/data/pages?name=${data.dataName}&type=${data.dataType}`);
|
||||||
|
let json = await response.text();
|
||||||
|
let object = JSON.parse(json);
|
||||||
|
let pages = object.links;
|
||||||
|
$("#pages").empty();
|
||||||
|
let page = 0;
|
||||||
|
$.each(pages, function (index, element) {
|
||||||
|
|
||||||
|
let currentPage = page;
|
||||||
|
page++;
|
||||||
|
let content = $('<button>', {
|
||||||
|
class: 'btn btn-primary margin-left',
|
||||||
|
text: index
|
||||||
|
}).click(async function () {
|
||||||
|
|
||||||
|
await onSelect(currentPage, element);
|
||||||
|
});
|
||||||
|
$("#pages").append(content);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateContent() {
|
||||||
|
console.log("updating content", data)
|
||||||
|
let response = await fetch(`${baseUrl}/tiktok/data?name=${data.dataName}&type=${data.dataType}&page=${data.page}`);
|
||||||
|
let json = await response.text();
|
||||||
|
let root = JSON.parse(json);
|
||||||
|
editor.setValue(root.content);
|
||||||
|
|
||||||
|
|
||||||
|
if(data.dataType === 'message')
|
||||||
|
{
|
||||||
|
console.log("sending proto version")
|
||||||
|
let response2 = await fetch(`${baseUrl}/tiktok/data?name=${data.dataName}&type=${data.dataType}&page=${data.page}&asProto=true`);
|
||||||
|
let json2 = await response2.text();
|
||||||
|
let root2 = JSON.parse(json2);
|
||||||
|
editor2.setValue(root2.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateDataNamesList(onSelect) {
|
||||||
|
let response = await fetch(`${baseUrl}/tiktok/data/names?type=${data.dataType}`);
|
||||||
|
let json = await response.text();
|
||||||
|
let responce = JSON.parse(json);
|
||||||
|
let element = $("#dataList");
|
||||||
|
console.log(responce)
|
||||||
|
element.empty();
|
||||||
|
$.each(responce, function (index, dataName) {
|
||||||
|
let listItem = $('<li>', {
|
||||||
|
class: 'list-group-item',
|
||||||
|
text: dataName
|
||||||
|
}).click(async function () {
|
||||||
|
onSelect(dataName)
|
||||||
|
});
|
||||||
|
element.append(listItem);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function dropDown(elementId, onUrl, onSelect) {
|
||||||
|
let dropDown = $("#" + elementId);
|
||||||
|
dropDown.on('show.bs.dropdown', async function (e, b) {
|
||||||
|
let response = await fetch(onUrl());
|
||||||
|
let json = await response.text();
|
||||||
|
let values = JSON.parse(json);
|
||||||
|
let optionsElement = dropDown.find("div")
|
||||||
|
optionsElement.empty();
|
||||||
|
let displayElement = dropDown.find("button")
|
||||||
|
for (let value of values) {
|
||||||
|
let dropDownItem = $('<p>', {
|
||||||
|
class: 'dropdown-item',
|
||||||
|
text: value
|
||||||
|
}).click(async function () {
|
||||||
|
displayElement.text(value)
|
||||||
|
onSelect(value)
|
||||||
|
});
|
||||||
|
optionsElement.append(dropDownItem)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
new Promise(async (a, b) => {
|
||||||
|
await updateConnectionButton()
|
||||||
|
});
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
|
|
||||||
|
$("#connectionButton").on('click', async (a) => {
|
||||||
|
|
||||||
|
if (!data.collector.connected) {
|
||||||
|
console.log("connecting")
|
||||||
|
await connect()
|
||||||
|
} else {
|
||||||
|
console.log("disconnecting")
|
||||||
|
await disconnect()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function updateConnectionButton() {
|
||||||
|
let button = $("#connectionButton");
|
||||||
|
let response = await fetch(`${baseUrl}/tiktok/status`);
|
||||||
|
let json = await response.text();
|
||||||
|
let values = JSON.parse(json);
|
||||||
|
console.log(values)
|
||||||
|
data.collector.connected = values;
|
||||||
|
if (data.collector.connected) {
|
||||||
|
button.text("disconnect");
|
||||||
|
} else {
|
||||||
|
button.text("connect");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function connect() {
|
||||||
|
let name = document.getElementById('name').value;
|
||||||
|
let session = document.getElementById('sessionTag').value;
|
||||||
|
data.collector.name = name
|
||||||
|
data.collector.sessionTag =session
|
||||||
|
|
||||||
|
let response = await fetch(`${baseUrl}/tiktok/connect?name=${data.collector.name}&session=${data.collector.sessionTag}`);
|
||||||
|
let greeting = await response.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function disconnect() {
|
||||||
|
let response = await fetch(`${baseUrl}/tiktok/disconnect`);
|
||||||
|
let greeting = await response.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
update()
|
||||||
@@ -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.0.7-Release</version>
|
<version>1.0.9-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -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.0.7-Release</version>
|
<version>1.0.9-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import com.google.gson.JsonArray;
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import io.github.jwdeveloper.tiktok.Constants;
|
import io.github.jwdeveloper.tiktok.Constants;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||||
@@ -78,7 +79,7 @@ public class GiftOfficialJson {
|
|||||||
|
|
||||||
public static JsonArray getJsonGifts() {
|
public static JsonArray getJsonGifts() {
|
||||||
var jar = new TikTokCookieJar();
|
var jar = new TikTokCookieJar();
|
||||||
var tiktokHttpClient = new TikTokHttpClient(jar, new TikTokHttpRequestFactory(jar));
|
var tiktokHttpClient = new TikTokHttpClient(jar, new TikTokHttpRequestFactory(jar, new TikTokEventObserver()));
|
||||||
var settings = Constants.DefaultClientSettings();
|
var settings = Constants.DefaultClientSettings();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user