Breaking changes:

'Gift': changed from class to enum, so now you can handle
incoming gifts in switch

`Events`
- new:
     onGiftComboFinished
- Removed:
      onGiftBrodcast
- Rename:
     onGiftMessage -> onGift
     onRoomPinMessage -> onRoomPin
     onRoomMessage -> onRoom
     onLinkMessage -> onLink
     onBarrageMessage -> onBarrage
     onPollMessage -> onPoll
     onShopMessage -> onShop
     onDetectMessage -> onDetect

`GiftManager`
   added:
      registerGift
      findById
      findByName
      getGifts
   removed:
      getActiveGifts
This commit is contained in:
JW
2023-10-05 09:04:39 +02:00
parent f55cbcae7e
commit f0d7cb0cbc
93 changed files with 5492 additions and 771 deletions

View File

@@ -32,11 +32,12 @@ import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.live.UserManager;
import io.github.jwdeveloper.tiktok.models.ConnectionState;
import io.github.jwdeveloper.tiktok.live.GiftManager;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import java.util.logging.Logger;
@@ -44,7 +45,7 @@ public class TikTokLiveClient implements LiveClient {
private final TikTokRoomInfo liveRoomInfo;
private final TikTokGiftManager tikTokGiftManager;
private final TikTokApiService apiService;
private final TikTokWebSocketClient webSocketClient;
private final SocketClient webSocketClient;
private final TikTokEventObserver tikTokEventHandler;
private final ClientSettings clientSettings;
private final TikTokListenersManager listenersManager;
@@ -52,7 +53,7 @@ public class TikTokLiveClient implements LiveClient {
public TikTokLiveClient(TikTokRoomInfo tikTokLiveMeta,
TikTokApiService tikTokApiService,
TikTokWebSocketClient webSocketClient,
SocketClient webSocketClient,
TikTokGiftManager tikTokGiftManager,
TikTokEventObserver tikTokEventHandler,
ClientSettings clientSettings,
@@ -120,7 +121,7 @@ public class TikTokLiveClient implements LiveClient {
}
else
{
var roomId = apiService.fetchRoomId(liveRoomInfo.getUserName());
var roomId = apiService.fetchRoomId(liveRoomInfo.getHostName());
liveRoomInfo.setRoomId(roomId);
}
@@ -145,16 +146,25 @@ public class TikTokLiveClient implements LiveClient {
return listenersManager;
}
@Override
public Logger getLogger() {
return logger;
}
@Override
public GiftManager getGiftManager() {
return tikTokGiftManager;
}
@Override
public UserManager getUserManager() {
return null;
}
private void setState(ConnectionState connectionState) {
logger.info("TikTokLive client state: " + connectionState.name());
liveRoomInfo.setConnectionState(connectionState);
}
}

View File

@@ -28,12 +28,17 @@ import io.github.jwdeveloper.tiktok.events.TikTokEventConsumer;
import io.github.jwdeveloper.tiktok.events.messages.*;
import io.github.jwdeveloper.tiktok.events.messages.TikTokConnectedEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokGiftComboFinishedEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.events.messages.gift.TikTokGiftComboFinishedEvent;
import io.github.jwdeveloper.tiktok.events.messages.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokFollowEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokBarrageEvent;
import io.github.jwdeveloper.tiktok.events.messages.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokShareEvent;
import io.github.jwdeveloper.tiktok.events.messages.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.events.messages.websocket.TikTokWebsocketUnhandledMessageEvent;
import io.github.jwdeveloper.tiktok.events.messages.websocket.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
@@ -57,10 +62,10 @@ import java.util.logging.Level;
import java.util.logging.Logger;
public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveClientBuilder> {
private final ClientSettings clientSettings;
private final Logger logger;
private final TikTokEventObserver tikTokEventHandler;
private final List<TikTokEventListener> listeners;
protected final ClientSettings clientSettings;
protected final Logger logger;
protected final TikTokEventObserver tikTokEventHandler;
protected final List<TikTokEventListener> listeners;
public TikTokLiveClientBuilder(String userName) {
this.tikTokEventHandler = new TikTokEventObserver();
@@ -80,7 +85,7 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
return this;
}
private void validate() {
protected void validate() {
if (clientSettings.getTimeout() == null) {
clientSettings.setTimeout(Duration.ofSeconds(Constants.DEFAULT_TIMEOUT));
@@ -110,7 +115,7 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
validate();
var tiktokRoomInfo = new TikTokRoomInfo();
tiktokRoomInfo.setUserName(clientSettings.getHostName());
tiktokRoomInfo.setHostName(clientSettings.getHostName());
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
var cookieJar = new TikTokCookieJar();
@@ -289,9 +294,9 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
return this;
}
public TikTokLiveClientBuilder onRoomViewerData(
TikTokEventConsumer<TikTokRoomViewerDataEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomViewerDataEvent.class, event);
public TikTokLiveClientBuilder onRoomUserInfo(
TikTokEventConsumer<TikTokRoomUserInfoEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomUserInfoEvent.class, event);
return this;
}
@@ -325,10 +330,7 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
return this;
}
public TikTokLiveClientBuilder onUnhandled(TikTokEventConsumer<TikTokUnhandledWebsocketMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledWebsocketMessageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onJoin(TikTokEventConsumer<TikTokJoinEvent> event) {
tikTokEventHandler.subscribe(TikTokJoinEvent.class, event);
@@ -379,12 +381,23 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketResponse(TikTokEventConsumer<TikTokWebsocketResponseEvent> event) {
tikTokEventHandler.subscribe(TikTokWebsocketResponseEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketMessage(TikTokEventConsumer<TikTokWebsocketMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokWebsocketMessageEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketUnhandledMessage(TikTokEventConsumer<TikTokWebsocketUnhandledMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokWebsocketUnhandledMessageEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onReconnecting(TikTokEventConsumer<TikTokReconnectingEvent> event) {
tikTokEventHandler.subscribe(TikTokReconnectingEvent.class, event);

View File

@@ -38,7 +38,7 @@ public class TikTokRoomInfo implements LiveRoomInfo
private boolean ageRestricted;
private String userName;
private String hostName;
private ConnectionState connectionState = ConnectionState.DISCONNECTED;

View File

@@ -25,6 +25,7 @@ package io.github.jwdeveloper.tiktok.handlers;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.TikTokEventConsumer;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import java.util.HashMap;
import java.util.HashSet;
@@ -38,7 +39,7 @@ public class TikTokEventObserver {
events = new HashMap<>();
}
public void publish(TikTokLiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
public void publish(LiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
if (events.containsKey(TikTokEvent.class)) {
var handlers = events.get(TikTokEvent.class);
for (var handle : handlers) {

View File

@@ -24,13 +24,14 @@ package io.github.jwdeveloper.tiktok.handlers;
import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokUnhandledWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.events.messages.websocket.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.events.messages.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.events.messages.websocket.TikTokWebsocketUnhandledMessageEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.util.Arrays;
@@ -60,13 +61,12 @@ public abstract class TikTokMessageHandler {
registerMapping(input, (e) -> mapMessageToEvent(input, output, e));
}
public void handle(TikTokLiveClient client, WebcastResponse webcastResponse) {
public void handle(LiveClient client, WebcastResponse webcastResponse) {
tikTokEventHandler.publish(client, new TikTokWebsocketResponseEvent(webcastResponse));
for (var message : webcastResponse.getMessagesList()) {
try
{
try {
handleSingleMessage(client, message);
} catch (Exception e)
{
} catch (Exception e) {
var exception = new TikTokLiveMessageException(message, webcastResponse, e);
tikTokEventHandler.publish(client, new TikTokErrorEvent(exception));
}
@@ -74,12 +74,17 @@ public abstract class TikTokMessageHandler {
}
public void handleSingleMessage(TikTokLiveClient client, WebcastResponse.Message message) throws Exception {
if (!handlers.containsKey(message.getMethod())) {
tikTokEventHandler.publish(client, new TikTokUnhandledWebsocketMessageEvent(message));
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message) throws Exception {
var methodName = message.getMethod();
if (!methodName.contains("Webcast")) {
methodName = "Webcast" + methodName;
}
if (!handlers.containsKey(methodName)) {
tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message));
return;
}
var handler = handlers.get(message.getMethod());
var handler = handlers.get(methodName);
var tiktokEvent = handler.handle(message);
tikTokEventHandler.publish(client, new TikTokWebsocketMessageEvent(tiktokEvent, message));
tikTokEventHandler.publish(client, tiktokEvent);
@@ -89,15 +94,13 @@ public abstract class TikTokMessageHandler {
try {
var parseMethod = inputClazz.getDeclaredMethod("parseFrom", ByteString.class);
var deserialized = parseMethod.invoke(null, message.getPayload());
var constructors = Arrays.stream(outputClass.getConstructors())
.filter(ea -> Arrays.stream(ea.getParameterTypes())
.toList()
.contains(inputClazz))
.findFirst();
if(constructors.isEmpty())
{
if (constructors.isEmpty()) {
throw new TikTokMessageMappingException(inputClazz, outputClass, "Unable to find constructor with input class type");
}

View File

@@ -26,10 +26,16 @@ import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.messages.*;
import io.github.jwdeveloper.tiktok.events.messages.TikTokBarrageEvent;
import io.github.jwdeveloper.tiktok.events.messages.gift.TikTokGiftComboFinishedEvent;
import io.github.jwdeveloper.tiktok.events.messages.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.events.messages.poll.TikTokPollEndEvent;
import io.github.jwdeveloper.tiktok.events.messages.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.events.messages.poll.TikTokPollStartEvent;
import io.github.jwdeveloper.tiktok.events.messages.poll.TikTokPollUpdateEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokFollowEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokShareEvent;
import io.github.jwdeveloper.tiktok.events.objects.Gift;
import io.github.jwdeveloper.tiktok.events.objects.Picture;
import io.github.jwdeveloper.tiktok.events.objects.Text;
@@ -128,7 +134,7 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
(int) giftMessage.getGift().getId(),
giftMessage.getGift().getName(),
giftMessage.getGift().getDiamondCount(),
Picture.Map(giftMessage.getGift().getImage()));
Picture.map(giftMessage.getGift().getImage()));
}
if (giftMessage.getRepeatEnd() > 0) {
@@ -171,8 +177,8 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
}
private TikTokEvent handleRoomUserSeqMessage(WebcastResponse.Message msg) {
var event = (TikTokRoomViewerDataEvent) mapMessageToEvent(WebcastRoomUserSeqMessage.class, TikTokRoomViewerDataEvent.class, msg);
roomInfo.setViewersCount(event.getViewerCount());
var event = (TikTokRoomUserInfoEvent) mapMessageToEvent(WebcastRoomUserSeqMessage.class, TikTokRoomUserInfoEvent.class, msg);
roomInfo.setViewersCount(event.getTotalUsers());
return event;
}

View File

@@ -120,7 +120,7 @@ public class TikTokApiService {
try {
var response = tiktokHttpClient.getJObjectFromWebcastAPI("room/info/", clientSettings.getClientParameters());
var mapper = new LiveRoomMetaMapper();
var liveRoomMeta = mapper.mapFrom(response);
var liveRoomMeta = mapper.map(response);
logger.info("RoomInfo status -> " + liveRoomMeta.getStatus());
return liveRoomMeta;
} catch (Exception e) {

View File

@@ -28,7 +28,7 @@ import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
public class LiveRoomMetaMapper implements Mapper<JsonObject, LiveRoomMeta>
{
@Override
public LiveRoomMeta mapFrom(JsonObject input) {
public LiveRoomMeta map(JsonObject input) {
var liveRoomMeta = new LiveRoomMeta();
if (!input.has("data")) {

View File

@@ -0,0 +1,37 @@
/*
* 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.messages;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.mappers.Mapper;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLikeMessage;
public class TikTokLikeEventMapper implements Mapper<WebcastLikeMessage, TikTokLikeEvent>
{
@Override
public TikTokLikeEvent map(WebcastLikeMessage webcastLikeMessage) {
return null;
}
}

View File

@@ -31,6 +31,7 @@ import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import io.github.jwdeveloper.tiktok.http.HttpUtils;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import org.java_websocket.client.WebSocketClient;
@@ -39,7 +40,7 @@ import java.util.HashMap;
import java.util.TreeMap;
import java.util.logging.Logger;
public class TikTokWebSocketClient {
public class TikTokWebSocketClient implements SocketClient {
private final Logger logger;
private final ClientSettings clientSettings;
private final TikTokCookieJar tikTokCookieJar;
@@ -62,7 +63,7 @@ public class TikTokWebSocketClient {
isConnected = false;
}
public void start(WebcastResponse webcastResponse, TikTokLiveClient tikTokLiveClient) {
public void start(WebcastResponse webcastResponse, LiveClient tikTokLiveClient) {
if (isConnected) {
stop();
}
@@ -90,7 +91,7 @@ public class TikTokWebSocketClient {
}
}
private WebSocketClient startWebSocket(String url, TikTokLiveClient liveClient) {
private WebSocketClient startWebSocket(String url, LiveClient liveClient) {
var cookie = tikTokCookieJar.parseCookies();
var map = new HashMap<String, String>();
map.put("Cookie", cookie);

View File

@@ -30,6 +30,7 @@ import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastPushFrame;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastWebsocketAck;
@@ -46,14 +47,14 @@ public class TikTokWebSocketListener extends WebSocketClient {
private final TikTokMessageHandlerRegistration webResponseHandler;
private final TikTokEventObserver tikTokEventHandler;
private final TikTokLiveClient tikTokLiveClient;
private final LiveClient tikTokLiveClient;
public TikTokWebSocketListener(URI serverUri,
Map<String, String> httpHeaders,
int connectTimeout,
TikTokMessageHandlerRegistration webResponseHandler,
TikTokEventObserver tikTokEventHandler,
TikTokLiveClient tikTokLiveClient) {
LiveClient tikTokLiveClient) {
super(serverUri, new Draft_6455(), httpHeaders,connectTimeout);
this.webResponseHandler = webResponseHandler;
this.tikTokEventHandler = tikTokEventHandler;
@@ -105,7 +106,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
return;
}
var websocketMessage = websocketMessageOptional.get();
sendAckId(websocketMessage.getSeqId());
sendAckId(websocketMessage.getLogId());
var webResponse = getWebResponseMessage(websocketMessage.getPayload());
webResponseHandler.handle(tikTokLiveClient, webResponse);

View File

@@ -35,7 +35,6 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -130,7 +129,7 @@ public class TikTokApiServiceTest
when(clientSettings.getClientParameters()).thenReturn(clientParameters);
when(tiktokHttpClient.getJObjectFromWebcastAPI(anyString(), any())).thenReturn(mockResponse);
when(new LiveRoomMetaMapper().mapFrom(mockResponse)).thenReturn(expectedLiveRoomMeta); // Assuming LiveRoomMetaMapper is a simple mapper class
when(new LiveRoomMetaMapper().map(mockResponse)).thenReturn(expectedLiveRoomMeta); // Assuming LiveRoomMetaMapper is a simple mapper class
LiveRoomMeta liveRoomMeta = tikTokApiService.fetchRoomInfo();

View File

@@ -24,8 +24,8 @@ package io.github.jwdeveloper.tiktok.listener;
import io.github.jwdeveloper.tiktok.annotations.TikTokEventHandler;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.events.messages.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.live.LiveClient;