mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-27 16:59:39 -05:00
Compare commits
30 Commits
develop-1-
...
1.0.10-Rel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fee805f0ea | ||
|
|
1733102aff | ||
|
|
89f54d5976 | ||
|
|
39055b5f3a | ||
|
|
cd9e9ead85 | ||
|
|
5a2d2d23f0 | ||
|
|
3eed982d6b | ||
|
|
385560de3a | ||
|
|
2e37b6627b | ||
|
|
c4f0d63b43 | ||
|
|
15550ed703 | ||
|
|
c7d84218f2 | ||
|
|
1ecd192539 | ||
|
|
d6c0d50ac3 | ||
|
|
b4997da0a8 | ||
|
|
82990665b8 | ||
|
|
155b47977d | ||
|
|
3e262773a4 | ||
|
|
89fbeb848b | ||
|
|
aa99c5929b | ||
|
|
4dd866c6cc | ||
|
|
0d384f0fdc | ||
|
|
4f3ec1c6d9 | ||
|
|
31075e5f09 | ||
|
|
33a3f7afb8 | ||
|
|
6c888c5d5b | ||
|
|
214aa3b1ff | ||
|
|
3f2c9083d5 | ||
|
|
450014759c | ||
|
|
790f568244 |
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>1.0.6-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,28 +26,34 @@ 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
|
||||
public class TikTokGiftEvent extends TikTokHeaderEvent {
|
||||
private final Gift gift;
|
||||
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 = 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);
|
||||
|
||||
@@ -1,73 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.github.jwdeveloper.tiktok.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),"");
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,25 @@
|
||||
/*
|
||||
* 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.utils;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
/*
|
||||
* 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.utils;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
/*
|
||||
* 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.utils;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
/*
|
||||
* 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.utils;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
@@ -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,9 +1124,394 @@ message LinkerUpdateUserContent {
|
||||
}
|
||||
|
||||
message LinkerUpdateUserSettingContent {
|
||||
// Data.LinkmicUserSettingInfo UpdateUserSettingInfo = 1;
|
||||
// Data.LinkmicUserSettingInfo UpdateUserSettingInfo = 1;
|
||||
}
|
||||
|
||||
message LinkerWaitingListChangeContent {
|
||||
|
||||
}
|
||||
|
||||
|
||||
message LinkmicUserSettingInfo {
|
||||
int64 userId = 1;
|
||||
int64 layout = 2; // @warning Enum not found, should be Layout
|
||||
int64 fixMicNum = 3; // @warning Enum not found, should be FixMicNum
|
||||
int64 allowRequestFromUser = 4; // @warning Enum not found, should be AllowRequestFromUser
|
||||
int64 allowRequestFromFollowerOnly = 5; // @warning Enum not found, should be AllowRequestFromFollowerOnly
|
||||
LinkmicApplierSortSetting applierSortSetting = 7; // Enum
|
||||
}
|
||||
|
||||
|
||||
message Player {
|
||||
int64 roomId = 1;
|
||||
int64 userId = 2;
|
||||
}
|
||||
|
||||
message AllListUser {
|
||||
repeated LinkLayerListUser linkedList = 2;
|
||||
repeated LinkLayerListUser appliedList = 3;
|
||||
repeated LinkLayerListUser invitedList = 4;
|
||||
repeated LinkLayerListUser readyList = 5;
|
||||
}
|
||||
|
||||
message LinkLayerListUser {
|
||||
User user = 1;
|
||||
int64 linkmicId = 2;
|
||||
Position pos = 3;
|
||||
int64 linkedTimeNano = 4;
|
||||
string appVersion = 5;
|
||||
int64 magicNumber1 = 7;
|
||||
}
|
||||
|
||||
message Position {
|
||||
int32 type = 1;
|
||||
LinkPosition link = 2;
|
||||
}
|
||||
|
||||
message LinkPosition {
|
||||
int32 position = 1;
|
||||
int32 opt = 2;
|
||||
}
|
||||
|
||||
message GroupPlayer {
|
||||
int64 channelId = 1;
|
||||
User user = 2;
|
||||
}
|
||||
|
||||
message DSLConfig {
|
||||
int32 sceneVersion = 1;
|
||||
string layoutId = 2;
|
||||
}
|
||||
|
||||
message GroupChannelAllUser {
|
||||
int64 groupChannelId = 1;
|
||||
repeated GroupChannelUser userList = 2;
|
||||
}
|
||||
|
||||
message GroupChannelUser {
|
||||
int64 channelId = 1;
|
||||
GroupStatus status = 2; // Enum
|
||||
TextType type = 3; // Enum
|
||||
AllListUser allUser = 4;
|
||||
int64 joinTime = 5;
|
||||
int64 linkedTime = 6;
|
||||
GroupPlayer ownerUser = 7;
|
||||
}
|
||||
|
||||
message RTCExtraInfo {
|
||||
RTCEngineConfig liveRtcEngineConfig = 1;
|
||||
repeated RTCLiveVideoParam liveRtcVideoParamList = 2;
|
||||
RTCBitrateMap rtcBitrateMap = 3;
|
||||
int32 rtcFps = 4;
|
||||
string rtcBusinessId = 8;
|
||||
int32 interactClientType = 10;
|
||||
|
||||
message RTCEngineConfig {
|
||||
string rtcAppId = 1;
|
||||
string rtcUserId = 2;
|
||||
string rtcToken = 3;
|
||||
int64 rtcChannelId = 4;
|
||||
}
|
||||
|
||||
message RTCLiveVideoParam {
|
||||
int32 strategyId = 1;
|
||||
RTCVideoParam params = 2;
|
||||
}
|
||||
|
||||
message RTCVideoParam {
|
||||
int32 width = 1;
|
||||
int32 height = 2;
|
||||
int32 fps = 3;
|
||||
int32 bitrateKbps = 4;
|
||||
}
|
||||
|
||||
message RTCBitrateMap {
|
||||
int32 xx1 = 1;
|
||||
int32 xx2 = 2;
|
||||
int32 xx3 = 3;
|
||||
int32 xx4 = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message CreateChannelContent {
|
||||
Player owner = 1;
|
||||
string ownerLinkMicId = 2;
|
||||
}
|
||||
|
||||
message ListChangeContent {
|
||||
TextType type = 1; // Enum
|
||||
AllListUser list = 2;
|
||||
}
|
||||
|
||||
message MultiLiveContent {
|
||||
InviteBizContent inviteBizContent = 2;
|
||||
ReplyBizContent replyBizContent = 3;
|
||||
PermitBizContent permitBizContent = 4;
|
||||
KickOutBizContent kickOutBizContent = 6;
|
||||
|
||||
|
||||
message InviteBizContent {
|
||||
LinkmicUserSettingInfo anchorSettingInfo = 1;
|
||||
int64 inviteSource = 2; // @warning Enum not found, should be InviteSource
|
||||
User operatorUserInfo = 3;
|
||||
int64 operatorLinkAdminType = 4; // @warning Enum not found, should be OperatorLinkAdminType
|
||||
User inviteeUserInfo = 5;
|
||||
}
|
||||
|
||||
|
||||
message ReplyBizContent {
|
||||
int32 linkType = 1;
|
||||
int32 isTurnOffInvitation = 2;
|
||||
User replyUserInfo = 3;
|
||||
}
|
||||
|
||||
message PermitBizContent {
|
||||
LinkmicUserSettingInfo anchorSettingInfo = 1;
|
||||
int64 expireTimestamp = 2;
|
||||
User operatorUserInfo = 3;
|
||||
int64 operatorLinkAdminType = 4; // @warning Enum not found, should be OperatorLinkAdminType
|
||||
}
|
||||
|
||||
message KickOutBizContent {
|
||||
User operatorUserInfo = 1;
|
||||
int64 operatorLinkAdminType = 2; // @warning Enum not found, should be OperatorLinkAdminType
|
||||
User kickPlayerUserInfo = 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
message InviteContent {
|
||||
Player invitor = 1;
|
||||
RTCExtraInfo inviteeRtcExtInfo = 2;
|
||||
string invitorLinkMicId = 3;
|
||||
string inviteeLinkMicId = 4;
|
||||
bool isOwner = 5;
|
||||
Position pos = 6;
|
||||
DSLConfig dsl = 7;
|
||||
User invitee = 8;
|
||||
User operator = 9;
|
||||
}
|
||||
|
||||
|
||||
// @ApplyContent
|
||||
// proto.webcast.im
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message ApplyContent {
|
||||
Player applier = 1;
|
||||
string applierLinkMicId = 2;
|
||||
}
|
||||
|
||||
|
||||
// @PermitApplyContent
|
||||
// proto.webcast.im
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message PermitApplyContent {
|
||||
Player permiter = 1;
|
||||
string permiterLinkMicId = 2;
|
||||
Position applierPos = 3;
|
||||
ReplyStatus replyStatus = 4; // Enum
|
||||
DSLConfig dsl = 5;
|
||||
User applier = 6;
|
||||
User operator = 7;
|
||||
string applierLinkMicId = 8;
|
||||
}
|
||||
|
||||
|
||||
// @ReplyInviteContent
|
||||
// proto.webcast.im
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message ReplyInviteContent {
|
||||
Player invitee = 1;
|
||||
ReplyStatus replyStatus = 2; // Enum
|
||||
string inviteeLinkMicId = 3;
|
||||
Position inviteePos = 4;
|
||||
Player inviteOperatorUser = 5;
|
||||
}
|
||||
|
||||
|
||||
// @KickOutContent
|
||||
// proto.webcast.im
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message KickOutContent {
|
||||
Player offliner = 1;
|
||||
KickoutReason kickoutReason = 2; // Enum
|
||||
}
|
||||
|
||||
|
||||
// @CancelApplyContent
|
||||
// proto.webcast.im
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message CancelApplyContent {
|
||||
Player applier = 1;
|
||||
string applierLinkMicId = 2;
|
||||
}
|
||||
|
||||
|
||||
// @CancelInviteContent
|
||||
// proto.webcast.im
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message CancelInviteContent {
|
||||
Player invitor = 1;
|
||||
string invitorLinkMicId = 2;
|
||||
string inviteeLinkMicId = 3;
|
||||
int64 inviteSeqId = 4;
|
||||
Player invitee = 5;
|
||||
}
|
||||
|
||||
|
||||
// @LeaveContent
|
||||
// proto.webcast.im
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message LeaveContent {
|
||||
Player leaver = 1;
|
||||
int64 leaveReason = 2;
|
||||
}
|
||||
|
||||
|
||||
// @FinishChannelContent
|
||||
// proto.webcast.im
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message FinishChannelContent {
|
||||
Player owner = 1;
|
||||
int64 finishReason = 2;
|
||||
}
|
||||
|
||||
|
||||
// @JoinDirectContent
|
||||
// proto.webcast.im
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message JoinDirectContent {
|
||||
LinkLayerListUser joiner = 1;
|
||||
AllListUser allUsers = 2;
|
||||
}
|
||||
|
||||
|
||||
// @LeaveJoinGroupContent
|
||||
// proto.webcast.im
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message LeaveJoinGroupContent {
|
||||
GroupPlayer operator = 1;
|
||||
int64 groupChannelId = 2;
|
||||
string leaveSource = 3;
|
||||
}
|
||||
|
||||
|
||||
// @PermitJoinGroupContent
|
||||
// proto.webcast.im
|
||||
message PermitJoinGroupContent {
|
||||
GroupPlayer approver = 1;
|
||||
AgreeStatus agreeStatus = 2; // Enum
|
||||
TextType type = 3; // Enum
|
||||
repeated RTCExtraInfo groupExtInfoList = 4;
|
||||
GroupChannelAllUser groupUser = 5;
|
||||
}
|
||||
|
||||
|
||||
// @CancelJoinGroupContent
|
||||
// proto.webcast.im
|
||||
message CancelJoinGroupContent {
|
||||
repeated GroupPlayer leaverList = 1;
|
||||
GroupPlayer operator = 2;
|
||||
TextType type = 3; // Enum
|
||||
}
|
||||
|
||||
|
||||
|
||||
message P2PGroupChangeContent {
|
||||
repeated RTCExtraInfo groupExtInfoList = 1;
|
||||
GroupChannelAllUser groupUser = 2;
|
||||
}
|
||||
|
||||
|
||||
message BusinessContent {
|
||||
int64 overLength = 1;
|
||||
MultiLiveContent multiLiveContent = 100;
|
||||
CohostContent cohostContent = 200;
|
||||
|
||||
message CohostContent {
|
||||
JoinGroupBizContent joinGroupBizContent = 1;
|
||||
|
||||
}
|
||||
|
||||
message JoinGroupBizContent {
|
||||
int32 fromRoomAgeRestricted = 1;
|
||||
Tag fromTag = 2;
|
||||
PerceptionDialogInfo dialog = 3;
|
||||
PunishEventInfo punishInfo = 4;
|
||||
JoinGroupMessageExtra joinGroupMsgExtra = 101;
|
||||
}
|
||||
|
||||
message Tag {
|
||||
int32 tagType = 1;
|
||||
string tagValue = 2;
|
||||
string tagText = 3;
|
||||
}
|
||||
|
||||
message PerceptionDialogInfo {
|
||||
int64 iconType = 1; // @warning Enum not found, should be IconType
|
||||
Text title = 2;
|
||||
Text subTitle = 3;
|
||||
Text adviceActionText = 4;
|
||||
Text defaultActionText = 5;
|
||||
string violationDetailUrl = 6;
|
||||
int32 scene = 7;
|
||||
int64 targetUserId = 8;
|
||||
int64 targetRoomId = 9;
|
||||
int64 countDownTime = 10;
|
||||
bool showFeedback = 11;
|
||||
repeated PerceptionFeedbackOption feedbackOptionsList = 12;
|
||||
int64 policyTip = 13;
|
||||
}
|
||||
|
||||
message PerceptionFeedbackOption {
|
||||
int64 id = 1;
|
||||
string contentKey = 2;
|
||||
}
|
||||
|
||||
message JoinGroupMessageExtra {
|
||||
int64 sourceType = 1;
|
||||
RivalExtra extra = 2;
|
||||
repeated RivalExtra otherUsersList = 3;
|
||||
|
||||
|
||||
// @RivalExtra
|
||||
// proto.webcast.im.JoinGroupMessageExtra
|
||||
// C:\Users\ja\RiderProjects\TikTokProBufferGenerator\Application\output\sources\test.js
|
||||
message RivalExtra {
|
||||
int64 userCount = 4;
|
||||
Image avatarThumb = 5;
|
||||
string displayId = 6;
|
||||
AuthenticationInfo authenticationInfo = 7;
|
||||
string nickname = 8;
|
||||
int64 followStatus = 9;
|
||||
Hashtag hashtag = 10;
|
||||
TopHostInfo topHostInfo = 11;
|
||||
int64 userId = 12;
|
||||
bool isBestTeammate = 13;
|
||||
|
||||
message AuthenticationInfo {
|
||||
string customVerify = 1;
|
||||
string enterpriseVerifyReason = 2;
|
||||
Image authenticationBadge = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
message Hashtag {
|
||||
int64 id = 1;
|
||||
string title = 2;
|
||||
Image image = 3;
|
||||
HashtagNamespace namespace = 4; // Enum
|
||||
}
|
||||
|
||||
message TopHostInfo {
|
||||
string rankType = 1;
|
||||
int64 topIndex = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message JoinGroupContent {
|
||||
GroupChannelAllUser groupUser = 1;
|
||||
GroupPlayer joinUser = 2;
|
||||
TextType type = 3; // Enum
|
||||
}
|
||||
@@ -25,6 +25,85 @@ enum EmotePrivateType {
|
||||
EMOTE_PRIVATE_TYPE_SUB_WAVE = 1;
|
||||
}
|
||||
|
||||
enum TextType {
|
||||
DISPLAY_TEXT = 0;
|
||||
CONTENT = 1;
|
||||
}
|
||||
|
||||
enum LinkmicApplierSortSetting {
|
||||
LINKMIC_APPLIER_SORT_SETTING_NONE = 0;
|
||||
LINKMIC_APPLIER_SORT_SETTING_BY_GIFT_SCORE = 1;
|
||||
}
|
||||
|
||||
enum HashtagNamespace {
|
||||
GLOBAL = 0;
|
||||
GAMING = 1;
|
||||
}
|
||||
|
||||
enum AgreeStatus {
|
||||
AGREE_UNKNOWN = 0;
|
||||
AGREE = 1;
|
||||
REJECT = 2;
|
||||
}
|
||||
|
||||
enum KickoutReason {
|
||||
KICKOUT_REASON_UNKNOWN = 0;
|
||||
KICKOUT_REASON_FIRST_FRAME_TIMEOUT = 1;
|
||||
KICKOUT_REASON_BY_HOST = 2;
|
||||
KICKOUT_REASON_RTC_LOST_CONNECTION = 3;
|
||||
KICKOUT_REASON_BY_PUNISH = 4;
|
||||
KICKOUT_REASON_BY_ADMIN = 5;
|
||||
KICKOUT_REASON_HOST_REMOVE_ALL_GUESTS = 6;
|
||||
}
|
||||
|
||||
|
||||
enum GroupStatus {
|
||||
GROUP_STATUS_UNKNOWN = 0;
|
||||
GROUP_STATUS_WAITING = 1;
|
||||
GROUP_STATUS_LINKED = 3;
|
||||
}
|
||||
|
||||
enum BusinessCase {
|
||||
BUSINESS_NOT_SET = 0;
|
||||
APPLY_BIZ_CONTENT = 1;
|
||||
INVITE_BIZ_CONTENT = 2;
|
||||
REPLY_BIZ_CONTENT = 3;
|
||||
PERMIT_BIZ_CONTENT = 4;
|
||||
JOIN_DIRECT_BIZ_CONTENT = 5;
|
||||
KICK_OUT_BIZ_CONTENT = 6;
|
||||
LIST_CHANGE_BIZ_CONTENT = 11;
|
||||
MULTI_LIVE_CONTENT = 100;
|
||||
COHOST_CONTENT = 200;
|
||||
}
|
||||
|
||||
enum ReplyStatus {
|
||||
REPLY_STATUS_UNKNOWN = 0;
|
||||
REPLY_STATUS_AGREE = 1;
|
||||
REPLY_STATUS_REFUSE_PERSONALLY = 2;
|
||||
REPLY_STATUS_REFUSE_TYPE_NOT_SUPPORT = 3;
|
||||
REPLY_STATUS_REFUSE_PROCESSING_INVITATION = 4;
|
||||
REPLY_STATUS_REFUSE_BY_TIMEOUT = 5;
|
||||
REPLY_STATUS_REFUSE_EXCEPTION = 6;
|
||||
REPLY_STATUS_REFUSE_SYSTEM_NOT_SUPPORTED = 7;
|
||||
REPLY_STATUS_REFUSE_SUBTYPE_DIFFERENCE = 8;
|
||||
REPLY_STATUS_REFUSE_IN_MICROOM = 9;
|
||||
REPLY_STATUS_REFUSE_NOT_LOAD_PLUGIN = 10;
|
||||
REPLY_STATUS_REFUSE_IN_MULTI_GUEST = 11;
|
||||
REPLY_STATUS_REFUSE_PAUSE_LIVE = 12;
|
||||
REPLY_STATUS_REFUSE_OPEN_CAMERA_DIALOG_SHOWING = 13;
|
||||
REPLY_STATUS_REFUSE_DRAW_GUESSING = 14;
|
||||
REPLY_STATUS_REFUSE_RANDOM_MATCHING = 15;
|
||||
REPLY_STATUS_REFUSE_IN_MATCH_PROCESSING = 16;
|
||||
REPLY_STATUS_REFUSE_IN_MICROOM_FOR_MULTI_COHOST = 17;
|
||||
REPLY_STATUS_REFUSE_COHOST_FINISHED = 18;
|
||||
REPLY_STATUS_REFUSE_NOT_CONNECTED = 19;
|
||||
REPLY_STATUS_REFUSE_LINKMIC_FULL = 20;
|
||||
REPLY_STATUS_REFUSE_ARC_INCOMPATIBLE = 21;
|
||||
REPLY_STATUS_REFUSE_PROCESSING_OTHER_INVITE = 22;
|
||||
REPLY_STATUS_REFUSE_PROCESSING_OTHER_APPLY = 23;
|
||||
REPLY_STATUS_REFUSE_IN_ANCHOR_COHOST = 24;
|
||||
REPLY_STATUS_REFUSE_TOPIC_PAIRING = 25;
|
||||
}
|
||||
|
||||
enum SubscribeType {
|
||||
SUBSCRIBETYPE_ONCE = 0;
|
||||
@@ -137,3 +216,50 @@ enum EnvelopeDisplay
|
||||
EnvelopeDisplayNew = 1;
|
||||
EnvelopeDisplayHide = 2;
|
||||
}
|
||||
|
||||
|
||||
enum CommonContentCase {
|
||||
COMMON_CONTENT_NOT_SET = 0;
|
||||
CREATE_CHANNEL_CONTENT = 100;
|
||||
LIST_CHANGE_CONTENT = 102;
|
||||
INVITE_CONTENT = 103;
|
||||
APPLY_CONTENT = 104;
|
||||
PERMIT_APPLY_CONTENT = 105;
|
||||
REPLY_INVITE_CONTENT = 106;
|
||||
KICK_OUT_CONTENT = 107;
|
||||
CANCEL_APPLY_CONTENT = 108;
|
||||
CANCEL_INVITE_CONTENT = 109;
|
||||
LEAVE_CONTENT = 110;
|
||||
FINISH_CONTENT = 111;
|
||||
JOIN_DIRECT_CONTENT = 112;
|
||||
JOIN_GROUP_CONTENT = 113;
|
||||
PERMIT_GROUP_CONTENT = 114;
|
||||
CANCEL_GROUP_CONTENT = 115;
|
||||
LEAVE_GROUP_CONTENT = 116;
|
||||
P2P_GROUP_CHANGE_CONTENT = 117;
|
||||
GROUP_CHANGE_CONTENT = 118;
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum MessageType {
|
||||
MESSAGETYPE_SUBSUCCESS = 0;
|
||||
MESSAGETYPE_ANCHORREMINDER = 1;
|
||||
MESSAGETYPE_ENTERROOMEXPIRESOON = 2;
|
||||
MESSAGETYPE_SUBGOALCREATETOANCHOR = 3;
|
||||
MESSAGETYPE_SUBGOALCOMPLETETOAUDIENCE = 4;
|
||||
MESSAGETYPE_SUBGOALCOMPLETETOANCHOR = 5;
|
||||
MESSAGETYPE_SUBGIFTTIKTOK2USERNOTICE = 6;
|
||||
MESSAGETYPE_SUBGIFTTIKTOK2ANCHORNOTICE = 7;
|
||||
MESSAGETYPE_SUBGIFTTRECEIVESENDNOTICE = 8;
|
||||
MESSAGETYPE_SUBGIFTSENDSUCCEEDROOMMESSAGE = 9;
|
||||
MESSAGETYPE_SUBGIFTSENDSUCCEEDANCHORNOTICE = 10;
|
||||
MESSAGETYPE_SUBGIFTLOWVERSIONUPGRADENOTICE = 11;
|
||||
MESSAGETYPE_SUBGIFTUSERBUYAUTHNOTICE = 12;
|
||||
}
|
||||
|
||||
enum Scene {
|
||||
SCENE_UNKNOWN = 0;
|
||||
SCENE_CO_HOST = 2;
|
||||
SCENE_MULTI_LIVE = 4;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -442,7 +448,7 @@ message WebcastMemberMessage {
|
||||
//@WebcastPollMessage
|
||||
message WebcastPollMessage {
|
||||
Common common = 1;
|
||||
int32 messageType = 2;
|
||||
MessageType messageType = 2;
|
||||
int64 pollId = 3;
|
||||
PollStartContent startContent = 4;
|
||||
PollEndContent endContent = 5;
|
||||
@@ -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,11 +620,10 @@ message WebcastLinkMicFanTicketMethod {
|
||||
Common common = 1;
|
||||
FanTicketRoomNoticeContent FanTicketRoomNotice = 2;
|
||||
}
|
||||
|
||||
//@WebcastLinkMicMethod
|
||||
message WebcastLinkMicMethod {
|
||||
Common common = 1;
|
||||
int64 messageType = 2;
|
||||
MessageType messageType = 2;
|
||||
string accessKey = 3;
|
||||
int64 anchorLinkmicId = 4;
|
||||
int64 userId = 5;
|
||||
@@ -590,6 +637,8 @@ message WebcastLinkMicMethod {
|
||||
int64 inviteUid = 13;
|
||||
}
|
||||
|
||||
//<Battles>
|
||||
|
||||
//@WebcastLiveIntroMessage
|
||||
message WebcastLiveIntroMessage {
|
||||
Common common = 1;
|
||||
@@ -610,7 +659,7 @@ message WebcastUnauthorizedMemberMessage {
|
||||
string nickName = 4;
|
||||
Text enterText = 5;
|
||||
}
|
||||
S
|
||||
|
||||
//@WebcastMsgDetectMessage
|
||||
message WebcastMsgDetectMessage {
|
||||
Common common = 1;
|
||||
@@ -683,9 +732,9 @@ message WebcastSystemMessage {
|
||||
//@WebcastLinkMessage
|
||||
message WebcastLinkMessage {
|
||||
Common common = 1;
|
||||
int64 MessageType = 2;
|
||||
MessageType MessageType = 2;
|
||||
int64 LinkerId = 3;
|
||||
int64 Scene = 4;
|
||||
Scene Scene = 4;
|
||||
LinkerInviteContent InviteContent = 5;
|
||||
LinkerReplyContent ReplyContent = 6;
|
||||
LinkerCreateContent CreateContent = 7;
|
||||
@@ -712,14 +761,34 @@ message WebcastLinkMessage {
|
||||
string TransferExtra = 202;
|
||||
}
|
||||
|
||||
//@WebcastLinkLayerMessage
|
||||
|
||||
// @WebcastLinkLayerMessage
|
||||
message WebcastLinkLayerMessage {
|
||||
Common common = 1;
|
||||
LinkLayerMessageType messageType = 2;
|
||||
MessageType messageType = 2; // Enum
|
||||
int64 channelId = 3;
|
||||
Scene scene = 4; // Enum
|
||||
CreateChannelContent createChannelContent = 100;
|
||||
ListChangeContent listChangeContent = 102;
|
||||
InviteContent inviteContent = 103;
|
||||
ApplyContent applyContent = 104;
|
||||
PermitApplyContent permitApplyContent = 105;
|
||||
ReplyInviteContent replyInviteContent = 106;
|
||||
KickOutContent kickOutContent = 107;
|
||||
CancelApplyContent cancelApplyContent = 108;
|
||||
CancelInviteContent cancelInviteContent = 109;
|
||||
LeaveContent leaveContent = 110;
|
||||
FinishChannelContent finishContent = 111;
|
||||
JoinDirectContent joinDirectContent = 112;
|
||||
JoinGroupContent joinGroupContent = 113;
|
||||
PermitJoinGroupContent permitGroupContent = 114;
|
||||
CancelJoinGroupContent cancelGroupContent = 115;
|
||||
LeaveJoinGroupContent leaveGroupContent = 116;
|
||||
P2PGroupChangeContent p2pGroupChangeContent = 117;
|
||||
BusinessContent businessContent = 200;
|
||||
}
|
||||
|
||||
|
||||
// @RoomVerifyMessage
|
||||
message RoomVerifyMessage {
|
||||
Common common = 1;
|
||||
int32 action = 2;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>1.0.6-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];
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.github.jwdeveloper.tiktok.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;
|
||||
@@ -10,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 {
|
||||
}
|
||||
@@ -1,4 +1,26 @@
|
||||
package io.github.jwdeveloper.tiktok.mappers.events;
|
||||
/*
|
||||
* 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.mappers.handlers;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||
@@ -43,9 +65,9 @@ public class TikTokCommonEventHandler
|
||||
public TikTokEvent handlePollEvent(byte[] msg) {
|
||||
var poolMessage = WebcastPollMessage.parseFrom(msg);
|
||||
return switch (poolMessage.getMessageType()) {
|
||||
case 0 -> new TikTokPollStartEvent(poolMessage);
|
||||
case 1 -> new TikTokPollEndEvent(poolMessage);
|
||||
case 2 -> new TikTokPollUpdateEvent(poolMessage);
|
||||
case MESSAGETYPE_SUBSUCCESS -> new TikTokPollStartEvent(poolMessage);
|
||||
case MESSAGETYPE_ANCHORREMINDER -> new TikTokPollEndEvent(poolMessage);
|
||||
case MESSAGETYPE_ENTERROOMEXPIRESOON -> new TikTokPollUpdateEvent(poolMessage);
|
||||
default -> new TikTokPollEvent(poolMessage);
|
||||
};
|
||||
}
|
||||
@@ -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.6-Release</version>
|
||||
<version>1.0.9-Release</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -1,54 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package io.github.jwdeveloper.tiktok;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
31
README.md
31
README.md
@@ -1,7 +1,6 @@
|
||||
<div align="center" >
|
||||
<a target="blank" >
|
||||
<img src="https://raw.githubusercontent.com/jwdeveloper/TikTokLiveJava/develop-1_0_0/Tools-ReadmeGenerator/src/main/resources/logo.svg" width="15%" >
|
||||
</img>
|
||||
</a>
|
||||
</div>
|
||||
<div align="center" >
|
||||
@@ -12,18 +11,15 @@
|
||||
<div align="center" >
|
||||
<a href="https://jitpack.io/#jwdeveloper/TikTok-Live-Java" target="blank" >
|
||||
<img src="https://jitpack.io/v/jwdeveloper/TikTok-Live-Java.svg" width="20%" >
|
||||
</img>
|
||||
</a>
|
||||
|
||||
|
||||
<a href="https://discord.gg/e2XwPNTBBr" target="blank" >
|
||||
<img src="https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white" >
|
||||
</img>
|
||||
</a>
|
||||
|
||||
<a target="blank" >
|
||||
<img src="https://img.shields.io/badge/java-%23ED8B00.svg?style=for-the-badge&logo=openjdk&logoColor=white" >
|
||||
</img>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -33,6 +29,9 @@ A Java library inspired by [TikTokLive](https://github.com/isaackogan/TikTokLive
|
||||
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
|
||||
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
|
||||
|
||||
# Contributors
|
||||
[Library documentation for contributors](https://github.com/jwdeveloper/TikTokLiveJava/wiki)
|
||||
|
||||
<div align="center">
|
||||
<a href="https://www.youtube.com/watch?v=eerWGgUKc6c" align="right" target="blank"><img src="https://img.youtube.com/vi/eerWGgUKc6c/hqdefault.jpg" alt="IMAGE ALT TEXT" width="38%" align="right"></a>
|
||||
</div>
|
||||
@@ -55,8 +54,9 @@ Do you prefer other programming languages?
|
||||
|
||||
## Getting started
|
||||
|
||||
1. Install the package via Maven
|
||||
1. Install the package
|
||||
|
||||
Maven
|
||||
```xml
|
||||
<repositories>
|
||||
<repository>
|
||||
@@ -69,12 +69,27 @@ Do you prefer other programming languages?
|
||||
<dependency>
|
||||
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
|
||||
<artifactId>Client</artifactId>
|
||||
<version>1.0.6-Release</version>
|
||||
<version>1.0.8-Release</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
Gradle
|
||||
```gradle
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.0.8-Release'
|
||||
}
|
||||
```
|
||||
|
||||
2. Create your first chat connection
|
||||
|
||||
```java
|
||||
@@ -419,9 +434,9 @@ Triggered every time gift is sent
|
||||
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
|
||||
<p>Combo: 4 -> comboState = GiftSendType.Active</p>
|
||||
<p>Combo: 8 -> comboState = GiftSendType.Active</p>
|
||||
<p>Combo: 12 -> comboState = GiftSendType.Finsihed</p>
|
||||
<p>Combo: 12 -> comboState = GiftSendType.Finished</p>
|
||||
|
||||
Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
|
||||
Remember if comboState is Finished both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
|
||||
|
||||
|
||||
```java
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>1.0.6-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.6-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>
|
||||
|
||||
|
||||
<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
|
||||
});
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
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">
|
||||
<body class="container-fluid 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">
|
||||
|
||||
<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="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 class="content row mt-5">
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<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.6-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.6-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.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user