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

@@ -17,6 +17,11 @@
<version>3.24.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
<build>

View File

@@ -22,11 +22,8 @@
*/
package io.github.jwdeveloper.tiktok.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public enum EventType
{
Control, Message, Custom
Control, Message, Custom, Debug
}

View File

@@ -23,13 +23,16 @@
package io.github.jwdeveloper.tiktok.events;
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import lombok.Getter;
/*
Base class for all events
*/
@Getter
public abstract class TikTokEvent
{
public abstract class TikTokEvent {
public String toJson() {
return JsonUtil.toJson(this);
}
}

View File

@@ -23,103 +23,113 @@
package io.github.jwdeveloper.tiktok.events;
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.TikTokBarrageEvent;
import io.github.jwdeveloper.tiktok.events.messages.poll.TikTokPollEvent;
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.social.TikTokShareEvent;
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;
public interface TikTokEventBuilder<T> {
T onUnhandledSocial(TikTokEventConsumer<TikTokUnhandledSocialEvent> event);
T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);
T onEnvelope(TikTokEventConsumer<TikTokEnvelopeEvent> event);
T onShop(TikTokEventConsumer<TikTokShopEvent> event);
T onDetect(TikTokEventConsumer<TikTokDetectEvent> event);
T onLinkLayer(TikTokEventConsumer<TikTokLinkLayerEvent> event);
T onConnected(TikTokEventConsumer<TikTokConnectedEvent> event);
T onCaption(TikTokEventConsumer<TikTokCaptionEvent> event);
T onQuestion(TikTokEventConsumer<TikTokQuestionEvent> event);
T onRoomPin(TikTokEventConsumer<TikTokRoomPinEvent> event);
T onRoom(TikTokEventConsumer<TikTokRoomEvent> event);
T onLivePaused(TikTokEventConsumer<TikTokLivePausedEvent> event);
T onLike(TikTokEventConsumer<TikTokLikeEvent> event);
T onBarrage(TikTokEventConsumer<TikTokBarrageEvent> event);
T onGift(TikTokEventConsumer<TikTokGiftEvent> event);
T onLinkMicArmies(TikTokEventConsumer<TikTokLinkMicArmiesEvent> event);
T onEmote(TikTokEventConsumer<TikTokEmoteEvent> event);
T onUnauthorizedMember(TikTokEventConsumer<TikTokUnauthorizedMemberEvent> event);
T onInRoomBanner(TikTokEventConsumer<TikTokInRoomBannerEvent> event);
T onLinkMicMethod(TikTokEventConsumer<TikTokLinkMicMethodEvent> event);
T onSubscribe(TikTokEventConsumer<TikTokSubscribeEvent> event);
T onPoll(TikTokEventConsumer<TikTokPollEvent> event);
T onFollow(TikTokEventConsumer<TikTokFollowEvent> event);
T onRoomViewerData(TikTokEventConsumer<TikTokRoomViewerDataEvent> event);
T onGoalUpdate(TikTokEventConsumer<TikTokGoalUpdateEvent> event);
T onRoomUserInfo(TikTokEventConsumer<TikTokRoomUserInfoEvent> event);
T onComment(TikTokEventConsumer<TikTokCommentEvent> event);
T onRankUpdate(TikTokEventConsumer<TikTokRankUpdateEvent> event);
T onIMDelete(TikTokEventConsumer<TikTokIMDeleteEvent> event);
T onLiveEnded(TikTokEventConsumer<TikTokLiveEndedEvent> event);
T onError(TikTokEventConsumer<TikTokErrorEvent> event);
T onUnhandled(TikTokEventConsumer<TikTokUnhandledWebsocketMessageEvent> event);
T onJoin(TikTokEventConsumer<TikTokJoinEvent> event);
T onRankText(TikTokEventConsumer<TikTokRankTextEvent> event);
T onShare(TikTokEventConsumer<TikTokShareEvent> event);
T onUnhandledMember(TikTokEventConsumer<TikTokUnhandledMemberEvent> event);
T onSubNotify(TikTokEventConsumer<TikTokSubNotifyEvent> event);
T onLinkMicBattle(TikTokEventConsumer<TikTokLinkMicBattleEvent> event);
T onDisconnected(TikTokEventConsumer<TikTokDisconnectedEvent> event);
T onGiftCombo(TikTokEventConsumer<TikTokGiftComboFinishedEvent> event);
T onUnhandledControl(TikTokEventConsumer<TikTokUnhandledControlEvent> event);
T onEvent(TikTokEventConsumer<TikTokEvent> event);
T onWebsocketMessage(TikTokEventConsumer<TikTokWebsocketMessageEvent> event);
T onWebsocketResponse(TikTokEventConsumer<TikTokWebsocketResponseEvent> event);
T onWebsocketUnhandledMessage(TikTokEventConsumer<TikTokWebsocketUnhandledMessageEvent> event);
T onGiftCombo(TikTokEventConsumer<TikTokGiftComboFinishedEvent> event);
T onGift(TikTokEventConsumer<TikTokGiftEvent> event);
T onSubscribe(TikTokEventConsumer<TikTokSubscribeEvent> event);
T onFollow(TikTokEventConsumer<TikTokFollowEvent> event);
T onLike(TikTokEventConsumer<TikTokLikeEvent> event);
T onEmote(TikTokEventConsumer<TikTokEmoteEvent> event);
T onJoin(TikTokEventConsumer<TikTokJoinEvent> event);
T onShare(TikTokEventConsumer<TikTokShareEvent> event);
T onUnhandledSocial(TikTokEventConsumer<TikTokUnhandledSocialEvent> event);
T onLivePaused(TikTokEventConsumer<TikTokLivePausedEvent> event);
T onLiveEnded(TikTokEventConsumer<TikTokLiveEndedEvent> event);
T onConnected(TikTokEventConsumer<TikTokConnectedEvent> event);
T onReconnecting(TikTokEventConsumer<TikTokReconnectingEvent> event);
T onDisconnected(TikTokEventConsumer<TikTokDisconnectedEvent> event);
T onError(TikTokEventConsumer<TikTokErrorEvent> event);
T onEvent(TikTokEventConsumer<TikTokEvent> event);
// TODO implement later
//T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);
//T onEnvelope(TikTokEventConsumer<TikTokEnvelopeEvent> event);
//T onShop(TikTokEventConsumer<TikTokShopEvent> event);
//T onDetect(TikTokEventConsumer<TikTokDetectEvent> event);
//T onLinkLayer(TikTokEventConsumer<TikTokLinkLayerEvent> event);
//T onCaption(TikTokEventConsumer<TikTokCaptionEvent> event);
//T onQuestion(TikTokEventConsumer<TikTokQuestionEvent> event);
//T onRoomPin(TikTokEventConsumer<TikTokRoomPinEvent> event);
//T onBarrage(TikTokEventConsumer<TikTokBarrageEvent> event);
//T onLinkMicArmies(TikTokEventConsumer<TikTokLinkMicArmiesEvent> event);
//T onUnauthorizedMember(TikTokEventConsumer<TikTokUnauthorizedMemberEvent> event);
//T onInRoomBanner(TikTokEventConsumer<TikTokInRoomBannerEvent> event);
//T onLinkMicMethod(TikTokEventConsumer<TikTokLinkMicMethodEvent> event);
//T onPoll(TikTokEventConsumer<TikTokPollEvent> event);
//T onGoalUpdate(TikTokEventConsumer<TikTokGoalUpdateEvent> event);
//T onRankUpdate(TikTokEventConsumer<TikTokRankUpdateEvent> event);
//T onIMDelete(TikTokEventConsumer<TikTokIMDeleteEvent> event);
//T onRankText(TikTokEventConsumer<TikTokRankTextEvent> event);
//T onUnhandledMember(TikTokEventConsumer<TikTokUnhandledMemberEvent> event);
//T onSubNotify(TikTokEventConsumer<TikTokSubNotifyEvent> event);
//T onLinkMicBattle(TikTokEventConsumer<TikTokLinkMicBattleEvent> event);
//T onUnhandledControl(TikTokEventConsumer<TikTokUnhandledControlEvent> event);
}

View File

