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-11 01:20:07 +02:00
parent 043dfe95d8
commit de27e71e93
64 changed files with 548 additions and 630 deletions

View File

@@ -32,13 +32,15 @@ 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.live.LiveRoomMeta;
import io.github.jwdeveloper.tiktok.models.ConnectionState;
import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.logging.Logger;
public class TikTokLiveClient implements LiveClient {
@@ -70,22 +72,37 @@ public class TikTokLiveClient implements LiveClient {
}
public void connectAsync(Consumer<LiveClient> onConnection) {
CompletableFuture.supplyAsync(() ->
{
connect();
onConnection.accept(this);
return this;
});
}
public CompletableFuture<LiveClient> connectAsync() {
return CompletableFuture.supplyAsync(() ->
{
connect();
return this;
});
}
public void connect() {
try {
tryConnect();
}
catch (TikTokLiveException e)
} catch (TikTokLiveException e)
{
setState(ConnectionState.DISCONNECTED);
tikTokEventHandler.publish(this, new TikTokErrorEvent(e));
tikTokEventHandler.publish(this, new TikTokDisconnectedEvent());
if(e instanceof TikTokLiveOfflineHostException && clientSettings.isRetryOnConnectionFailure())
{
if (e instanceof TikTokLiveOfflineHostException && clientSettings.isRetryOnConnectionFailure()) {
try {
Thread.sleep(clientSettings.getRetryConnectionTimeout().toMillis());
} catch (Exception ignored) {
}
catch (Exception ignored){}
logger.info("Reconnecting");
tikTokEventHandler.publish(this, new TikTokReconnectingEvent());
this.connect();
@@ -108,27 +125,22 @@ public class TikTokLiveClient implements LiveClient {
if (liveRoomInfo.hasConnectionState(ConnectionState.CONNECTING))
throw new TikTokLiveException("Already connecting");
logger.info("Connecting");
setState(ConnectionState.CONNECTING);
apiService.updateSessionId();
if(clientSettings.getRoomId() != null)
{
if (clientSettings.getRoomId() != null) {
liveRoomInfo.setRoomId(clientSettings.getRoomId());
logger.info("Using roomID from settings: "+clientSettings.getRoomId());
}
else
{
logger.info("Using roomID from settings: " + clientSettings.getRoomId());
} else {
var roomId = apiService.fetchRoomId(liveRoomInfo.getHostName());
liveRoomInfo.setRoomId(roomId);
}
var roomData = apiService.fetchRoomInfo();
if (roomData.getStatus() == 0 || roomData.getStatus() == 4) {
throw new TikTokLiveOfflineHostException("LiveStream for HostID could not be found. Is the Host online?");
if (roomData.getStatus() != LiveRoomMeta.LiveRoomStatus.HostOnline) {
throw new TikTokLiveOfflineHostException("LiveStream for Host name could not be found. Is the Host online?");
}
var clientData = apiService.fetchClientData();
@@ -140,9 +152,9 @@ public class TikTokLiveClient implements LiveClient {
public LiveRoomInfo getRoomInfo() {
return liveRoomInfo;
}
@Override
public ListenersManager getListenersManager()
{
public ListenersManager getListenersManager() {
return listenersManager;
}
@@ -156,11 +168,6 @@ public class TikTokLiveClient implements LiveClient {
return tikTokGiftManager;
}
@Override
public UserManager getUserManager() {
return null;
}
private void setState(ConnectionState connectionState) {
logger.info("TikTokLive client state: " + connectionState.name());

View File

@@ -22,26 +22,21 @@
*/
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.builder.EventBuilder;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.TikTokConnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboFinishedEvent;
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.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomUserInfoEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokBarrageEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokShareEvent;
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.TikTokWebsocketUnhandledMessageEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
@@ -53,6 +48,7 @@ import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
@@ -64,8 +60,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.logging.*;
public class TikTokLiveClientBuilder implements LiveClientBuilder
{
public class TikTokLiveClientBuilder implements LiveClientBuilder {
protected final ClientSettings clientSettings;
protected final Logger logger;
@@ -76,7 +71,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder
this.tikTokEventHandler = new TikTokEventObserver();
this.clientSettings = Constants.DefaultClientSettings();
this.clientSettings.setHostName(userName);
this.logger = Logger.getLogger(TikTokLive.class.getSimpleName()+" "+userName);
this.logger = Logger.getLogger(TikTokLive.class.getSimpleName() + " " + userName);
this.listeners = new ArrayList<>();
}
@@ -105,16 +100,21 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder
throw new TikTokLiveException("HostName can not be null");
}
if (clientSettings.getHostName().startsWith("@"))
{
clientSettings.setHostName(clientSettings.getHostName().substring(1));
}
var params = clientSettings.getClientParameters();
params.put("app_language", clientSettings.getClientLanguage());
params.put("webcast_language", clientSettings.getClientLanguage());
logger.setLevel(clientSettings.getLogLevel());
var handler = new ConsoleHandler();
handler.setFormatter(new Formatter() {
@Override
public String format(LogRecord record)
{
public String format(LogRecord record) {
var sb = new StringBuilder();
sb.append(ConsoleColors.GREEN).append("[").append(record.getLoggerName()).append("] ");
sb.append(ConsoleColors.GREEN).append("[").append(record.getLevel()).append("]: ");
@@ -126,9 +126,13 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder
logger.setUseParentHandlers(false);
logger.addHandler(handler);
logger.setLevel(clientSettings.getLogLevel());
if (clientSettings.isPrintToConsole() && clientSettings.getLogLevel() == Level.OFF) {
logger.setLevel(Level.ALL);
}
}
public LiveClient build() {
@@ -171,7 +175,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder
}
public CompletableFuture<LiveClient> buildAndConnectAsync() {
return CompletableFuture.supplyAsync(this::buildAndConnect);
return build().connectAsync();
}
public TikTokLiveClientBuilder onUnhandledSocial(
@@ -261,8 +265,8 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder
return this;
}
public TikTokLiveClientBuilder onGiftCombo(EventConsumer<TikTokGiftComboFinishedEvent> event) {
tikTokEventHandler.subscribe(TikTokGiftComboFinishedEvent.class, event);
public TikTokLiveClientBuilder onGiftCombo(EventConsumer<TikTokGiftComboEvent> event) {
tikTokEventHandler.subscribe(TikTokGiftComboEvent.class, event);
return this;
}
@@ -318,7 +322,6 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder
}
public TikTokLiveClientBuilder onComment(EventConsumer<TikTokCommentEvent> event) {
tikTokEventHandler.subscribe(TikTokCommentEvent.class, event);
return this;
@@ -328,6 +331,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder
tikTokEventHandler.subscribe(TikTokGoalUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRankUpdate(EventConsumer<TikTokRankUpdateEvent> event) {
tikTokEventHandler.subscribe(TikTokRankUpdateEvent.class, event);
return this;
@@ -349,7 +353,6 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder
}
public TikTokLiveClientBuilder onJoin(EventConsumer<TikTokJoinEvent> event) {
tikTokEventHandler.subscribe(TikTokJoinEvent.class, event);
return this;
@@ -404,6 +407,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder
tikTokEventHandler.subscribe(TikTokWebsocketResponseEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokWebsocketMessageEvent.class, event);

View File

@@ -26,7 +26,7 @@ import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.TikTokBarrageEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboFinishedEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEndEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
@@ -142,7 +142,7 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
}
if (giftMessage.getRepeatEnd() > 0) {
return new TikTokGiftComboFinishedEvent(gift, giftMessage);
return new TikTokGiftComboEvent(gift, giftMessage);
}
return new TikTokGiftEvent(gift, giftMessage);

View File

@@ -30,6 +30,7 @@ import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
import io.github.jwdeveloper.tiktok.mappers.LiveRoomMetaMapper;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import javax.script.ScriptEngineManager;
import java.util.HashMap;
import java.util.logging.Logger;
import java.util.regex.Pattern;
@@ -116,22 +117,24 @@ public class TikTokApiService {
public LiveRoomMeta fetchRoomInfo() {
logger.info("Fetch RoomInfo");
logger.info("Fetching RoomInfo");
try {
var response = tiktokHttpClient.getJObjectFromWebcastAPI("room/info/", clientSettings.getClientParameters());
var mapper = new LiveRoomMetaMapper();
var liveRoomMeta = mapper.map(response);
logger.info("RoomInfo status -> " + liveRoomMeta.getStatus());
return liveRoomMeta;
} catch (Exception e) {
} catch (Exception e)
{
throw new TikTokLiveRequestException("Failed to fetch room info from WebCast, see stacktrace for more info.", e);
}
}
public WebcastResponse fetchClientData() {
logger.info("Fetch ClientData");
logger.info("Fetching ClientData");
try {
var response = tiktokHttpClient.getDeserializedMessage("im/fetch/", clientSettings.getClientParameters());
var response = tiktokHttpClient.getSigningServerMessage("im/fetch/", clientSettings.getClientParameters());
clientSettings.getClientParameters().put("cursor", response.getCursor());
clientSettings.getClientParameters().put("internal_ext", response.getInternalExt());
return response;

View File

@@ -73,7 +73,7 @@ public class TikTokHttpClient {
return jsonObject;
}
public WebcastResponse getDeserializedMessage(String path, Map<String, Object> parameters) {
public WebcastResponse getSigningServerMessage(String path, Map<String, Object> parameters) {
var bytes = getSignRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
try {
return WebcastResponse.parseFrom(bytes);

View File

@@ -25,11 +25,11 @@ package io.github.jwdeveloper.tiktok.listener;
import io.github.jwdeveloper.tiktok.annotations.TikTokEventHandler;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import io.github.jwdeveloper.tiktok.exceptions.TikTokEventListenerMethodException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -42,7 +42,10 @@ public class TikTokListenersManager implements ListenersManager {
public TikTokListenersManager(List<TikTokEventListener> listeners, TikTokEventObserver tikTokEventHandler) {
this.eventObserver = tikTokEventHandler;
this.bindingModels = new ArrayList<>(listeners.stream().map(this::bindToEvents).toList());
this.bindingModels = new ArrayList<>(listeners.size());
for (var listener : listeners) {
addListener(listener);
}
}
@Override

View File

@@ -25,9 +25,14 @@ package io.github.jwdeveloper.tiktok.mappers;
import com.google.gson.JsonObject;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
public class LiveRoomMetaMapper
{
public class LiveRoomMetaMapper {
/**
* 0 - Unknown
* 1 - ?
* 2 - Online
* 3 - ?
* 4 - Offline
*/
public LiveRoomMeta map(JsonObject input) {
var liveRoomMeta = new LiveRoomMeta();
@@ -35,16 +40,27 @@ public class LiveRoomMetaMapper
return liveRoomMeta;
}
var data = input.getAsJsonObject("data");
if (data.has("status")) {
var status = data.get("status");
liveRoomMeta.setStatus(status.getAsInt());
var statusId = status.getAsInt();
var statusValue = switch (statusId) {
case 0 -> LiveRoomMeta.LiveRoomStatus.HostNotFound;
case 2 -> LiveRoomMeta.LiveRoomStatus.HostOnline;
case 4 -> LiveRoomMeta.LiveRoomStatus.HostOffline;
default-> LiveRoomMeta.LiveRoomStatus.HostNotFound;
};
liveRoomMeta.setStatus(statusValue);
}
else
{
liveRoomMeta.setStatus(LiveRoomMeta.LiveRoomStatus.HostNotFound);
}
if(data.has("age_restricted"))
{
if (data.has("age_restricted")) {
var element = data.getAsJsonObject("age_restricted");
var restricted= element.get("restricted").getAsBoolean();
var restricted = element.get("restricted").getAsBoolean();
liveRoomMeta.setAgeRestricted(restricted);
}
return liveRoomMeta;

View File

@@ -75,7 +75,7 @@ public class TikTokWebSocketClient implements SocketClient {
try {
if (clientSettings.isHandleExistingEvents()) {
logger.info("Handling existing messages");
logger.info("Handling existing events");
webResponseHandler.handle(tikTokLiveClient, webcastResponse);
}
var url = getWebSocketUrl(webcastResponse);