mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-27 08:49:40 -05:00
Compare commits
8 Commits
1.0.9-Rele
...
1.0.10-Rel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fee805f0ea | ||
|
|
1733102aff | ||
|
|
89f54d5976 | ||
|
|
39055b5f3a | ||
|
|
cd9e9ead85 | ||
|
|
5a2d2d23f0 | ||
|
|
3eed982d6b | ||
|
|
385560de3a |
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>1.0.8-Release</version>
|
||||
<version>1.0.9-Release</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>API</artifactId>
|
||||
|
||||
@@ -56,7 +56,7 @@ public class ClientSettings {
|
||||
* Whether to print Logs to Console
|
||||
*/
|
||||
|
||||
private boolean printToConsole;
|
||||
private boolean printToConsole = true;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TikTokEventHandler
|
||||
public @interface TikTokEventObserver
|
||||
{
|
||||
|
||||
}
|
||||
@@ -47,11 +47,11 @@ public class TikTokCommentEvent extends TikTokHeaderEvent {
|
||||
|
||||
public TikTokCommentEvent(WebcastChatMessage msg) {
|
||||
super(msg.getCommon());
|
||||
user = User.map(msg.getUser());
|
||||
user = User.map(msg.getUser(),msg.getUserIdentity());
|
||||
text = msg.getContent();
|
||||
visibleToSender = msg.getVisibleToSender();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,17 +26,20 @@ package io.github.jwdeveloper.tiktok.data.events.gift;
|
||||
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
|
||||
import io.github.jwdeveloper.tiktok.annotations.EventType;
|
||||
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.GiftSendType;
|
||||
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
/**
|
||||
* Triggered when user sends gifts that has
|
||||
* no combo (most of expensive gifts)
|
||||
* or if combo has finished
|
||||
* no combo (most of expensive gifts)
|
||||
* or if combo has finished
|
||||
*/
|
||||
@EventMeta(eventType = EventType.Message)
|
||||
@Getter
|
||||
@@ -45,11 +48,12 @@ public class TikTokGiftEvent extends TikTokHeaderEvent {
|
||||
private final User user;
|
||||
private final User toUser;
|
||||
private final int combo;
|
||||
|
||||
public TikTokGiftEvent(Gift gift, WebcastGiftMessage msg) {
|
||||
super(msg.getCommon());
|
||||
this.gift = gift;
|
||||
user = User.map(msg.getUser(), msg.getUserIdentity());
|
||||
toUser = User.map(msg.getToUser());
|
||||
toUser = new User(msg.getUserGiftReciever().getUserId(), "", "", new Picture(""), 0, 0, new ArrayList<>());
|
||||
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;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
|
||||
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
|
||||
|
||||
@@ -55,6 +56,11 @@ public interface LiveClient {
|
||||
void disconnect();
|
||||
|
||||
|
||||
/**
|
||||
* You to manually trigger event
|
||||
*/
|
||||
void publishEvent(TikTokEvent event);
|
||||
|
||||
/**
|
||||
* 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.gift.TikTokGiftComboEvent;
|
||||
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.social.TikTokFollowEvent;
|
||||
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> {
|
||||
|
||||
/**
|
||||
* Method used to register own custom events
|
||||
* @param eventClazz event class
|
||||
* @param event action
|
||||
* Invoked whenever specified event is triggered
|
||||
*
|
||||
* @param eventClass event class
|
||||
* @param action action
|
||||
*/
|
||||
<E extends TikTokEvent> T onCustomEvent(Class<E> eventClazz, EventConsumer<E> event);
|
||||
|
||||
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);
|
||||
<E extends TikTokEvent> T onEvent(Class<E> eventClass, EventConsumer<E> action);
|
||||
|
||||
|
||||
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
|
||||
// T onChest(EventConsumer<TikTokChestEvent> event);
|
||||
|
||||
//T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);
|
||||
|
||||
//T onEnvelope(TikTokEventConsumer<TikTokEnvelopeEvent> event);
|
||||
|
||||
@@ -24,72 +24,32 @@ package io.github.jwdeveloper.tiktok.mappers;
|
||||
|
||||
import com.google.protobuf.GeneratedMessageV3;
|
||||
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;
|
||||
|
||||
public interface TikTokMapper {
|
||||
|
||||
|
||||
/**
|
||||
* Triggered when `sourceClass` is mapped,
|
||||
* 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);
|
||||
* })
|
||||
* * if mapper is not found for messageName, TikTokLiveException is thrown
|
||||
*
|
||||
* @param sourceClass protocol buffer webcast class
|
||||
* @param onMapping lambda function that is triggered on mapping. takes as input ProtocolBuffer object and as output TikTokEvent
|
||||
* @param messageName
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName, MappingAction<MappingResult> onMapping);
|
||||
|
||||
void bytesToEvents(String messageName, Function<byte[], List<TikTokEvent>> onMapping);
|
||||
TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName, Function<byte[], TikTokEvent> onMapping);
|
||||
|
||||
boolean isRegistered(String 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> boolean isRegistered(Class<T> mapperName);
|
||||
|
||||
<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;
|
||||
oneof textPieceType
|
||||
{
|
||||
TextPieceUser userValue = 21;
|
||||
TextPieceGift giftValue = 22;
|
||||
TextPieceUser userValue = 21;
|
||||
TextPieceGift giftValue = 22;
|
||||
}
|
||||
TextPiecePatternRef patternRefValue = 24;
|
||||
}
|
||||
@@ -155,7 +155,7 @@ message BadgeStruct {
|
||||
|
||||
message ProfileCardPanel {
|
||||
bool useNewProfileCardStyle = 1;
|
||||
// BadgeTextPosition badgeTextPosition = 2; // Enum
|
||||
// BadgeTextPosition badgeTextPosition = 2; // Enum
|
||||
ProjectionConfig projectionConfig = 3;
|
||||
ProfileContent profileContent = 4;
|
||||
}
|
||||
@@ -1000,8 +1000,8 @@ message LinkerCreateContent {
|
||||
|
||||
message LinkerEnterContent {
|
||||
repeated User LinkedUsersList = 1;
|
||||
// LinkmicMultiLiveEnum AnchorMultiLiveEnum = 2;
|
||||
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 3;
|
||||
// LinkmicMultiLiveEnum AnchorMultiLiveEnum = 2;
|
||||
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 3;
|
||||
}
|
||||
|
||||
message LinkerInviteContent {
|
||||
@@ -1018,15 +1018,15 @@ message LinkerInviteContent {
|
||||
//Data.LinkmicMultiLiveEnum AnchorMultiLiveEnum = 11;
|
||||
//Data.LinkmicUserSettingInfo AnchorSettingInfo = 12;
|
||||
string InviterLinkmicIdStr = 13;
|
||||
// InviteTopHostInfo FromTopHostInfo = 16;
|
||||
// InviteTopHostInfo FromTopHostInfo = 16;
|
||||
int64 ActionId = 17;
|
||||
// repeated LinkmicUserInfo LinkedUsersList = 18;
|
||||
// Data.PerceptionDialogInfo Dialog = 19;
|
||||
// Data.PunishEventInfo PunishInfo = 20;
|
||||
// repeated LinkmicUserInfo LinkedUsersList = 18;
|
||||
// Data.PerceptionDialogInfo Dialog = 19;
|
||||
// Data.PunishEventInfo PunishInfo = 20;
|
||||
int32 FromRoomAgeRestricted = 21;
|
||||
// Data.Tag FromTag = 22;
|
||||
// repeated Data.CohostABTestSetting AbTestSettingList = 23;
|
||||
// Data.LinkerInviteMessageExtra LinkerInviteMsgExtra = 101;
|
||||
// Data.Tag FromTag = 22;
|
||||
// repeated Data.CohostABTestSetting AbTestSettingList = 23;
|
||||
// Data.LinkerInviteMessageExtra LinkerInviteMsgExtra = 101;
|
||||
}
|
||||
|
||||
message LinkerKickOutContent {
|
||||
@@ -1046,17 +1046,17 @@ message LinkerLinkedListChangeContent {
|
||||
}
|
||||
|
||||
message LinkerListChangeContent {
|
||||
repeated User LinkedUsersList = 1;
|
||||
repeated User AppliedUsersList = 2;
|
||||
repeated User ConnectingUsersList = 3;
|
||||
repeated LinkLayerListUser LinkedUsersList = 1;
|
||||
repeated LinkLayerListUser AppliedUsersList = 2;
|
||||
repeated LinkLayerListUser ConnectingUsersList = 3;
|
||||
}
|
||||
|
||||
message LinkerMediaChangeContent {
|
||||
// MicIdxOperation Op = 1;
|
||||
// MicIdxOperation Op = 1;
|
||||
int64 ToUserId = 2;
|
||||
int64 AnchorId = 3;
|
||||
int64 RoomId = 4;
|
||||
// LinkerSceneType ChangeScene = 5;
|
||||
// LinkerSceneType ChangeScene = 5;
|
||||
}
|
||||
|
||||
message LinkerMicIdxUpdateContent {
|
||||
@@ -1064,14 +1064,14 @@ message LinkerMicIdxUpdateContent {
|
||||
}
|
||||
|
||||
message LinkerMicIdxUpdateInfo {
|
||||
// MicIdxOperation Op = 1;
|
||||
// MicIdxOperation Op = 1;
|
||||
int64 UserId = 2;
|
||||
int64 MicIdx = 3;
|
||||
}
|
||||
|
||||
message LinkerMuteContent {
|
||||
int64 UserId = 1;
|
||||
// Data.MuteStatus Status = 2;
|
||||
// Data.MuteStatus Status = 2;
|
||||
}
|
||||
|
||||
message LinkerRandomMatchContent {
|
||||
@@ -1085,9 +1085,9 @@ message LinkerRandomMatchContent {
|
||||
message LinkerReplyContent {
|
||||
int64 FromUserId = 1;
|
||||
int64 FromRoomId = 2;
|
||||
// LinkmicInfo FromUserLinkmicInfo = 3;
|
||||
// LinkmicInfo FromUserLinkmicInfo = 3;
|
||||
int64 ToUserId = 4;
|
||||
// LinkmicInfo ToUserLinkmicInfo = 5;
|
||||
// LinkmicInfo ToUserLinkmicInfo = 5;
|
||||
int64 LinkType = 6;
|
||||
int64 ReplyStatus = 7;
|
||||
LinkerSetting LinkerSetting = 8;
|
||||
@@ -1096,10 +1096,10 @@ message LinkerReplyContent {
|
||||
map<int64, string> RtcExtInfoMap = 11;
|
||||
LinkerMicIdxUpdateInfo InviteeMicIdxUpdateInfo = 12;
|
||||
map<int64, int64> ApplierMicIdxInfoMap = 13;
|
||||
// Data.LinkmicMultiLiveEnum AnchorMultiLiveEnum = 14;
|
||||
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 15;
|
||||
// Data.LinkmicMultiLiveEnum AnchorMultiLiveEnum = 14;
|
||||
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 15;
|
||||
int64 ActionId = 16;
|
||||
// repeated LinkmicUserInfo LinkedUsersList = 17;
|
||||
// repeated LinkmicUserInfo LinkedUsersList = 17;
|
||||
int64 SourceType = 18;
|
||||
}
|
||||
|
||||
@@ -1124,7 +1124,7 @@ message LinkerUpdateUserContent {
|
||||
}
|
||||
|
||||
message LinkerUpdateUserSettingContent {
|
||||
// Data.LinkmicUserSettingInfo UpdateUserSettingInfo = 1;
|
||||
// Data.LinkmicUserSettingInfo UpdateUserSettingInfo = 1;
|
||||
}
|
||||
|
||||
message LinkerWaitingListChangeContent {
|
||||
@@ -1156,10 +1156,11 @@ message AllListUser {
|
||||
|
||||
message LinkLayerListUser {
|
||||
User user = 1;
|
||||
string linkmicId = 2;
|
||||
int64 linkmicId = 2;
|
||||
Position pos = 3;
|
||||
int64 linkedTimeNano = 4;
|
||||
string appVersion = 5;
|
||||
int64 magicNumber1 = 7;
|
||||
}
|
||||
|
||||
message Position {
|
||||
|
||||
@@ -68,7 +68,6 @@ message WebcastGiftMessage {
|
||||
int32 repeatCount = 5;
|
||||
int32 comboCount = 6;
|
||||
User user = 7;
|
||||
User toUser = 8;
|
||||
int32 repeatEnd = 9;
|
||||
int64 groupId = 11;
|
||||
int64 incomeTaskgifts = 12;
|
||||
@@ -81,6 +80,13 @@ message WebcastGiftMessage {
|
||||
bool isFirstSent = 25;
|
||||
string orderId = 28;
|
||||
UserIdentity userIdentity = 32;
|
||||
UserGiftReciever userGiftReciever = 23;
|
||||
|
||||
message UserGiftReciever
|
||||
{
|
||||
int64 userId =1;
|
||||
string deviceName = 10;
|
||||
}
|
||||
|
||||
message GiftIMPriority {
|
||||
repeated int64 queueSizesList = 1;
|
||||
@@ -507,6 +513,9 @@ message WebcastHourlyRankMessage {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//<Battles>
|
||||
|
||||
//@WebcastLinkMicArmies
|
||||
message WebcastLinkMicArmies {
|
||||
Common common = 1;
|
||||
@@ -523,6 +532,45 @@ message WebcastLinkMicArmies {
|
||||
uint32 data4 = 12;
|
||||
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
|
||||
message WebcastLinkMicBattle {
|
||||
@@ -572,7 +620,6 @@ message WebcastLinkMicFanTicketMethod {
|
||||
Common common = 1;
|
||||
FanTicketRoomNoticeContent FanTicketRoomNotice = 2;
|
||||
}
|
||||
|
||||
//@WebcastLinkMicMethod
|
||||
message WebcastLinkMicMethod {
|
||||
Common common = 1;
|
||||
@@ -590,6 +637,8 @@ message WebcastLinkMicMethod {
|
||||
int64 inviteUid = 13;
|
||||
}
|
||||
|
||||
//<Battles>
|
||||
|
||||
//@WebcastLiveIntroMessage
|
||||
message WebcastLiveIntroMessage {
|
||||
Common common = 1;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>1.0.8-Release</version>
|
||||
<version>1.0.9-Release</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -87,4 +87,5 @@ public class TikTokLive
|
||||
{
|
||||
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.TikTokErrorEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
|
||||
@@ -189,4 +190,8 @@ public class TikTokLiveClient implements LiveClient {
|
||||
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.gift.TikTokGiftComboEvent;
|
||||
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.room.TikTokRoomInfoEvent;
|
||||
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.handlers.TikTokEventObserver;
|
||||
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.TikTokCookieJar;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
|
||||
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.builder.EventConsumer;
|
||||
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||
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.utils.ConsoleColors;
|
||||
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
|
||||
@@ -88,12 +91,12 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings) {
|
||||
this.onCustomMappings = onCustomMappings;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> onConfigure) {
|
||||
onConfigure.accept(clientSettings);
|
||||
return this;
|
||||
@@ -159,7 +162,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||
|
||||
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
|
||||
var cookieJar = new TikTokCookieJar();
|
||||
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
|
||||
var requestFactory = new TikTokHttpRequestFactory(cookieJar, tikTokEventHandler);
|
||||
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
|
||||
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
|
||||
var giftManager = new TikTokGiftManager(logger);
|
||||
@@ -167,7 +170,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||
var messageHandler = new TikTokMessageHandler(tikTokEventHandler, eventsMapper);
|
||||
|
||||
|
||||
var webSocketClient = new TikTokWebSocketClient(logger,
|
||||
var webSocketClient = new TikTokWebSocketClient(
|
||||
cookieJar,
|
||||
clientSettings,
|
||||
messageHandler,
|
||||
@@ -185,7 +188,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||
|
||||
public TikTokLiveMapper createMapper(GiftManager giftManager, TikTokRoomInfo roomInfo) {
|
||||
var eventMapper = new TikTokGenericEventMapper();
|
||||
var mapper = new TikTokLiveMapper(eventMapper);
|
||||
var mapper = new TikTokLiveMapper(new TikTokLiveMapperHelper(eventMapper));
|
||||
|
||||
//ConnectionEvents events
|
||||
var commonHandler = new TikTokCommonEventHandler();
|
||||
@@ -193,48 +196,77 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||
var roomInfoHandler = new TikTokRoomInfoEventHandler(roomInfo);
|
||||
var socialHandler = new TikTokSocialMediaEventHandler(roomInfo);
|
||||
|
||||
mapper.bytesToEvent(WebcastControlMessage.class, commonHandler::handleWebcastControlMessage);
|
||||
|
||||
mapper.forMessage(WebcastControlMessage.class, commonHandler::handleWebcastControlMessage);
|
||||
|
||||
//Room status events
|
||||
mapper.bytesToEvent(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
|
||||
mapper.bytesToEvent(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
|
||||
mapper.forMessage(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
|
||||
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
|
||||
mapper.webcastObjectToConstructor(WebcastChatMessage.class, TikTokCommentEvent.class);
|
||||
mapper.bytesToEvents(WebcastLikeMessage.class, roomInfoHandler::handleLike);
|
||||
mapper.bytesToEvents(WebcastGiftMessage.class, giftHandler::handleGift);
|
||||
mapper.bytesToEvent(WebcastSocialMessage.class, socialHandler::handle);
|
||||
mapper.bytesToEvents(WebcastMemberMessage.class, roomInfoHandler::handleMemberMessage);
|
||||
mapper.forMessage(WebcastChatMessage.class, (inputBytes, messageName, mapperHelper) ->
|
||||
{
|
||||
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
|
||||
return MappingResult.of(messageObject, new TikTokCommentEvent(messageObject));
|
||||
});
|
||||
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
|
||||
mapper.bytesToEvent(WebcastPollMessage.class, commonHandler::handlePollEvent);
|
||||
mapper.bytesToEvent(WebcastRoomPinMessage.class, commonHandler::handlePinMessage);
|
||||
mapper.webcastObjectToConstructor(WebcastGoalUpdateMessage.class, TikTokGoalUpdateEvent.class);
|
||||
mapper.forMessage(WebcastPollMessage.class, commonHandler::handlePollEvent);
|
||||
mapper.forMessage(WebcastRoomPinMessage.class, commonHandler::handlePinMessage);
|
||||
mapper.forMessage(WebcastChatMessage.class, (inputBytes, messageName, mapperHelper) ->
|
||||
{
|
||||
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
|
||||
return MappingResult.of(messageObject, new TikTokCommentEvent(messageObject));
|
||||
});
|
||||
|
||||
|
||||
//LinkMic events
|
||||
mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
|
||||
|
||||
//Rank events
|
||||
mapper.webcastObjectToConstructor(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
|
||||
|
||||
//Others events
|
||||
mapper.webcastObjectToConstructor(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastQuestionNewMessage.class, TikTokQuestionEvent.class);
|
||||
mapper.bytesToEvents(WebcastEnvelopeMessage.class, commonHandler::handleEnvelop);
|
||||
mapper.webcastObjectToConstructor(WebcastSubNotifyMessage.class, TikTokSubscribeEvent.class);
|
||||
mapper.webcastObjectToConstructor(WebcastEmoteChatMessage.class, TikTokEmoteEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
|
||||
// mapper.webcastObjectToConstructor(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
|
||||
// mapper.bytesToEvents(WebcastEnvelopeMessage.class, commonHandler::handleEnvelop);
|
||||
|
||||
|
||||
onCustomMappings.accept(mapper);
|
||||
return mapper;
|
||||
@@ -315,8 +347,8 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends TikTokEvent> LiveClientBuilder onCustomEvent(Class<E> eventClazz, EventConsumer<E> event) {
|
||||
tikTokEventHandler.subscribe(eventClazz, event);
|
||||
public <E extends TikTokEvent> LiveClientBuilder onEvent(Class<E> eventClass, EventConsumer<E> event) {
|
||||
tikTokEventHandler.subscribe(eventClass, event);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -416,6 +448,12 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveClientBuilder onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action) {
|
||||
tikTokEventHandler.subscribe(TikTokHttpResponseEvent.class, action);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TikTokLiveClientBuilder onGoalUpdate(EventConsumer<TikTokGoalUpdateEvent> event) {
|
||||
tikTokEventHandler.subscribe(TikTokGoalUpdateEvent.class, event);
|
||||
return this;
|
||||
|
||||
@@ -62,7 +62,7 @@ public class TikTokRoomInfo implements LiveRoomInfo {
|
||||
|
||||
@Override
|
||||
public User getHostUser() {
|
||||
return null;
|
||||
return host;
|
||||
}
|
||||
|
||||
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.data.dto.TikTokUserInfo;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.Logger;
|
||||
@@ -54,7 +55,7 @@ public class TikTokDataChecker {
|
||||
|
||||
public TikTokApiService getApiService() {
|
||||
var jar = new TikTokCookieJar();
|
||||
var factory = new TikTokHttpRequestFactory(jar);
|
||||
var factory = new TikTokHttpRequestFactory(jar,new TikTokEventObserver());
|
||||
var client = new TikTokHttpClient(jar, factory);
|
||||
var settings = new ClientSettings();
|
||||
settings.setClientParameters(Constants.DefaultClientParams());
|
||||
|
||||
@@ -91,7 +91,6 @@ public class TikTokHttpClient {
|
||||
if (parameters == null) {
|
||||
parameters = new HashMap<>();
|
||||
}
|
||||
System.out.println("RomMID: "+parameters.get("room_id"));
|
||||
var request = requestFactory.setQueries(parameters);
|
||||
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.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.handlers.TikTokEventObserver;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.net.CookieManager;
|
||||
@@ -45,26 +48,27 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
private final Map<String, String> defaultHeaders;
|
||||
private final TikTokCookieJar tikTokCookieJar;
|
||||
private final HttpClient client;
|
||||
private final TikTokEventObserver eventHandler;
|
||||
private String query;
|
||||
|
||||
public TikTokHttpRequestFactory(TikTokCookieJar tikTokCookieJar) {
|
||||
public TikTokHttpRequestFactory(TikTokCookieJar tikTokCookieJar, TikTokEventObserver eventHandler) {
|
||||
this.tikTokCookieJar = tikTokCookieJar;
|
||||
this.cookieManager = new CookieManager();
|
||||
this.eventHandler = eventHandler;
|
||||
defaultHeaders = Constants.DefaultRequestHeaders();
|
||||
client = HttpClient.newBuilder()
|
||||
.cookieHandler(cookieManager)
|
||||
.connectTimeout(Duration.ofSeconds(2))
|
||||
.build();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public String get(String url) {
|
||||
var uri = URI.create(url);
|
||||
var requestBuilder = HttpRequest.newBuilder().GET();
|
||||
|
||||
for (var header : defaultHeaders.entrySet())
|
||||
{
|
||||
if(header.getKey().equals("Connection") || header.getKey().equals("Accept-Encoding"))
|
||||
{
|
||||
for (var header : defaultHeaders.entrySet()) {
|
||||
if (header.getKey().equals("Connection") || header.getKey().equals("Accept-Encoding")) {
|
||||
continue;
|
||||
}
|
||||
requestBuilder.setHeader(header.getKey(), header.getValue());
|
||||
@@ -73,9 +77,7 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
var baseUri = uri.toString();
|
||||
var requestUri = URI.create(baseUri + "?" + query);
|
||||
requestBuilder.uri(requestUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
requestBuilder.uri(uri);
|
||||
}
|
||||
|
||||
@@ -88,15 +90,13 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
public String post(String url) {
|
||||
var uri = URI.create(url);
|
||||
var request = HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(""));
|
||||
for (var header : defaultHeaders.entrySet())
|
||||
{
|
||||
if(header.getKey().equals("Connection"))
|
||||
{
|
||||
for (var header : defaultHeaders.entrySet()) {
|
||||
if (header.getKey().equals("Connection")) {
|
||||
continue;
|
||||
}
|
||||
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());
|
||||
|
||||
|
||||
@@ -104,11 +104,8 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
var baseUri = uri.toString();
|
||||
var requestUri = URI.create(baseUri + "?" + query);
|
||||
request.uri(requestUri);
|
||||
System.out.println(requestUri.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
return getContent(request.build());
|
||||
}
|
||||
|
||||
@@ -125,7 +122,7 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
public TikTokHttpRequest setQueries(Map<String, Object> queries) {
|
||||
if (queries == null)
|
||||
return this;
|
||||
var testMap = new TreeMap<String,Object>(queries);
|
||||
var testMap = new TreeMap<String, Object>(queries);
|
||||
query = String.join("&", testMap.entrySet().stream().map(x ->
|
||||
{
|
||||
var key = x.getKey();
|
||||
@@ -143,6 +140,9 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
|
||||
private String getContent(HttpRequest request) throws Exception {
|
||||
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) {
|
||||
throw new TikTokLiveRequestException("Request responded with 404 NOT_FOUND");
|
||||
}
|
||||
@@ -155,8 +155,6 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
for (var cookie : cookies) {
|
||||
var split = cookie.split(";")[0].split("=");
|
||||
var uri = request.uri();
|
||||
|
||||
|
||||
var key = split[0];
|
||||
var value = split[1];
|
||||
tikTokCookieJar.set(key, value);
|
||||
|
||||
@@ -23,11 +23,10 @@
|
||||
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.exceptions.TikTokEventListenerMethodException;
|
||||
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.builder.EventConsumer;
|
||||
|
||||
@@ -37,10 +36,10 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class TikTokListenersManager implements ListenersManager {
|
||||
private final TikTokEventObserver eventObserver;
|
||||
private final io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver eventObserver;
|
||||
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.bindingModels = new ArrayList<>(listeners.size());
|
||||
for (var listener : listeners) {
|
||||
@@ -93,7 +92,7 @@ public class TikTokListenersManager implements ListenersManager {
|
||||
var clazz = listener.getClass();
|
||||
var methods = Arrays.stream(clazz.getDeclaredMethods()).filter(m ->
|
||||
m.getParameterCount() == 2 &&
|
||||
m.isAnnotationPresent(TikTokEventHandler.class)).toList();
|
||||
m.isAnnotationPresent(TikTokEventObserver.class)).toList();
|
||||
var eventsMap = new HashMap<Class<?>, List<EventConsumer<?>>>();
|
||||
for (var method : methods) {
|
||||
var eventClazz = method.getParameterTypes()[1];
|
||||
|
||||
@@ -24,7 +24,8 @@ package io.github.jwdeveloper.tiktok.mappers;
|
||||
|
||||
import com.google.protobuf.GeneratedMessageV3;
|
||||
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.List;
|
||||
@@ -32,79 +33,68 @@ import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
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.genericMapper = genericMapper;
|
||||
this.mapperUtils = mapperUtils;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bytesToEvent(String messageName, Function<byte[], TikTokEvent> onMapping) {
|
||||
mappers.put(messageName, messagePayload -> List.of(onMapping.apply(messagePayload)));
|
||||
public TikTokMapperModel forMessage(String messageName) {
|
||||
if (!isRegistered(messageName)) {
|
||||
var model = new TikTokLiveMapperModel(messageName);
|
||||
mappers.put(messageName, model);
|
||||
}
|
||||
return mappers.get(messageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bytesToEvents(String messageName, Function<byte[], List<TikTokEvent>> onMapping) {
|
||||
mappers.put(messageName, onMapping::apply);
|
||||
}
|
||||
|
||||
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);
|
||||
public TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName) {
|
||||
return forMessage(mapperName.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void webcastObjectToConstructor(Class<? extends GeneratedMessageV3> sourceClass, Class<? extends TikTokEvent> outputClass) {
|
||||
bytesToEvent(sourceClass, (e) -> genericMapper.mapToEvent(sourceClass, outputClass, e));
|
||||
public TikTokMapperModel forMessage(String mapperName, MappingAction<MappingResult> onMapping) {
|
||||
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
|
||||
public <T extends GeneratedMessageV3> void webcastObjectToEvent(Class<T> source, Function<T, TikTokEvent> onMapping) {
|
||||
bytesToEvent(source, (bytes) ->
|
||||
{
|
||||
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 TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName, Function<byte[], TikTokEvent> onMapping) {
|
||||
return forMessage(mapperName, (inputBytes, messageName, mapperHelper) -> MappingResult.of(inputBytes, onMapping.apply(inputBytes)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends GeneratedMessageV3> void webcastObjectToEvents(Class<T> source, Function<T, List<TikTokEvent>> onMapping) {
|
||||
bytesToEvents(source, (bytes) ->
|
||||
{
|
||||
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 mapperName) {
|
||||
return mappers.containsKey(mapperName);
|
||||
}
|
||||
|
||||
public boolean isRegistered(String input) {
|
||||
return mappers.containsKey(input);
|
||||
public <T extends GeneratedMessageV3> boolean isRegistered(Class<T> mapperName) {
|
||||
return mappers.containsKey(mapperName.getSimpleName());
|
||||
}
|
||||
|
||||
public List<TikTokEvent> handleMapping(String input, byte[] bytes) {
|
||||
if (!isRegistered(input)) {
|
||||
public List<TikTokEvent> handleMapping(String messageName, byte[] bytes) {
|
||||
if (!isRegistered(messageName)) {
|
||||
return List.of();
|
||||
}
|
||||
var mapper = mappers.get(input);
|
||||
var events = mapper.apply(bytes);
|
||||
return events;
|
||||
var mapperModel = mappers.get(messageName);
|
||||
|
||||
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
|
||||
* 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 {
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
* 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.mappers.events;
|
||||
package io.github.jwdeveloper.tiktok.mappers.handlers;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||
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
|
||||
* 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.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.exceptions.TikTokLiveException;
|
||||
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 lombok.SneakyThrows;
|
||||
import sun.misc.Unsafe;
|
||||
@@ -48,9 +50,10 @@ public class TikTokGiftEventHandler {
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public List<TikTokEvent> handleGift(byte[] msg) {
|
||||
public MappingResult handleGifts(byte[] msg, String name, TikTokMapperHelper helper) {
|
||||
var currentMessage = WebcastGiftMessage.parseFrom(msg);
|
||||
return handleGift(currentMessage);
|
||||
var gifts = handleGift(currentMessage);
|
||||
return MappingResult.of(currentMessage,gifts);
|
||||
}
|
||||
|
||||
public List<TikTokEvent> handleGift(WebcastGiftMessage currentMessage) {
|
||||
@@ -20,7 +20,7 @@
|
||||
* 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.mappers.events;
|
||||
package io.github.jwdeveloper.tiktok.mappers.handlers;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||
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.models.RankingUser;
|
||||
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.WebcastLiveIntroMessage;
|
||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
|
||||
@@ -76,8 +78,7 @@ public class TikTokRoomInfoEventHandler {
|
||||
|
||||
return handleRoomInfo(tikTokRoomInfo ->
|
||||
{
|
||||
if(tikTokRoomInfo.getHost() == null)
|
||||
{
|
||||
if (tikTokRoomInfo.getHost() == null) {
|
||||
tikTokRoomInfo.setHost(hostUser);
|
||||
}
|
||||
tikTokRoomInfo.setLanguage(language);
|
||||
@@ -85,7 +86,7 @@ public class TikTokRoomInfoEventHandler {
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public List<TikTokEvent> handleMemberMessage(byte[] msg) {
|
||||
public MappingResult handleMemberMessage(byte[] msg, String name, TikTokMapperHelper helper) {
|
||||
var message = WebcastMemberMessage.parseFrom(msg);
|
||||
|
||||
var event = switch (message.getAction()) {
|
||||
@@ -98,18 +99,17 @@ public class TikTokRoomInfoEventHandler {
|
||||
{
|
||||
tikTokRoomInfo.setViewersCount(message.getMemberCount());
|
||||
});
|
||||
|
||||
return List.of(event, roomInfoEvent);
|
||||
return MappingResult.of(message, List.of(event, roomInfoEvent));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public List<TikTokEvent> handleLike(byte[] msg)
|
||||
{
|
||||
public MappingResult handleLike(byte[] msg, String name, TikTokMapperHelper helper) {
|
||||
var message = WebcastLikeMessage.parseFrom(msg);
|
||||
var event = new TikTokLikeEvent(message);
|
||||
var roomInfoEvent = this.handleRoomInfo(tikTokRoomInfo ->
|
||||
{
|
||||
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
|
||||
* 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.data.events.TikTokUnhandledSocialEvent;
|
||||
@@ -39,7 +39,6 @@ import java.util.TreeMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class TikTokWebSocketClient implements SocketClient {
|
||||
private final Logger logger;
|
||||
private final ClientSettings clientSettings;
|
||||
private final TikTokCookieJar tikTokCookieJar;
|
||||
private final TikTokMessageHandler messageHandler;
|
||||
@@ -48,12 +47,11 @@ public class TikTokWebSocketClient implements SocketClient {
|
||||
private TikTokWebSocketPingingTask pingingTask;
|
||||
private boolean isConnected;
|
||||
|
||||
public TikTokWebSocketClient(Logger logger,
|
||||
public TikTokWebSocketClient(
|
||||
TikTokCookieJar tikTokCookieJar,
|
||||
ClientSettings clientSettings,
|
||||
TikTokMessageHandler messageHandler,
|
||||
TikTokEventObserver tikTokEventHandler) {
|
||||
this.logger = logger;
|
||||
this.tikTokCookieJar = tikTokCookieJar;
|
||||
this.clientSettings = clientSettings;
|
||||
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.gifts.GiftSendType;
|
||||
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.Image;
|
||||
import io.github.jwdeveloper.tiktok.messages.data.User;
|
||||
|
||||
@@ -22,12 +22,11 @@
|
||||
*/
|
||||
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.gift.TikTokGiftEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -42,12 +41,12 @@ import static org.mockito.Mockito.verify;
|
||||
|
||||
class TikTokListenersManagerTest {
|
||||
|
||||
private TikTokEventObserver eventObserver;
|
||||
private io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver eventObserver;
|
||||
private TikTokListenersManager tikTokListenersManager;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
eventObserver = Mockito.mock(TikTokEventObserver.class);
|
||||
eventObserver = Mockito.mock(io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver.class);
|
||||
List<TikTokEventListener> listeners = new ArrayList<>();
|
||||
tikTokListenersManager = new TikTokListenersManager(listeners, eventObserver);
|
||||
}
|
||||
@@ -93,19 +92,19 @@ class TikTokListenersManagerTest {
|
||||
|
||||
public static class TikTokEventListenerTest implements TikTokEventListener
|
||||
{
|
||||
@TikTokEventHandler
|
||||
@TikTokEventObserver
|
||||
public void onJoin(LiveClient client, TikTokJoinEvent joinEvent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@TikTokEventHandler
|
||||
@TikTokEventObserver
|
||||
public void onGift(LiveClient client, TikTokGiftEvent giftMessageEvent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@TikTokEventHandler
|
||||
@TikTokEventObserver
|
||||
public void onEvent(LiveClient client, TikTokEvent event)
|
||||
{
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>1.0.8-Release</version>
|
||||
<version>1.0.9-Release</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -22,55 +22,64 @@
|
||||
*/
|
||||
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.gift.TikTokGiftEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
|
||||
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
|
||||
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 static void main(String[] args) {
|
||||
TikTokLive.newClient("vadimpyrography")
|
||||
.onCustomEvent(CustomChatEvent.class, (liveClient, event) ->
|
||||
TikTokLive.newClient("saszareznikow")
|
||||
.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) ->
|
||||
{
|
||||
event.getException().printStackTrace();
|
||||
})
|
||||
.onMapping(mapper ->
|
||||
{
|
||||
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();
|
||||
.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;
|
||||
|
||||
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.TikTokErrorEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||
@@ -65,24 +65,24 @@ public class ListenerExample
|
||||
|
||||
public static class CustomListener implements TikTokEventListener {
|
||||
|
||||
@TikTokEventHandler
|
||||
@TikTokEventObserver
|
||||
public void onLike(LiveClient liveClient, TikTokLikeEvent event) {
|
||||
System.out.println(event.toString());
|
||||
}
|
||||
|
||||
@TikTokEventHandler
|
||||
@TikTokEventObserver
|
||||
public void onError(LiveClient liveClient, TikTokErrorEvent event) {
|
||||
// event.getException().printStackTrace();
|
||||
}
|
||||
|
||||
@TikTokEventHandler
|
||||
@TikTokEventObserver
|
||||
public void onComment(LiveClient liveClient, TikTokCommentEvent event) {
|
||||
var userName = event.getUser().getName();
|
||||
var text = event.getText();
|
||||
liveClient.getLogger().info(userName + ": " + text);
|
||||
}
|
||||
|
||||
@TikTokEventHandler
|
||||
@TikTokEventObserver
|
||||
public void onGift(LiveClient liveClient, TikTokGiftEvent event) {
|
||||
var message = switch (event.getGift()) {
|
||||
case ROSE -> "Thanks :)";
|
||||
@@ -95,7 +95,7 @@ public class ListenerExample
|
||||
liveClient.getLogger().info(message);
|
||||
}
|
||||
|
||||
@TikTokEventHandler
|
||||
@TikTokEventObserver
|
||||
public void onAnyEvent(LiveClient liveClient, TikTokEvent event) {
|
||||
liveClient.getLogger().info(event.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>1.0.8-Release</version>
|
||||
<version>1.0.9-Release</version>
|
||||
</parent>
|
||||
<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
|
||||
* 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
|
||||
public class TikTokResponseModel
|
||||
{
|
||||
private Integer id;
|
||||
void connect();
|
||||
|
||||
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
|
||||
* 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
|
||||
{
|
||||
public static TikTokMessagessCollectorBuilder create(String outputName)
|
||||
{
|
||||
return new TikTokMessagessCollectorBuilder(outputName);
|
||||
}
|
||||
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||
import lombok.Data;
|
||||
|
||||
public static TikTokMessagessCollectorBuilder create(MessageCollector messageCollector, String outputName)
|
||||
{
|
||||
return new TikTokMessagessCollectorBuilder(messageCollector,outputName);
|
||||
}
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
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.logging.Logger;
|
||||
|
||||
public class MessageCollector {
|
||||
public class MessagesManager {
|
||||
|
||||
@Getter
|
||||
Map<String, Queue<MessageData>> messages;
|
||||
String outputName;
|
||||
|
||||
int limit = 20;
|
||||
public MessageCollector(String outputName) {
|
||||
public MessagesManager(String outputName) {
|
||||
this.messages = new TreeMap<>();
|
||||
this.outputName = outputName;
|
||||
load();
|
||||
@@ -22,104 +22,16 @@
|
||||
*/
|
||||
package io.github.jwdeveloper.tiktok.tools.collector.client;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.TikTokLive;
|
||||
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;
|
||||
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
|
||||
|
||||
public class TikTokClientFactory {
|
||||
private final MessageCollector messageCollector;
|
||||
private final MessagesManager messageCollector;
|
||||
private final TikTokDatabase tikTokDatabase;
|
||||
|
||||
public TikTokClientFactory(MessageCollector messageCollector, TikTokDatabase tikTokDatabase) {
|
||||
public TikTokClientFactory(MessagesManager messageCollector, TikTokDatabase tikTokDatabase) {
|
||||
this.messageCollector = messageCollector;
|
||||
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
|
||||
* 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 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,
|
||||
hostName TEXT,
|
||||
type TEXT,
|
||||
eventName TEXT,
|
||||
eventContent TEXT,
|
||||
sessionTag TEXT,
|
||||
tiktokUser TEXT,
|
||||
dataType TEXT,
|
||||
dataTypeName TEXT,
|
||||
content 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
|
||||
* 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.customizer.BindBean;
|
||||
@@ -20,7 +20,7 @@
|
||||
* 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.tables;
|
||||
package io.github.jwdeveloper.tiktok.tools.db.tables;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
@@ -20,23 +20,24 @@
|
||||
* 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.tables;
|
||||
package io.github.jwdeveloper.tiktok.tools.db.tables;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
public class TikTokMessageModel
|
||||
public class TikTokDataTable
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
* 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.tables;
|
||||
package io.github.jwdeveloper.tiktok.tools.db.tables;
|
||||
|
||||
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;
|
||||
|
||||
import com.google.gson.JsonParser;
|
||||
import io.github.jwdeveloper.tiktok.mockClient.TikTokClientMock;
|
||||
import io.github.jwdeveloper.tiktok.mockClient.mocks.LiveClientMock;
|
||||
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.TikTokLiveMock;
|
||||
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.LiveClientMock;
|
||||
import io.github.jwdeveloper.tiktok.tools.util.MessageUtil;
|
||||
|
||||
import java.io.FileReader;
|
||||
@@ -37,7 +37,7 @@ public class RunJsonTester {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
var messages = getMessages();
|
||||
var client =(LiveClientMock) TikTokClientMock.create()
|
||||
var client =(LiveClientMock) TikTokLiveMock.create()
|
||||
.onWebsocketUnhandledMessage((liveClient, event) ->
|
||||
{
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
@@ -20,25 +20,22 @@
|
||||
* 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.mockClient;
|
||||
package io.github.jwdeveloper.tiktok.tools.tester.mockClient;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
|
||||
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||
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.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.TikTokHttpClient;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||
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.mockClient.mocks.ApiServiceMock;
|
||||
import io.github.jwdeveloper.tiktok.mockClient.mocks.LiveClientMock;
|
||||
import io.github.jwdeveloper.tiktok.mockClient.mocks.WebsocketClientMock;
|
||||
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.ApiServiceMock;
|
||||
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.LiveClientMock;
|
||||
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.WebsocketClientMock;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
@@ -96,7 +93,7 @@ public class TikTokMockBuilder extends TikTokLiveClientBuilder {
|
||||
|
||||
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
|
||||
var giftManager = new TikTokGiftManager(logger);
|
||||
var requestFactory = new TikTokHttpRequestFactory(cookie);
|
||||
var requestFactory = new TikTokHttpRequestFactory(cookie, new TikTokEventObserver());
|
||||
var apiClient = new TikTokHttpClient(cookie, requestFactory);
|
||||
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
|
||||
var mapper = createMapper(giftManager, tiktokRoomInfo);
|
||||
@@ -20,7 +20,7 @@
|
||||
* 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.mockClient.mocks;
|
||||
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
||||
@@ -20,7 +20,7 @@
|
||||
* 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.mockClient.mocks;
|
||||
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
|
||||
@@ -54,8 +54,11 @@ public class LiveClientMock extends TikTokLiveClient {
|
||||
listenersManager,
|
||||
logger);
|
||||
this.websocketClientMock = webSocketClient;
|
||||
websocketClientMock.setClient(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void publishMessage(String type, String base64) {
|
||||
websocketClientMock.addMessage(type, base64);
|
||||
}
|
||||
@@ -75,5 +78,4 @@ public class LiveClientMock extends TikTokLiveClient {
|
||||
public void publishResponse(WebcastResponse message) {
|
||||
websocketClientMock.addResponse(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
* 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.mockClient.mocks;
|
||||
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||
@@ -39,12 +39,19 @@ import java.util.logging.Logger;
|
||||
public class WebsocketClientMock implements SocketClient {
|
||||
Logger logger;
|
||||
Stack<WebcastResponse> responses;
|
||||
|
||||
Stack<MsgStruct> messages;
|
||||
TikTokMessageHandler messageHandler;
|
||||
|
||||
LiveClient client;
|
||||
|
||||
Thread thread;
|
||||
|
||||
private boolean isRunning;
|
||||
|
||||
public void setClient(LiveClientMock liveClientMock) {
|
||||
this.client = liveClientMock;
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class MsgStruct {
|
||||
String messageType;
|
||||
@@ -87,38 +94,28 @@ public class WebsocketClientMock implements SocketClient {
|
||||
@Override
|
||||
public void start(WebcastResponse webcastResponse, LiveClient tikTokLiveClient) {
|
||||
logger.info("Running message: " + responses.size());
|
||||
|
||||
|
||||
thread = new Thread(() ->
|
||||
{
|
||||
|
||||
while (isRunning)
|
||||
{
|
||||
while (!responses.isEmpty()) {
|
||||
var response = responses.pop();
|
||||
messageHandler.handle(client, response);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
isRunning = true;
|
||||
while (!responses.isEmpty() || !messages.isEmpty()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
thread.start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
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 {
|
||||
|
||||
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 deserialized = parseMethod.invoke(null, bytes);
|
||||
return JsonUtil.messageToJson(deserialized);
|
||||
} catch (Exception ex) {
|
||||
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");
|
||||
var structure = ProtocolUtils.getProtocolBufferStructure(bytes);
|
||||
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>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>1.0.8-Release</version>
|
||||
<version>1.0.9-Release</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>Tools-EventsWebViewer</artifactId>
|
||||
|
||||
@@ -22,13 +22,35 @@
|
||||
*/
|
||||
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.services.TikTokCollectorService;
|
||||
import io.github.jwdeveloper.tiktok.webviewer.services.TikTokDatabaseService;
|
||||
import io.javalin.Javalin;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.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 ->
|
||||
{
|
||||
config.plugins.enableCors(corsContainer ->
|
||||
@@ -39,13 +61,19 @@ public class Main {
|
||||
});
|
||||
});
|
||||
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/disconnect", handler::disconnect);
|
||||
app.get("/tiktok/events", handler::events);
|
||||
app.get("/tiktok/events/pages", handler::eventPages);
|
||||
app.get("/tiktok/events/message", handler::eventMessage);
|
||||
|
||||
app.get("/tiktok/data/pages", handler::getDataPages);
|
||||
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.GsonBuilder;
|
||||
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 lombok.Value;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class TikTokHandler {
|
||||
private final TikTokManager tikTokManager;
|
||||
private final TikTokDatabaseService databaseService;
|
||||
private final Settings settings;
|
||||
private final TikTokCollectorService collectorService;
|
||||
|
||||
public TikTokHandler(TikTokManager tikTokManager) {
|
||||
this.tikTokManager = tikTokManager;
|
||||
public TikTokHandler(TikTokDatabaseService databaseService,
|
||||
Settings settings,
|
||||
TikTokCollectorService collectorService) {
|
||||
this.databaseService = databaseService;
|
||||
this.settings = settings;
|
||||
this.collectorService = collectorService;
|
||||
}
|
||||
|
||||
|
||||
public void connect(Context context) throws SQLException {
|
||||
String name = context.queryParam("name");
|
||||
if (name.equals(" ")) {
|
||||
context.result("Name can not be empty");
|
||||
context.status(400);
|
||||
return;
|
||||
}
|
||||
tikTokManager.connect(name);
|
||||
public void connect(Context context) {
|
||||
var name = context.queryParam("name");
|
||||
var sessionTag = context.queryParam("session");
|
||||
System.out.println("Session tag" + sessionTag);
|
||||
collectorService.start(name, sessionTag);
|
||||
settings.setUserName(name);
|
||||
context.status(200);
|
||||
}
|
||||
|
||||
public void disconnect(Context context){
|
||||
tikTokManager.disconnect();
|
||||
context.status(200);
|
||||
}
|
||||
|
||||
public void events(Context context) {
|
||||
var events = tikTokManager.getEventsNames();
|
||||
var gson = getGson();
|
||||
var result = gson.toJson(events);
|
||||
public void connectionStatus(Context context) {
|
||||
var isWorking = collectorService.isRunning();
|
||||
var result = getGson().toJson(isWorking);
|
||||
context.result(result);
|
||||
context.status(200);
|
||||
}
|
||||
|
||||
public void eventMessage(Context context) throws InvalidProtocolBufferException {
|
||||
String name = context.queryParam("eventName");
|
||||
String page = context.queryParam("page");
|
||||
public void disconnect(Context context) {
|
||||
|
||||
var result = tikTokManager.getMessage(name, page);
|
||||
var gson = getGson();
|
||||
context.result(gson.toJson(result));
|
||||
collectorService.stop();
|
||||
context.status(200);
|
||||
}
|
||||
|
||||
public void eventPages(Context context) throws InvalidProtocolBufferException {
|
||||
String name = context.queryParam("eventName");
|
||||
var result = tikTokManager.getPages(name);
|
||||
|
||||
public void getUsers(Context context) {
|
||||
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();
|
||||
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() {
|
||||
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>
|
||||
<meta charset="UTF-8">
|
||||
<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">
|
||||
<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" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/editor/editor.main.css">
|
||||
<link rel="stylesheet"
|
||||
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>
|
||||
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
body, html {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #121212; /* Dark background */
|
||||
}
|
||||
#app {
|
||||
height: 100vh; /* 100% of the viewport height */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.btn-primary
|
||||
{
|
||||
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>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/editor/editor.main.css">
|
||||
<link rel="stylesheet" , href="index.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/loader.min.js"></script>
|
||||
<script>
|
||||
require.config({
|
||||
paths: {'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs'}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
var editor;
|
||||
var editor2;
|
||||
require(['vs/editor/editor.main'], function () {
|
||||
editor = monaco.editor.create(document.getElementById('editor'), {
|
||||
value: [
|
||||
'Hello world!',
|
||||
].join('\n'),
|
||||
language: 'json',
|
||||
theme: 'vs-dark',
|
||||
automaticLayout: true
|
||||
});
|
||||
|
||||
editor2 = monaco.editor.create(document.getElementById('editor2'), {
|
||||
value: [
|
||||
'Hello world!',
|
||||
].join('\n'),
|
||||
language: 'json',
|
||||
theme: 'vs-dark',
|
||||
automaticLayout: true
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body class="bg-dark">
|
||||
|
||||
<div id="app" class="container-fluid mt-5">
|
||||
<div >
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Name:</label>
|
||||
<input type="text" id="name" name="name" class="form-control">
|
||||
<body class="container-fluid bg-dark">
|
||||
|
||||
|
||||
<div class="row ">
|
||||
<div class="col-2 ">
|
||||
<div class="form margin">
|
||||
<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>
|
||||
<button type="button" onclick="connect()" class="btn btn-primary">Connect</button>
|
||||
<button type="button" onclick="disconnect()" class="btn btn-primary">Disconnect</button>
|
||||
<button onclick="showEvents()" class="btn btn-primary">Show Events</button>
|
||||
</div>
|
||||
|
||||
<div class="content row mt-5">
|
||||
|
||||
<div class="col-md-2 ">
|
||||
<ul id="eventList" class="list-group" style="max-height: 100%; overflow-y: auto;">
|
||||
<!-- List items will be added dynamically -->
|
||||
<div class="form-group ">
|
||||
<label class="form-label">SessionTag</label>
|
||||
<input type="text" id="sessionTag" class="form-control">
|
||||
</div>
|
||||
<button id="connectionButton" type="button" class="btn btn-primary mt-3 connect-btn">Connect </button>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<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>
|
||||
</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 class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
|
||||
<div class="col-10 margin">
|
||||
<nav aria-label="Page navigation example">
|
||||
<ul id="pages" class="pagination">
|
||||
</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>
|
||||
|
||||
|
||||
|
||||
<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="index.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://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>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>1.0.8-Release</version>
|
||||
<version>1.0.9-Release</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>1.0.8-Release</version>
|
||||
<version>1.0.9-Release</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import io.github.jwdeveloper.tiktok.Constants;
|
||||
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.TikTokHttpClient;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||
@@ -78,7 +79,7 @@ public class GiftOfficialJson {
|
||||
|
||||
public static JsonArray getJsonGifts() {
|
||||
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();
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
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