@@ -45,10 +45,10 @@ public class TikTokBarrageEvent extends TikTokHeaderEvent {
public TikTokBarrageEvent(WebcastBarrageMessage msg) {
super(msg.getCommon());
icon = Picture.Map(msg.getIcon());
icon = Picture.map(msg.getIcon());
eventName = msg.getEvent().getEventName();
backGround = Picture.Map(msg.getBackground());
rightIcon = Picture.Map(msg.getRightIcon());
backGround = Picture.map(msg.getBackground());
rightIcon = Picture.map(msg.getRightIcon());
duration = msg.getDuration();
switch (msg.getMsgType()) {
case GRADEUSERENTRANCENOTIFICATION:

View File

@@ -38,9 +38,9 @@ public class TikTokCaptionEvent extends TikTokHeaderEvent {
String text;
public TikTokCaptionEvent(WebcastCaptionMessage msg) {
super(msg.getHeader());
super(msg.getCommon());
captionTimeStamp = msg.getTimeStamp();
iSOLanguage = msg.getCaptionData().getISOLanguage();
iSOLanguage = msg.getCaptionData().getLanguage();
text = msg.getCaptionData().getText();
}
}

View File

@@ -26,7 +26,7 @@ import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.Picture;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastChatMessage;
import lombok.Getter;
@@ -40,16 +40,18 @@ import java.util.List;
public class TikTokCommentEvent extends TikTokHeaderEvent {
private final User user;
private final String text;
private final String language;
private final List<User> mentionedUsers;
private final String getUserLanguage;
private final User mentionedUser;
private final List<Picture> pictures;
private final boolean visibleToSender;
public TikTokCommentEvent(WebcastChatMessage msg) {
super(msg.getCommon());
user = User.mapOrEmpty(msg.getUser());
user = User.map(msg.getUser());
text = msg.getContent();
language = msg.getContentLanguage();
mentionedUsers = List.of(User.mapOrEmpty(msg.getAtUser()));
pictures = msg.getEmotesListList().stream().map(e -> Picture.Map(e.getEmote().getImage())).toList();
visibleToSender = msg.getVisibleToSender();
getUserLanguage = msg.getContentLanguage();
mentionedUser = User.map(msg.getAtUser(),msg.getUserIdentity());
pictures = msg.getEmotesListList().stream().map(e -> Picture.map(e.getEmote().getImage())).toList();
}
}

View File

@@ -26,7 +26,7 @@ import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.Emote;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastEmoteChatMessage;
import lombok.Value;
@@ -43,7 +43,7 @@ public class TikTokEmoteEvent extends TikTokHeaderEvent {
public TikTokEmoteEvent(WebcastEmoteChatMessage msg) {
super(msg.getCommon());
user = User.mapOrEmpty(msg.getUser());
user = User.map(msg.getUser());
emotes = msg.getEmoteListList().stream().map(Emote::map).toList();
}
}

View File

@@ -25,7 +25,7 @@ package io.github.jwdeveloper.tiktok.events.messages;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastEnvelopeMessage;
import lombok.Value;

View File

@@ -26,7 +26,7 @@ import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.Picture;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGoalUpdateMessage;
import lombok.Getter;
@@ -43,13 +43,13 @@ public class TikTokGoalUpdateEvent extends TikTokHeaderEvent {
public TikTokGoalUpdateEvent(WebcastGoalUpdateMessage msg) {
super(msg.getCommon());
picture = Picture.Map(msg.getContributorAvatar());
picture = Picture.map(msg.getContributorAvatar());
goalId = msg.getGoal().getId();
description = msg.getGoal().getDescription();
users = msg.getGoal()
.getContributorsListList()
.stream()
.map(u -> new User(u.getUserId(), u.getDisplayId(), Picture.Map(u.getAvatar())))
.map(u -> new User(u.getUserId(), u.getDisplayId(), Picture.map(u.getAvatar())))
.toList();
}
}

View File

@@ -25,7 +25,7 @@ package io.github.jwdeveloper.tiktok.events.messages;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;

View File

@@ -51,7 +51,7 @@ public class TikTokLinkMicArmiesEvent extends TikTokHeaderEvent {
super(msg.getCommon());
battleId = msg.getId();
armies = msg.getBattleItemsList().stream().map(LinkMicArmy::new).toList();
picture = Picture.Map(msg.getImage());
picture = Picture.map(msg.getImage());
battleStatus = msg.getBattleStatus();
}
}

View File

@@ -25,7 +25,7 @@ package io.github.jwdeveloper.tiktok.events.messages;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastQuestionNewMessage;
import lombok.Getter;

View File

@@ -25,33 +25,37 @@ package io.github.jwdeveloper.tiktok.events.messages;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.events.objects.users.UserAttribute;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSystemMessage;
import lombok.Getter;
import lombok.NonNull;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokRoomEvent extends TikTokHeaderEvent {
private User host;
public class TikTokRoomEvent extends TikTokHeaderEvent
{
private User hostUser;
private String hostLanguage;
private final String message;
private final String welcomeMessage;
public TikTokRoomEvent(WebcastRoomMessage msg) {
super(msg.getCommon());
message = msg.getContent();
welcomeMessage = msg.getContent();
}
public TikTokRoomEvent(WebcastSystemMessage msg) {
super(msg.getCommon());
message = msg.getMessage();
welcomeMessage = msg.getMessage();
}
public TikTokRoomEvent(WebcastLiveIntroMessage msg) {
super(msg.getCommon());
host = User.mapOrEmpty(msg.getHost());
message = msg.getContent();
hostUser = User.map(msg.getHost());
hostUser.addAttribute(UserAttribute.LiveHost);
welcomeMessage = msg.getContent();
hostLanguage = msg.getLanguage();
}

View File

@@ -25,23 +25,31 @@ package io.github.jwdeveloper.tiktok.events.messages;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.TopViewer;
import io.github.jwdeveloper.tiktok.events.objects.RankingUser;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomUserSeqMessage;
import lombok.Getter;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokRoomViewerDataEvent extends TikTokHeaderEvent {
private final Integer viewerCount;
private final List<TopViewer> topViewers;
public class TikTokRoomUserInfoEvent extends TikTokHeaderEvent {
private final int totalUsers;
public TikTokRoomViewerDataEvent(WebcastRoomUserSeqMessage msg) {
/**
* Only top 5 users in ranking has detailed data
* rest has only ID
*/
private final List<RankingUser> usersRanking;
public TikTokRoomUserInfoEvent(WebcastRoomUserSeqMessage msg) {
super(msg.getCommon());
//TODO sorting by rank TopViewers = msg?.TopViewers?.Select(t => new Objects.TopViewer(t))?.OrderBy(t => t.Rank)?
viewerCount = (int) msg.getTotalUser();
topViewers = msg.getRanksListList().stream().map(TopViewer::new).toList();
totalUsers = msg.getTotalUser();
usersRanking = msg.getRanksListList().stream().map(RankingUser::new)
.sorted((ru1, ru2) -> Integer.compare(ru2.getScore(), ru1.getScore()))
.collect(Collectors.toList());
}
}

View File

@@ -25,7 +25,7 @@ package io.github.jwdeveloper.tiktok.events.messages;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSubNotifyMessage;
import lombok.Value;
@@ -36,7 +36,7 @@ public class TikTokSubNotifyEvent extends TikTokHeaderEvent {
public TikTokSubNotifyEvent(WebcastSubNotifyMessage msg) {
super(msg.getCommon());
user = User.mapOrEmpty(msg.getUser());
user = User.map(msg.getUser());
}
}

View File

@@ -25,7 +25,7 @@ package io.github.jwdeveloper.tiktok.events.messages;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
import lombok.Getter;
@@ -35,14 +35,14 @@ import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Custom)
public class TikTokSubscribeEvent extends TikTokHeaderEvent {
private User newSubscriber;
private User user;
public TikTokSubscribeEvent(WebcastMemberMessage msg) {
super(msg.getCommon());
if(msg.hasUser())
{
newSubscriber = new User(msg.getUser());
user = new User(msg.getUser());
}
}

View File

@@ -20,7 +20,7 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.events.messages;
package io.github.jwdeveloper.tiktok.events.messages.gift;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;

View File

@@ -20,14 +20,14 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.events.messages;
package io.github.jwdeveloper.tiktok.events.messages.gift;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.Gift;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import lombok.Getter;
@@ -39,20 +39,20 @@ import lombok.Getter;
@Getter
public class TikTokGiftEvent extends TikTokHeaderEvent {
private final Gift gift;
private final User sender;
private final User user;
private final String purchaseId;
private final String receipt;
private final Long comboCount;
private final int combo;
private final boolean comboFinished;
private final Long comboIndex;
private final int comboIndex;
public TikTokGiftEvent(Gift gift, WebcastGiftMessage msg) {
super(msg.getCommon());
this.gift = gift;
sender = User.mapOrEmpty(msg.getUser());
user = User.map(msg.getUser());
purchaseId = msg.getOrderId();
receipt = msg.getMonitorExtra();
comboCount = msg.getComboCount();
combo = msg.getComboCount();
comboFinished = msg.getRepeatEnd() > 0;
comboIndex = msg.getRepeatCount();
}

View File

@@ -25,7 +25,7 @@ package io.github.jwdeveloper.tiktok.events.messages.poll;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.objects.PollOption;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastPollMessage;
import lombok.Getter;
@@ -40,7 +40,7 @@ public class TikTokPollEndEvent extends TikTokPollEvent
public TikTokPollEndEvent(WebcastPollMessage msg) {
super(msg);
var end = msg.getEndContent();
operator = User.mapOrEmpty(end.getOperator());
operator = User.map(end.getOperator());
options = end.getOptionListList().stream().map(PollOption::map).toList();
}
}

View File

@@ -25,7 +25,7 @@ package io.github.jwdeveloper.tiktok.events.messages.poll;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.objects.PollOption;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastPollMessage;
import lombok.Getter;
@@ -44,7 +44,7 @@ public class TikTokPollStartEvent extends TikTokPollEvent {
var startContent = msg.getStartContent();
title = startContent.getTitle();
operator = User.mapOrEmpty(startContent.getOperator());
operator = User.map(startContent.getOperator());
options = startContent.getOptionListList().stream().map(PollOption::map).toList();
}
}

View File

@@ -20,12 +20,13 @@
* 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.events.messages;
package io.github.jwdeveloper.tiktok.events.messages.social;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.mappers.MappingContext;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Value;
@@ -37,11 +38,12 @@ import lombok.Value;
public class TikTokFollowEvent extends TikTokHeaderEvent
{
User user;
Long totalFollowers;
int totalFollowers;
public TikTokFollowEvent(WebcastSocialMessage msg) {
super(msg.getCommon());
user = User.mapOrEmpty(msg.getUser());
user = User.map(msg.getUser());
totalFollowers = msg.getFollowCount();
}
}

View File

@@ -20,12 +20,12 @@
* 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.events.messages;
package io.github.jwdeveloper.tiktok.events.messages.social;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Getter;
@@ -34,17 +34,17 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Custom)
public class TikTokJoinEvent extends TikTokHeaderEvent {
private final User user;
private final int viewersCount;
private final int totalUsers;
public TikTokJoinEvent(WebcastSocialMessage msg, int viewersCount) {
super(msg.getCommon());
user = User.mapOrEmpty(msg.getUser());
this.viewersCount = viewersCount;
user = User.map(msg.getUser());
this.totalUsers = viewersCount;
}
public TikTokJoinEvent(WebcastMemberMessage msg) {
super(msg.getCommon());
user = User.mapOrEmpty(msg.getUser());
viewersCount = msg.getMemberCount();
user = User.map(msg.getUser());
totalUsers = msg.getMemberCount();
}
}

View File

@@ -20,12 +20,12 @@
* 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.events.messages;
package io.github.jwdeveloper.tiktok.events.messages.social;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLikeMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Getter;
@@ -40,21 +40,21 @@ public class TikTokLikeEvent extends TikTokHeaderEvent
{
private final User user;
private final Integer count;
private final int likes;
private final Integer totalLikes;
private final int totalLikes;
public TikTokLikeEvent(WebcastSocialMessage msg, int totalLikes) {
super(msg.getCommon());
user = User.mapOrEmpty(msg.getUser());
count = 1;
user = User.map(msg.getUser());
likes = 1;
this.totalLikes = totalLikes;
}
public TikTokLikeEvent(WebcastLikeMessage msg) {
super(msg.getCommon());
user = User.mapOrEmpty(msg.getUser());
count = msg.getCount();
user = User.map(msg.getUser());
likes = msg.getCount();
totalLikes = msg.getTotal();
}
}

View File

@@ -20,12 +20,12 @@
* 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.events.messages;
package io.github.jwdeveloper.tiktok.events.messages.social;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.base.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Getter;
@@ -36,18 +36,18 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Custom)
public class TikTokShareEvent extends TikTokHeaderEvent {
private final User user;
private final Integer amount;
private final int totalShares;
public TikTokShareEvent(WebcastSocialMessage msg, Integer amount) {
super(msg.getCommon());
user = User.mapOrEmpty(msg.getUser());
this.amount = amount;
user = User.map(msg.getUser());
this.totalShares = amount;
}
public TikTokShareEvent(WebcastSocialMessage msg) {
super(msg.getCommon());
user = User.mapOrEmpty(msg.getUser());
amount = 1;
user = User.map(msg.getUser());
totalShares = 1;
}
}

View File

@@ -20,14 +20,13 @@
* 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.events.messages;
package io.github.jwdeveloper.tiktok.events.messages.websocket;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
@@ -36,7 +35,7 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
@EventMeta(eventType = EventType.Custom)
@EventMeta(eventType = EventType.Debug)
public class TikTokWebsocketMessageEvent extends TikTokEvent
{
private TikTokEvent event;

View File

@@ -20,35 +20,19 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.events.objects;
package io.github.jwdeveloper.tiktok.events.messages.websocket;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Value;
import java.util.List;
@Value
public class BarrageData {
String eventType;
String label;
List<BarrageUser> users;
public BarrageData(String eventType, String label, List<BarrageUser> users)
@Getter
@AllArgsConstructor
@EventMeta(eventType = EventType.Debug)
public class TikTokWebsocketResponseEvent extends TikTokEvent
{
this.eventType = eventType;
this.label = label;
this.users = users;
}
@Value
public static class BarrageUser
{
User user;
String data;
}
private WebcastResponse response;
}

View File

@@ -20,7 +20,7 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.events.messages;
package io.github.jwdeveloper.tiktok.events.messages.websocket;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
@@ -33,10 +33,10 @@ import lombok.Getter;
* Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
*/
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokUnhandledWebsocketMessageEvent extends TikTokUnhandledEvent<WebcastResponse.Message>
@EventMeta(eventType = EventType.Debug)
public class TikTokWebsocketUnhandledMessageEvent extends TikTokUnhandledEvent<WebcastResponse.Message>
{
public TikTokUnhandledWebsocketMessageEvent(WebcastResponse.Message data) {
public TikTokWebsocketUnhandledMessageEvent(WebcastResponse.Message data) {
super(data);
}
}

View File

@@ -1,99 +0,0 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.events.objects;
import io.github.jwdeveloper.tiktok.messages.data.BadgeStruct;
import lombok.Value;
import java.util.ArrayList;
import java.util.List;
@Value
public class Badge {
ComboBadge comboBadges;
List<TextBadge> textBadges;
List<ImageBadge> imageBadges;
public Badge(ComboBadge comboBadges, List<TextBadge> textBadges, List<ImageBadge> imageBadges) {
this.comboBadges = comboBadges;
this.textBadges = textBadges;
this.imageBadges = imageBadges;
}
public Badge(io.github.jwdeveloper.tiktok.messages.data.BadgeStruct badge)
{
comboBadges = ComboBadge.map(badge.getCombine());
textBadges = TextBadge.mapAll(badge.getTextList());
imageBadges = ImageBadge.mapAll(badge.getImageList());
}
@Value
public static class TextBadge {
EnumValue type;
String name;
public static TextBadge map(BadgeStruct.TextBadge input) {
return new TextBadge(EnumValue.Map(input.getDisplayType()),input.getKey());
}
public static List<TextBadge> mapAll(List<BadgeStruct.TextBadge> list) {
return list.stream().map(TextBadge::map).toList();
}
}
@Value
public static class ImageBadge {
EnumValue displayType;
Picture image;
public static ImageBadge map(BadgeStruct.ImageBadge input) {
return new ImageBadge(EnumValue.Map(input.getDisplayType()), Picture.Map(input.getImage()));
}
public static List<ImageBadge> mapAll(List<BadgeStruct.ImageBadge> list) {
return list.stream().map(ImageBadge::map).toList();
}
}
@Value
public static class ComboBadge {
Picture image;
String data;
public static ComboBadge map(BadgeStruct.CombineBadge input) {
return new ComboBadge(Picture.Map(input.getIcon()),input.getStr());
}
public static List<ComboBadge> mapAll(List<BadgeStruct.CombineBadge> list) {
return list.stream().map(ComboBadge::map).toList();
}
}
public static Badge Empty() {
var comboBadge = new ComboBadge(Picture.Empty(), "");
var textBadges = new ArrayList<TextBadge>();
var imageBadges = new ArrayList<ImageBadge>();
return new Badge(comboBadge, textBadges, imageBadges);
}
public static List<Badge> EmptyList() {
return new ArrayList<Badge>();
}
}

View File

@@ -33,7 +33,7 @@ public class Emote {
UUID uuid;
public static Emote map(io.github.jwdeveloper.tiktok.messages.data.Emote input) {
return new Emote(input.getEmoteId(), Picture.Map(input.getImage()), UUID.fromString(input.getUuid()));
return new Emote(input.getEmoteId(), Picture.map(input.getImage()), UUID.fromString(input.getUuid()));
}
}

View File

@@ -22,6 +22,7 @@
*/
package io.github.jwdeveloper.tiktok.events.objects;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.data.LinkMicArmiesItems;
import lombok.Value;
@@ -36,7 +37,7 @@ public class LinkMicArmy {
armyId = army.getHostUserId();
armies = army.getBattleGroupsList()
.stream()
.map(x -> new Army(x.getUsersList().stream().map(User::mapOrEmpty).toList(), x.getPoints()))
.map(x -> new Army(x.getUsersList().stream().map(User::map).toList(), x.getPoints()))
.toList();
}

View File

@@ -23,8 +23,8 @@
package io.github.jwdeveloper.tiktok.events.objects;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter;
import lombok.Value;
import java.util.List;

View File

@@ -43,14 +43,13 @@ public class Picture {
@Getter
private final String link;
private Image image;
public Picture(String link) {
this.link = link;
}
public static Picture Map(io.github.jwdeveloper.tiktok.messages.data.Image profilePicture) {
public static Picture map(io.github.jwdeveloper.tiktok.messages.data.Image profilePicture) {
var index = profilePicture.getUrlListCount() - 1;
if (index <= 0) {

View File

@@ -22,6 +22,7 @@
*/
package io.github.jwdeveloper.tiktok.events.objects;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.data.PollOptionInfo;
import lombok.Value;
@@ -37,7 +38,7 @@ public class PollOption {
public static PollOption map(PollOptionInfo pollOptionInfo) {
var users = pollOptionInfo.getVoteUserListList().stream().map(User::mapOrEmpty).toList();
var users = pollOptionInfo.getVoteUserListList().stream().map(User::map).toList();
return new PollOption(
pollOptionInfo.getOptionIdx(),
pollOptionInfo.getDisplayContent(),

View File

@@ -21,20 +21,19 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.events.objects;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import lombok.Value;
@Value
public class TopViewer {
Integer rank;
public class RankingUser {
int rank;
User user;
int score;
Integer coinsGiven;
public TopViewer(io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomUserSeqMessage.Contributor viewer)
{
rank = (int)viewer.getRank();
user = User.mapOrEmpty(viewer.getUser());
coinsGiven = (int)viewer.getScore();
public RankingUser(io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomUserSeqMessage.Contributor viewer) {
rank = viewer.getRank();
user = User.map(viewer.getUser());
score = viewer.getScore();
}
}

View File

@@ -22,6 +22,7 @@
*/
package io.github.jwdeveloper.tiktok.events.objects;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -50,11 +51,11 @@ public class Text {
{
return switch (input.getType())
{
case 0 -> {
var user = User.mapOrEmpty(input.getUserValue().getUser());
yield new UserTextPiece(input.getStringValue(), user);
case 11 -> {
var user = User.map(input.getUserValue().getUser());
yield new UserTextPiece(user);
}
case 1 -> new GiftTextPiece(input.getStringValue());
//case 12 -> new GiftTextPiece(input.getStringValue());
default -> throw new TikTokLiveException("Unknown text piece");
};
}
@@ -62,14 +63,12 @@ public class Text {
@Getter
@AllArgsConstructor
public static class TextPiece {
String value;
}
public static class UserTextPiece extends TextPiece {
User user;
public UserTextPiece(String value, User user) {
super(value);
public UserTextPiece(User user) {
this.user = user;
}
}
@@ -78,7 +77,7 @@ public class Text {
Gift gift;
public GiftTextPiece(String value) {
super(value);
}
}
}

View File

@@ -1,122 +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.events.objects;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastEnvelopeMessage;
import lombok.Getter;
import java.util.List;
@Getter
public class User {
private Long userId;
private String uniqueId;
private final String nickName;
private String description;
private Picture picture;
private long following;
private long followers;
private long followsHost;
private List<Badge> badges;
public User(Long userId,
String uniqueId,
String nickName,
String description,
Picture profilePicture,
Integer following,
Integer followers,
Integer followsHost,
List<Badge> badges) {
this.userId = userId;
this.uniqueId = uniqueId;
this.nickName = nickName;
this.description = description;
this.picture = profilePicture;
this.following = following;
this.followers = followers;
this.followsHost = followsHost;
this.badges = badges;
}
public User(String uniqueId,
String nickName) {
this.uniqueId = uniqueId;
this.nickName = nickName;
}
public User(Long userId,
String nickName,
Picture picture) {
this.userId = userId;
this.nickName = nickName;
this.picture = picture;
}
public User(io.github.jwdeveloper.tiktok.messages.data.User user) {
assert user != null;
userId = user.getId();
uniqueId = user.getSpecialId();
nickName = user.getNickname();
description = user.getBioDescription();
picture = Picture.Map(user.getAvatarThumb());
following = user.getFollowInfo().getFollowingCount();
followers = user.getFollowInfo().getFollowerCount();
followsHost = user.getFollowInfo().getFollowStatus();
badges = user.getBadgeListList().stream().map(Badge::new).toList();
}
public static User EMPTY = new User(0L,
"",
"",
"",
Picture.Empty(),
0,
0,
0,
Badge.EmptyList());
public static User mapOrEmpty(io.github.jwdeveloper.tiktok.messages.data.User user) {
if (user != null) {
return new User(user);
}
return EMPTY;
}
public static User mapOrEmpty(io.github.jwdeveloper.tiktok.messages.data.VoteUser user) {
return new User(user.getUserId()+"",user.getNickName());
}
public static User map(WebcastEnvelopeMessage.EnvelopeInfo envelopeInfo) {
return new User(0L,
envelopeInfo.getSendUserId(),
envelopeInfo.getSendUserName(),
"",
Picture.Map(envelopeInfo.getSendUserAvatar()),
0,
0,
0,
Badge.EmptyList());
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.events.objects.badges;
public class Badge {
public static Badge map(io.github.jwdeveloper.tiktok.messages.data.BadgeStruct badge) {
return switch (badge.getDisplayType()) {
case BADGEDISPLAYTYPE_TEXT -> new TextBadge(badge.getText());
case BADGEDISPLAYTYPE_IMAGE -> new PictureBadge(badge.getImage());
case BADGEDISPLAYTYPE_STRING -> new StringBadge(badge.getStr());
case BADGEDISPLAYTYPE_COMBINE -> new CombineBadge(badge.getCombine());
default -> empty();
};
}
public static Badge empty() {
return new Badge();
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.events.objects.badges;
import io.github.jwdeveloper.tiktok.events.objects.Picture;
import io.github.jwdeveloper.tiktok.messages.data.BadgeStruct;
public class CombineBadge extends Badge {
private final Picture picture;
private final String text;
private final String subText;
public CombineBadge(BadgeStruct.CombineBadge combineBadge) {
picture = Picture.map(combineBadge.getIcon());
text = combineBadge.getText().getDefaultPattern();
subText = combineBadge.getStr();
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.events.objects.badges;
import io.github.jwdeveloper.tiktok.events.objects.Picture;
import io.github.jwdeveloper.tiktok.messages.data.BadgeStruct;
public class PictureBadge extends Badge {
private final Picture picture;
public PictureBadge(BadgeStruct.ImageBadge imageBadge) {
picture = Picture.map(imageBadge.getImage());
}
}

View File

@@ -0,0 +1,34 @@
/*
* 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.events.objects.badges;
import io.github.jwdeveloper.tiktok.messages.data.BadgeStruct;
public class StringBadge extends Badge {
public String text;
public StringBadge(BadgeStruct.StringBadge stringBadge) {
this.text = stringBadge.getStr();
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.events.objects.badges;
import io.github.jwdeveloper.tiktok.messages.data.BadgeStruct;
public class TextBadge extends Badge
{
private final String text;
public TextBadge(BadgeStruct.TextBadge textBadge)
{
this.text = textBadge.getDefaultPattern();
}
}

View File

@@ -22,7 +22,7 @@
*/
package io.github.jwdeveloper.tiktok.events.objects.barrage;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastBarrageMessage;
public class FansLevelParam extends BarrageParam
@@ -32,6 +32,6 @@ public class FansLevelParam extends BarrageParam
public FansLevelParam(WebcastBarrageMessage.BarrageTypeFansLevelParam param)
{
this.currentGrade = param.getCurrentGrade();
this.user = User.mapOrEmpty(param.getUser());
this.user = User.map(param.getUser());
}
}

View File

@@ -22,7 +22,7 @@
*/
package io.github.jwdeveloper.tiktok.events.objects.barrage;
import io.github.jwdeveloper.tiktok.events.objects.User;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastBarrageMessage;
public class UserGradeParam extends BarrageParam {
@@ -30,6 +30,6 @@ public class UserGradeParam extends BarrageParam {
User user;
public UserGradeParam(WebcastBarrageMessage.BarrageTypeUserGradeParam param) {
this.currentGrade = param.getCurrentGrade();
this.user = User.mapOrEmpty(param.getUser());
this.user = User.map(param.getUser());
}
}

View File

@@ -0,0 +1,207 @@
/*
* 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.events.objects.users;
import io.github.jwdeveloper.tiktok.events.objects.badges.Badge;
import io.github.jwdeveloper.tiktok.events.objects.Picture;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastEnvelopeMessage;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Getter
public class User {
private final Long id;
private final String name;
private String displayName;
private String description;
private Picture picture;
private long following;
private long followers;
private List<Badge> badges;
@Getter(AccessLevel.NONE)
private Set<UserAttribute> attributes;
@Setter
private boolean tracked;
public List<UserAttribute> getAttributes() {
return attributes.stream().toList();
}
public boolean hasAttribute(UserAttribute userFlag) {
return attributes.contains(userFlag);
}
public void addAttribute(UserAttribute... flags) {
this.attributes.addAll(Arrays.stream(flags).toList());
}
public boolean isGiftGiver() {
return hasAttribute(UserAttribute.GiftGiver);
}
public boolean isSubscriber() {
return hasAttribute(UserAttribute.Subscriber);
}
public boolean isMutualFollowingWithHost() {
return hasAttribute(UserAttribute.MutualFollowingWithLiveHost);
}
public boolean isFollower() {
return hasAttribute(UserAttribute.Follower);
}
public boolean isAdmin() {
return hasAttribute(UserAttribute.Admin);
}
public boolean isMuted() {
return hasAttribute(UserAttribute.Muted);
}
public boolean isBlocked() {
return hasAttribute(UserAttribute.Blocked);
}
public boolean isModerator() {
return hasAttribute(UserAttribute.Moderator);
}
public boolean isLiveHost() {
return hasAttribute(UserAttribute.LiveHost);
}
public User(Long userId,
String nickName,
String description,
Picture profilePicture,
Integer following,
Integer followers,
List<Badge> badges) {
this.id = userId;
this.name = nickName;
this.description = description;
this.picture = profilePicture;
this.following = following;
this.followers = followers;
this.badges = badges;
this.attributes = new HashSet<>();
}
public User(Long userId,
String nickName) {
this.id = userId;
this.name = nickName;
this.attributes = new HashSet<>();
}
public User(Long userId,
String nickName,
Picture picture) {
this(userId, nickName);
this.picture = picture;
}
public User(io.github.jwdeveloper.tiktok.messages.data.User user) {
this(user.getId(), user.getDisplayId(), Picture.map(user.getAvatarThumb()));
description = user.getBioDescription();
displayName = user.getNickname();
following = user.getFollowInfo().getFollowingCount();
followers = user.getFollowInfo().getFollowerCount();
badges = user.getBadgeListList().stream().map(Badge::map).toList();
if (user.getIsFollower()) {
addAttribute(UserAttribute.Follower);
}
if (user.getSubscribeInfo() != null && user.getSubscribeInfo().getIsSubscribedToAnchor()) {
addAttribute(UserAttribute.Subscriber);
}
if (user.getUserAttr().getIsAdmin()) {
addAttribute(UserAttribute.Admin);
}
if (user.getUserAttr().getIsMuted()) {
addAttribute(UserAttribute.Muted);
}
if (user.getIsBlock()) {
addAttribute(UserAttribute.Blocked);
}
}
public static User EMPTY = new User(0L,
"",
"",
Picture.Empty(),
0,
0,
List.of(Badge.empty()));
public static User map(io.github.jwdeveloper.tiktok.messages.data.User user) {
return new User(user);
}
public static User map(io.github.jwdeveloper.tiktok.messages.data.User user,
io.github.jwdeveloper.tiktok.messages.data.UserIdentity userIdentity) {
var outUser = map(user);
if (userIdentity.getIsGiftGiverOfAnchor()) {
outUser.addAttribute(UserAttribute.GiftGiver);
}
if (userIdentity.getIsSubscriberOfAnchor()) {
outUser.addAttribute(UserAttribute.Subscriber);
}
if (userIdentity.getIsMutualFollowingWithAnchor()) {
outUser.addAttribute(UserAttribute.MutualFollowingWithLiveHost);
}
if (userIdentity.getIsFollowerOfAnchor()) {
outUser.addAttribute(UserAttribute.Follower);
}
if (userIdentity.getIsModeratorOfAnchor()) {
outUser.addAttribute(UserAttribute.Moderator);
}
if (userIdentity.getIsAnchor()) {
outUser.addAttribute(UserAttribute.LiveHost);
}
return outUser;
}
public static User map(io.github.jwdeveloper.tiktok.messages.data.VoteUser user) {
return new User(user.getUserId(), user.getNickName());
}
public static User map(WebcastEnvelopeMessage.EnvelopeInfo envelopeInfo) {
return new User(0L,
//envelopeInfo.getSendUserId(),
envelopeInfo.getSendUserName(),
"",
Picture.map(envelopeInfo.getSendUserAvatar()),
0,
0,
List.of(Badge.empty()));
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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.events.objects.users;
public enum UserAttribute
{
GiftGiver, Subscriber, Follower, Moderator, LiveHost, MutualFollowingWithLiveHost,Admin,Blocked,Muted
}

View File

@@ -25,6 +25,8 @@ package io.github.jwdeveloper.tiktok.live;
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
import java.util.logging.Logger;
public interface LiveClient {
/**
@@ -43,6 +45,12 @@ public interface LiveClient {
*/
GiftManager getGiftManager();
/**
* Get user manager
* @return
*/
UserManager getUserManager();
/**
* Gets the current room info from TikTok API including streamer info, room status and statistics.
*/
@@ -53,4 +61,10 @@ public interface LiveClient {
* @see TikTokEventListener
*/
ListenersManager getListenersManager();
/**
* Logger
* @return
*/
Logger getLogger();
}

View File

@@ -30,6 +30,6 @@ public interface LiveRoomInfo
int getLikesCount();
boolean isAgeRestricted();
String getRoomId();
String getUserName();
String getHostName();
ConnectionState getConnectionState();
}

View File

@@ -0,0 +1,36 @@
/*
* 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.live;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.objects.Gift;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import java.util.List;
public interface TrackedUser
{
List<TikTokEvent> getInvokedEvents();
List<Gift> getGifs();
User getUserData();
}

View File

@@ -0,0 +1,36 @@
/*
* 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.live;
import io.github.jwdeveloper.tiktok.events.objects.users.User;
import java.util.List;
public interface UserManager
{
TrackedUser observeUser(User user);
TrackedUser getTrackedUser(Long id);
List<TrackedUser> getTrackedUsers();
}

View File

@@ -24,5 +24,5 @@ package io.github.jwdeveloper.tiktok.mappers;
public interface Mapper<SOURCE,TARGET>
{
TARGET mapFrom(SOURCE source);
TARGET map(SOURCE source);
}

View File

@@ -0,0 +1,30 @@
/*
* 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;
public interface MappingContext<T>
{
T getMessage();
Mapper getMapper();
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.utils;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.GsonBuilder;
import java.awt.*;
import java.util.ArrayList;
public class JsonUtil {
public static String toJson(Object obj) {
return new GsonBuilder()
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
return false;
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
return aClass.equals(Image.class);
}
})
.disableHtmlEscaping()
.setPrettyPrinting()
.create()
.toJson(obj);
}
public static String messageToJson(Object obj) {
var ignoredFields = new ArrayList<String>();
ignoredFields.add("memoizedIsInitialized");
ignoredFields.add("memoizedSize");
ignoredFields.add("memoizedHashCode");
return new GsonBuilder()
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
if (ignoredFields.contains(fieldAttributes.getName())) {
return true;
}
if (fieldAttributes.getName().equals("common_")) {
return true;
}
if (fieldAttributes.getName().equals("bytes")) {
return true;
}
if (fieldAttributes.getName().equals("unknownFields")) {
return true;
}
return false;
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
return false;
}
})
.disableHtmlEscaping()
.setPrettyPrinting()
.create()
.toJson(obj);
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.websocket;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
public interface SocketClient {
void start(WebcastResponse webcastResponse, LiveClient tikTokLiveClient);
void stop();
}

View File

@@ -103,46 +103,21 @@ message Text {
// @Image
message Image {
repeated string urlList = 1;
string uri = 2;
int64 height = 3;
int64 width = 4;
string avgColor = 5;
int32 imageType = 6;
string openWebUrl = 7;
Content content = 8;
bool isAnimated = 9;
// @Content
// proto.webcast.data.Image
message Content {
string name = 1;
string fontColor = 2;
int64 level = 3;
}
}
// @Badge
message BadgeStruct {
BadgeDisplayType displayType = 1; // Enum
BadgePriorityType priorityType = 2; // Enum
BadgeSceneType sceneType = 3; // Enum
Position position = 4; // Enum
DisplayStatus displayStatus = 5; // Enum
int64 greyedByClient = 6;
ExhibitionType exhibitionType = 7; // Enum
string openweburl = 10;
bool display = 11;
// PrivilegeLogExtra privilegeLogExtra = 12;
repeated ImageBadge image = 20;
repeated TextBadge text = 21;
oneof badgeType
{
ImageBadge image = 20;
TextBadge text = 21;
StringBadge str = 22;
CombineBadge combine = 23;
}
message CombineBadge {
BadgeDisplayType displayType = 1; // Enum
Image icon = 2;
TextBadge text = 3;
string str = 4;
@@ -180,7 +155,7 @@ message BadgeStruct {
message ProfileCardPanel {
bool useNewProfileCardStyle = 1;
BadgeTextPosition badgeTextPosition = 2; // Enum
// BadgeTextPosition badgeTextPosition = 2; // Enum
ProjectionConfig projectionConfig = 3;
ProfileContent profileContent = 4;
}
@@ -192,15 +167,11 @@ message BadgeStruct {
}
message ImageBadge {
BadgeDisplayType displayType = 1; // Enum
Image image = 2;
}
message TextBadge {
BadgeDisplayType displayType = 1; // Enum
string key = 2;
string defaultPattern = 3;
repeated string piecesList = 4;
}
message IconConfig {
@@ -210,7 +181,6 @@ message BadgeStruct {
message StringBadge {
BadgeDisplayType displayType = 1; // Enum
string str = 2;
}
@@ -230,45 +200,8 @@ message BadgeStruct {
BADGEDISPLAYTYPE_COMBINE = 4;
}
enum BadgePriorityType {
BADGEPRIORITYTYPE_UNKNOWN = 0;
BADGEPRIORITYTYPE_STRONGRELATION = 10;
BADGEPRIORITYTYPE_PLATFORM = 20;
BADGEPRIORITYTYPE_RELATION = 30;
BADGEPRIORITYTYPE_ACTIVITY = 40;
BADGEPRIORITYTYPE_RANKLIST = 50;
}
enum BadgeSceneType {
BADGESCENETYPE_UNKNOWN = 0;
BADGESCENETYPE_ADMIN = 1;
BADGESCENETYPE_FIRSTRECHARGE = 2;
BADGESCENETYPE_FRIENDS = 3;
BADGESCENETYPE_SUBSCRIBER = 4;
BADGESCENETYPE_ACTIVITY = 5;
BADGESCENETYPE_RANKLIST = 6;
BADGESCENETYPE_NEWSUBSCRIBER = 7;
BADGESCENETYPE_USERGRADE = 8;
BADGESCENETYPE_STATECONTROLLEDMEDIA = 9;
BADGESCENETYPE_FANS = 10;
BADGESCENETYPE_LIVEPRO = 11;
}
enum DisplayStatus {
DISPLAYSTATUSNORMAL = 0;
DISPLAYSTATUSSHADOW = 1;
}
enum ExhibitionType {
EXHIBITIONTYPE_DEFAULT = 0;
EXHIBITIONTYPE_FOLD = 1;
EXHIBITIONTYPE_PUBLICSCREEN = 2;
}
enum BadgeTextPosition {
BADGETEXTPOSITIONUNKNOWN = 0;
BADGETEXTPOSITIONRIGHT = 1;
BADGETEXTPOSITIONBELOW = 2;
}
enum Position {
POSITIONUNKNOWN = 0;

View File

@@ -25,11 +25,7 @@ enum EmotePrivateType {
EMOTE_PRIVATE_TYPE_SUB_WAVE = 1;
}
enum ExhibitionType {
EXHIBITIONTYPE_DEFAULT = 0;
EXHIBITIONTYPE_FOLD = 1;
EXHIBITIONTYPE_PUBLICSCREEN = 2;
}
enum SubscribeType {
SUBSCRIBETYPE_ONCE = 0;
SUBSCRIBETYPE_AUTO = 1;

View File

@@ -64,9 +64,9 @@ message WebcastGiftMessage {
Common common = 1;
int64 giftId = 2;
int64 fanTicketCount = 3;
int64 groupCount = 4;
int64 repeatCount = 5;
int64 comboCount = 6;
int32 groupCount = 4;
int32 repeatCount = 5;
int32 comboCount = 6;
User user = 7;
User toUser = 8;
int32 repeatEnd = 9;
@@ -92,15 +92,6 @@ message WebcastGiftMessage {
Image userLabel = 1;
int64 userConsumeInRoom = 2;
}
message UserIdentity {
bool isGiftGiverOfAnchor = 1;
bool isSubscriberOfAnchor = 2;
bool isMutualFollowingWithAnchor = 3;
bool isFollowerOfAnchor = 4;
bool isModeratorOfAnchor = 5;
bool isAnchor = 6;
}
}
//@WebcastRoomMessage
@@ -170,14 +161,13 @@ message WebcastBarrageMessage {
//@WebcastCaptionMessage
// Closed Captioning for Video
message WebcastCaptionMessage {
Common header = 1;
Common common = 1;
uint64 timeStamp = 2;
uint32 data1 = 3;
CaptionData captionData = 4;
message CaptionData {
string ISOLanguage = 1;
string Text = 2;
string language = 1;
string text = 2;
}
}
@@ -198,6 +188,8 @@ message WebcastChatMessage {
string contentLanguage = 14;
int32 quickChatScene = 16;
int32 communityFlaggedStatus = 17;
UserIdentity UserIdentity = 18;
map<int32,string> CommentQualityScores = 19;
// @EmoteWithIndex
// proto.webcast.im.ChatMessage
@@ -339,16 +331,16 @@ message WebcastSocialMessage {
int64 shareType = 3;
int64 action = 4;
string shareTarget = 5;
int64 followCount = 6;
int32 followCount = 6;
int64 shareDisplayStyle = 7;
int64 shareCount = 8;
int32 shareCount = 8;
}
//@WebcastSubNotifyMessage
message WebcastSubNotifyMessage {
Common common = 1;
User user = 2;
ExhibitionType exhibitionType = 3; // Enum
// ExhibitionType exhibitionType = 3; // Enum
int64 subMonth = 4;
SubscribeType subscribeType = 5; // Enum
OldSubscribeStatus oldSubscribeStatus = 6; // Enum

View File

@@ -24,6 +24,11 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>

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;

View File

@@ -142,7 +142,7 @@ import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokCommentEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokGiftMessageEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
import io.github.jwdeveloper.tiktok.live.LiveClient;

View File

@@ -26,8 +26,8 @@ import io.github.jwdeveloper.tiktok.annotations.TikTokEventHandler;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokCommentEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.events.messages.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.events.messages.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
import io.github.jwdeveloper.tiktok.live.LiveClient;

View File

@@ -25,9 +25,11 @@ package io.github.jwdeveloper.tiktok;
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.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.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.social.TikTokShareEvent;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.util.ConsoleColors;
@@ -36,7 +38,7 @@ import java.time.Duration;
public class Main {
public static String TEST_TIKTOK_USER = "bangbetmenygy";
public static String TEST_TIKTOK_USER = "szwagierkaqueen";
public static void main(String[] args) throws IOException
{
@@ -55,7 +57,7 @@ public class Main {
})
.onConnected(Main::onConnected)
.onDisconnected(Main::onDisconnected)
.onRoomViewerData(Main::onViewerData)
.onRoomUserInfo(Main::onViewerData)
.onJoin(Main::onJoin)
.onComment(Main::onComment)
.onFollow(Main::onFollow)
@@ -79,8 +81,8 @@ public class Main {
private static void onGift(LiveClient tikTokLive, TikTokGiftEvent e)
{
switch (e.getGift()) {
case ROSE -> print( "\uD83D\uDC95",ConsoleColors.YELLOW,"x", e.getComboCount(), " roses!", "\uD83D\uDC95");
default -> print(ConsoleColors.YELLOW,"Thanks for gift: ", e.getGift().getName(),"X",e.getComboCount());
case ROSE -> print( "\uD83D\uDC95",ConsoleColors.YELLOW,"x", e.getCombo(), " roses!", "\uD83D\uDC95");
default -> print(ConsoleColors.YELLOW,"Thanks for gift: ", e.getGift().getName(),"X",e.getCombo());
}
if(e.getGift().hasDiamondCostRange(1000,10000))
{
@@ -91,36 +93,36 @@ public class Main {
private static void onDisconnected(LiveClient tikTokLive, TikTokDisconnectedEvent e) {
print(ConsoleColors.GREEN, "[Disconnected]");
}
private static void onViewerData(LiveClient tikTokLive, TikTokRoomViewerDataEvent e) {
print("Viewer count is:", e.getViewerCount());
private static void onViewerData(LiveClient tikTokLive, TikTokRoomUserInfoEvent e) {
print("Viewer count is:", e.getTotalUsers());
}
private static void onJoin(LiveClient tikTokLive, TikTokJoinEvent e) {
print(ConsoleColors.GREEN, "Join -> ", ConsoleColors.WHITE_BRIGHT, e.getUser().getNickName());
print(ConsoleColors.GREEN, "Join -> ", ConsoleColors.WHITE_BRIGHT, e.getUser().getName());
}
private static void onComment(LiveClient tikTokLive, TikTokCommentEvent e) {
print(ConsoleColors.WHITE, e.getUser().getUniqueId(), ":", ConsoleColors.WHITE_BRIGHT, e.getText());
print(ConsoleColors.WHITE, e.getUser().getId(), ":", ConsoleColors.WHITE_BRIGHT, e.getText());
}
private static void onFollow(LiveClient tikTokLive, TikTokFollowEvent e) {
print(e.getUser().getUniqueId(), "followed!");
print(e.getUser().getId(), "followed!");
}
private static void onShare(LiveClient tikTokLive, TikTokShareEvent e) {
print(e.getUser().getUniqueId(), "shared!");
print(e.getUser().getId(), "shared!");
}
private static void onSubscribe(LiveClient tikTokLive, TikTokSubscribeEvent e) {
print(e.getNewSubscriber().getUniqueId(), "subscribed!");
print(e.getUser().getId(), "subscribed!");
}
private static void onLike(LiveClient tikTokLive, TikTokLikeEvent e) {
print(e.getUser().getUniqueId(), "liked!");
print(e.getUser().getId(), "liked!");
}
private static void onEmote(LiveClient tikTokLive, TikTokEmoteEvent e) {
print(e.getUser().getUniqueId(), "sent", e.getEmotes().size());
print(e.getUser().getId(), "sent", e.getEmotes().size());
}
private static void print(Object... messages) {

View File

@@ -39,9 +39,9 @@ public class SimpleExample {
{
switch (event.getGift()) {
case ROSE ->
print("\uD83D\uDC95", ConsoleColors.YELLOW, "x", event.getComboCount(), " roses!", "\uD83D\uDC95");
print("\uD83D\uDC95", ConsoleColors.YELLOW, "x", event.getCombo(), " roses!", "\uD83D\uDC95");
default ->
print(ConsoleColors.GREEN, "[Thanks for gift] ",ConsoleColors.YELLOW, event.getGift().getName(), "X", event.getComboCount());
print(ConsoleColors.GREEN, "[Thanks for gift] ",ConsoleColors.YELLOW, event.getGift().getName(), "X", event.getCombo());
}
})
.onConnected((client, event) ->
@@ -50,15 +50,15 @@ public class SimpleExample {
})
.onFollow((liveClient, event) ->
{
print(ConsoleColors.BLUE, "Follow -> ", ConsoleColors.WHITE_BRIGHT, event.getUser().getNickName());
print(ConsoleColors.BLUE, "Follow -> ", ConsoleColors.WHITE_BRIGHT, event.getUser().getName());
})
.onJoin((client, event) ->
{
print(ConsoleColors.GREEN, "Join -> ", ConsoleColors.WHITE_BRIGHT, event.getUser().getNickName());
print(ConsoleColors.GREEN, "Join -> ", ConsoleColors.WHITE_BRIGHT, event.getUser().getName());
})
.onComment((client, event) ->
{
print(ConsoleColors.WHITE, event.getUser().getUniqueId(), ":", ConsoleColors.WHITE_BRIGHT, event.getText());
print(ConsoleColors.WHITE, event.getUser().getName(), ":", ConsoleColors.WHITE_BRIGHT, event.getText());
})
.onEvent((client, event) ->
{

View File

@@ -45,6 +45,12 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>Tools</artifactId>
<version>0.0.25-Release</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@@ -23,14 +23,12 @@
package io.github.jwdeveloper.tiktok.tools.collector;
import io.github.jwdeveloper.tiktok.TikTokLive;
import io.github.jwdeveloper.tiktok.events.messages.*;
import io.github.jwdeveloper.tiktok.events.messages.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.tools.collector.db.TikTokDatabase;
import io.github.jwdeveloper.tiktok.tools.collector.tables.ExceptionInfoModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -52,33 +50,26 @@ public class RunCollector {
//ignoredEvents = List.of("TikTokJoinEvent","TikTokLikeEvent");
filter = new ArrayList<>();
filter.add(TikTokUnhandledSocialEvent.class);
filter.add(TikTokFollowEvent.class);
filter.add(TikTokLikeEvent.class);
filter.add(TikTokShareEvent.class);
filter.add(TikTokJoinEvent.class);
// filter.add(TikTokUnhandledSocialEvent.class);
// filter.add(TikTokFollowEvent.class);
// filter.add(TikTokLikeEvent.class);
// filter.add(TikTokShareEvent.class);
// filter.add(TikTokJoinEvent.class);
var db = new TikTokDatabase("social_db");
var db = new TikTokDatabase("test");
db.init();
var errors = db.selectErrors();
var users = new ArrayList<String>();
users.add("mia_tattoo");
users.add("mr_wavecheck");
// users.add("mia_tattoo");
// users.add("mr_wavecheck");
users.add("bangbetmenygy");
users.add("larasworld0202");
for (var user : users)
{
users.add("szwagierkaqueen");
for (var user : users) {
try {
runTikTokLiveInstance(user, db);
}
catch (Exception e)
{
} catch (Exception e) {
}
}
}
@@ -87,29 +78,40 @@ public class RunCollector {
TikTokLive.newClient(tiktokUser)
.onConnected((liveClient, event) ->
{
System.out.println("CONNECTED TO "+liveClient.getRoomInfo().getUserName());
System.out.println("CONNECTED TO " + liveClient.getRoomInfo().getHostName());
})
.onWebsocketResponse((liveClient, event) ->
{
var response = Base64.getEncoder().encodeToString(event.getResponse().toByteArray());
var responseModel = new TikTokResponseModel();
responseModel.setResponse(response);
responseModel.setHostName(liveClient.getRoomInfo().getHostName());
tikTokDatabase.insertResponse(responseModel);
System.out.println("Included response");
})
.onWebsocketMessage((liveClient, event) ->
{
var eventName = event.getEvent().getClass().getSimpleName();
if(filter.size() != 0 && !filter.contains(event.getEvent().getClass()))
{
if (filter.size() != 0 && !filter.contains(event.getEvent().getClass())) {
return;
}
var binary = Base64.getEncoder().encodeToString(event.getMessage().toByteArray());
var messageBinary = Base64.getEncoder().encodeToString(event.getMessage().toByteArray());
var model = new TikTokMessageModel();
model.setType("messsage");
model.setHostName(tiktokUser);
model.setEventName(eventName);
model.setEventContent(binary);
model.setMessage(messageBinary);
tikTokDatabase.insertMessage(model);
// tikTokDatabase.insertMessage(model);
System.out.println("EVENT: [" + tiktokUser + "] " + eventName);
})
.onError((liveClient, event) ->
{
event.getException().printStackTrace();
var exception = event.getException();
var exceptionContent = ExceptionInfoModel.getStackTraceAsString(exception);
var errorModel = new TikTokErrorModel();

View File

@@ -48,4 +48,13 @@ public class SqlConsts
);
""";
public static String CREATE_RESPONSE_MODEL = """
CREATE TABLE IF NOT EXISTS TikTokResponseModel (
id INTEGER PRIMARY KEY AUTOINCREMENT,
hostName TEXT,
response TEXT,
createdAt TEXT
);
""";
}

View File

@@ -24,6 +24,7 @@ package io.github.jwdeveloper.tiktok.tools.collector.db;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
@@ -37,6 +38,7 @@ public class TikTokDatabase {
private final String database;
private TikTokMessageModelDAO messagesTable;
private TikTokErrorModelDAO errorTable;
private TikTokResponseModelDAO responseTable;
public TikTokDatabase(String database) {
this.database = database;
@@ -44,29 +46,34 @@ public class TikTokDatabase {
public void init() throws SQLException {
var jdbcUrl = "jdbc:sqlite:" + database + ".db";
var connection = DriverManager.getConnection(jdbcUrl);
DriverManager.getConnection(jdbcUrl);
var jdbi = Jdbi.create(jdbcUrl)
.installPlugin(new SqlObjectPlugin());
jdbi.useHandle(handle -> {
handle.execute(SqlConsts.CREATE_MESSAGES_TABLE);
handle.execute(SqlConsts.CREATE_ERROR_TABLE);
handle.execute(SqlConsts.CREATE_RESPONSE_MODEL);
});
messagesTable = jdbi.onDemand(TikTokMessageModelDAO.class);
errorTable = jdbi.onDemand(TikTokErrorModelDAO.class);
responseTable = jdbi.onDemand(TikTokResponseModelDAO.class);
}
public void insertMessage(TikTokMessageModel message) {
var dateFormat = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS");
message.setCreatedAt(dateFormat.format(new Date()));
message.setCreatedAt(getTime());
messagesTable.insertTikTokMessage(message);
}
public void insertError(TikTokErrorModel message) {
var dateFormat = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS");
message.setCreatedAt(dateFormat.format(new Date()));
message.setCreatedAt(getTime());
errorTable.insertTikTokMessage(message);
}
public void insertResponse(TikTokResponseModel message) {
message.setCreatedAt(getTime());
responseTable.insert(message);
}
public List<TikTokErrorModel> selectErrors() {
return errorTable.selectErrors();
}
@@ -74,4 +81,12 @@ public class TikTokDatabase {
public List<TikTokMessageModel> selectMessages() {
return messagesTable.select();
}
public List<TikTokResponseModel> selectResponces() {
return responseTable.select();
}
private String getTime() {
return new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS").format(new Date());
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.db;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import java.util.List;
@RegisterBeanMapper(TikTokResponseModel.class)
public interface TikTokResponseModelDAO
{
@SqlUpdate("INSERT INTO TikTokResponseModel (hostName, response, createdAt) " +
"VALUES (:hostName, :response, :createdAt)")
void insert(@BindBean TikTokResponseModel message);
@SqlQuery("SELECT * FROM TikTokResponseModel")
List<TikTokResponseModel> select();
}

View File

@@ -22,8 +22,6 @@
*/
package io.github.jwdeveloper.tiktok.tools.collector.tables;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -38,7 +36,7 @@ public class TikTokMessageModel
private String type;
private String eventContent;
private String message;
private String createdAt;
}

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.tools.collector.tables;
import lombok.Data;
@Data
public class TikTokResponseModel
{
private Integer id;
private String hostName;
private String response;
private String createdAt;
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester;
import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.mockClient.TikTokClientMock;
import io.github.jwdeveloper.tiktok.tools.collector.db.TikTokDatabase;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class RunDbTester {
public static void main(String[] args) throws Exception {
var db = new TikTokDatabase("test");
db.init();
var responses = db.selectResponces().stream().map(TikTokResponseModel::getResponse).toList();
var client = TikTokClientMock
.create()
.addResponses(responses)
.onWebsocketUnhandledMessage((liveClient, event) ->
{
liveClient.getLogger().info("Unhandled Message! " + event.getData().getMethod());
})
.onWebsocketMessage((liveClient, event) ->
{
var sb = new StringBuilder();
sb.append(event.getEvent().getClass().getSimpleName());
sb.append(event.getEvent().toJson());
// sb.append(ConsoleColors.YELLOW + messageContent(event.getMessage()));
liveClient.getLogger().info(sb.toString());
})
.build();
updateLogger(client.getLogger());
client.connect();
}
protected static String messageContent(WebcastResponse.Message message) {
try {
var methodName = message.getMethod();
if (!methodName.contains("Webcast")) {
methodName = "Webcast" + methodName;
}
var inputClazz = Class.forName("io.github.jwdeveloper.tiktok.messages.webcast." + methodName);
var parseMethod = inputClazz.getDeclaredMethod("parseFrom", ByteString.class);
var deserialized = parseMethod.invoke(null, message.getPayload());
return JsonUtil.messageToJson(deserialized);
} catch (Exception ex) {
return "";
}
}
public static void updateLogger(Logger logger) {
for (var handler : logger.getHandlers()) {
logger.removeHandler(handler);
}
var handler = new ConsoleHandler();
handler.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return ConsoleColors.WHITE_BRIGHT + record.getLevel() + ": " + ConsoleColors.GREEN + record.getMessage() + "\n" + ConsoleColors.RESET;
}
});
logger.setUseParentHandlers(false);
logger.addHandler(handler);
}
}

View File

@@ -22,17 +22,16 @@
*/
package io.github.jwdeveloper.tiktok.tools.tester;
import io.github.jwdeveloper.tiktok.events.objects.Gift;
import io.github.jwdeveloper.tiktok.mockClient.TikTokClientMock;
public class RunLogTester
{
public static void main(String[] args)
{
var mockClient = TikTokClientMock.create("123").buildAndRun();
public class RefelcionTest {
public static void main(String[] run) throws NoSuchFieldException, IllegalAccessException {
var gift = Gift.PANDA;
var url = gift.getPicture();
var field = gift.getClass().getDeclaredField("picture");
field.setAccessible(true);
field.set(gift, null);
var url2 = gift.getPicture();
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokGiftComboFinishedEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.tools.collector.db.TikTokDatabase;
import java.util.Base64;
public class RunTester {
public static void main(String[] args) throws Exception {
var db = new TikTokDatabase("test");
db.init();
var errors = db.selectErrors();
var handler = getMessageHandler();
for (var error : errors) {
var bytes = Base64.getDecoder().decode(error.getResponse());
var response = WebcastResponse.parseFrom(bytes);
handler.handle(null, response);
}
var messags = db.selectMessages();
for (var msg : messags) {
if (!msg.getEventName().contains("Gift")) {
continue;
}
var bytes = Base64.getDecoder().decode(msg.getEventContent());
var response = WebcastResponse.Message.parseFrom(bytes);
handler.handleSingleMessage(null, response);
}
}
public static TikTokMessageHandlerRegistration getMessageHandler() {
var observer = new TikTokEventObserver();
observer.<TikTokGiftEvent>subscribe(TikTokGiftEvent.class, (liveClient, event) ->
{
var sb = new StringBuilder();
sb.append("Event: " + event.getGift());
sb.append(" combo: " + event.getComboCount());
sb.append(" index " + event.getComboIndex());
sb.append(" sender " + event.getSender().getNickName());
System.out.println(sb.toString());
});
observer.<TikTokGiftComboFinishedEvent>subscribe(TikTokGiftComboFinishedEvent.class, (liveClient, event) ->
{
System.out.println("Combo finished event! " + event.getComboCount() + " " + event.getGift());
});
observer.<TikTokErrorEvent>subscribe(TikTokErrorEvent.class, (liveClient, event) ->
{
event.getException().printStackTrace();
});
var roomInfo = new TikTokRoomInfo();
var manager = new TikTokGiftManager();
return new TikTokMessageHandlerRegistration(observer, manager, roomInfo);
}
}

File diff suppressed because one or more lines are too long

View File

@@ -59,7 +59,7 @@ public class FullEventsExampleClass
{
})
.onRoomViewerData((liveClient, event) ->
.onRoomUserInfo((liveClient, event) ->
{
})

View File

@@ -0,0 +1,36 @@
/*
* 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.mockClient;
public class TikTokClientMock
{
public static TikTokMockBuilder create(String host)
{
return new TikTokMockBuilder(host);
}
public static TikTokMockBuilder create()
{
return create("MockHostName");
}
}

View File

@@ -0,0 +1,120 @@
/*
* 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.mockClient;
import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.mockClient.mocks.ApiServiceMock;
import io.github.jwdeveloper.tiktok.mockClient.mocks.LiveClientMock;
import io.github.jwdeveloper.tiktok.mockClient.mocks.WebsocketClientMock;
import java.util.Base64;
import java.util.List;
import java.util.Stack;
public class TikTokMockBuilder extends TikTokLiveClientBuilder {
Stack<WebcastResponse> responses;
public TikTokMockBuilder(String userName) {
super(userName);
responses = new Stack<>();
}
public TikTokMockBuilder addResponse(String value) {
var bytes = Base64.getDecoder().decode(value);
return addResponse(bytes);
}
public TikTokMockBuilder addResponses(List<String> values) {
for (var value : values) {
try {
addResponse(value);
} catch (Exception e) {
throw new TikTokLiveException(value, e);
}
}
return this;
}
public TikTokMockBuilder addResponse(byte[] bytes) {
try {
var response = WebcastResponse.parseFrom(bytes);
return addResponse(response);
} catch (Exception e) {
throw new RuntimeException("Unable to parse response from bytes", e);
}
}
public TikTokMockBuilder addResponse(WebcastResponse message) {
responses.push(message);
return this;
}
@Override
public LiveClientMock build() {
validate();
var cookie = new TikTokCookieJar();
var tiktokRoomInfo = new TikTokRoomInfo();
tiktokRoomInfo.setHostName(clientSettings.getHostName());
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
var giftManager = new TikTokGiftManager();
var requestFactory = new TikTokHttpRequestFactory(cookie);
var apiClient = new TikTokHttpClient(cookie, requestFactory);
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler,
giftManager,
tiktokRoomInfo);
var webSocketClient = new WebsocketClientMock(logger, responses, webResponseHandler);
return new LiveClientMock(tiktokRoomInfo,
apiService,
webSocketClient,
giftManager,
tikTokEventHandler,
clientSettings,
listenerManager,
logger);
}
@Override
public LiveClientMock buildAndRun() {
var client = build();
client.connect();
return client;
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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.mockClient.mocks;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.util.logging.Logger;
public class ApiServiceMock extends TikTokApiService {
public ApiServiceMock(TikTokHttpClient apiClient, Logger logger, ClientSettings clientSettings) {
super(apiClient, logger, clientSettings);
}
@Override
public void updateSessionId() {
}
@Override
public LiveRoomMeta fetchRoomInfo()
{
var meta = new LiveRoomMeta();
meta.setStatus(1);
return meta;
}
@Override
public WebcastResponse fetchClientData() {
return WebcastResponse.newBuilder().build();
}
@Override
public String fetchRoomId(String userName) {
return "mock-room-id";
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.mockClient.mocks;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.util.logging.Logger;
public class LiveClientMock extends TikTokLiveClient {
private final WebsocketClientMock websocketClientMock;
public LiveClientMock(TikTokRoomInfo tikTokLiveMeta,
TikTokApiService tikTokApiService,
WebsocketClientMock webSocketClient,
TikTokGiftManager tikTokGiftManager,
TikTokEventObserver tikTokEventHandler,
ClientSettings clientSettings,
TikTokListenersManager listenersManager,
Logger logger) {
super(tikTokLiveMeta,
tikTokApiService,
webSocketClient,
tikTokGiftManager,
tikTokEventHandler,
clientSettings,
listenersManager,
logger);
this.websocketClientMock = webSocketClient;
}
public void publishResponse(String value) {
websocketClientMock.addResponse(value);
}
public void publishResponse(byte[] bytes) {
websocketClientMock.addResponse(bytes);
}
public void publishResponse(WebcastResponse message) {
websocketClientMock.addResponse(message);
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.mockClient.mocks;
import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import java.util.Base64;
import java.util.Stack;
import java.util.logging.Logger;
public class WebsocketClientMock implements SocketClient {
Logger logger;
Stack<WebcastResponse> responses;
TikTokMessageHandler messageHandler;
private boolean isRunning;
public WebsocketClientMock(Logger logger, Stack<WebcastResponse> responses, TikTokMessageHandler messageHandler) {
this.logger = logger;
this.responses = responses;
this.messageHandler = messageHandler;
}
public WebsocketClientMock addResponse(String value) {
var bytes = Base64.getDecoder().decode(value);
return addResponse(bytes);
}
public WebsocketClientMock addResponse(byte[] bytes) {
try {
var response = WebcastResponse.parseFrom(bytes);
return addResponse(response);
} catch (Exception e) {
throw new RuntimeException("Unable to parse response from bytes", e);
}
}
public WebsocketClientMock addResponse(WebcastResponse message) {
responses.push(message);
return this;
}
@Override
public void start(WebcastResponse webcastResponse, LiveClient tikTokLiveClient) {
logger.info("Running message: " + responses.size());
isRunning =true;
while (isRunning) {
do {
if(responses.isEmpty())
{
break;
}
var response = responses.pop();
for (var message : response.getMessagesList()) {
try {
messageHandler.handleSingleMessage(tikTokLiveClient, message);
} catch (Exception e) {
logger.info("Unable to parse message for response " + response.getCursor());
throw new TikTokLiveMessageException(message, response, e);
}
}
}
while (!responses.isEmpty());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void stop() {
isRunning = true;
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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;
public class ConsoleColors
{
public static final String RESET = "\033[0m"; // Text Reset
// Regular Colors
public static final String BLACK = "\033[0;30m"; // BLACK
public static final String RED = "\033[0;31m"; // RED
public static final String GREEN = "\033[0;32m"; // GREEN
public static final String YELLOW = "\033[0;33m"; // YELLOW
public static final String BLUE = "\033[0;34m"; // BLUE
public static final String PURPLE = "\033[0;35m"; // PURPLE
public static final String CYAN = "\033[0;36m"; // CYAN
public static final String WHITE = "\033[0;37m"; // WHITE
// Bold
public static final String BLACK_BOLD = "\033[1;30m"; // BLACK
public static final String RED_BOLD = "\033[1;31m"; // RED
public static final String GREEN_BOLD = "\033[1;32m"; // GREEN
public static final String YELLOW_BOLD = "\033[1;33m"; // YELLOW
public static final String BLUE_BOLD = "\033[1;34m"; // BLUE
public static final String PURPLE_BOLD = "\033[1;35m"; // PURPLE
public static final String CYAN_BOLD = "\033[1;36m"; // CYAN
public static final String WHITE_BOLD = "\033[1;37m"; // WHITE
// Underline
public static final String BLACK_UNDERLINED = "\033[4;30m"; // BLACK
public static final String RED_UNDERLINED = "\033[4;31m"; // RED
public static final String GREEN_UNDERLINED = "\033[4;32m"; // GREEN
public static final String YELLOW_UNDERLINED = "\033[4;33m"; // YELLOW
public static final String BLUE_UNDERLINED = "\033[4;34m"; // BLUE
public static final String PURPLE_UNDERLINED = "\033[4;35m"; // PURPLE
public static final String CYAN_UNDERLINED = "\033[4;36m"; // CYAN
public static final String WHITE_UNDERLINED = "\033[4;37m"; // WHITE
// Background
public static final String BLACK_BACKGROUND = "\033[40m"; // BLACK
public static final String RED_BACKGROUND = "\033[41m"; // RED
public static final String GREEN_BACKGROUND = "\033[42m"; // GREEN
public static final String YELLOW_BACKGROUND = "\033[43m"; // YELLOW
public static final String BLUE_BACKGROUND = "\033[44m"; // BLUE
public static final String PURPLE_BACKGROUND = "\033[45m"; // PURPLE
public static final String CYAN_BACKGROUND = "\033[46m"; // CYAN
public static final String WHITE_BACKGROUND = "\033[47m"; // WHITE
// High Intensity
public static final String BLACK_BRIGHT = "\033[0;90m"; // BLACK
public static final String RED_BRIGHT = "\033[0;91m"; // RED
public static final String GREEN_BRIGHT = "\033[0;92m"; // GREEN
public static final String YELLOW_BRIGHT = "\033[0;93m"; // YELLOW
public static final String BLUE_BRIGHT = "\033[0;94m"; // BLUE
public static final String PURPLE_BRIGHT = "\033[0;95m"; // PURPLE
public static final String CYAN_BRIGHT = "\033[0;96m"; // CYAN
public static final String WHITE_BRIGHT = "\033[0;97m"; // WHITE
// Bold High Intensity
public static final String BLACK_BOLD_BRIGHT = "\033[1;90m"; // BLACK
public static final String RED_BOLD_BRIGHT = "\033[1;91m"; // RED
public static final String GREEN_BOLD_BRIGHT = "\033[1;92m"; // GREEN
public static final String YELLOW_BOLD_BRIGHT = "\033[1;93m";// YELLOW
public static final String BLUE_BOLD_BRIGHT = "\033[1;94m"; // BLUE
public static final String PURPLE_BOLD_BRIGHT = "\033[1;95m";// PURPLE
public static final String CYAN_BOLD_BRIGHT = "\033[1;96m"; // CYAN
public static final String WHITE_BOLD_BRIGHT = "\033[1;97m"; // WHITE
// High Intensity backgrounds
public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m";// BLACK
public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m";// RED
public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m";// GREEN
public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m";// YELLOW
public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m";// BLUE
public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE
public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN
public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; // WHITE
}