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-03 01:44:34 +02:00
parent 4690a75f20
commit e76703eae6
190 changed files with 25598 additions and 870 deletions

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.handlers;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
@@ -10,35 +32,32 @@ import java.util.Map;
import java.util.Set;
public class TikTokEventObserver {
private final Map<String, Set<TikTokEventConsumer>> events;
private final Map<Class<?>, Set<TikTokEventConsumer>> events;
public TikTokEventObserver() {
events = new HashMap<>();
}
public void publish(TikTokLiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
if (events.containsKey(TikTokEvent.class.getSimpleName())) {
var handlers = events.get(TikTokEvent.class.getSimpleName());
for(var handle : handlers)
{
if (events.containsKey(TikTokEvent.class)) {
var handlers = events.get(TikTokEvent.class);
for (var handle : handlers) {
handle.onEvent(tikTokLiveClient, tikTokEvent);
}
}
var name = tikTokEvent.getClass().getSimpleName();
if (!events.containsKey(name)) {
if (!events.containsKey(tikTokEvent.getClass())) {
return;
}
var handlers = events.get(name);
for(var handler : handlers)
{
var handlers = events.get(tikTokEvent.getClass());
for (var handler : handlers) {
handler.onEvent(tikTokLiveClient, tikTokEvent);
}
}
public <T extends TikTokEvent> void subscribe(Class<?> clazz, TikTokEventConsumer<T> event)
{
events.computeIfAbsent(clazz.getSimpleName(), e -> new HashSet<>()).add(event);
public <T extends TikTokEvent> void subscribe(Class<?> clazz, TikTokEventConsumer<T> event) {
events.computeIfAbsent(clazz, e -> new HashSet<>()).add(event);
}
public <T extends TikTokEvent> void unsubscribeAll(Class<?> clazz) {
@@ -46,9 +65,22 @@ public class TikTokEventObserver {
}
public <T extends TikTokEvent> void unsubscribe(TikTokEventConsumer<T> consumer) {
for(var entry : events.entrySet())
{
for (var entry : events.entrySet()) {
entry.getValue().remove(consumer);
}
}
public <T extends TikTokEvent> void unsubscribe(Class<?> clazz, TikTokEventConsumer<T> consumer) {
if (clazz == null) {
return;
}
if (!events.containsKey(clazz)) {
return;
}
var eventSet = events.get(clazz);
eventSet.remove(consumer);
}
}

View File

@@ -1,8 +1,29 @@
/*
* 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 com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
@@ -13,57 +34,47 @@ import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.logging.Logger;
public abstract class TikTokMessageHandler {
private final Map<String, io.github.jwdeveloper.tiktok.handler.TikTokMessageHandler> handlers;
private final TikTokEventObserver tikTokEventHandler;
private final ClientSettings clientSettings;
protected final Logger logger;
public TikTokMessageHandler(TikTokEventObserver tikTokEventHandler, ClientSettings clientSettings, Logger logger) {
public TikTokMessageHandler(TikTokEventObserver tikTokEventHandler) {
handlers = new HashMap<>();
this.tikTokEventHandler = tikTokEventHandler;
this.clientSettings = clientSettings;
this.logger = logger;
init();
}
public abstract void init();
public void register(Class<?> clazz, Function<WebcastResponse.Message, TikTokEvent> func) {
public void registerMapping(Class<?> clazz, Function<WebcastResponse.Message, TikTokEvent> func) {
handlers.put(clazz.getSimpleName(), func::apply);
}
public void register(Class<?> input, Class<?> output) {
register(input, (e) -> mapMessageToEvent(input, output, e));
public void registerMapping(Class<?> input, Class<?> output) {
registerMapping(input, (e) -> mapMessageToEvent(input, output, e));
}
public void handle(TikTokLiveClient client, WebcastResponse webcastResponse) {
for (var message : webcastResponse.getMessagesList()) {
try
{
if(clientSettings.isPrintMessageData())
{
var type= message.getType();
var base64 = Base64.getEncoder().encodeToString(message.getBinary().toByteArray());
logger.info(type+": \n "+base64);
}
handleSingleMessage(client, message);
} catch (Exception e) {
} catch (Exception e)
{
var exception = new TikTokLiveMessageException(message, webcastResponse, e);
tikTokEventHandler.publish(client, new TikTokErrorEvent(exception));
}
}
}
private void handleSingleMessage(TikTokLiveClient client, WebcastResponse.Message message) throws Exception {
public void handleSingleMessage(TikTokLiveClient client, WebcastResponse.Message message) throws Exception {
if (!handlers.containsKey(message.getType())) {
tikTokEventHandler.publish(client, new TikTokUnhandledWebsocketMessageEvent(message));
return;

View File

@@ -1,27 +1,48 @@
/*
* 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.ClientSettings;
import io.github.jwdeveloper.tiktok.TikTokGiftManager;
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.objects.Gift;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.messages.*;
import io.github.jwdeveloper.tiktok.models.SocialTypes;
import lombok.SneakyThrows;
import java.util.logging.Logger;
import java.util.regex.Pattern;
public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
private final TikTokGiftManager giftManager;
private final TikTokRoomInfo roomInfo;
private final Pattern socialMediaPattern = Pattern.compile("pm_mt_guidance_viewer_([0-9]+)_share");
public TikTokMessageHandlerRegistration(TikTokEventObserver tikTokEventHandler,
ClientSettings clientSettings,
Logger logger,
TikTokGiftManager giftManager,
TikTokRoomInfo roomInfo) {
super(tikTokEventHandler, clientSettings, logger);
super(tikTokEventHandler);
this.giftManager = giftManager;
this.roomInfo = roomInfo;
}
@@ -30,57 +51,55 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
public void init() {
//ConnectionEvents events
register(WebcastControlMessage.class, this::handleWebcastControlMessage);
register(SystemMessage.class,TikTokRoomMessageEvent.class);
registerMapping(WebcastControlMessage.class, this::handleWebcastControlMessage);
registerMapping(SystemMessage.class, TikTokRoomEvent.class);
//Room status events
register(WebcastLiveIntroMessage.class, TikTokRoomMessageEvent.class);
register(WebcastRoomUserSeqMessage.class, this::handleRoomUserSeqMessage);
register(RoomMessage.class, TikTokRoomMessageEvent.class);
register(WebcastRoomMessage.class, TikTokRoomMessageEvent.class);
register(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
registerMapping(WebcastLiveIntroMessage.class, TikTokRoomEvent.class);
registerMapping(WebcastRoomUserSeqMessage.class, this::handleRoomUserSeqMessage);
registerMapping(RoomMessage.class, TikTokRoomEvent.class);
registerMapping(WebcastRoomMessage.class, TikTokRoomEvent.class);
registerMapping(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
//User Interactions events
register(WebcastChatMessage.class, TikTokCommentEvent.class);
register(WebcastLikeMessage.class, TikTokLikeEvent.class);
register(WebcastGiftMessage.class, this::handleGift);
register(WebcastSocialMessage.class, this::handleSocialMedia);
register(WebcastMemberMessage.class, this::handleMemberMessage);
registerMapping(WebcastChatMessage.class, TikTokCommentEvent.class);
registerMapping(WebcastLikeMessage.class, TikTokLikeEvent.class);
registerMapping(WebcastGiftMessage.class, this::handleGift);
registerMapping(WebcastSocialMessage.class, this::handleSocialMedia);
registerMapping(WebcastMemberMessage.class, this::handleMemberMessage);
//Host Interaction events
register(WebcastPollMessage.class, TikTokPollMessageEvent.class);
register(WebcastRoomPinMessage.class, TikTokRoomPinMessageEvent.class);
register(WebcastGoalUpdateMessage.class, TikTokGoalUpdateEvent.class);
registerMapping(WebcastPollMessage.class, TikTokPollEvent.class);
registerMapping(WebcastRoomPinMessage.class, TikTokRoomPinEvent.class);
registerMapping(WebcastGoalUpdateMessage.class, TikTokGoalUpdateEvent.class);
//LinkMic events
register(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
register(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
register(LinkMicMethod.class, TikTokLinkMicMethodEvent.class);
register(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
register(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
registerMapping(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
registerMapping(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
registerMapping(LinkMicMethod.class, TikTokLinkMicMethodEvent.class);
registerMapping(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
registerMapping(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
//Rank events
register(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
register(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
register(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
registerMapping(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
registerMapping(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
registerMapping(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
//Others events
register(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
register(WebcastMsgDetectMessage.class, TikTokDetectMessageEvent.class);
register(WebcastBarrageMessage.class, TikTokBarrageMessageEvent.class);
register(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
register(WebcastGiftBroadcastMessage.class, TikTokGiftBroadcastEvent.class);
register(WebcastOecLiveShoppingMessage.class, TikTokShopMessageEvent.class);
register(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
register(WebcastQuestionNewMessage.class, TikTokQuestionEvent.class);
register(WebcastEnvelopeMessage.class, TikTokEnvelopeEvent.class);
register(WebcastSubNotifyMessage.class, TikTokSubNotifyEvent.class);
register(WebcastEmoteChatMessage.class, TikTokEmoteEvent.class);
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);
registerMapping(WebcastEnvelopeMessage.class, TikTokEnvelopeEvent.class);
registerMapping(WebcastSubNotifyMessage.class, TikTokSubNotifyEvent.class);
registerMapping(WebcastEmoteChatMessage.class, TikTokEmoteEvent.class);
}
@SneakyThrows
private TikTokEvent handleWebcastControlMessage(WebcastResponse.Message msg) {
var message = WebcastControlMessage.parseFrom(msg.getBinary());
@@ -95,7 +114,23 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
private TikTokEvent handleGift(WebcastResponse.Message msg) {
var giftMessage = WebcastGiftMessage.parseFrom(msg.getBinary());
giftManager.updateActiveGift(giftMessage);
return new TikTokGiftMessageEvent(giftMessage);
var gift = giftManager.findById((int) giftMessage.getGiftId());
if (gift == Gift.UNDEFINED) {
gift = giftManager.findByName(giftMessage.getGift().getName());
}
if (gift == Gift.UNDEFINED) {
gift = giftManager.registerGift(
(int) giftMessage.getGift().getId(),
giftMessage.getGift().getName(),
giftMessage.getGift().getDiamondCount());
}
if (giftMessage.getRepeatEnd() > 0) {
return new TikTokGiftComboFinishedEvent(gift, giftMessage);
}
return new TikTokGiftEvent(gift, giftMessage);
}
@SneakyThrows
@@ -103,11 +138,9 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
var message = WebcastSocialMessage.parseFrom(msg.getBinary());
var socialType = message.getHeader().getSocialData().getType();
var pattern = Pattern.compile("pm_mt_guidance_viewer_([0-9]+)_share");
var matcher = pattern.matcher(socialType);
var matcher = socialMediaPattern.matcher(socialType);
if (matcher.find())
{
if (matcher.find()) {
var value = matcher.group(1);
var number = Integer.parseInt(value);
return new TikTokShareEvent(message, number);
@@ -132,9 +165,8 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
};
}
private TikTokEvent handleRoomUserSeqMessage(WebcastResponse.Message msg)
{
var event = (TikTokRoomViewerDataEvent)mapMessageToEvent(WebcastRoomUserSeqMessage.class, TikTokRoomViewerDataEvent.class, msg);
private TikTokEvent handleRoomUserSeqMessage(WebcastResponse.Message msg) {
var event = (TikTokRoomViewerDataEvent) mapMessageToEvent(WebcastRoomUserSeqMessage.class, TikTokRoomViewerDataEvent.class, msg);
roomInfo.setViewersCount(event.getViewerCount());
return event;
}