mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-27 08:49:40 -05:00
Changes:
onCustomEvent() <- registering custom events onMapping() <- custom mappings check out 'CustomMappingExample' more gifs has been added exceptions are more explicit
This commit is contained in:
@@ -26,15 +26,20 @@ package io.github.jwdeveloper.tiktok.exceptions;
|
|||||||
/**
|
/**
|
||||||
* Happens when incoming data from TikTok can not be mapped to TikTokEvent's
|
* Happens when incoming data from TikTok can not be mapped to TikTokEvent's
|
||||||
*/
|
*/
|
||||||
public class TikTokMessageMappingException extends TikTokLiveException
|
public class TikTokMessageMappingException extends TikTokLiveException {
|
||||||
{
|
public TikTokMessageMappingException(Class<?> inputClazz, Class<?> outputClass, Throwable throwable) {
|
||||||
public TikTokMessageMappingException(Class<?> inputClazz, Class<?> outputClass, Throwable throwable)
|
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + " to class " + outputClass.getSimpleName(), throwable);
|
||||||
{
|
|
||||||
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + " to class " + outputClass.getSimpleName(),throwable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokMessageMappingException(Class<?> inputClazz, Class<?> outputClass, String message)
|
public TikTokMessageMappingException(Class<?> inputClazz, Class<?> outputClass, String message) {
|
||||||
{
|
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + " to class " + outputClass.getSimpleName() + ": " + message);
|
||||||
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + " to class " + outputClass.getSimpleName()+": "+message);
|
}
|
||||||
|
|
||||||
|
public TikTokMessageMappingException(Class<?> inputClazz, String message, Throwable throwable) {
|
||||||
|
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + ": " + message, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TikTokMessageMappingException(String message, Throwable throwable) {
|
||||||
|
super( message, throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,12 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandl
|
|||||||
|
|
||||||
public interface EventsBuilder<T> {
|
public interface EventsBuilder<T> {
|
||||||
|
|
||||||
T onCustomEvent(EventConsumer<CustomEvent> event);
|
/**
|
||||||
|
* Method used to register own custom events
|
||||||
|
* @param eventClazz event class
|
||||||
|
* @param event action
|
||||||
|
*/
|
||||||
|
<E extends TikTokEvent> T onCustomEvent(Class<E> eventClazz, EventConsumer<E> event);
|
||||||
|
|
||||||
T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event);
|
T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event);
|
||||||
|
|
||||||
@@ -52,6 +57,7 @@ public interface EventsBuilder<T> {
|
|||||||
|
|
||||||
|
|
||||||
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> event);
|
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> event);
|
||||||
|
|
||||||
T onGift(EventConsumer<TikTokGiftEvent> event);
|
T onGift(EventConsumer<TikTokGiftEvent> event);
|
||||||
|
|
||||||
T onQuestion(EventConsumer<TikTokQuestionEvent> event);
|
T onQuestion(EventConsumer<TikTokQuestionEvent> event);
|
||||||
@@ -68,7 +74,7 @@ public interface EventsBuilder<T> {
|
|||||||
|
|
||||||
T onShare(EventConsumer<TikTokShareEvent> event);
|
T onShare(EventConsumer<TikTokShareEvent> event);
|
||||||
|
|
||||||
// T onChest(EventConsumer<TikTokChestEvent> event);
|
// T onChest(EventConsumer<TikTokChestEvent> event);
|
||||||
|
|
||||||
T onLivePaused(EventConsumer<TikTokLivePausedEvent> event);
|
T onLivePaused(EventConsumer<TikTokLivePausedEvent> event);
|
||||||
|
|
||||||
@@ -83,11 +89,10 @@ public interface EventsBuilder<T> {
|
|||||||
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> event);
|
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> event);
|
||||||
|
|
||||||
T onError(EventConsumer<TikTokErrorEvent> event);
|
T onError(EventConsumer<TikTokErrorEvent> event);
|
||||||
|
|
||||||
T onEvent(EventConsumer<TikTokEvent> event);
|
T onEvent(EventConsumer<TikTokEvent> event);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO Figure out how those events works
|
// TODO Figure out how those events works
|
||||||
//T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);
|
//T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);
|
||||||
|
|
||||||
|
|||||||
@@ -23,20 +23,60 @@
|
|||||||
package io.github.jwdeveloper.tiktok.live.builder;
|
package io.github.jwdeveloper.tiktok.live.builder;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.ClientSettings;
|
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
|
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
|
public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
|
||||||
LiveClientBuilder configure(Consumer<ClientSettings> consumer);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is triggered after default mappings are registered
|
||||||
|
* It could be used to OVERRIDE behaviour of mappings and implement custom behaviour
|
||||||
|
*
|
||||||
|
* Be aware if for example you override WebcastGiftEvent, onGiftEvent() will not be working
|
||||||
|
*
|
||||||
|
* @param onCustomMappings lambda method
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration of client settings
|
||||||
|
* @see ClientSettings
|
||||||
|
* @param onConfigure
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
LiveClientBuilder configure(Consumer<ClientSettings> onConfigure);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TikTokEventListener
|
||||||
|
* Adding events listener class, its fancy way to register events without using lamda method
|
||||||
|
* but actual method in class that implements TikTokEventListener
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
LiveClientBuilder addListener(TikTokEventListener listener);
|
LiveClientBuilder addListener(TikTokEventListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return LiveClient object
|
||||||
|
*/
|
||||||
LiveClient build();
|
LiveClient build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return LiveClient object and connects to TikTok live
|
||||||
|
*/
|
||||||
LiveClient buildAndConnect();
|
LiveClient buildAndConnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return LiveClient object and connects to TikTok live asynchronously
|
||||||
|
*/
|
||||||
CompletableFuture<LiveClient> buildAndConnectAsync();
|
CompletableFuture<LiveClient> buildAndConnectAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.mappers;
|
||||||
|
|
||||||
|
import com.google.protobuf.GeneratedMessageV3;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
|
||||||
|
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);
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* @param sourceClass protocol buffer webcast class
|
||||||
|
* @param onMapping lambda function that is triggered on mapping. takes as input ProtocolBuffer object and as output TikTokEvent
|
||||||
|
*/
|
||||||
|
void bytesToEvent(Class<? extends GeneratedMessageV3> sourceClass, Function<byte[], TikTokEvent> onMapping);
|
||||||
|
|
||||||
|
void bytesToEvents(Class<? extends GeneratedMessageV3> sourceClass, Function<byte[], List<TikTokEvent>> onMapping);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case you found some TikTok message that has not Webcast class use this method
|
||||||
|
*
|
||||||
|
* @param messageName Name of TikTok data event
|
||||||
|
* @param onMapping lambda function that is triggered on mapping. takes as input ProtocolBuffer object and as output TikTokEvent
|
||||||
|
*/
|
||||||
|
void bytesToEvent(String messageName, Function<byte[], TikTokEvent> onMapping);
|
||||||
|
|
||||||
|
void bytesToEvents(String messageName, Function<byte[], List<TikTokEvent>> onMapping);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method can be used to override default mapping for
|
||||||
|
* certain TikTok incoming data message. For this example
|
||||||
|
* we are overriding WebcastGiftMessage and retuning CustomGiftEvent
|
||||||
|
* instead of TikTokGiftEvent
|
||||||
|
* <p>
|
||||||
|
* webcastObjectToEvent(WebcastGiftMessage.class, webcastGiftMessage ->
|
||||||
|
* {
|
||||||
|
* var giftName = webcastGiftMessage.getGift().getName();
|
||||||
|
* var user = webcastGiftMessage.getUser().getNickname();
|
||||||
|
* return new CustomGiftEvent(giftName, user);
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* @param sourceClass ProtocolBuffer class that represent incoming custom data, hint class should starts with Webcast prefix
|
||||||
|
* @param onMapping lambda function that is triggered on mapping. takes as input ProtocolBuffer object and as output TikTokEvent
|
||||||
|
*/
|
||||||
|
<T extends GeneratedMessageV3> void webcastObjectToEvent(Class<T> sourceClass, Function<T, TikTokEvent> onMapping);
|
||||||
|
|
||||||
|
<T extends GeneratedMessageV3> void webcastObjectToEvents(Class<T> sourceClass, Function<T, List<TikTokEvent>> onMapping);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered when `sourceClass` is mapped,
|
||||||
|
* looking for constructor in `outputClass` with one parameter that is of type `sourceClass`
|
||||||
|
* and created instance of object from this constructor
|
||||||
|
*
|
||||||
|
* @param sourceClass protocol buffer webcast class
|
||||||
|
* @param outputClass TikTok event class
|
||||||
|
*/
|
||||||
|
void webcastObjectToConstructor(Class<? extends GeneratedMessageV3> sourceClass, Class<? extends TikTokEvent> outputClass);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,60 +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.utils;
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
|
||||||
|
|
||||||
public class CancelationToken
|
|
||||||
{
|
|
||||||
private boolean isCanceled =false;
|
|
||||||
|
|
||||||
public void cancel()
|
|
||||||
{
|
|
||||||
isCanceled =true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCancel()
|
|
||||||
{
|
|
||||||
|
|
||||||
return isCanceled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void throwIfCancel()
|
|
||||||
{
|
|
||||||
if(!isCanceled)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new TikTokLiveException("Token requested cancelation");
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNotCancel()
|
|
||||||
{
|
|
||||||
return !isCancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CancelationToken create()
|
|
||||||
{
|
|
||||||
return new CancelationToken();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.utils;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
public class ProtoBufferFileGenerator {
|
||||||
|
|
||||||
|
|
||||||
|
public static String generate(ProtoBufferObject protoBuffObj, String name) {
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var offset = 2;
|
||||||
|
sb.append("message ").append(name).append(" { \n");
|
||||||
|
|
||||||
|
var objects = new TreeMap<String, ProtoBufferObject>();
|
||||||
|
var objectCounter = 0;
|
||||||
|
for (var entry : protoBuffObj.getFields().entrySet()) {
|
||||||
|
var index = entry.getKey();
|
||||||
|
var field = entry.getValue();
|
||||||
|
var fieldName = field.type.toLowerCase() + "Value";
|
||||||
|
var value = field.value;
|
||||||
|
if (field.value instanceof ProtoBufferObject object) {
|
||||||
|
fieldName += objectCounter;
|
||||||
|
value = "";
|
||||||
|
objects.put(fieldName,object);
|
||||||
|
objectCounter++;
|
||||||
|
|
||||||
|
}
|
||||||
|
for (var i = 0; i < offset; i++) {
|
||||||
|
sb.append(" ");
|
||||||
|
}
|
||||||
|
sb.append(field.type).append(" ").append(fieldName)
|
||||||
|
.append(" ")
|
||||||
|
.append("=")
|
||||||
|
.append(" ")
|
||||||
|
.append(index)
|
||||||
|
.append(";")
|
||||||
|
.append(" //")
|
||||||
|
.append(value)
|
||||||
|
.append("\n");
|
||||||
|
}
|
||||||
|
sb.append(" \n");
|
||||||
|
for(var object : objects.entrySet())
|
||||||
|
{
|
||||||
|
var structure = generate(object.getValue(),object.getKey());
|
||||||
|
sb.append(structure);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sb.append(" \n");
|
||||||
|
sb.append("} \n");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.utils;
|
||||||
|
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class ProtoBufferJsonGenerator {
|
||||||
|
public static JsonObject genratejson(ProtoBufferObject protoBuffObj) {
|
||||||
|
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
for (var entry : protoBuffObj.getFields().entrySet()) {
|
||||||
|
var fieldName = entry.getKey() + "_" + entry.getValue().type;
|
||||||
|
if (entry.getValue().value instanceof ProtoBufferObject protoObj)
|
||||||
|
{
|
||||||
|
JsonObject childJson = genratejson(protoObj);
|
||||||
|
jsonObject.add(fieldName, childJson);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = entry.getValue().value.toString();
|
||||||
|
jsonObject.addProperty(fieldName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String generate(ProtoBufferObject protoBufferObject) {
|
||||||
|
var json = genratejson(protoBufferObject);
|
||||||
|
var gson = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
return gson.toJson(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.utils;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
public class ProtoBufferObject {
|
||||||
|
@Getter
|
||||||
|
private final Map<Integer, ProtoBufferField> fields;
|
||||||
|
|
||||||
|
public ProtoBufferObject() {
|
||||||
|
this.fields = new TreeMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addField(int index, String type, Object value) {
|
||||||
|
fields.put(index, new ProtoBufferField(type, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addField(int index, ProtoBufferField value) {
|
||||||
|
fields.put(index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String toProtoFile()
|
||||||
|
{
|
||||||
|
return ProtoBufferFileGenerator.generate(this,"UnknownMessage");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toJson()
|
||||||
|
{
|
||||||
|
return ProtoBufferJsonGenerator.generate(this);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toString(0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString(int offset ,boolean nested) {
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.append("\n");
|
||||||
|
for (var entry : fields.entrySet()) {
|
||||||
|
var index = entry.getKey();
|
||||||
|
var field = entry.getValue();
|
||||||
|
|
||||||
|
for(var i =0;i<offset;i++)
|
||||||
|
{
|
||||||
|
sb.append(" ");
|
||||||
|
}
|
||||||
|
sb.append(index).append(" ")
|
||||||
|
.append(field.type).append(" ");
|
||||||
|
|
||||||
|
var value = field.value;
|
||||||
|
if (value instanceof ProtoBufferObject child) {
|
||||||
|
sb.append(child.toString(offset+2,nested));
|
||||||
|
} else {
|
||||||
|
sb.append(entry.getValue().value);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ProtoBufferField {
|
||||||
|
public String type;
|
||||||
|
|
||||||
|
public Object value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.utils;
|
||||||
|
|
||||||
|
import com.google.protobuf.ByteString;
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
import com.google.protobuf.UnknownFieldSet;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class ProtocolUtils {
|
||||||
|
public static String toBase64(byte[] bytes) {
|
||||||
|
|
||||||
|
return Base64.getEncoder().encodeToString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toBase64(WebcastResponse.Message bytes) {
|
||||||
|
return Base64.getEncoder().encodeToString(bytes.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static byte[] fromBase64(String base64) {
|
||||||
|
|
||||||
|
return Base64.getDecoder().decode(base64);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProtoBufferObject getProtocolBufferStructure(byte[] bytes) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
var files = UnknownFieldSet.parseFrom(bytes);
|
||||||
|
var protoBufferObject = new ProtoBufferObject();
|
||||||
|
createStructure(files, protoBufferObject);
|
||||||
|
return protoBufferObject;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void createStructure(UnknownFieldSet unknownFieldSet, ProtoBufferObject root) throws InvalidProtocolBufferException {
|
||||||
|
for (var entry : unknownFieldSet.asMap().entrySet()) {
|
||||||
|
var objectValue = entry.getValue();
|
||||||
|
var type = "undefind";
|
||||||
|
Object value = null;
|
||||||
|
var index = entry.getKey();
|
||||||
|
if (!objectValue.getLengthDelimitedList().isEmpty()) {
|
||||||
|
var nestedObject = new ProtoBufferObject();
|
||||||
|
for (var str : objectValue.getLengthDelimitedList()) {
|
||||||
|
try {
|
||||||
|
var nestedFieldsSet = UnknownFieldSet.parseFrom(str);
|
||||||
|
createStructure(nestedFieldsSet, nestedObject);
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
type = "string";
|
||||||
|
value = str.toStringUtf8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (value != null) {
|
||||||
|
root.addField(index, "string", value);
|
||||||
|
} else {
|
||||||
|
root.addField(index, "object", nestedObject);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!objectValue.getFixed32List().isEmpty()) {
|
||||||
|
type = "Fixed32List";
|
||||||
|
value = objectValue.getFixed32List();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!objectValue.getFixed64List().isEmpty()) {
|
||||||
|
type = "Fixed64List";
|
||||||
|
value = objectValue.getFixed64List();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!objectValue.getGroupList().isEmpty()) {
|
||||||
|
type = "getGroupList";
|
||||||
|
value = objectValue.getGroupList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!objectValue.getVarintList().isEmpty()) {
|
||||||
|
type = "int";
|
||||||
|
value = objectValue.getVarintList().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
root.addField(index, type, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WebcastResponse.Message fromBase64ToMessage(String base64) throws InvalidProtocolBufferException {
|
||||||
|
var bytes = fromBase64(base64);
|
||||||
|
return WebcastResponse.Message.parseFrom(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -177,6 +177,8 @@ message WebcastCaptionMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Comment sent by User
|
// Comment sent by User
|
||||||
//@WebcastChatMessage
|
//@WebcastChatMessage
|
||||||
message WebcastChatMessage {
|
message WebcastChatMessage {
|
||||||
|
|||||||
@@ -40,10 +40,14 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandl
|
|||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
|
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokRoomInfoEventHandler;
|
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokSocialMediaEventHandler;
|
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.events.TikTokCommonEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.events.TikTokGiftEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.events.TikTokRoomInfoEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.events.TikTokSocialMediaEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
||||||
@@ -54,6 +58,7 @@ import io.github.jwdeveloper.tiktok.live.LiveClient;
|
|||||||
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
|
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
|
||||||
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||||
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
|
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.*;
|
||||||
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
||||||
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
|
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
|
||||||
|
|
||||||
@@ -67,9 +72,11 @@ import java.util.logging.*;
|
|||||||
public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||||
|
|
||||||
protected final ClientSettings clientSettings;
|
protected final ClientSettings clientSettings;
|
||||||
|
|
||||||
protected final Logger logger;
|
protected final Logger logger;
|
||||||
protected final TikTokEventObserver tikTokEventHandler;
|
protected final TikTokEventObserver tikTokEventHandler;
|
||||||
protected final List<TikTokEventListener> listeners;
|
protected final List<TikTokEventListener> listeners;
|
||||||
|
protected Consumer<TikTokMapper> onCustomMappings;
|
||||||
|
|
||||||
public TikTokLiveClientBuilder(String userName) {
|
public TikTokLiveClientBuilder(String userName) {
|
||||||
this.tikTokEventHandler = new TikTokEventObserver();
|
this.tikTokEventHandler = new TikTokEventObserver();
|
||||||
@@ -77,10 +84,18 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
this.clientSettings.setHostName(userName);
|
this.clientSettings.setHostName(userName);
|
||||||
this.logger = Logger.getLogger(TikTokLive.class.getSimpleName() + " " + userName);
|
this.logger = Logger.getLogger(TikTokLive.class.getSimpleName() + " " + userName);
|
||||||
this.listeners = new ArrayList<>();
|
this.listeners = new ArrayList<>();
|
||||||
|
this.onCustomMappings = (e) -> {
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> consumer) {
|
|
||||||
consumer.accept(clientSettings);
|
public LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings) {
|
||||||
|
this.onCustomMappings = onCustomMappings;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> onConfigure) {
|
||||||
|
onConfigure.accept(clientSettings);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,8 +119,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
throw new TikTokLiveException("HostName can not be null");
|
throw new TikTokLiveException("HostName can not be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientSettings.getHostName().startsWith("@"))
|
if (clientSettings.getHostName().startsWith("@")) {
|
||||||
{
|
|
||||||
clientSettings.setHostName(clientSettings.getHostName().substring(1));
|
clientSettings.setHostName(clientSettings.getHostName().substring(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,9 +149,6 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
if (!clientSettings.isPrintToConsole()) {
|
if (!clientSettings.isPrintToConsole()) {
|
||||||
logger.setLevel(Level.OFF);
|
logger.setLevel(Level.OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveClient build() {
|
public LiveClient build() {
|
||||||
@@ -152,23 +163,14 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
|
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
|
||||||
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
|
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
|
||||||
var giftManager = new TikTokGiftManager(logger);
|
var giftManager = new TikTokGiftManager(logger);
|
||||||
var eventMapper = new TikTokGenericEventMapper();
|
var eventsMapper = createMapper(giftManager, tiktokRoomInfo);
|
||||||
|
var messageHandler = new TikTokMessageHandler(tikTokEventHandler, eventsMapper);
|
||||||
|
|
||||||
var giftHandler = new TikTokGiftEventHandler(giftManager);
|
|
||||||
var roomInfoHandler = new TikTokRoomInfoEventHandler(tiktokRoomInfo);
|
|
||||||
var socialHandler = new TikTokSocialMediaEventHandler(tiktokRoomInfo);
|
|
||||||
|
|
||||||
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler,
|
|
||||||
roomInfoHandler,
|
|
||||||
eventMapper,
|
|
||||||
giftHandler,
|
|
||||||
socialHandler
|
|
||||||
);
|
|
||||||
|
|
||||||
var webSocketClient = new TikTokWebSocketClient(logger,
|
var webSocketClient = new TikTokWebSocketClient(logger,
|
||||||
cookieJar,
|
cookieJar,
|
||||||
clientSettings,
|
clientSettings,
|
||||||
webResponseHandler,
|
messageHandler,
|
||||||
tikTokEventHandler);
|
tikTokEventHandler);
|
||||||
|
|
||||||
return new TikTokLiveClient(tiktokRoomInfo,
|
return new TikTokLiveClient(tiktokRoomInfo,
|
||||||
@@ -181,6 +183,64 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
logger);
|
logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TikTokLiveMapper createMapper(GiftManager giftManager, TikTokRoomInfo roomInfo) {
|
||||||
|
var eventMapper = new TikTokGenericEventMapper();
|
||||||
|
var mapper = new TikTokLiveMapper(eventMapper);
|
||||||
|
|
||||||
|
//ConnectionEvents events
|
||||||
|
var commonHandler = new TikTokCommonEventHandler();
|
||||||
|
var giftHandler = new TikTokGiftEventHandler(giftManager);
|
||||||
|
var roomInfoHandler = new TikTokRoomInfoEventHandler(roomInfo);
|
||||||
|
var socialHandler = new TikTokSocialMediaEventHandler(roomInfo);
|
||||||
|
|
||||||
|
mapper.bytesToEvent(WebcastControlMessage.class, commonHandler::handleWebcastControlMessage);
|
||||||
|
|
||||||
|
//Room status events
|
||||||
|
mapper.bytesToEvent(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
|
||||||
|
mapper.bytesToEvent(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
//Host Interaction events
|
||||||
|
mapper.bytesToEvent(WebcastPollMessage.class, commonHandler::handlePollEvent);
|
||||||
|
mapper.bytesToEvent(WebcastRoomPinMessage.class, commonHandler::handlePinMessage);
|
||||||
|
mapper.webcastObjectToConstructor(WebcastGoalUpdateMessage.class, TikTokGoalUpdateEvent.class);
|
||||||
|
|
||||||
|
//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);
|
||||||
|
|
||||||
|
//Rank events
|
||||||
|
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);
|
||||||
|
|
||||||
|
onCustomMappings.accept(mapper);
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public LiveClient buildAndConnect() {
|
public LiveClient buildAndConnect() {
|
||||||
var client = build();
|
var client = build();
|
||||||
client.connect();
|
client.connect();
|
||||||
@@ -191,11 +251,6 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return build().connectAsync();
|
return build().connectAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveClientBuilder onCustomEvent(EventConsumer<CustomEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(CustomEvent.class, event);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onUnhandledSocial(
|
public TikTokLiveClientBuilder onUnhandledSocial(
|
||||||
EventConsumer<TikTokUnhandledSocialEvent> event) {
|
EventConsumer<TikTokUnhandledSocialEvent> event) {
|
||||||
@@ -203,7 +258,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
public LiveClientBuilder onChest(EventConsumer<TikTokChestEvent> event) {
|
public LiveClientBuilder onChest(EventConsumer<TikTokChestEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokChestEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokChestEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
@@ -259,6 +314,13 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <E extends TikTokEvent> LiveClientBuilder onCustomEvent(Class<E> eventClazz, EventConsumer<E> event) {
|
||||||
|
tikTokEventHandler.subscribe(eventClazz, event);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) {
|
public LiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokRoomInfoEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokRoomInfoEvent.class, event);
|
||||||
@@ -266,7 +328,6 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLivePaused(EventConsumer<TikTokLivePausedEvent> event) {
|
public TikTokLiveClientBuilder onLivePaused(EventConsumer<TikTokLivePausedEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokLivePausedEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokLivePausedEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -25,46 +25,28 @@ package io.github.jwdeveloper.tiktok.handlers;
|
|||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.dto.MessageMetaData;
|
import io.github.jwdeveloper.tiktok.data.dto.MessageMetaData;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent;
|
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
|
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent;
|
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
|
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
import io.github.jwdeveloper.tiktok.utils.Stopwatch;
|
import io.github.jwdeveloper.tiktok.utils.Stopwatch;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class TikTokMessageHandler {
|
public class TikTokMessageHandler {
|
||||||
|
|
||||||
private final Map<String, io.github.jwdeveloper.tiktok.handler.TikTokMessageHandler> handlers;
|
|
||||||
private final TikTokEventObserver tikTokEventHandler;
|
private final TikTokEventObserver tikTokEventHandler;
|
||||||
protected final TikTokGenericEventMapper mapper;
|
private final TikTokLiveMapper mapper;
|
||||||
|
|
||||||
public TikTokMessageHandler(TikTokEventObserver tikTokEventHandler, TikTokGenericEventMapper mapper) {
|
public TikTokMessageHandler(TikTokEventObserver tikTokEventHandler, TikTokLiveMapper mapper) {
|
||||||
handlers = new HashMap<>();
|
|
||||||
this.tikTokEventHandler = tikTokEventHandler;
|
this.tikTokEventHandler = tikTokEventHandler;
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerMapping(Class<?> clazz, Function<byte[], TikTokEvent> func) {
|
|
||||||
handlers.put(clazz.getSimpleName(), messagePayload -> List.of(func.apply(messagePayload)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerMappings(Class<?> clazz, Function<byte[], List<TikTokEvent>> func) {
|
|
||||||
handlers.put(clazz.getSimpleName(), func::apply);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerMapping(Class<?> input, Class<?> output) {
|
|
||||||
registerMapping(input, (e) -> mapper.mapToEvent(input, output, e));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handle(LiveClient client, WebcastResponse webcastResponse) {
|
public void handle(LiveClient client, WebcastResponse webcastResponse) {
|
||||||
tikTokEventHandler.publish(client, new TikTokWebsocketResponseEvent(webcastResponse));
|
tikTokEventHandler.publish(client, new TikTokWebsocketResponseEvent(webcastResponse));
|
||||||
@@ -80,14 +62,13 @@ public abstract class TikTokMessageHandler {
|
|||||||
|
|
||||||
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message) throws Exception {
|
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message) throws Exception {
|
||||||
var messageClassName = message.getMethod();
|
var messageClassName = message.getMethod();
|
||||||
if (!handlers.containsKey(messageClassName)) {
|
if (!mapper.isRegistered(messageClassName)) {
|
||||||
tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message));
|
tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var handler = handlers.get(messageClassName);
|
|
||||||
var stopwatch = new Stopwatch();
|
var stopwatch = new Stopwatch();
|
||||||
stopwatch.start();
|
stopwatch.start();
|
||||||
var events = handler.handle(message.getPayload().toByteArray());
|
var events = mapper.handleMapping(messageClassName, message.getPayload().toByteArray());
|
||||||
var handlingTimeInMs = stopwatch.stop();
|
var handlingTimeInMs = stopwatch.stop();
|
||||||
var metadata = new MessageMetaData(Duration.ofNanos(handlingTimeInMs));
|
var metadata = new MessageMetaData(Duration.ofNanos(handlingTimeInMs));
|
||||||
|
|
||||||
|
|||||||
@@ -1,206 +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.handlers;
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
|
||||||
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.poll.TikTokPollEndEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollStartEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollUpdateEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
|
|
||||||
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.chest.Chest;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokRoomInfoEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokSocialMediaEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.enums.EnvelopeDisplay;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.*;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
|
||||||
|
|
||||||
private final TikTokGiftEventHandler giftHandler;
|
|
||||||
private final TikTokRoomInfoEventHandler roomInfoHandler;
|
|
||||||
private final TikTokSocialMediaEventHandler socialHandler;
|
|
||||||
|
|
||||||
public TikTokMessageHandlerRegistration(TikTokEventObserver tikTokEventHandler,
|
|
||||||
TikTokRoomInfoEventHandler roomInfoHandler,
|
|
||||||
TikTokGenericEventMapper genericTikTokEventMapper,
|
|
||||||
TikTokGiftEventHandler tikTokGiftEventHandler,
|
|
||||||
TikTokSocialMediaEventHandler tikTokSocialMediaEventHandler) {
|
|
||||||
super(tikTokEventHandler, genericTikTokEventMapper);
|
|
||||||
this.giftHandler = tikTokGiftEventHandler;
|
|
||||||
this.roomInfoHandler = roomInfoHandler;
|
|
||||||
this.socialHandler = tikTokSocialMediaEventHandler;
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
|
|
||||||
|
|
||||||
registerMapping(WebcastGiftMessage.class, bytes ->
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
WebcastGiftMessage tiktokData = WebcastGiftMessage.parseFrom(bytes);
|
|
||||||
|
|
||||||
io.github.jwdeveloper.tiktok.messages.data.User tiktokProtocolBufferUser = tiktokData.getUser();
|
|
||||||
io.github.jwdeveloper.tiktok.data.models.users.User tiktokLiveJavaUser = User.map(tiktokProtocolBufferUser);
|
|
||||||
|
|
||||||
return new CustomEvent(tiktokLiveJavaUser, "hello word");
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new TikTokLiveException("Unable to parse our custom event", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//ConnectionEvents events
|
|
||||||
registerMapping(WebcastControlMessage.class, this::handleWebcastControlMessage);
|
|
||||||
|
|
||||||
//Room status events
|
|
||||||
registerMapping(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
|
|
||||||
registerMapping(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
|
|
||||||
|
|
||||||
registerMapping(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
|
|
||||||
|
|
||||||
//User Interactions events
|
|
||||||
registerMapping(WebcastChatMessage.class, TikTokCommentEvent.class);
|
|
||||||
registerMappings(WebcastLikeMessage.class, this::handleLike);
|
|
||||||
registerMappings(WebcastGiftMessage.class, giftHandler::handleGift);
|
|
||||||
registerMapping(WebcastSocialMessage.class, socialHandler::handle);
|
|
||||||
registerMappings(WebcastMemberMessage.class, this::handleMemberMessage);
|
|
||||||
|
|
||||||
//Host Interaction events
|
|
||||||
registerMapping(WebcastPollMessage.class, this::handlePollEvent);
|
|
||||||
registerMapping(WebcastRoomPinMessage.class, this::handlePinMessage);
|
|
||||||
registerMapping(WebcastGoalUpdateMessage.class, TikTokGoalUpdateEvent.class);
|
|
||||||
|
|
||||||
//LinkMic events
|
|
||||||
registerMapping(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
|
|
||||||
registerMapping(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
|
|
||||||
registerMapping(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
|
|
||||||
registerMapping(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
|
|
||||||
|
|
||||||
//Rank events
|
|
||||||
registerMapping(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
|
|
||||||
registerMapping(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
|
|
||||||
registerMapping(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
|
|
||||||
|
|
||||||
//Others events
|
|
||||||
registerMapping(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
|
|
||||||
registerMapping(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
|
|
||||||
registerMapping(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
|
|
||||||
registerMapping(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
|
|
||||||
registerMapping(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
|
|
||||||
registerMapping(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
|
|
||||||
registerMapping(WebcastQuestionNewMessage.class, TikTokQuestionEvent.class);
|
|
||||||
registerMappings(WebcastEnvelopeMessage.class, this::handleEnvelop);
|
|
||||||
registerMapping(WebcastSubNotifyMessage.class, TikTokSubscribeEvent.class);
|
|
||||||
registerMapping(WebcastEmoteChatMessage.class, TikTokEmoteEvent.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private TikTokEvent handleWebcastControlMessage(byte[] msg) {
|
|
||||||
var message = WebcastControlMessage.parseFrom(msg);
|
|
||||||
return switch (message.getAction()) {
|
|
||||||
case STREAM_PAUSED -> new TikTokLivePausedEvent();
|
|
||||||
case STREAM_ENDED -> new TikTokLiveEndedEvent();
|
|
||||||
case STREAM_UNPAUSED -> new TikTokLiveUnpausedEvent();
|
|
||||||
default -> new TikTokUnhandledControlEvent(message);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private List<TikTokEvent> handleMemberMessage(byte[] msg) {
|
|
||||||
var message = WebcastMemberMessage.parseFrom(msg);
|
|
||||||
|
|
||||||
var event = switch (message.getAction()) {
|
|
||||||
case JOINED -> new TikTokJoinEvent(message);
|
|
||||||
case SUBSCRIBED -> new TikTokSubscribeEvent(message);
|
|
||||||
default -> new TikTokUnhandledMemberEvent(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
var roomInfoEvent = roomInfoHandler.handleRoomInfo(tikTokRoomInfo ->
|
|
||||||
{
|
|
||||||
tikTokRoomInfo.setViewersCount(message.getMemberCount());
|
|
||||||
});
|
|
||||||
|
|
||||||
return List.of(event, roomInfoEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<TikTokEvent> handleLike(byte[] msg) {
|
|
||||||
var event = (TikTokLikeEvent) mapper.mapToEvent(WebcastLikeMessage.class, TikTokLikeEvent.class, msg);
|
|
||||||
var roomInfoEvent = roomInfoHandler.handleRoomInfo(tikTokRoomInfo ->
|
|
||||||
{
|
|
||||||
tikTokRoomInfo.setLikesCount(event.getTotalLikes());
|
|
||||||
});
|
|
||||||
return List.of(event, roomInfoEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private TikTokEvent handlePinMessage(byte[] msg) {
|
|
||||||
var pinMessage = WebcastRoomPinMessage.parseFrom(msg);
|
|
||||||
var chatMessage = WebcastChatMessage.parseFrom(pinMessage.getPinnedMessage());
|
|
||||||
var chatEvent = new TikTokCommentEvent(chatMessage);
|
|
||||||
return new TikTokRoomPinEvent(pinMessage, chatEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Probably not working
|
|
||||||
@SneakyThrows
|
|
||||||
private 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);
|
|
||||||
default -> new TikTokPollEvent(poolMessage);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private List<TikTokEvent> handleEnvelop(byte[] data) {
|
|
||||||
var msg = WebcastEnvelopeMessage.parseFrom(data);
|
|
||||||
if (msg.getDisplay() != EnvelopeDisplay.EnvelopeDisplayNew) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
var totalDiamonds = msg.getEnvelopeInfo().getDiamondCount();
|
|
||||||
var totalUsers = msg.getEnvelopeInfo().getPeopleCount();
|
|
||||||
var chest = new Chest(totalDiamonds, totalUsers);
|
|
||||||
|
|
||||||
return List.of(new TikTokChestEvent(chest, msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -74,7 +74,7 @@ public class TikTokGenericEventMapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Method getParsingMethod(Class<?> input) throws NoSuchMethodException {
|
public Method getParsingMethod(Class<?> input) throws NoSuchMethodException {
|
||||||
if (methodCache.containsKey(input)) {
|
if (methodCache.containsKey(input)) {
|
||||||
return methodCache.get(input);
|
return methodCache.get(input);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
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 java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
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) {
|
||||||
|
this.mappers = new HashMap<>();
|
||||||
|
this.genericMapper = genericMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bytesToEvent(String messageName, Function<byte[], TikTokEvent> onMapping) {
|
||||||
|
mappers.put(messageName, messagePayload -> List.of(onMapping.apply(messagePayload)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void webcastObjectToConstructor(Class<? extends GeneratedMessageV3> sourceClass, Class<? extends TikTokEvent> outputClass) {
|
||||||
|
bytesToEvent(sourceClass, (e) -> genericMapper.mapToEvent(sourceClass, outputClass, e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 input) {
|
||||||
|
return mappers.containsKey(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TikTokEvent> handleMapping(String input, byte[] bytes) {
|
||||||
|
if (!isRegistered(input)) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
var mapper = mappers.get(input);
|
||||||
|
var events = mapper.apply(bytes);
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.handlers.events;
|
package io.github.jwdeveloper.tiktok.mappers.events;
|
||||||
|
|
||||||
public class TikTokChestEventHandler {
|
public class TikTokChestEventHandler {
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.mappers.events;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||||
|
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.poll.TikTokPollEndEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollStartEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollUpdateEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.chest.Chest;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.enums.EnvelopeDisplay;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.*;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TikTokCommonEventHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public TikTokEvent handleWebcastControlMessage(byte[] msg) {
|
||||||
|
var message = WebcastControlMessage.parseFrom(msg);
|
||||||
|
return switch (message.getAction()) {
|
||||||
|
case STREAM_PAUSED -> new TikTokLivePausedEvent();
|
||||||
|
case STREAM_ENDED -> new TikTokLiveEndedEvent();
|
||||||
|
case STREAM_UNPAUSED -> new TikTokLiveUnpausedEvent();
|
||||||
|
default -> new TikTokUnhandledControlEvent(message);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public TikTokEvent handlePinMessage(byte[] msg) {
|
||||||
|
var pinMessage = WebcastRoomPinMessage.parseFrom(msg);
|
||||||
|
var chatMessage = WebcastChatMessage.parseFrom(pinMessage.getPinnedMessage());
|
||||||
|
var chatEvent = new TikTokCommentEvent(chatMessage);
|
||||||
|
return new TikTokRoomPinEvent(pinMessage, chatEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO Probably not working
|
||||||
|
@SneakyThrows
|
||||||
|
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);
|
||||||
|
default -> new TikTokPollEvent(poolMessage);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public List<TikTokEvent> handleEnvelop(byte[] data) {
|
||||||
|
var msg = WebcastEnvelopeMessage.parseFrom(data);
|
||||||
|
if (msg.getDisplay() != EnvelopeDisplay.EnvelopeDisplayNew) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
var totalDiamonds = msg.getEnvelopeInfo().getDiamondCount();
|
||||||
|
var totalUsers = msg.getEnvelopeInfo().getPeopleCount();
|
||||||
|
var chest = new Chest(totalDiamonds, totalUsers);
|
||||||
|
|
||||||
|
return List.of(new TikTokChestEvent(chest, msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.handlers.events;
|
package io.github.jwdeveloper.tiktok.mappers.events;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
||||||
@@ -20,17 +20,24 @@
|
|||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.handlers.events;
|
package io.github.jwdeveloper.tiktok.mappers.events;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.TikTokUnhandledMemberEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
||||||
|
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.RankingUser;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLikeMessage;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomUserSeqMessage;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomUserSeqMessage;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -76,4 +83,33 @@ public class TikTokRoomInfoEventHandler {
|
|||||||
tikTokRoomInfo.setLanguage(language);
|
tikTokRoomInfo.setLanguage(language);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public List<TikTokEvent> handleMemberMessage(byte[] msg) {
|
||||||
|
var message = WebcastMemberMessage.parseFrom(msg);
|
||||||
|
|
||||||
|
var event = switch (message.getAction()) {
|
||||||
|
case JOINED -> new TikTokJoinEvent(message);
|
||||||
|
case SUBSCRIBED -> new TikTokSubscribeEvent(message);
|
||||||
|
default -> new TikTokUnhandledMemberEvent(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
var roomInfoEvent = this.handleRoomInfo(tikTokRoomInfo ->
|
||||||
|
{
|
||||||
|
tikTokRoomInfo.setViewersCount(message.getMemberCount());
|
||||||
|
});
|
||||||
|
|
||||||
|
return List.of(event, roomInfoEvent);
|
||||||
|
}
|
||||||
|
@SneakyThrows
|
||||||
|
public List<TikTokEvent> handleLike(byte[] msg)
|
||||||
|
{
|
||||||
|
var message = WebcastLikeMessage.parseFrom(msg);
|
||||||
|
var event = new TikTokLikeEvent(message);
|
||||||
|
var roomInfoEvent = this.handleRoomInfo(tikTokRoomInfo ->
|
||||||
|
{
|
||||||
|
tikTokRoomInfo.setLikesCount(event.getTotalLikes());
|
||||||
|
});
|
||||||
|
return List.of(event, roomInfoEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.handlers.events;
|
package io.github.jwdeveloper.tiktok.mappers.events;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.TikTokUnhandledSocialEvent;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokUnhandledSocialEvent;
|
||||||
@@ -24,11 +24,9 @@ package io.github.jwdeveloper.tiktok.websocket;
|
|||||||
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.ClientSettings;
|
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||||
import io.github.jwdeveloper.tiktok.Constants;
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
|
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
|
||||||
import io.github.jwdeveloper.tiktok.http.HttpUtils;
|
import io.github.jwdeveloper.tiktok.http.HttpUtils;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
@@ -44,7 +42,7 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final ClientSettings clientSettings;
|
private final ClientSettings clientSettings;
|
||||||
private final TikTokCookieJar tikTokCookieJar;
|
private final TikTokCookieJar tikTokCookieJar;
|
||||||
private final TikTokMessageHandlerRegistration webResponseHandler;
|
private final TikTokMessageHandler messageHandler;
|
||||||
private final TikTokEventObserver tikTokEventHandler;
|
private final TikTokEventObserver tikTokEventHandler;
|
||||||
private WebSocketClient webSocketClient;
|
private WebSocketClient webSocketClient;
|
||||||
private TikTokWebSocketPingingTask pingingTask;
|
private TikTokWebSocketPingingTask pingingTask;
|
||||||
@@ -53,12 +51,12 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
public TikTokWebSocketClient(Logger logger,
|
public TikTokWebSocketClient(Logger logger,
|
||||||
TikTokCookieJar tikTokCookieJar,
|
TikTokCookieJar tikTokCookieJar,
|
||||||
ClientSettings clientSettings,
|
ClientSettings clientSettings,
|
||||||
TikTokMessageHandlerRegistration webResponseHandler,
|
TikTokMessageHandler messageHandler,
|
||||||
TikTokEventObserver tikTokEventHandler) {
|
TikTokEventObserver tikTokEventHandler) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.tikTokCookieJar = tikTokCookieJar;
|
this.tikTokCookieJar = tikTokCookieJar;
|
||||||
this.clientSettings = clientSettings;
|
this.clientSettings = clientSettings;
|
||||||
this.webResponseHandler = webResponseHandler;
|
this.messageHandler = messageHandler;
|
||||||
this.tikTokEventHandler = tikTokEventHandler;
|
this.tikTokEventHandler = tikTokEventHandler;
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
}
|
}
|
||||||
@@ -74,7 +72,7 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
webResponseHandler.handle(tikTokLiveClient, webcastResponse);
|
messageHandler.handle(tikTokLiveClient, webcastResponse);
|
||||||
var url = getWebSocketUrl(webcastResponse);
|
var url = getWebSocketUrl(webcastResponse);
|
||||||
webSocketClient = startWebSocket(url, tikTokLiveClient);
|
webSocketClient = startWebSocket(url, tikTokLiveClient);
|
||||||
webSocketClient.connect();
|
webSocketClient.connect();
|
||||||
@@ -107,7 +105,7 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
return new TikTokWebSocketListener(url,
|
return new TikTokWebSocketListener(url,
|
||||||
headers,
|
headers,
|
||||||
3000,
|
3000,
|
||||||
webResponseHandler,
|
messageHandler,
|
||||||
tikTokEventHandler,
|
tikTokEventHandler,
|
||||||
liveClient);
|
liveClient);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
|
|||||||
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastPushFrame;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastPushFrame;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
@@ -44,33 +44,22 @@ import java.util.Optional;
|
|||||||
|
|
||||||
public class TikTokWebSocketListener extends WebSocketClient {
|
public class TikTokWebSocketListener extends WebSocketClient {
|
||||||
|
|
||||||
private final TikTokMessageHandlerRegistration webResponseHandler;
|
private final TikTokMessageHandler messageHandler;
|
||||||
private final TikTokEventObserver tikTokEventHandler;
|
private final TikTokEventObserver tikTokEventHandler;
|
||||||
private final LiveClient tikTokLiveClient;
|
private final LiveClient tikTokLiveClient;
|
||||||
|
|
||||||
public TikTokWebSocketListener(URI serverUri,
|
public TikTokWebSocketListener(URI serverUri,
|
||||||
Map<String, String> httpHeaders,
|
Map<String, String> httpHeaders,
|
||||||
int connectTimeout,
|
int connectTimeout,
|
||||||
TikTokMessageHandlerRegistration webResponseHandler,
|
TikTokMessageHandler messageHandler,
|
||||||
TikTokEventObserver tikTokEventHandler,
|
TikTokEventObserver tikTokEventHandler,
|
||||||
LiveClient tikTokLiveClient) {
|
LiveClient tikTokLiveClient) {
|
||||||
super(serverUri, new Draft_6455(), httpHeaders,connectTimeout);
|
super(serverUri, new Draft_6455(), httpHeaders,connectTimeout);
|
||||||
this.webResponseHandler = webResponseHandler;
|
this.messageHandler = messageHandler;
|
||||||
this.tikTokEventHandler = tikTokEventHandler;
|
this.tikTokEventHandler = tikTokEventHandler;
|
||||||
this.tikTokLiveClient = tikTokLiveClient;
|
this.tikTokLiveClient = tikTokLiveClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOpen(ServerHandshake serverHandshake) {
|
|
||||||
tikTokEventHandler.publish(tikTokLiveClient,new TikTokConnectedEvent());
|
|
||||||
if(isNotClosing())
|
|
||||||
{
|
|
||||||
sendPing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(ByteBuffer bytes)
|
public void onMessage(ByteBuffer bytes)
|
||||||
{
|
{
|
||||||
@@ -85,6 +74,19 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(ServerHandshake serverHandshake) {
|
||||||
|
tikTokEventHandler.publish(tikTokLiveClient,new TikTokConnectedEvent());
|
||||||
|
if(isNotClosing())
|
||||||
|
{
|
||||||
|
sendPing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose(int i, String s, boolean b) {
|
public void onClose(int i, String s, boolean b) {
|
||||||
tikTokEventHandler.publish(tikTokLiveClient,new TikTokDisconnectedEvent());
|
tikTokEventHandler.publish(tikTokLiveClient,new TikTokDisconnectedEvent());
|
||||||
@@ -114,7 +116,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
|||||||
// sendAckId(webResponse.getFetchInterval());
|
// sendAckId(webResponse.getFetchInterval());
|
||||||
}
|
}
|
||||||
|
|
||||||
webResponseHandler.handle(tikTokLiveClient, webResponse);
|
messageHandler.handle(tikTokLiveClient, webResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<WebcastPushFrame> getWebcastWebsocketMessage(byte[] buffer) {
|
private Optional<WebcastPushFrame> getWebcastWebsocketMessage(byte[] buffer) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
|||||||
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
||||||
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
||||||
|
import io.github.jwdeveloper.tiktok.mappers.events.TikTokGiftEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.messages.data.GiftStruct;
|
import io.github.jwdeveloper.tiktok.messages.data.GiftStruct;
|
||||||
import io.github.jwdeveloper.tiktok.messages.data.Image;
|
import io.github.jwdeveloper.tiktok.messages.data.Image;
|
||||||
import io.github.jwdeveloper.tiktok.messages.data.User;
|
import io.github.jwdeveloper.tiktok.messages.data.User;
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
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.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) ->
|
||||||
|
{
|
||||||
|
System.out.println("hello world!");
|
||||||
|
})
|
||||||
|
.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();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CustomChatEvent extends TikTokEvent {
|
||||||
|
private final String langauge;
|
||||||
|
private final String userName;
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
public CustomChatEvent(String language, String userName, String message) {
|
||||||
|
this.langauge = language;
|
||||||
|
this.userName = userName;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLangauge() {
|
||||||
|
return langauge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CustomChatEvent{" +
|
||||||
|
"language='" + langauge + '\'' +
|
||||||
|
", userName='" + userName + '\'' +
|
||||||
|
", message='" + message + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,9 @@ import io.github.jwdeveloper.tiktok.data.events.TikTokSubNotifyEvent;
|
|||||||
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
||||||
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
||||||
|
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@@ -42,6 +44,8 @@ public class SimpleExample {
|
|||||||
// set tiktok username
|
// set tiktok username
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
//Optional checking if host name is correct
|
//Optional checking if host name is correct
|
||||||
if(TikTokLive.isHostNameValid(TIKTOK_HOSTNAME))
|
if(TikTokLive.isHostNameValid(TIKTOK_HOSTNAME))
|
||||||
@@ -50,14 +54,33 @@ public class SimpleExample {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Optional checking if live is online
|
// Optional checking if live is online
|
||||||
if(TikTokLive.isLiveOnline(TIKTOK_HOSTNAME))
|
if (TikTokLive.isLiveOnline(TIKTOK_HOSTNAME)) {
|
||||||
{
|
|
||||||
System.out.println("Live is online!");
|
System.out.println("Live is online!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TikTokLive.newClient("test")
|
||||||
|
.onWebsocketResponse((liveClient, event) ->
|
||||||
|
{
|
||||||
|
var response = event.getResponse();
|
||||||
|
for (var message : response.getMessagesList()) {
|
||||||
|
var name = message.getMethod();
|
||||||
|
var binaryData = message.getPayload();
|
||||||
|
System.out.println("Event name: " + name);
|
||||||
|
if (name.equals("WebcastGiftEvent")) {
|
||||||
|
try {
|
||||||
|
WebcastGiftMessage giftMessage = WebcastGiftMessage.parseFrom(binaryData);
|
||||||
|
var giftName = giftMessage.getGift().getName();
|
||||||
|
var giftId = giftMessage.getGiftId();
|
||||||
|
var userName = giftMessage.getUser().getNickname();
|
||||||
|
System.out.println("Gift: "+giftName+" id: "+giftId+" from user: "+userName);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Mapping error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).buildAndConnect();
|
||||||
|
|
||||||
|
|
||||||
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
|
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
|
||||||
@@ -96,9 +119,8 @@ public class SimpleExample {
|
|||||||
|
|
||||||
|
|
||||||
var tiktokLiveEvent = event.getEvent();
|
var tiktokLiveEvent = event.getEvent();
|
||||||
if(tiktokLiveEvent instanceof TikTokSubNotifyEvent e)
|
if (tiktokLiveEvent instanceof TikTokSubNotifyEvent e) {
|
||||||
{
|
System.out.println("it was subscrible event");
|
||||||
System.out.println("it was subscrible event");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
Binary file not shown.
@@ -26,6 +26,7 @@ import com.google.protobuf.ByteString;
|
|||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
||||||
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
|
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
|
||||||
|
import io.github.jwdeveloper.tiktok.utils.ProtocolUtils;
|
||||||
|
|
||||||
public class MessageUtil {
|
public class MessageUtil {
|
||||||
public static String getContent(WebcastResponse.Message message) {
|
public static String getContent(WebcastResponse.Message message) {
|
||||||
@@ -50,39 +51,11 @@ public class MessageUtil {
|
|||||||
return JsonUtil.messageToJson(deserialized);
|
return JsonUtil.messageToJson(deserialized);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.append("Can not find mapper for " + methodName);
|
sb.append("Can not find protocolbuffer file message representation for " + methodName);
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
try {
|
var structure = ProtocolUtils.getProtocolBufferStructure(bytes);
|
||||||
var files = com.google.protobuf.UnknownFieldSet.parseFrom(bytes);
|
var json =structure.toJson();
|
||||||
for (var field : files.asMap().entrySet())
|
sb.append(json);
|
||||||
{
|
|
||||||
var value = field.getValue();
|
|
||||||
if(!value.getLengthDelimitedList().isEmpty())
|
|
||||||
{
|
|
||||||
sb.append(field.getKey()+" LengthDelimited "+value.getLengthDelimitedList()+" \n");
|
|
||||||
}
|
|
||||||
if(!value.getFixed32List().isEmpty())
|
|
||||||
{
|
|
||||||
sb.append(field.getKey()+" fixed32 "+value.getFixed32List()+" \n");
|
|
||||||
}
|
|
||||||
if(!value.getFixed64List().isEmpty())
|
|
||||||
{
|
|
||||||
sb.append(field.getKey()+" fixed64 "+value.getFixed64List()+" \n");
|
|
||||||
}
|
|
||||||
if(!value.getGroupList().isEmpty())
|
|
||||||
{
|
|
||||||
sb.append(field.getKey()+" group "+value.getGroupList()+" \n");
|
|
||||||
}
|
|
||||||
if(!value.getVarintList().isEmpty())
|
|
||||||
{
|
|
||||||
sb.append(field.getKey()+" varint "+value.getVarintList()+" \n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
sb.append("Error while getting unknown fileds "+e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//String jsonString = JsonFormat.printToString(protobufData);
|
//String jsonString = JsonFormat.printToString(protobufData);
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
|
|||||||
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
|
import io.github.jwdeveloper.tiktok.mappers.events.TikTokGiftEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokRoomInfoEventHandler;
|
import io.github.jwdeveloper.tiktok.mappers.events.TikTokRoomInfoEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokSocialMediaEventHandler;
|
import io.github.jwdeveloper.tiktok.mappers.events.TikTokSocialMediaEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||||
@@ -99,12 +99,9 @@ public class TikTokMockBuilder extends TikTokLiveClientBuilder {
|
|||||||
var requestFactory = new TikTokHttpRequestFactory(cookie);
|
var requestFactory = new TikTokHttpRequestFactory(cookie);
|
||||||
var apiClient = new TikTokHttpClient(cookie, requestFactory);
|
var apiClient = new TikTokHttpClient(cookie, requestFactory);
|
||||||
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
|
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
|
||||||
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler,
|
var mapper = createMapper(giftManager, tiktokRoomInfo);
|
||||||
new TikTokRoomInfoEventHandler(tiktokRoomInfo),
|
var handler = new TikTokMessageHandler(tikTokEventHandler, mapper);
|
||||||
new TikTokGenericEventMapper(),
|
var webSocketClient = new WebsocketClientMock(logger, responses, handler);
|
||||||
new TikTokGiftEventHandler(giftManager),
|
|
||||||
new TikTokSocialMediaEventHandler(tiktokRoomInfo));
|
|
||||||
var webSocketClient = new WebsocketClientMock(logger, responses, webResponseHandler);
|
|
||||||
|
|
||||||
return new LiveClientMock(tiktokRoomInfo,
|
return new LiveClientMock(tiktokRoomInfo,
|
||||||
apiService,
|
apiService,
|
||||||
|
|||||||
Reference in New Issue
Block a user