Compare commits

..

6 Commits

Author SHA1 Message Date
kohlerpop1
39c3b5b1bc Final Proxy Commit! 2024-01-14 20:55:00 +01:00
kohlerpop1
f40a26ad7c Push for proxy test pt 4! 2024-01-14 20:55:00 +01:00
kohlerpop1
4fab46b3d9 Push for proxy test pt 3! 2024-01-14 20:55:00 +01:00
kohlerpop1
a89e2c2e08 Push for proxy test pt 2! 2024-01-14 20:55:00 +01:00
kohlerpop1
bc8c56982f Push for proxy test! 2024-01-14 20:55:00 +01:00
kohlerpop1
fa5385d893 Added convenience methods back to TikTokLive and changed sing to sign where misspelled! 2024-01-14 20:55:00 +01:00
256 changed files with 217661 additions and 5481 deletions

3
.gitignore vendored
View File

@@ -1,11 +1,10 @@
backend-infrastructure/.aws-sam
.db
# Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode
*.db
### Linux ###
*~
.db
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.7.2-Release</version>
<version>1.0.16-Release</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>API</artifactId>

View File

@@ -50,12 +50,16 @@ public class ProxyData
return new ProxyData(address, port);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Port must be a valid integer!", e);
throw new IllegalArgumentException("Port must be a valid integer!");
} catch (UnknownHostException e) {
throw new IllegalArgumentException("Address must be valid IPv4, IPv6, or domain name!", e);
throw new IllegalArgumentException("Address must be valid IPv4, IPv6, or domain name!");
}
}
public ProxyData clone() {
return new ProxyData(address, port);
}
public InetSocketAddress toSocketAddress() {
return new InetSocketAddress(address, port);
}

View File

@@ -20,18 +20,24 @@
* 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.data.events.control;
package io.github.jwdeveloper.tiktok.data.events;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import lombok.Data;
/**
* Triggered when client is connecting to live is successfully established.
*/
@EventMeta(eventType = EventType.Control)
public class TikTokConnectingEvent extends TikTokLiveClientEvent
{
@Data
@EventMeta(eventType = EventType.Message)
public class CustomEvent extends TikTokHeaderEvent {
private final User user;
private final String title;
public CustomEvent(User user, String title) {
this.user = user;
this.title = title;
}
}

View File

@@ -38,7 +38,8 @@ public class TikTokBarrageEvent extends TikTokHeaderEvent {
private final Picture rightIcon;
private final String eventName;
private final int duration;
private final BarrageParam barrageParam;
private BarrageParam barrageParam;
public TikTokBarrageEvent(WebcastBarrageMessage msg) {
super(msg.getCommon());
@@ -48,5 +49,6 @@ public class TikTokBarrageEvent extends TikTokHeaderEvent {
rightIcon = Picture.map(msg.getRightIcon());
duration = msg.getDuration();
barrageParam = BarrageParam.map(msg);
}
}
}

View File

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

View File

@@ -40,30 +40,18 @@ import java.util.List;
public class TikTokCommentEvent extends TikTokHeaderEvent {
private final User user;
private final String text;
private final String userLanguage;
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.map(msg.getUser(), msg.getUserIdentity());
user = User.map(msg.getUser(),msg.getUserIdentity());
text = msg.getContent();
visibleToSender = msg.getVisibleToSender();
userLanguage = msg.getContentLanguage();
getUserLanguage = msg.getContentLanguage();
mentionedUser = User.map(msg.getAtUser());
pictures = msg.getEmotesListList().stream().map(e -> Picture.map(e.getEmote().getImage())).toList();
}
public static TikTokCommentEvent of(String userName, String message) {
var builder = WebcastChatMessage.newBuilder();
builder.setUser(io.github.jwdeveloper.tiktok.messages.data.User.newBuilder()
.setNickname(userName)
.build());
builder.setContentLanguage("en");
builder.setVisibleToSender(true);
builder.setContent(message);
return new TikTokCommentEvent(builder.build());
}
}
}

View File

@@ -30,10 +30,14 @@ import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokDetectEvent extends TikTokHeaderEvent {
private final String language;
String language;
public TikTokDetectEvent(WebcastMsgDetectMessage msg) {
super(msg.getCommon());
language = msg.getFromRegion();
}
}
public TikTokDetectEvent(WebcastMsgDetectMessage msg) {
super(msg.getCommon());
language = msg.getFromRegion();
}
}

View File

@@ -30,11 +30,9 @@ import lombok.Getter;
* Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic.
* Note that you should wait a little bit before attempting a reconnect to to avoid being rate-limited.
*/
@Getter
@EventMeta(eventType = EventType.Control)
public class TikTokDisconnectedEvent extends TikTokLiveClientEvent {
private final String reason;
@Getter private final String reason;
public TikTokDisconnectedEvent(String reason) {
this.reason = reason.isBlank() ? "None" : reason;
}

View File

@@ -36,9 +36,9 @@ import lombok.Value;
@Value
@EventMeta(eventType = EventType.Message)
public class TikTokEnvelopeEvent extends TikTokHeaderEvent {
User user;
public TikTokEnvelopeEvent(WebcastEnvelopeMessage msg) {
super(msg.getCommon());
user = User.map(msg.getEnvelopeInfo());
}
}
User user;
public TikTokEnvelopeEvent(WebcastEnvelopeMessage msg) {
super(msg.getCommon());
user = User.map(msg.getEnvelopeInfo());
}
}

View File

@@ -34,10 +34,9 @@ import java.util.List;
@EventMeta(eventType = EventType.Message)
public class TikTokIMDeleteEvent extends TikTokHeaderEvent {
private final List<Long> msgIds, userIds;
List<Long> userIds;
public TikTokIMDeleteEvent(WebcastImDeleteMessage msg) {
super(msg.getCommon());
this.msgIds = msg.getDeleteMsgIdsListList();
this.userIds = msg.getDeleteUserIdsListList();
}
}
}

View File

@@ -31,10 +31,10 @@ import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokInRoomBannerEvent extends TikTokHeaderEvent {
private final String json;
private final String json;
public TikTokInRoomBannerEvent(WebcastInRoomBannerMessage msg) {
super(msg.getHeader());
json = msg.getJson();
}
}
public TikTokInRoomBannerEvent(WebcastInRoomBannerMessage msg) {
super(msg.getHeader());
json = msg.getJson();
}
}

View File

@@ -20,24 +20,24 @@
* 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.data.events.link;
package io.github.jwdeveloper.tiktok.data.events;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
import java.util.List;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkEvent extends TikTokHeaderEvent {
private final String extra, transferExtra;
private final long expireTimestamp;
public TikTokLinkEvent(WebcastLinkMessage msg) {
super(msg.getCommon());
this.extra = msg.getExtra();
this.expireTimestamp = msg.getExpireTimestamp();
this.transferExtra = msg.getTransferExtra();
}
}
}

View File

@@ -33,7 +33,11 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Message)
public class TikTokLinkLayerEvent extends TikTokHeaderEvent {
public TikTokLinkLayerEvent(WebcastLinkLayerMessage msg) {
super(msg.getCommon());
}
}
}

View File

@@ -27,12 +27,12 @@ import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.LinkMicArmy;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.messages.enums.LinkMicBattleStatus;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicArmies;
import lombok.Getter;
import java.util.List;
/**
* Triggered every time a battle participant receives points. Contains the current status of the battle and the army that suported the group.
*/
@@ -40,10 +40,8 @@ import java.util.List;
@EventMeta(eventType = EventType.Message)
public class TikTokLinkMicArmiesEvent extends TikTokHeaderEvent {
private final Long battleId;
/**
true if battle is finished otherwise false
*/
private final boolean finished;
private final Integer battleStatus;
private final Picture picture;
@@ -54,6 +52,6 @@ public class TikTokLinkMicArmiesEvent extends TikTokHeaderEvent {
battleId = msg.getId();
armies = msg.getBattleItemsList().stream().map(LinkMicArmy::new).toList();
picture = Picture.map(msg.getImage());
finished = msg.getBattleStatus() == LinkMicBattleStatus.ARMY_FINISHED;
battleStatus = msg.getBattleStatus();
}
}
}

View File

@@ -22,62 +22,29 @@
*/
package io.github.jwdeveloper.tiktok.data.events;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.battles.*;
import io.github.jwdeveloper.tiktok.messages.enums.LinkMicBattleStatus;
import io.github.jwdeveloper.tiktok.data.models.LinkMicBattleTeam;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.*;
import lombok.Getter;
import java.util.*;
import java.util.List;
/**
* Triggered every time a battle starts & ends
* Triggered every time a battle starts.
*/
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent
{
private final Long battleId;
/**
true if battle is finished otherwise false
*/
private final boolean finished;
@Getter(AccessLevel.NONE)
private final boolean oneVsOne;
private final List<Team> teams;
public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent {
private final Long battleId;
private final List<LinkMicBattleTeam> team1;
private final List<LinkMicBattleTeam> team2;
public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) {
super(msg.getCommon());
battleId = msg.getId();
finished = msg.getBattleStatus() == LinkMicBattleStatus.BATTLE_FINISHED;
teams = new ArrayList<>();
if (msg.getHostTeamCount() == 2) { // 1v1 battle
teams.add(new Team1v1(msg.getHostTeam(0), msg));
teams.add(new Team1v1(msg.getHostTeam(1), msg));
oneVsOne = true;
} else { // 2v2 battle
if (isFinished()) {
teams.add(new Team2v2(msg.getHostData2V2List().stream().filter(data -> data.getTeamNumber() == 1).findFirst().orElse(null), msg));
teams.add(new Team2v2(msg.getHostData2V2List().stream().filter(data -> data.getTeamNumber() == 2).findFirst().orElse(null), msg));
} else {
teams.add(new Team2v2(msg.getHostTeam(0), msg.getHostTeam(1), msg));
teams.add(new Team2v2(msg.getHostTeam(2), msg.getHostTeam(3), msg));
}
oneVsOne = false;
}
// Info:
// - msg.getDetailsList() & msg.getViewerTeamList() both only have content when battle is finished
// - msg.getDetailsCount() & msg.getViewerTeamCount() always is 2 only when battle is finished
// - msg.getHostTeamCount() always is 2 for 1v1 or 4 for 2v2
}
public boolean is1v1() {
return oneVsOne;
}
public boolean is2v2() {
return !oneVsOne;
}
}
public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) {
super(msg.getCommon());
battleId = msg.getId();
team1 = msg.getTeams1List().stream().map(LinkMicBattleTeam::new).toList();
team2 = msg.getTeams2List().stream().map(LinkMicBattleTeam::new).toList();
}
}

View File

@@ -32,8 +32,10 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Message)
public class TikTokLinkMicMethodEvent extends TikTokHeaderEvent {
public TikTokLinkMicMethodEvent(WebcastLinkMicMethod msg) {
super(msg.getCommon());
public TikTokLinkMicMethodEvent(WebcastLinkMicMethod msg) {
super(msg.getCommon());
}
}
}
}

View File

@@ -32,14 +32,15 @@ import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokRankTextEvent extends TikTokHeaderEvent {
private final String eventType;
private final String eventType;
private final String label;
private final String label;
public TikTokRankTextEvent(WebcastRankTextMessage msg) {
super(msg.getCommon());
var text = Text.map(msg.getSelfGetBadgeMsg());
label = text.getPattern();
eventType = text.getKey();
}
}
public TikTokRankTextEvent(WebcastRankTextMessage msg) {
super(msg.getCommon());
var text = Text.map(msg.getSelfGetBadgeMsg());
label = text.getPattern();
eventType = text.getKey();
}
}

View File

@@ -33,11 +33,13 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Message)
public class TikTokRankUpdateEvent extends TikTokHeaderEvent {
public TikTokRankUpdateEvent(WebcastHourlyRankMessage msg) {
super(msg.getCommon());
}
public TikTokRankUpdateEvent(WebcastHourlyRankMessage msg) {
super(msg.getCommon());
public TikTokRankUpdateEvent(WebcastRankUpdateMessage msg) {
super(msg.getCommon());
}
}
}
public TikTokRankUpdateEvent(WebcastRankUpdateMessage msg) {
super(msg.getCommon());
}
}

View File

@@ -32,24 +32,25 @@ import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokShopEvent extends TikTokHeaderEvent {
private final String title;
private final String title;
private final String price;
private final String price;
private final Picture picture;
private final Picture picture;
private final String shopUrl;
private final String shopUrl;
private final String shopName;
private final String shopName;
//Not working
public TikTokShopEvent(WebcastOecLiveShoppingMessage msg) {
super(msg.getCommon());
var data = msg.getShopData();
title = data.getTitle();
price = data.getPriceString();
picture = new Picture(data.getImageUrl());
shopUrl = data.getShopUrl();
shopName = data.getShopName();
}
}
//Not working
public TikTokShopEvent(WebcastOecLiveShoppingMessage msg) {
super(msg.getCommon());
var data = msg.getShopData();
title = data.getTitle();
price = data.getPriceString();
picture = new Picture(data.getImageUrl());
shopUrl = data.getShopUrl();
shopName = data.getShopName();
}
}

View File

@@ -36,10 +36,10 @@ import lombok.Getter;
*/
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokSubscribeEvent extends TikTokHeaderEvent {
public class TikTokSubscribeEvent extends TikTokHeaderEvent
{
private final User user;
public TikTokSubscribeEvent(WebcastMemberMessage msg) {
super(msg.getCommon());
user = User.map(msg.getUser());
@@ -52,11 +52,4 @@ public class TikTokSubscribeEvent extends TikTokHeaderEvent {
user.addAttribute(UserAttribute.Subscriber);
}
public static TikTokSubscribeEvent of(String userName) {
return new TikTokSubscribeEvent(WebcastMemberMessage.newBuilder()
.setUser(io.github.jwdeveloper.tiktok.messages.data.User.newBuilder()
.setNickname(userName)
.build())
.build());
}
}

View File

@@ -1,45 +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.data.events.control;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
import io.github.jwdeveloper.tiktok.data.requests.*;
import lombok.*;
/**
* Triggered before the connection is established.
*/
@Getter
@EventMeta(eventType = EventType.Control)
public class TikTokPreConnectionEvent extends TikTokLiveClientEvent
{
private final LiveUserData.Response userData;
private final LiveData.Response roomData;
@Setter boolean cancelConnection = false;
public TikTokPreConnectionEvent(LiveUserData.Response userData, LiveData.Response liveData) {
this.userData = userData;
this.roomData = liveData;
}
}

View File

@@ -22,9 +22,10 @@
*/
package io.github.jwdeveloper.tiktok.data.events.gift;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.gifts.*;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import lombok.Getter;
@@ -33,7 +34,7 @@ import lombok.Getter;
/**
* Triggered every time gift is sent
*
* @see GiftComboStateType it has 3 states
* @see GiftSendType it has 3 states
*
* <p>Example when user sends gift with combo</p>
* <p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
@@ -46,21 +47,10 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Message)
@Getter
public class TikTokGiftComboEvent extends TikTokGiftEvent {
private final GiftComboStateType comboState;
private final GiftSendType comboState;
public TikTokGiftComboEvent(Gift gift, User host, WebcastGiftMessage msg, GiftComboStateType comboState) {
public TikTokGiftComboEvent(Gift gift, User host, WebcastGiftMessage msg, GiftSendType comboState) {
super(gift, host, msg);
this.comboState = comboState;
}
public static TikTokGiftComboEvent of(Gift gift, int combo, GiftComboStateType comboState) {
return new TikTokGiftComboEvent(
gift,
new User(0L, "Test", new Picture("")),
WebcastGiftMessage
.newBuilder()
.setComboCount(combo)
.build(),
comboState);
}
}
}

View File

@@ -23,14 +23,18 @@
package io.github.jwdeveloper.tiktok.data.events.gift;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.gifts.*;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import lombok.Getter;
import java.util.ArrayList;
/**
* Triggered when user sends gifts that has
@@ -56,20 +60,4 @@ public class TikTokGiftEvent extends TikTokHeaderEvent {
}
combo = msg.getComboCount();
}
public TikTokGiftEvent(Gift gift) {
this.gift = gift;
user = new User(0L, "sender", new Picture(""));
toUser = new User(0L, "receiver", new Picture(""));
combo = 1;
}
public static TikTokGiftEvent of(Gift gift) {
return new TikTokGiftEvent(gift);
}
public static TikTokGiftEvent of(String name, int id, int diamonds) {
return TikTokGiftEvent.of(new Gift(id, name, diamonds, ""));
}
}

View File

@@ -1,38 +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.data.events.http;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
@EventMeta(eventType = EventType.Debug)
public class TikTokRoomDataResponseEvent extends TikTokEvent
{
private final LiveData.Response liveData;
}

View File

@@ -1,45 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkAcceptNoticeEvent extends TikTokLinkEvent {
private final long fromUserId, fromRoomId, toUserId;
public TikTokLinkAcceptNoticeEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasAcceptNoticeContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Accept Notice Content!");
var content = msg.getAcceptNoticeContent();
this.fromUserId = content.getFromUserId();
this.fromRoomId = content.getFromRoomId();
this.toUserId = content.getToUserId();
}
}

View File

@@ -1,46 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkCancelEvent extends TikTokLinkEvent {
private final long fromUserId, toUserId, cancelType, actionId;
public TikTokLinkCancelEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasCancelContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Cancel Content!");
var content = msg.getCancelContent();
this.fromUserId = content.getFromUserId();
this.toUserId = content.getToUserId();
this.cancelType = content.getCancelType();
this.actionId = content.getActionId();
}
}

View File

@@ -1,39 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkCloseEvent extends TikTokLinkEvent {
public TikTokLinkCloseEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasCloseContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Close Content!");
// Proto Empty
}
}

View File

@@ -1,39 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkCohostListChangeEvent extends TikTokLinkEvent {
public TikTokLinkCohostListChangeEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasCohostListChangeContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Cohost List Change Content!");
// Proto Empty
}
}

View File

@@ -1,44 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkCreateEvent extends TikTokLinkEvent {
private final long hostId, roomId, linkType;
public TikTokLinkCreateEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasCreateContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Create Content!");
var content = msg.getCreateContent();
this.hostId = content.getOwnerId();
this.roomId = content.getOwnerRoomId();
this.linkType = content.getLinkType();
}
}

View File

@@ -1,48 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.users.ListUser;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
import java.util.List;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkEnterEvent extends TikTokLinkEvent {
private final List<ListUser> listUsers;
private final int anchorMultiLiveEnum;
public TikTokLinkEnterEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasEnterContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Enter Content!");
var content = msg.getEnterContent();
this.listUsers = content.getLinkedUsersListList().stream().map(ListUser::map).toList();
this.anchorMultiLiveEnum = content.getAnchorMultiLiveEnum();
}
}

View File

@@ -1,46 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkInviteEvent extends TikTokLinkEvent {
private final long roomId;
private final User inviter;
public TikTokLinkInviteEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasInviteContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Invite Content!");
var content = msg.getInviteContent();
this.roomId = content.getFromRoomId();
this.inviter = User.map(content.getFromUser());
}
}

View File

@@ -1,55 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkKickOutEvent extends TikTokLinkEvent {
private final long fromUserId;
private final KickOutReason kickOutReason;
public TikTokLinkKickOutEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasKickOutContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Kick Out Content!");
var content = msg.getKickOutContent();
this.fromUserId = content.getFromUserId();
this.kickOutReason = KickOutReason.values()[content.getKickoutReasonValue()];
}
public enum KickOutReason {
KICKOUT_REASON_UNKNOWN,
KICKOUT_REASON_FIRST_FRAME_TIMEOUT,
KICKOUT_REASON_BY_HOST,
KICKOUT_REASON_RTC_LOST_CONNECTION,
KICKOUT_REASON_BY_PUNISH,
KICKOUT_REASON_BY_ADMIN,
KICKOUT_REASON_HOST_REMOVE_ALL_GUESTS
}
}

View File

@@ -1,47 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkLeaveEvent extends TikTokLinkEvent {
private final long userId, sendLeaveUid, leaveReason;
private final String linkmicIdStr;
public TikTokLinkLeaveEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasLeaveContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Leave Content!");
var content = msg.getLeaveContent();
this.userId = content.getUserId();
this.linkmicIdStr = content.getLinkmicIdStr();
this.sendLeaveUid = content.getSendLeaveUid();
this.leaveReason = content.getLeaveReason();
}
}

View File

@@ -1,39 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkLinkedListChangeEvent extends TikTokLinkEvent {
public TikTokLinkLinkedListChangeEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasLinkedListChangeContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Linked List Change Content!");
// Proto Empty
}
}

View File

@@ -1,48 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.users.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
import java.util.List;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkListChangeEvent extends TikTokLinkEvent {
private final List<ListUser> linkedUsers, appliedUsers, connectingUsers;
public TikTokLinkListChangeEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasListChangeContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with List Change Content!");
var content = msg.getListChangeContent();
this.linkedUsers = content.getLinkedUsersList().stream().map(ListUser::map).toList();
this.appliedUsers = content.getAppliedUsersList().stream().map(ListUser::map).toList();
this.connectingUsers = content.getConnectingUsersList().stream().map(ListUser::map).toList();
}
}

View File

@@ -1,47 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkMediaChangeEvent extends TikTokLinkEvent {
private final long op, toUserId, anchorId, roomId, changeScene;
public TikTokLinkMediaChangeEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasMediaChangeContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Media Change Content!");
var content = msg.getMediaChangeContent();
this.op = content.getOp();
this.toUserId = content.getToUserId();
this.anchorId = content.getAnchorId();
this.roomId = content.getRoomId();
this.changeScene = content.getChangeScene();
}
}

View File

@@ -1,39 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkMicIdxUpdateEvent extends TikTokLinkEvent {
public TikTokLinkMicIdxUpdateEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasMicIdxUpdateContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Mic Idx Update Content!");
// Proto Empty
}
}

View File

@@ -1,44 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkMuteEvent extends TikTokLinkEvent {
private final long userId, status;
public TikTokLinkMuteEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasMuteContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Mute Content!");
var content = msg.getMuteContent();
this.userId = content.getUserId();
this.status = content.getStatus();
}
}

View File

@@ -1,50 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkRandomMatchEvent extends TikTokLinkEvent {
private final User user;
private final long roomId, inviteType, innerChannelId;
private final String matchId;
public TikTokLinkRandomMatchEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasRandomMatchContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Random Match Content!");
var content = msg.getRandomMatchContent();
this.user = User.map(content.getUser());
this.roomId = content.getRoomId();
this.inviteType = content.getInviteType();
this.matchId = content.getMatchId();
this.innerChannelId = content.getInnerChannelId();
}
}

View File

@@ -1,47 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkReplyEvent extends TikTokLinkEvent {
private final long roomId;
private final User fromUser, toUser;
public TikTokLinkReplyEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasReplyContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Reply Content!");
var content = msg.getReplyContent();
this.roomId = content.getFromRoomId();
this.fromUser = User.map(content.getFromUser());
this.toUser = User.map(content.getToUser());
}
}

View File

@@ -1,45 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkSysKickOutEvent extends TikTokLinkEvent {
private final long userId;
private final String linkmicIdStr;
public TikTokLinkSysKickOutEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasSysKickOutContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Sys Kick Out Content!");
var content = msg.getSysKickOutContent();
this.userId = content.getUserId();
this.linkmicIdStr = content.getLinkmicIdStr();
}
}

View File

@@ -1,44 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkUpdateUserEvent extends TikTokLinkEvent {
private final long fromUserId, toUserId;
public TikTokLinkUpdateUserEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasUpdateUserContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Update User Content!");
var content = msg.getUpdateUserContent();
this.fromUserId = content.getFromUserId();
this.toUserId = content.getToUserId();
}
}

View File

@@ -1,39 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkUpdateUserSettingEvent extends TikTokLinkEvent {
public TikTokLinkUpdateUserSettingEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasUpdateUserSettingContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Update User Setting Content!");
// Proto Empty
}
}

View File

@@ -1,47 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.Text;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkUserToastEvent extends TikTokLinkEvent {
private final long userId, roomId;
private final Text displayText;
public TikTokLinkUserToastEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasUserToastContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with User Toast Content!");
var content = msg.getUserToastContent();
this.userId = content.getUserId();
this.roomId = content.getRoomId();
this.displayText = Text.map(content.getDisplayText());
}
}

View File

@@ -1,39 +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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkWaitListChangeEvent extends TikTokLinkEvent {
public TikTokLinkWaitListChangeEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasWaitingListChangeContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Waiting List Change Content!");
// Proto Empty
}
}

View File

@@ -30,7 +30,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/**
/*
Triggered when LiveRoomInfo got updated such as likes, viewers, ranking ....
*/
@Getter
@@ -39,4 +39,4 @@ Triggered when LiveRoomInfo got updated such as likes, viewers, ranking ....
public class TikTokRoomInfoEvent extends TikTokEvent
{
LiveRoomInfo roomInfo;
}
}

View File

@@ -33,13 +33,15 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Message)
public class TikTokRoomPinEvent extends TikTokHeaderEvent
{
private final TikTokCommentEvent pinnedMessage;
private final long timestamp;
public TikTokRoomPinEvent(WebcastRoomPinMessage msg, TikTokCommentEvent commentEvent)
{
super(msg.getCommon());
this.timestamp = msg.getTimestamp();
this.pinnedMessage = commentEvent;
}
}
private TikTokCommentEvent pinnedMessage;
private long timestamp;
public TikTokRoomPinEvent(WebcastRoomPinMessage msg, TikTokCommentEvent commentEvent)
{
super(msg.getCommon());
this.timestamp = msg.getTimestamp();
this.pinnedMessage = commentEvent;
}
}

View File

@@ -36,21 +36,13 @@ import lombok.Value;
@EventMeta(eventType = EventType.Message)
public class TikTokFollowEvent extends TikTokHeaderEvent
{
User user;
int totalFollowers;
User user;
int totalFollowers;
public TikTokFollowEvent(WebcastSocialMessage msg) {
super(msg.getCommon());
user = User.map(msg.getUser());
totalFollowers = msg.getFollowCount();
}
public TikTokFollowEvent(WebcastSocialMessage msg) {
super(msg.getCommon());
user = User.map(msg.getUser());
totalFollowers = msg.getFollowCount();
}
public static TikTokFollowEvent of(String userName)
{
return new TikTokFollowEvent(WebcastSocialMessage.newBuilder()
.setUser(io.github.jwdeveloper.tiktok.messages.data.User.newBuilder()
.setNickname(userName)
.build())
.build());
}
}
}

View File

@@ -26,7 +26,6 @@ import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLikeMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Getter;
@@ -48,13 +47,4 @@ public class TikTokJoinEvent extends TikTokHeaderEvent {
user = User.map(msg.getUser());
totalUsers = msg.getMemberCount();
}
public static TikTokJoinEvent of(String userName)
{
return new TikTokJoinEvent(WebcastMemberMessage.newBuilder()
.setUser(io.github.jwdeveloper.tiktok.messages.data.User.newBuilder()
.setNickname(userName)
.build())
.build());
}
}

View File

@@ -57,15 +57,4 @@ public class TikTokLikeEvent extends TikTokHeaderEvent
likes = msg.getCount();
totalLikes = msg.getTotal();
}
public static TikTokLikeEvent of(String userName, int likes)
{
return new TikTokLikeEvent(WebcastLikeMessage.newBuilder()
.setCount(likes)
.setTotal(likes)
.setUser(io.github.jwdeveloper.tiktok.messages.data.User.newBuilder()
.setNickname(userName)
.build())
.build());
}
}

View File

@@ -35,18 +35,19 @@ import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokShareEvent extends TikTokHeaderEvent {
private final User user;
private final int totalShares;
private final User user;
private final int totalShares;
public TikTokShareEvent(WebcastSocialMessage msg, Integer amount) {
super(msg.getCommon());
user = User.map(msg.getUser());
this.totalShares = amount;
}
public TikTokShareEvent(WebcastSocialMessage msg, Integer amount) {
super(msg.getCommon());
user = User.map(msg.getUser());
this.totalShares = amount;
}
public TikTokShareEvent(WebcastSocialMessage msg) {
super(msg.getCommon());
user = User.map(msg.getUser());
totalShares = 1;
}
}
public TikTokShareEvent(WebcastSocialMessage msg) {
super(msg.getCommon());
user = User.map(msg.getUser());
totalShares = 1;
}
}

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.data.models;
import lombok.Value;
@Value
public class EnumValue
{
public int value;
public String name;
public static EnumValue Map(Enum<?> _enum)
{
return new EnumValue(_enum.ordinal() ,_enum.name());
}
}

View File

@@ -46,4 +46,4 @@ public class LinkMicArmy {
List<User> Users;
Integer Points;
}
}
}

View File

@@ -20,17 +20,22 @@
* 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.data.events.link;
package io.github.jwdeveloper.tiktok.data.models;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkApplyEvent extends TikTokLinkEvent {
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Value;
public TikTokLinkApplyEvent(WebcastLinkMessage msg) {
super(msg);
import java.util.List;
@Value
public class LinkMicBattleTeam {
Long teamId;
List<User> users;
public LinkMicBattleTeam(WebcastLinkMicBattle.LinkMicBattleTeam team) {
this.teamId = team.getId();
this.users = team.getUsersList().stream().map(User::new).toList();
}
}
}

View File

@@ -44,11 +44,11 @@ public class Picture {
}
public static Picture map(io.github.jwdeveloper.tiktok.messages.data.Image profilePicture) {
var index = profilePicture.getUrlCount() - 1;
var index = profilePicture.getUrlListCount() - 1;
if (index < 0) {
return new Picture("");
}
var url = profilePicture.getUrl(index);
var url = profilePicture.getUrlList(index);
return new Picture(url);
}
@@ -93,7 +93,7 @@ public class Picture {
}
}
public static Picture empty() {
public static Picture Empty() {
return new Picture("");
}

View File

@@ -1,69 +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.data.models.battles;
public abstract class Team {
/**
* Provides a check for verifying if this team represents a 1v1 Team.
* @return true if this team is of type {@link Team1v1}, false otherwise.
*/
public boolean is1v1Team() {
return this instanceof Team1v1;
}
/**
* Provides a check for verifying if this team represents a 1v1 Team.
* @return true if this team is of type {@link Team1v1}, false otherwise.
*/
public boolean is2v2Team() {
return this instanceof Team2v2;
}
/**
* Convenience method to get this team as a {@link Team1v1}. If this team is of some
* other type, an {@link IllegalStateException} will result. Hence it is best to use this method
* after ensuring that this element is of the desired type by calling {@link #is1v1Team()} first.
*
* @return this team as a {@link Team1v1}.
* @throws IllegalStateException if this team is of another type.
*/
public Team1v1 getAs1v1Team() {
if (is1v1Team())
return (Team1v1) this;
throw new IllegalStateException("Not a 1v1Team: " + this);
}
/**
* Convenience method to get this team as a {@link Team2v2}. If this team is of some
* other type, an {@link IllegalStateException} will result. Hence it is best to use this method
* after ensuring that this element is of the desired type by calling {@link #is2v2Team()} first.
*
* @return this team as a {@link Team2v2}.
* @throws IllegalStateException if this team is of another type.
*/
public Team2v2 getAs2v2Team() {
if (is2v2Team())
return (Team2v2) this;
throw new IllegalStateException("Not a 2v2Team: " + this);
}
}

View File

@@ -1,48 +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.data.models.battles;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter;
import java.util.*;
@Getter
public class Team1v1 extends Team
{
/** Value >= 0 when finished otherwise -1 */
private final int totalPoints;
private final int winStreak;
private final User host;
private final List<Viewer> viewers;
public Team1v1(WebcastLinkMicBattle.LinkMicBattleHost hostTeam, WebcastLinkMicBattle msg) {
long hostId = hostTeam.getId();
this.winStreak = msg.getTeamDataList().stream().filter(data -> data.getTeamId() == hostId).map(data -> data.getData().getWinStreak()).findFirst().orElse(-1);
this.totalPoints = msg.getDetailsList().stream().filter(dets -> dets.getId() == hostId).map(dets -> dets.getSummary().getPoints()).findFirst().orElse(-1);
this.host = new User(hostTeam.getHostGroup(0).getHost(0));
this.viewers = msg.getViewerTeamList().stream().filter(team -> team.getId() == hostId).findFirst().map(topViewers ->
topViewers.getViewerGroup(0).getViewerList().stream().map(Viewer::new).toList()).orElseGet(ArrayList::new);
}
}

View File

@@ -1,53 +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.data.models.battles;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter;
import java.util.*;
@Getter
public class Team2v2 extends Team {
/** Value >= 0 when finished otherwise -1 */
private final int totalPoints;
private final List<User> hosts;
private final List<Viewer> viewers;
public Team2v2(WebcastLinkMicBattle.LinkMicBattleHost hostTeam1, WebcastLinkMicBattle.LinkMicBattleHost hostTeam2, WebcastLinkMicBattle msg) {
this.totalPoints = -1;
this.hosts = List.of(new User(hostTeam1.getHostGroup(0).getHost(0)), new User(hostTeam2.getHostGroup(0).getHost(0)));
this.viewers = new ArrayList<>();
}
public Team2v2(WebcastLinkMicBattle.Host2v2Data hd, WebcastLinkMicBattle msg) {
this.totalPoints = hd.getTotalPoints();
var host = new User(msg.getHostTeamList().stream().filter(data -> data.getId() == hd.getHostdata(0).getHostId()).findFirst().orElseThrow().getHostGroup(0).getHost(0));
var cohost = new User(msg.getHostTeamList().stream().filter(data -> data.getId() == hd.getHostdata(1).getHostId()).findFirst().orElseThrow().getHostGroup(0).getHost(0));
this.hosts = List.of(host, cohost);
this.viewers = msg.getViewerTeamList().stream().filter(team -> team.getId() == host.getId() || team.getId() == cohost.getId()).findFirst().map(topViewers ->
topViewers.getViewerGroup(0).getViewerList().stream().map(Viewer::new).toList()).orElseGet(ArrayList::new);
}
}

View File

@@ -22,15 +22,19 @@
*/
package io.github.jwdeveloper.tiktok.data.models.gifts;
public enum GiftComboStateType {
public enum GiftSendType
{
Finished,
Begin,
Active;
public static GiftComboStateType fromNumber(long number) {
public static GiftSendType fromNumber(long number)
{
return switch ((int) number) {
case 1, 2, 4 -> GiftComboStateType.Active;
default -> GiftComboStateType.Finished;
case 0 -> GiftSendType.Finished;
case 1, 2, 4 -> GiftSendType.Active;
default -> GiftSendType.Finished;
};
}
}
}

View File

@@ -1,56 +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.data.models.users;
import lombok.Getter;
@Getter
public class ListUser
{
private final User user;
private final LinkType linkType;
private final long linkMicId, linkStatus, modifyTime, linkerId;
private final int userPosition, silenceStatus, roleType;
public ListUser(io.github.jwdeveloper.tiktok.messages.data.ListUser listUser) {
this.user = User.map(listUser.getUser());
this.linkMicId = listUser.getLinkmicId();
this.linkStatus = listUser.getLinkStatus();
this.linkType = LinkType.values()[listUser.getLinkTypeValue()];
this.userPosition = listUser.getUserPosition();
this.silenceStatus = listUser.getSilenceStatus();
this.modifyTime = listUser.getModifyTime();
this.linkerId = listUser.getLinkerId();
this.roleType = listUser.getRoleType();
}
public static ListUser map(io.github.jwdeveloper.tiktok.messages.data.ListUser listUser) {
return new ListUser(listUser);
}
public enum LinkType {
UNKNOWN,
AUDIO,
VIDEO
}
}

View File

@@ -24,7 +24,7 @@ package io.github.jwdeveloper.tiktok.data.models.users;
import io.github.jwdeveloper.tiktok.data.models.badges.Badge;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.messages.webcast.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastEnvelopeMessage;
import lombok.AccessLevel;
import lombok.Getter;
@@ -136,14 +136,6 @@ public class User {
this.picture = picture;
}
public User(long id, String name, String profileId, Picture picture) {
this(id, name, profileId, picture, 0, 0, List.of(Badge.empty()));
}
public User(WebcastLinkMicBattle.LinkMicBattleHost.HostGroup.Host host) {
this(host.getId(), host.getName(), host.getProfileId(), Picture.map(host.getImages(0)));
}
public User(io.github.jwdeveloper.tiktok.messages.data.User user) {
this(user.getId(), user.getDisplayId(), Picture.map(user.getAvatarThumb()));
profileName = user.getNickname();
@@ -167,9 +159,10 @@ public class User {
}
}
public static User EMPTY = new User(0L,
"",
Picture.empty(),
Picture.Empty(),
0,
0,
List.of(Badge.empty()));
@@ -216,18 +209,4 @@ public class User {
0,
List.of(Badge.empty()));
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + "'" +
", profileName='" + profileName + "'" +
", picture=" + picture +
", following=" + following +
", followers=" + followers +
", badges=" + badges +
", attributes=" + attributes +
"}";
}
}

View File

@@ -23,17 +23,35 @@
package io.github.jwdeveloper.tiktok.data.requests;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import lombok.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import java.util.List;
public class GiftsData
{
@Getter
public final class Request
{
}
@Getter
@AllArgsConstructor
public static final class Response
{
private String json;
private List<Gift> gifts;
private List<GiftModel> gifts;
}
}
@Data
public static class GiftModel
{
private int id;
private String name;
private int diamondCost;
private String image;
}
}

View File

@@ -35,7 +35,6 @@ public class LiveData {
}
@Data
@AllArgsConstructor
public static class Response {
private String json;
private LiveStatus liveStatus;
@@ -45,12 +44,6 @@ public class LiveData {
private int totalViewers;
private boolean ageRestricted;
private User host;
private LiveType liveType;
public Response() {
}
}
public enum LiveStatus {
@@ -58,11 +51,4 @@ public class LiveData {
HostOnline,
HostOffline,
}
public enum LiveType {
SOLO,
BOX,
BATTLE,
CO_HOST
}
}
}

View File

@@ -27,23 +27,18 @@ import lombok.*;
public class LiveUserData {
@Getter
@AllArgsConstructor
public static class Request {
private final String userName;
public Request(String userName) {
if (userName == null || userName.isBlank())
throw new IllegalArgumentException("Invalid empty username!");
this.userName = userName;
}
private String userName;
}
@Getter
@AllArgsConstructor
public static class Response {
private final String json;
private final UserStatus userStatus;
private final String roomId;
private final long startTime;
private String json;
private UserStatus userStatus;
private String roomId;
private long startedAtTimeStamp;
public boolean isLiveOnline() {
return userStatus == LiveUserData.UserStatus.Live || userStatus == LiveUserData.UserStatus.LivePaused;

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.data.requests;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class SignServerResponse
{
private String signedUrl;
private String userAgent;
}

View File

@@ -34,24 +34,30 @@ import java.util.TreeMap;
import java.util.function.Consumer;
@Getter
public class HttpClientSettings {
private final Map<String, Object> params;
@Getter
final Map<String, Object> params;
private final Map<String, String> headers;
@Getter
final Map<String, String> headers;
private final Map<String, String> cookies;
@Getter
final Map<String, String> cookies;
@Getter
@Setter
ProxyClientSettings proxyClientSettings;
@Getter
Consumer<HttpClient.Builder> onClientCreating;
@Getter
Consumer<HttpRequest.Builder> onRequestCreating;
@Setter
private ProxyClientSettings proxyClientSettings;
private Consumer<HttpClient.Builder> onClientCreating;
private Consumer<HttpRequest.Builder> onRequestCreating;
@Setter
private Duration timeout;
@Getter
Duration timeout;
public HttpClientSettings() {
this.params = new TreeMap<>();
@@ -59,8 +65,10 @@ public class HttpClientSettings {
this.cookies = new HashMap<>();
this.timeout = Duration.ofSeconds(2);
this.proxyClientSettings = new ProxyClientSettings();
this.onClientCreating = (x) -> {};
this.onRequestCreating = (x) -> {};
this.onClientCreating = (x) -> {
};
this.onRequestCreating = (x) -> {
};
}
/**
@@ -97,7 +105,7 @@ public class HttpClientSettings {
newSettings.getHeaders().putAll(new TreeMap<>(this.headers));
newSettings.getCookies().putAll(new TreeMap<>(this.cookies));
newSettings.getParams().putAll(new TreeMap<>(this.params));
newSettings.setProxyClientSettings(this.proxyClientSettings);
newSettings.proxyClientSettings = this.proxyClientSettings;
return newSettings;
}

View File

@@ -33,21 +33,10 @@ import java.util.logging.Level;
@Data
public class LiveClientSettings {
/**
* Sets client to offline mode, prohibits connection to TikTok servers
* @apiNote Useful when testing client with custom events
*/
private boolean offline;
/**
* Fetch and download gifts data before TikTokLive starts
* @apiNote If `false`, client.giftManager() does not contain initial gifts
*/
private boolean fetchGifts = true;
/**
* ISO-Language for Client
*/
private String clientLanguage;
/**
@@ -55,6 +44,7 @@ public class LiveClientSettings {
*/
private boolean retryOnConnectionFailure;
/**
* Before retrying connect, wait for select amount of time
*/
@@ -63,49 +53,44 @@ public class LiveClientSettings {
/**
* Whether to print Logs to Console
*/
private boolean printToConsole = true;
private boolean printToConsole = true;
/**
* LoggingLevel for Logs
*/
private Level logLevel;
/**
* Optional: Use it if you need to change TikTok live hostname in builder
*/
private String hostName;
/**
* Parameters used in requests to TikTok api
*/
private HttpClientSettings httpSettings;
/**
* Interval of time in milliseconds between pings to TikTok
* @apiNote Min: 250 (0.25 seconds), Default: 5000 (5 seconds)
/*
* Optional: Sometimes not every messages from chat are send to TikTokLiveJava to fix this issue you can set sessionId
* documentation how to obtain sessionId https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages
*/
private long pingInterval = 5000;
/** Throw an exception on 18+ Age Restriction */
private boolean throwOnAgeRestriction;
/**
* Optional: Sometimes not every messages from chat are send to TikTokLiveJava to fix this issue you can set sessionId
* @see <a href="https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages">Documentation: How to obtain sessionId</a>
*/
private String sessionId;
/**
/*
* Optional: By default roomID is fetched before connect to live, but you can set it manually
*
*/
private String roomId;
/**
* Optional: API Key for increased limit to signing server
*/
private String apiKey;
public static LiveClientSettings createDefault() {
public static LiveClientSettings createDefault()
{
var httpSettings = new HttpClientSettings();
httpSettings.getParams().putAll(DefaultClientParams());
httpSettings.getHeaders().putAll(DefaultRequestHeaders());
@@ -118,10 +103,12 @@ public class LiveClientSettings {
clientSettings.setPrintToConsole(false);
clientSettings.setLogLevel(Level.ALL);
clientSettings.setHttpSettings(httpSettings);
return clientSettings;
}
/**
* Default Parameters for HTTP-Request
*/
@@ -160,9 +147,11 @@ public class LiveClientSettings {
clientParams.put("webcast_sdk_version", "1.3.0");
clientParams.put("update_version_code", "1.3.0");
return clientParams;
}
/**
* Default Headers for HTTP-Request
*/
@@ -178,4 +167,6 @@ public class LiveClientSettings {
headers.put("Accept-Language", "en-US,en; q=0.9");
return headers;
}
}
}

View File

@@ -31,17 +31,18 @@ import java.util.function.Consumer;
@Getter
@Setter
public class ProxyClientSettings implements Iterator<ProxyData>, Iterable<ProxyData>
public class ProxyClientSettings implements Iterator<ProxyData>
{
private boolean enabled, autoDiscard = true, fallback = true;
private boolean enabled, lastSuccess;
private Rotation rotation = Rotation.CONSECUTIVE;
private final List<ProxyData> proxyList = new ArrayList<>();
private int index;
private int index = 0;
private boolean autoDiscard = true;
private Proxy.Type type = Proxy.Type.DIRECT;
private Consumer<ProxyData> onProxyUpdated = x -> {};
public boolean addProxy(String addressPort) {
return addProxy(ProxyData.map(addressPort).toSocketAddress());
return proxyList.add(ProxyData.map(addressPort));
}
public boolean addProxy(String address, int port) {
@@ -57,27 +58,34 @@ public class ProxyClientSettings implements Iterator<ProxyData>, Iterable<ProxyD
}
@Override
public synchronized boolean hasNext() {
public boolean hasNext() {
return !proxyList.isEmpty();
}
@Override
public synchronized ProxyData next() {
try {
var nextProxy = proxyList.get(index);
onProxyUpdated.accept(nextProxy);
return nextProxy;
} finally {
switch (rotation) {
case CONSECUTIVE -> index = ++index % proxyList.size();
case RANDOM -> index = (int) (Math.random() * proxyList.size());
case NONE -> index = Math.max(index, 0);
public ProxyData next() {
return lastSuccess ? proxyList.get(index) : rotate();
}
public ProxyData rotate() {
var nextProxy = switch (rotation)
{
case CONSECUTIVE -> {
index = (index+1) % proxyList.size();
yield proxyList.get(index).clone();
}
}
case RANDOM -> {
index = new Random().nextInt(proxyList.size());
yield proxyList.get(index).clone();
}
case NONE -> proxyList.get(index).clone();
};
onProxyUpdated.accept(nextProxy);
return nextProxy;
}
@Override
public synchronized void remove() {
public void remove() {
proxyList.remove(index);
}
@@ -90,9 +98,8 @@ public class ProxyClientSettings implements Iterator<ProxyData>, Iterable<ProxyD
this.index = index;
}
}
@Override
public ProxyClientSettings clone() {
public ProxyClientSettings clone()
{
ProxyClientSettings settings = new ProxyClientSettings();
settings.setEnabled(enabled);
settings.setRotation(rotation);
@@ -103,27 +110,6 @@ public class ProxyClientSettings implements Iterator<ProxyData>, Iterable<ProxyD
return settings;
}
@Override
public String toString() {
return "ProxyClientSettings{" +
"enabled=" + enabled +
", autoDiscard=" + autoDiscard +
", fallback=" + fallback +
", rotation=" + rotation +
", proxyList=" + proxyList +
", index=" + index +
", type=" + type +
'}';
}
/**
* With {@code Iterable<ProxyData>} interface, you can use this object inside for loop!
*/
@Override
public Iterator<ProxyData> iterator() {
return this;
}
public enum Rotation
{
/** Rotate addresses consecutively, from proxy 0 -> 1 -> 2 -> ...etc. */

View File

@@ -23,7 +23,7 @@
package io.github.jwdeveloper.tiktok.exceptions;
/**
/*
* Happens while bad response from Http request to TikTok
*/
public class TikTokLiveRequestException extends TikTokLiveException
@@ -46,4 +46,4 @@ public class TikTokLiveRequestException extends TikTokLiveException
public TikTokLiveRequestException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
}

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.handler;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import java.util.List;
public interface TikTokMessageHandler
{
List<TikTokEvent> handle(byte[] messagePayload) throws Exception;
}

View File

@@ -27,46 +27,38 @@ import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
public interface LiveHttpClient
{
public interface LiveHttpClient {
/**
* @return {@link GiftsData.Response} list of gifts that are compiled and available on github
* @return list of gifts that are available in your country
*/
GiftsData.Response fetchGiftsData();
/**
* @return {@link GiftsData.Response} list of gifts that are available in your region / livestream
*/
GiftsData.Response fetchRoomGiftsData(String room_id);
/**
* Returns information about user that is having a livestream
* @param userName name of user
* @return {@link LiveUserData.Response}
*
* @param userName
* @return
*/
default LiveUserData.Response fetchLiveUserData(String userName) {
return fetchLiveUserData(new LiveUserData.Request(userName));
}
LiveUserData.Response fetchLiveUserData(String userName);
LiveUserData.Response fetchLiveUserData(LiveUserData.Request request);
/**
* @param roomId can be obtained from browsers cookies or by invoked fetchLiveUserData
* @return {@link LiveData.Response}
* @return
*/
default LiveData.Response fetchLiveData(String roomId) {
return fetchLiveData(new LiveData.Request(roomId));
}
LiveData.Response fetchLiveData(String roomId);
LiveData.Response fetchLiveData(LiveData.Request request);
/**
* @param roomId can be obtained from browsers cookies or by invoked fetchLiveUserData
* @return {@link LiveConnectionData.Response}
* @return
*/
default LiveConnectionData.Response fetchLiveConnectionData(String roomId) {
return fetchLiveConnectionData(new LiveConnectionData.Request(roomId));
}
LiveConnectionData.Response fetchLiveConnectionData(String roomId);
LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request);
}
}

View File

@@ -33,7 +33,6 @@ import java.util.List;
public interface ListenersManager
{
List<TikTokEventListener> getListeners();
void addListener(TikTokEventListener listener);
void removeListener(TikTokEventListener listener);

View File

@@ -22,52 +22,53 @@
*/
package io.github.jwdeveloper.tiktok.listener;
import io.github.jwdeveloper.tiktok.live.LiveClient;
/**
* ListenersManager
* <p>
*
* @see ListenersManager
*
* TikTokEventListener is an alternative way of handing TikTok events.
* <p>
* {@code TikTokLive.newClient("someuser").addListener(listener);}
* <p>
* After registertion, all listeners are kept in Listener manager - {@link LiveClient#getListenersManager()}
* <p>
* Method in TikTokEventListener should meet requirements below to be detected
* <p>- @TikTokEventObserver annotation
* <p>- 2 parameters of (LiveClient, Class extending TikTokEvent)
* <pre>
* {@code
* public static class CustomListener implements TikTokEventListener
* {
* @TikTokEventObserver
* public void onError(LiveClient liveClient, TikTokErrorEvent event)
* {
* System.out.println(event.getException().getMessage());
* }
*
* @TikTokEventObserver
* public void onCommentMessage(LiveClient liveClient, TikTokCommentEvent event)
* {
* System.out.println(event.getText());
* }
* TikTokLive.newClient("someuser").addListener(listener)
*
* @TikTokEventObserver
* public void onGiftMessage(LiveClient liveClient, TikTokGiftMessageEvent event)
* {
* System.out.println(event.getGift().getDescription());
* }
* After registertion all listeners are kept in Listener manager
* that could be obtained by client.getListenerManager();
*
* Method in TikTokEventListener should meet 4 requirements to be detected
* - must have @TikTokEventHandler annotation
* - must have 2 parameters
* - first parameter must be LiveClient
* - second must be class that extending TikTokEvent
*
* public static class CustomListener implements TikTokEventListener
* {
* @TikTokEventHandler
* public void onError(LiveClient liveClient, TikTokErrorEvent event)
* {
* System.out.println(event.getException().getMessage());
* }
*
* @TikTokEventHandler
* public void onCommentMessage(LiveClient liveClient, TikTokCommentEvent event)
* {
* System.out.println(event.getText());
* }
*
* @TikTokEventHandler
* public void onGiftMessage(LiveClient liveClient, TikTokGiftMessageEvent event)
* {
* System.out.println(event.getGift().getDescription());
* }
*
* @TikTokEventHandler
* public void onAnyEvent(LiveClient liveClient, TikTokEvent event)
* {
* System.out.println(event.getClass().getSimpleName());
* }
* }
*
* @TikTokEventObserver
* public void onAnyEvent(LiveClient liveClient, TikTokEvent event)
* {
* System.out.println(event.getClass().getSimpleName());
* }
* }
* }
* </pre>
*/
public interface TikTokEventListener
{
}
}

View File

@@ -1,156 +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.listener;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.control.TikTokPreConnectionEvent;
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.*;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.link.*;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.data.events.room.*;
import io.github.jwdeveloper.tiktok.data.events.social.*;
import io.github.jwdeveloper.tiktok.data.events.websocket.*;
import io.github.jwdeveloper.tiktok.live.LiveClient;
public abstract class TikTokEventListenerBase implements TikTokEventListener
{
public void onUnhandledSocial(LiveClient client, TikTokUnhandledSocialEvent event) {}
public void onChest(LiveClient client, TikTokChestEvent event) {}
public void onLinkMicFanTicket(LiveClient client, TikTokLinkMicFanTicketEvent event) {}
public void onEnvelope(LiveClient client, TikTokEnvelopeEvent event) {}
public void onShop(LiveClient client, TikTokShopEvent event) {}
public void onDetect(LiveClient client, TikTokDetectEvent event) {}
public void onLinkLayer(LiveClient client, TikTokLinkLayerEvent event) {}
public void onConnected(LiveClient client, TikTokConnectedEvent event) {}
public void onPreConnection(LiveClient client, TikTokPreConnectionEvent event) {}
public void onCaption(LiveClient client, TikTokCaptionEvent event) {}
public void onQuestion(LiveClient client, TikTokQuestionEvent event) {}
public void onRoomPin(LiveClient client, TikTokRoomPinEvent event) {}
public void onRoomInfo(LiveClient client, TikTokRoomInfoEvent event) {}
public void onLivePaused(LiveClient client, TikTokLivePausedEvent event) {}
public void onLiveUnpaused(LiveClient client, TikTokLiveUnpausedEvent event) {}
public void onLike(LiveClient client, TikTokLikeEvent event) {}
public void onLink(LiveClient client, TikTokLinkEvent event) {}
public void onLinkInvite(LiveClient client, TikTokLinkInviteEvent event) {}
public void onLinkReply(LiveClient client, TikTokLinkReplyEvent event) {}
public void onLinkCreate(LiveClient client, TikTokLinkCreateEvent event) {}
public void onLinkClose(LiveClient client, TikTokLinkCloseEvent event) {}
public void onLinkEnter(LiveClient client, TikTokLinkEnterEvent event) {}
public void onLinkLeave(LiveClient client, TikTokLinkLeaveEvent event) {}
public void onLinkCancel(LiveClient client, TikTokLinkCancelEvent event) {}
public void onLinkKickOut(LiveClient client, TikTokLinkKickOutEvent event) {}
public void onLinkLinkedListChange(LiveClient client, TikTokLinkLinkedListChangeEvent event) {}
public void onLinkUpdateUser(LiveClient client, TikTokLinkUpdateUserEvent event) {}
public void onLinkWaitListChange(LiveClient client, TikTokLinkWaitListChangeEvent event) {}
public void onLinkMute(LiveClient client, TikTokLinkMuteEvent event) {}
public void onLinkRandomMatch(LiveClient client, TikTokLinkRandomMatchEvent event) {}
public void onLinkUpdateUserSettings(LiveClient client, TikTokLinkUpdateUserSettingEvent event) {}
public void onLinkMicIdxUpdate(LiveClient client, TikTokLinkMicIdxUpdateEvent event) {}
public void onLinkListChange(LiveClient client, TikTokLinkListChangeEvent event) {}
public void onLinkCohostListChange(LiveClient client, TikTokLinkCohostListChangeEvent event) {}
public void onLinkMediaChange(LiveClient client, TikTokLinkMediaChangeEvent event) {}
public void onLinkAcceptNotice(LiveClient client, TikTokLinkAcceptNoticeEvent event) {}
public void onLinkSysKickOut(LiveClient client, TikTokLinkSysKickOutEvent event) {}
public void onLinkUserToast(LiveClient client, TikTokLinkUserToastEvent event) {}
public void onBarrage(LiveClient client, TikTokBarrageEvent event) {}
public void onGift(LiveClient client, TikTokGiftEvent event) {}
public void onGiftCombo(LiveClient client, TikTokGiftComboEvent event) {}
public void onLinkMicArmies(LiveClient client, TikTokLinkMicArmiesEvent event) {}
public void onEmote(LiveClient client, TikTokEmoteEvent event) {}
public void onUnauthorizedMember(LiveClient client, TikTokUnauthorizedMemberEvent event) {}
public void onInRoomBanner(LiveClient client, TikTokInRoomBannerEvent event) {}
public void onLinkMicMethod(LiveClient client, TikTokLinkMicMethodEvent event) {}
public void onSubscribe(LiveClient client, TikTokSubscribeEvent event) {}
public void onPoll(LiveClient client, TikTokPollEvent event) {}
public void onFollow(LiveClient client, TikTokFollowEvent event) {}
public void onComment(LiveClient client, TikTokCommentEvent event) {}
public void onHttpResponse(LiveClient client, TikTokHttpResponseEvent action) {}
public void onGoalUpdate(LiveClient client, TikTokGoalUpdateEvent event) {}
public void onRankUpdate(LiveClient client, TikTokRankUpdateEvent event) {}
public void onIMDelete(LiveClient client, TikTokIMDeleteEvent event) {}
public void onLiveEnded(LiveClient client, TikTokLiveEndedEvent event) {}
public void onError(LiveClient client, TikTokErrorEvent event) {}
public void onJoin(LiveClient client, TikTokJoinEvent event) {}
public void onRankText(LiveClient client, TikTokRankTextEvent event) {}
public void onShare(LiveClient client, TikTokShareEvent event) {}
public void onUnhandledMember(LiveClient client, TikTokUnhandledMemberEvent event) {}
public void onSubNotify(LiveClient client, TikTokSubNotifyEvent event) {}
public void onLinkMicBattle(LiveClient client, TikTokLinkMicBattleEvent event) {}
public void onDisconnected(LiveClient client, TikTokDisconnectedEvent event) {}
public void onUnhandledControl(LiveClient client, TikTokUnhandledControlEvent event) {}
public void onEvent(LiveClient client, TikTokEvent event) {}
public void onWebsocketResponse(LiveClient client, TikTokWebsocketResponseEvent event) {}
public void onWebsocketMessage(LiveClient client, TikTokWebsocketMessageEvent event) {}
public void onWebsocketUnhandledMessage(LiveClient client, TikTokWebsocketUnhandledMessageEvent event) {}
public void onReconnecting(LiveClient client, TikTokReconnectingEvent event) {}
}

View File

@@ -20,20 +20,44 @@
* 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.data.models.battles;
package io.github.jwdeveloper.tiktok.live;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter;
@Getter
public class Viewer {
private final User user;
private final int points;
import java.util.List;
public Viewer(WebcastLinkMicBattle.LinkMicBattleTopViewers.TopViewerGroup.TopViewer topViewer) {
this.user = new User(topViewer.getId(), null, topViewer.getProfileId(), Picture.map(topViewer.getImages(0)));
this.points = topViewer.getPoints();
}
}
public interface GiftManager {
/**
* In case you can't find your gift in Gift enum. You can register gift
* manually here to make it detected while TikTokGiftEvent
*
* @param id gift's id
* @param name gift's name
* @param diamondCost diamond cost
* @return
*/
Gift registerGift(int id, String name, int diamondCost, Picture picture);
/**
*
* @param giftId
* @return
*/
Gift findById(int giftId);
/**
*
* @param giftName
* @return
*/
Gift findByName(String giftName);
/**
*
* @return all gifts
*/
List<Gift> getGifts();
}

View File

@@ -1,86 +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.live;
import com.google.gson.JsonObject;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.gifts.*;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
public interface GiftsManager {
/**
* You can create and attach your own custom gift to manager
*
* @param gift
*/
void attachGift(Gift gift);
/**
* You can create and attach your own custom gift to manager
*
* @param gifts
*/
void attachGiftsList(List<Gift> gifts);
/**
* finds gift by name
* When gift not found return Gift.UNDEFINED;
*
* @param name gift name
*/
Gift getByName(String name);
/**
* finds gift by id
* When gift not found return Gift.UNDEFINED;
*
* @param giftId giftId
*/
Gift getById(int giftId);
/**
* finds gift by filter
* When gift not found return Gift.UNDEFINED;
*/
Gift getByFilter(Predicate<Gift> filter);
List<Gift> getManyByFilter(Predicate<Gift> filter);
/**
* @return list of all gifts
*/
List<Gift> toList();
/**
* @return list of all map of all gifts where Integer is gift Id
*/
Map<Integer, Gift> toMap();
}

View File

@@ -59,21 +59,12 @@ public interface LiveClient {
/**
* Use to manually invoke event
*/
void publishEvent(TikTokEvent event);
/**
* @param webcastMessageName name of TikTok protocol-buffer message
* @param payloadBase64 protocol-buffer message bytes payload
*/
void publishMessage(String webcastMessageName, String payloadBase64);
void publishMessage(String webcastMessageName, byte[] payload);
void publishEvent(TikTokEvent event);
/**
* Get information about gifts
*/
GiftsManager getGiftManager();
GiftManager getGiftManager();
/**
* Gets the current room info from TikTok API including streamer info, room status and statistics.

View File

@@ -47,7 +47,7 @@ public interface LiveRoomInfo
String getRoomId();
String getHostName();
String getTitle();
User getHost();
User getHostUser();
List<RankingUser> getUsersRanking();
ConnectionState getConnectionState();
}

View File

@@ -25,13 +25,7 @@ package io.github.jwdeveloper.tiktok.live.builder;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.LiveClient;
@FunctionalInterface
public interface EventConsumer<T extends TikTokEvent>
{
/**
*
* @param liveClient TikTok live client
* @param event event data object
*/
void onEvent(LiveClient liveClient, T event);
}

View File

@@ -24,7 +24,6 @@ package io.github.jwdeveloper.tiktok.live.builder;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.control.TikTokPreConnectionEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
@@ -52,70 +51,77 @@ public interface EventsBuilder<T> {
/**
* Invoked whenever any event is triggered
*
* @param action consumable action
* @return self instance
* @param action
* @return
*/
T onEvent(EventConsumer<TikTokEvent> action);
/**
* Invoked when information about room (live) got updated such as viewer count, etc..
*
* @param action consumable action
* @return self instance
* @param action
* @return
*/
T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> action);
/**
* Invoked when someone send message to chat
* @param action consumable action
* @return self instance
*
* @param action
* @return
*/
T onComment(EventConsumer<TikTokCommentEvent> action);
/**
* Invoked when TikTokLiveJava makes http request and getting response
* @param action consumable action
* @return self instance
*
* @param action
* @return
*/
T onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action);
/**
* Invoked when TikTok protocolBuffer data "message" was successfully mapped to event
* events contains protocol-buffer "Message" and TikTokLiveJava "Event"
* @param action consumable action
* @return self instance
*
* @param action
* @return
*/
T onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> action);
/**
* Invoked when there was not found event mapper for TikTok protocolBuffer data "message"
* @param action consumable action
* @return self instance
*
* @param action
* @return
*/
T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> action);
/**
* Invoked every time TikTok sends protocolBuffer data to websocket
* Response contains list of messages that are later mapped to events
* @param action consumable action
* @return self instance
* @param action
* @return
*/
T onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> action);
/**
* Invoked for gifts that has no combo, or when combo finishes
* @param action consumable action
* @return self instance
* @param action
* @return
*/
T onGift(EventConsumer<TikTokGiftEvent> action);
/**
* Invoked for gifts that has combo options such as roses
* @param action consumable action
* @return self instance
* @param action
* @return
*/
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> action);
T onQuestion(EventConsumer<TikTokQuestionEvent> action);
T onSubscribe(EventConsumer<TikTokSubscribeEvent> action);
@@ -138,36 +144,29 @@ public interface EventsBuilder<T> {
/**
* Invoked when client has been successfully connected to live
* @param action consumable action
* @return self instance
* @param action
* @return
*/
T onConnected(EventConsumer<TikTokConnectedEvent> action);
/**
* Invoked before client has been successfully connected to live
* @param action consumable action
* @return self instance
*/
T onPreConnection(EventConsumer<TikTokPreConnectionEvent> action);
/**
* Invoked when client tries to reconnect
* @param action consumable action
* @return self instance
* @param action
* @return
*/
T onReconnecting(EventConsumer<TikTokReconnectingEvent> action);
/**
* Invoked when client disconnected
* @param action consumable action
* @return self instance
* @param action
* @return
*/
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> action);
/**
* Invoked when exception was throed inside client or event handler
* @param action consumable action
* @return self instance
* @param action
* @return
*/
T onError(EventConsumer<TikTokErrorEvent> action);
@@ -216,4 +215,6 @@ public interface EventsBuilder<T> {
//T onLinkMicBattle(TikTokEventConsumer<TikTokLinkMicBattleEvent> event);
//T onUnhandledControl(TikTokEventConsumer<TikTokUnhandledControlEvent> event);
}
}

View File

@@ -32,18 +32,13 @@ import java.util.function.Function;
public interface TikTokMapper {
/**
* when mapper is not found for messageName, TikTokLiveException is thrown
* * if mapper is not found for messageName, TikTokLiveException is thrown
*
* @param messageName
* @return TikTokMapperModel
*/
TikTokMapperModel forMessage(String messageName);
/**
*
* @param mapperName protocol buffer class type
* @return
*/
TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName);
TikTokMapperModel forMessage(String mapperName, MappingAction<MappingResult> onMapping);

View File

@@ -102,8 +102,7 @@ message Text {
// @Image
message Image {
repeated string url = 1;
string extras = 2;
repeated string urlList = 1;
bool isAnimated = 9;
}
@@ -1062,9 +1061,9 @@ message CohostListChangeContent {
message LinkerListChangeContent {
repeated ListUser linkedUsers = 1;
repeated ListUser appliedUsers = 2;
repeated ListUser connectingUsers = 3;
repeated ListUser linkedUsersList = 1;
repeated ListUser appliedUsersList = 2;
repeated ListUser connectingUsersList = 3;
}
message LinkerMediaChangeContent {

View File

@@ -35,14 +35,6 @@ enum LinkmicApplierSortSetting {
LINKMIC_APPLIER_SORT_SETTING_BY_GIFT_SCORE = 1;
}
enum LinkMicBattleStatus {
BATTLE_ARMY_UNKNOWN = 0;
ARMY_ONGOING = 1;
ARMY_FINISHED = 2;
BATTLE_ONGOING = 4;
BATTLE_FINISHED = 5;
}
enum HashtagNamespace {
GLOBAL = 0;
GAMING = 1;
@@ -250,21 +242,21 @@ enum CommonContentCase {
enum LinkMessageType {
TYPE_LINKER_UNKNOWN = 0;
TPYE_LINKER_UNKNOWN = 0;
TYPE_LINKER_CREATE = 1;
TYPE_LINKER_CLOSE = 2;
TYPE_LINKER_INVITE = 3;
TYPE_LINKER_APPLY = 4;
TYPE_LINKER_REPLY = 5;
TYPE_LINKER_ENTER = 6;
TYPE_LINKER_LEAVE = 7;
TPYE_LINKER_ENTER = 6;
TPYE_LINKER_LEAVE = 7;
TYPE_LINKER_PERMIT = 8;
TYPE_LINKER_CANCEL_INVITE = 9;
TPYE_LINKER_CANCEL_INVITE = 9;
TYPE_LINKER_WAITING_LIST_CHANGE = 10;
TYPE_LINKER_LINKED_LIST_CHANGE = 11;
TYPE_LINKER_UPDATE_USER = 12;
TYPE_LINKER_KICK_OUT = 13;
TYPE_LINKER_CANCEL_APPLY = 14;
TPYE_LINKER_KICK_OUT = 13;
TPYE_LINKER_CANCEL_APPLY = 14;
TYPE_LINKER_MUTE = 15;
TYPE_LINKER_MATCH = 16;
TYPE_LINKER_UPDATE_USER_SETTING = 17;
@@ -275,8 +267,8 @@ enum LinkMessageType {
TYPE_LINKER_COHOST_LIST_CHANGE = 22;
TYPE_LINKER_MEDIA_CHANGE = 23;
TYPE_LINKER_ACCEPT_NOTICE = 24;
TYPE_LINKER_SYS_KICK_OUT = 101;
TYPE_LINKMIC_USER_TOAST = 102;
TPYE_LINKER_SYS_KICK_OUT = 101;
TPYE_LINKMIC_USER_TOAST = 102;
}
enum MessageType {

View File

@@ -521,7 +521,7 @@ message WebcastLinkMicArmies {
uint64 id2 = 4;
uint64 timeStamp1 = 5;
uint64 timeStamp2 = 6;
LinkMicBattleStatus battleStatus = 7;
int32 battleStatus = 7; // SHOULD BE AN ENUM
uint64 data1 = 8;
uint64 data2 = 9;
uint32 data3 = 10;
@@ -574,26 +574,11 @@ message WebcastLinkMicBattle {
Common common = 1;
uint64 id = 2;
LinkMicBattleConfig battleConfig = 3;
LinkMicBattleStatus battleStatus = 4;
uint32 data2 = 4;
repeated LinkMicBattleDetails details = 5;
repeated LinkMicBattleTopViewers viewerTeam = 9;
repeated LinkMicBattleHost hostTeam = 10;
repeated LinkMicBattleTeam teams1 = 9;
repeated LinkMicBattleTeam teams2 = 10;
repeated LinkMicBattleTeamData teamData = 13;
uint64 unknownData16 = 16;
repeated Host2v2Data hostData2v2 = 17;
message Host2v2Data {
uint32 teamNumber = 1;
repeated HostData hostdata = 2;
uint32 unknownData3 = 3;
uint32 totalPoints = 4;
message HostData {
uint64 hostId = 1;
uint32 points = 2;
string hostIdStr = 3;
}
}
message LinkMicBattleConfig {
uint64 id1 = 1;
@@ -601,69 +586,29 @@ message WebcastLinkMicBattle {
uint32 data1 = 3;
uint64 id2 = 4;
uint32 data2 = 5;
uint32 data3 = 6;
uint32 data4 = 8;
}
message LinkMicBattleTeamData {
uint64 teamId = 1;
LinkMicBattleData data = 2;
}
message LinkMicBattleData {
uint64 id = 1;
uint32 data1 = 2;
uint32 winStreak = 3;
uint32 data2 = 3;
uint32 data3 = 5;
string url = 6;
}
message LinkMicBattleDetails {
uint64 id = 1;
LinkMicBattleDetailsSummary summary = 2;
message LinkMicBattleDetailsSummary {
uint64 id = 1;
uint32 unknownData2 = 2;
uint32 points = 3;
}
LinkMicBattleData details = 2;
}
message LinkMicBattleTopViewers {
message LinkMicBattleTeam {
uint64 id = 1;
repeated TopViewerGroup viewerGroup = 2;
message TopViewerGroup {
repeated TopViewer viewer = 1;
uint32 points = 2;
string hostIdOrTeamNum = 3; // 1v1 Battle = HostId | 2v2 Battle = Team # - 1 & 2
message TopViewer {
uint64 id = 1;
uint32 points = 2;
string profileId = 3;
repeated Image images = 4;
string stringId = 6;
}
}
repeated User users = 2;
}
message LinkMicBattleHost {
uint64 id = 1;
repeated HostGroup hostGroup = 2;
message HostGroup {
repeated Host host = 1;
uint32 points = 2;
string hostId = 3;
message Host {
uint64 id = 1;
string profileId = 2;
repeated Image images = 3;
string name = 4;
}
}
message LinkMicBattleTeamData {
uint64 teamId = 1;
LinkMicBattleData data = 2;
}
}
@@ -805,7 +750,7 @@ message WebcastLinkMessage {
LinkerListChangeContent ListChangeContent = 20;
CohostListChangeContent CohostListChangeContent = 21;
LinkerMediaChangeContent MediaChangeContent = 22;
LinkerAcceptNoticeContent AcceptNoticeContent = 23;
LinkerAcceptNoticeContent ReplyAcceptNoticeContent = 23;
LinkerSysKickOutContent SysKickOutContent = 101;
LinkmicUserToastContent UserToastContent = 102;
string extra = 200;
@@ -847,4 +792,6 @@ message RoomVerifyMessage {
string content = 3;
int64 noticeType = 4;
bool closeRoom = 5;
}
}

View File

@@ -5,18 +5,12 @@
<parent>
<artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.7.2-Release</version>
<version>1.0.16-Release</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Client</artifactId>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
@@ -30,12 +24,7 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.jwdeveloper.DepenDance</groupId>
<artifactId>DepenDance-Full</artifactId>
<version>0.0.18-Release</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
@@ -50,7 +39,7 @@
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.5</version>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>

View File

@@ -23,21 +23,16 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftsManager;
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public class TikTokLive {
/**
* Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo'
*
* @param hostName profile name of TikTok user could be found in profile link
* @param hostName profile name of Tiktok user could be found in profile link
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
* @return LiveClientBuilder
*/
public static LiveClientBuilder newClient(String hostName) {
@@ -45,52 +40,48 @@ public class TikTokLive {
}
/**
* Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo'
*
* @param hostName profile name of TikTok user could be found in profile link
* @param hostName profile name of Tiktok user could be found in profile link
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
* @return true if live is Online, false if is offline
*/
public static boolean isLiveOnline(String hostName) {
public static boolean isLiveOnline(String hostName)
{
return requests().fetchLiveUserData(hostName).isLiveOnline();
}
/**
* Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo'
*
* @param hostName profile name of TikTok user could be found in profile link
* @param hostName profile name of Tiktok user could be found in profile link
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
* @return true if live is Online, false if is offline
*/
public static CompletableFuture<Boolean> isLiveOnlineAsync(String hostName) {
return CompletableFuture.supplyAsync(() -> isLiveOnline(hostName));
public static CompletableFuture<Boolean> isLiveOnlineAsync(String hostName)
{
return CompletableFuture.supplyAsync(()-> isLiveOnline(hostName));
}
/**
* Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo'
*
* @param hostName profile name of TikTok user could be found in profile link
* @param hostName profile name of Tiktok user could be found in profile link
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
* @return true is hostName name is valid and exists, false if not
*/
public static boolean isHostNameValid(String hostName) {
public static boolean isHostNameValid(String hostName)
{
return requests().fetchLiveUserData(hostName).isHostNameValid();
}
/**
* Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo'
*
* @param hostName profile name of TikTok user could be found in profile link
* @param hostName profile name of Tiktok user could be found in profile link
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
* @return true is hostName name is valid and exists, false if not
*/
public static CompletableFuture<Boolean> isHostNameValidAsync(String hostName) {
return CompletableFuture.supplyAsync(() -> isHostNameValid(hostName));
}
/**
* Use to get some data from TikTok about users are lives
*
* @return LiveHttpClient
*/
public static LiveHttpClient requests(Consumer<LiveClientSettings> consumer) {
return new TikTokLiveHttpClient(consumer);
public static CompletableFuture<Boolean> isHostNameValidAsync(String hostName)
{
return CompletableFuture.supplyAsync(()-> isHostNameValid(hostName));
}
/**
@@ -99,22 +90,6 @@ public class TikTokLive {
* @return LiveHttpClient
*/
public static LiveHttpClient requests() {
return requests(liveClientSettings -> {});
}
private static GiftsManager giftsManager;
/**
* Fetch gifts from endpoint and returns GiftManager
*
* @return GiftsManager
*/
public static GiftsManager gifts() {
if (giftsManager == null) {
synchronized (GiftsManager.class) {
giftsManager = new TikTokGiftsManager(requests().fetchGiftsData().getGifts());
}
}
return giftsManager;
return new TikTokLiveHttpClient();
}
}

View File

@@ -22,53 +22,50 @@
*/
package io.github.jwdeveloper.tiktok;
import com.google.protobuf.ByteString;
import io.github.jwdeveloper.dependance.injector.api.annotations.Inject;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.control.*;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.data.requests.*;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.exceptions.*;
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.listener.*;
import io.github.jwdeveloper.tiktok.live.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
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.models.ConnectionState;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import java.util.Base64;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.logging.Logger;
public class TikTokLiveClient implements LiveClient
{
public class TikTokLiveClient implements LiveClient {
private final TikTokRoomInfo liveRoomInfo;
private final LiveHttpClient httpClient;
private final TikTokGiftManager tikTokGiftManager;
private final TikTokLiveHttpClient httpClient;
private final SocketClient webSocketClient;
private final TikTokLiveEventHandler tikTokEventHandler;
private final LiveClientSettings clientSettings;
private final ListenersManager listenersManager;
private final TikTokListenersManager listenersManager;
private final Logger logger;
private final GiftsManager giftsManager;
private final TikTokLiveMessageHandler messageHandler;
public TikTokLiveClient(
TikTokLiveMessageHandler messageHandler,
GiftsManager giftsManager,
TikTokRoomInfo tikTokLiveMeta,
LiveHttpClient tiktokHttpClient,
SocketClient webSocketClient,
TikTokLiveEventHandler tikTokEventHandler,
LiveClientSettings clientSettings,
ListenersManager listenersManager,
Logger logger) {
this.messageHandler = messageHandler;
this.giftsManager = giftsManager;
public TikTokLiveClient(TikTokRoomInfo tikTokLiveMeta,
TikTokLiveHttpClient tiktokHttpClient,
SocketClient webSocketClient,
TikTokGiftManager tikTokGiftManager,
TikTokLiveEventHandler tikTokEventHandler,
LiveClientSettings clientSettings,
TikTokListenersManager listenersManager,
Logger logger) {
this.liveRoomInfo = tikTokLiveMeta;
this.tikTokGiftManager = tikTokGiftManager;
this.httpClient = tiktokHttpClient;
this.webSocketClient = webSocketClient;
this.tikTokEventHandler = tikTokEventHandler;
@@ -104,8 +101,7 @@ public class TikTokLiveClient implements LiveClient
if (e instanceof TikTokLiveOfflineHostException && clientSettings.isRetryOnConnectionFailure()) {
try {
Thread.sleep(clientSettings.getRetryConnectionTimeout().toMillis());
} catch (Exception ignored) {
}
} catch (Exception ignored) {}
logger.info("Reconnecting");
tikTokEventHandler.publish(this, new TikTokReconnectingEvent());
this.connect();
@@ -124,34 +120,26 @@ public class TikTokLiveClient implements LiveClient
}
setState(ConnectionState.CONNECTING);
tikTokEventHandler.publish(this, new TikTokConnectingEvent());
var userDataRequest = new LiveUserData.Request(liveRoomInfo.getHostName());
var userData = httpClient.fetchLiveUserData(userDataRequest);
liveRoomInfo.setStartTime(userData.getStartTime());
liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp());
liveRoomInfo.setRoomId(userData.getRoomId());
if (clientSettings.isFetchGifts())
giftsManager.attachGiftsList(httpClient.fetchRoomGiftsData(userData.getRoomId()).getGifts());
if (userData.getUserStatus() == LiveUserData.UserStatus.Offline)
throw new TikTokLiveOfflineHostException("User is offline: " + liveRoomInfo.getHostName());
if (userData.getUserStatus() == LiveUserData.UserStatus.NotFound)
throw new TikTokLiveOfflineHostException("User not found: " + liveRoomInfo.getHostName());
if (userData.getUserStatus() == LiveUserData.UserStatus.Offline) {
throw new TikTokLiveOfflineHostException("User is offline: "+liveRoomInfo.getHostUser());
}
if (userData.getUserStatus() == LiveUserData.UserStatus.NotFound) {
throw new TikTokLiveOfflineHostException("User not found: "+liveRoomInfo.getHostUser());
}
var liveDataRequest = new LiveData.Request(userData.getRoomId());
var liveData = httpClient.fetchLiveData(liveDataRequest);
if (liveData.isAgeRestricted() && clientSettings.isThrowOnAgeRestriction())
throw new TikTokLiveException("Livestream for " + liveRoomInfo.getHostName() + " is 18+ or age restricted!");
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound)
throw new TikTokLiveOfflineHostException("LiveStream for " + liveRoomInfo.getHostName() + " could not be found.");
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostOffline)
throw new TikTokLiveOfflineHostException("LiveStream for " + liveRoomInfo.getHostName() + " not found, is the Host offline?");
tikTokEventHandler.publish(this, new TikTokRoomDataResponseEvent(liveData));
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound) {
throw new TikTokLiveOfflineHostException("LiveStream for Host name could not be found.");
}
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostOffline) {
throw new TikTokLiveOfflineHostException("LiveStream for not be found, is the Host offline?");
}
liveRoomInfo.setTitle(liveData.getTitle());
liveRoomInfo.setViewersCount(liveData.getViewers());
@@ -159,12 +147,7 @@ public class TikTokLiveClient implements LiveClient
liveRoomInfo.setAgeRestricted(liveData.isAgeRestricted());
liveRoomInfo.setHost(liveData.getHost());
var preconnectEvent = new TikTokPreConnectionEvent(userData, liveData);
tikTokEventHandler.publish(this, preconnectEvent);
if (preconnectEvent.isCancelConnection())
throw new TikTokLiveException("TikTokPreConnectionEvent cancelled connection!");
var liveConnectionRequest = new LiveConnectionData.Request(userData.getRoomId());
var liveConnectionRequest =new LiveConnectionData.Request(userData.getRoomId());
var liveConnectionData = httpClient.fetchLiveConnectionData(liveConnectionRequest);
webSocketClient.start(liveConnectionData, this);
@@ -176,8 +159,8 @@ public class TikTokLiveClient implements LiveClient
if (liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
return;
}
setState(ConnectionState.DISCONNECTED);
webSocketClient.stop();
setState(ConnectionState.DISCONNECTED);
}
private void setState(ConnectionState connectionState) {
@@ -189,25 +172,6 @@ public class TikTokLiveClient implements LiveClient
tikTokEventHandler.publish(this, event);
}
@Override
public void publishMessage(String webcastMessageName, String payloadBase64) {
this.publishMessage(webcastMessageName, Base64.getDecoder().decode(payloadBase64));
}
@Override
public void publishMessage(String webcastMessageName, byte[] payload) {
var builder = WebcastResponse.Message.newBuilder();
builder.setMethod(webcastMessageName);
builder.setPayload(ByteString.copyFrom(payload));
var message = builder.build();
messageHandler.handleSingleMessage(this, message);
}
@Override
public GiftsManager getGiftManager() {
return giftsManager;
}
public LiveRoomInfo getRoomInfo() {
return liveRoomInfo;
}
@@ -221,4 +185,9 @@ public class TikTokLiveClient implements LiveClient
public Logger getLogger() {
return logger;
}
@Override
public GiftManager getGiftManager() {
return tikTokGiftManager;
}
}

View File

@@ -22,163 +22,249 @@
*/
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.dependance.Dependance;
import io.github.jwdeveloper.dependance.api.DependanceContainer;
import io.github.jwdeveloper.tiktok.mappers.MessagesMapperFactory;
import io.github.jwdeveloper.tiktok.common.LoggerFactory;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.control.TikTokPreConnectionEvent;
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.*;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.link.*;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.data.events.room.*;
import io.github.jwdeveloper.tiktok.data.events.social.*;
import io.github.jwdeveloper.tiktok.data.events.websocket.*;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokShareEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftsManager;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.http.HttpClientFactory;
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.listener.*;
import io.github.jwdeveloper.tiktok.live.*;
import io.github.jwdeveloper.tiktok.live.builder.*;
import io.github.jwdeveloper.tiktok.mappers.*;
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.live.GiftManager;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper;
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapperHelper;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokCommonEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokGiftEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokRoomInfoEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokSocialMediaEventHandler;
import io.github.jwdeveloper.tiktok.websocket.*;
import io.github.jwdeveloper.tiktok.messages.webcast.*;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.logging.Logger;
import java.util.logging.*;
public class TikTokLiveClientBuilder implements LiveClientBuilder {
protected final LiveClientSettings clientSettings;
protected final TikTokLiveEventHandler eventHandler;
protected final Logger logger;
protected final TikTokLiveEventHandler tikTokEventHandler;
protected final List<TikTokEventListener> listeners;
protected final List<Consumer<TikTokMapper>> onCustomMappings;
protected Consumer<TikTokMapper> onCustomMappings;
public TikTokLiveClientBuilder(String userName) {
public TikTokLiveClientBuilder(String userName)
{
this.clientSettings = LiveClientSettings.createDefault();
this.clientSettings.setHostName(userName);
this.eventHandler = new TikTokLiveEventHandler();
this.tikTokEventHandler = new TikTokLiveEventHandler();
this.logger = Logger.getLogger(TikTokLive.class.getSimpleName() + " " + userName);
this.listeners = new ArrayList<>();
this.onCustomMappings = new ArrayList<>();
this.onCustomMappings = (e) -> {
};
}
public LiveClientBuilder onMapping(Consumer<TikTokMapper> consumer) {
this.onCustomMappings.add(consumer);
public LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings) {
this.onCustomMappings = onCustomMappings;
return this;
}
public TikTokLiveClientBuilder configure(Consumer<LiveClientSettings> onConfigure) {
onConfigure.accept(clientSettings);
return this;
}
public TikTokLiveClientBuilder addListener(TikTokEventListener listener) {
if (listener != null)
listeners.add(listener);
listeners.add(listener);
return this;
}
protected void validate() {
if (clientSettings.getClientLanguage() == null || clientSettings.getClientLanguage().isEmpty())
if (clientSettings.getClientLanguage() == null || clientSettings.getClientLanguage().isEmpty()) {
clientSettings.setClientLanguage("en");
}
if (clientSettings.getHostName() == null || clientSettings.getHostName().isEmpty())
if (clientSettings.getHostName() == null || clientSettings.getHostName().isEmpty()) {
throw new TikTokLiveException("HostName can not be null");
}
if (clientSettings.getHostName().startsWith("@"))
if (clientSettings.getHostName().startsWith("@")) {
clientSettings.setHostName(clientSettings.getHostName().substring(1));
}
if (clientSettings.getPingInterval() < 250)
throw new TikTokLiveException("Minimum allowed ping interval is 250 millseconds");
var httpSettings = clientSettings.getHttpSettings();
httpSettings.getParams().put("app_language", clientSettings.getClientLanguage());
httpSettings.getParams().put("webcast_language", clientSettings.getClientLanguage());
var handler = new ConsoleHandler();
handler.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
var sb = new StringBuilder();
sb.append(ConsoleColors.GREEN).append("[").append(record.getLoggerName()).append("] ");
sb.append(ConsoleColors.GREEN).append("[").append(record.getLevel()).append("]: ");
sb.append(ConsoleColors.WHITE_BRIGHT).append(record.getMessage());
sb.append(ConsoleColors.RESET).append("\n");
return sb.toString();
}
});
logger.setUseParentHandlers(false);
logger.addHandler(handler);
logger.setLevel(clientSettings.getLogLevel());
if (!clientSettings.isPrintToConsole()) {
logger.setLevel(Level.OFF);
}
}
//TODO each class registered to container should implement own interface,
public LiveClient build() {
validate();
//Docs: https://github.com/jwdeveloper/DepenDance?tab=readme-ov-file#01-basic
var dependance = Dependance.newContainer();
var tiktokRoomInfo = new TikTokRoomInfo();
tiktokRoomInfo.setHostName(clientSettings.getHostName());
//config
dependance.registerSingleton(LiveClientSettings.class, clientSettings);
dependance.registerSingleton(Logger.class, LoggerFactory.create(clientSettings.getHostName(), clientSettings));
dependance.registerSingleton(TikTokRoomInfo.class, container ->
{
var roomInfo = new TikTokRoomInfo();
roomInfo.setHostName(clientSettings.getHostName());
return roomInfo;
});
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
//messages
dependance.registerSingleton(TikTokLiveEventHandler.class, eventHandler);
dependance.registerSingleton(TikTokLiveMessageHandler.class);
var giftManager = new TikTokGiftManager(logger);
var eventsMapper = createMapper(giftManager, tiktokRoomInfo);
var messageHandler = new TikTokLiveMessageHandler(tikTokEventHandler, eventsMapper);
//listeners
dependance.registerSingletonList(TikTokEventListener.class, (e) -> listeners);
dependance.registerSingleton(ListenersManager.class, TikTokListenersManager.class);
//networking
dependance.registerSingleton(HttpClientFactory.class);
if (clientSettings.isOffline()) {
dependance.registerSingleton(SocketClient.class, TikTokWebSocketOfflineClient.class);
dependance.registerSingleton(LiveHttpClient.class, TikTokLiveHttpOfflineClient.class);
} else {
dependance.registerSingleton(SocketClient.class, TikTokWebSocketClient.class);
dependance.registerSingleton(LiveHttpClient.class, TikTokLiveHttpClient.class);
}
var httpClientFactory = new HttpClientFactory(clientSettings);
var tikTokLiveHttpClient = new TikTokLiveHttpClient(httpClientFactory, clientSettings);
/* TODO in future, custom proxy implementation that can be provided via builder
* if(customProxy != null)
* dependance.registerSingleton(TikTokProxyProvider.class,customProxy);
* else
* dependance.registerSingleton(TikTokProxyProvider.class,DefaultProxyProvider.class);
var webSocketClient = new TikTokWebSocketClient(
clientSettings,
messageHandler,
tikTokEventHandler);
return new TikTokLiveClient(tiktokRoomInfo,
tikTokLiveHttpClient,
webSocketClient,
giftManager,
tikTokEventHandler,
clientSettings,
listenerManager,
logger);
}
public TikTokLiveMapper createMapper(GiftManager giftManager, TikTokRoomInfo roomInfo) {
/*
//
*/
//gifts
if (clientSettings.isFetchGifts()) {
dependance.registerSingleton(GiftsManager.class, TikTokLive.gifts());
} else {
dependance.registerSingleton(GiftsManager.class, new TikTokGiftsManager(List.of()));
}
//mapper
dependance.registerSingleton(TikTokGenericEventMapper.class);
dependance.registerSingleton(TikTokMapperHelper.class, TikTokLiveMapperHelper.class);
dependance.registerSingleton(TikTokMapper.class, (container) ->
var eventMapper = new TikTokGenericEventMapper();
var mapper = new TikTokLiveMapper(new TikTokLiveMapperHelper(eventMapper));
//ConnectionEvents events
var commonHandler = new TikTokCommonEventHandler();
var giftHandler = new TikTokGiftEventHandler(giftManager, roomInfo);
var roomInfoHandler = new TikTokRoomInfoEventHandler(roomInfo);
var socialHandler = new TikTokSocialMediaEventHandler(roomInfo);
mapper.forMessage(WebcastControlMessage.class, commonHandler::handleWebcastControlMessage);
//Room status events
mapper.forMessage(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
mapper.forMessage(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
mapper.forMessage(WebcastCaptionMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var dependace = (DependanceContainer) container.find(DependanceContainer.class);
var mapper = MessagesMapperFactory.create(dependace);
onCustomMappings.forEach(action -> action.accept(mapper));
return mapper;
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastCaptionMessage.class);
return MappingResult.of(messageObject, new TikTokCaptionEvent(messageObject));
});
//mapper handlers
dependance.registerSingleton(TikTokCommonEventHandler.class);
dependance.registerSingleton(TikTokGiftEventHandler.class);
dependance.registerSingleton(TikTokRoomInfoEventHandler.class);
dependance.registerSingleton(TikTokSocialMediaEventHandler.class);
//client
dependance.registerSingleton(LiveClient.class, TikTokLiveClient.class);
//User Interactions events
mapper.forMessage(WebcastChatMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
return MappingResult.of(messageObject, new TikTokCommentEvent(messageObject));
});
mapper.forMessage(WebcastSubNotifyMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastSubNotifyMessage.class);
return MappingResult.of(messageObject, new TikTokSubscribeEvent(messageObject));
});
mapper.forMessage(WebcastEmoteChatMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastEmoteChatMessage.class);
return MappingResult.of(messageObject, new TikTokEmoteEvent(messageObject));
});
mapper.forMessage(WebcastQuestionNewMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastQuestionNewMessage.class);
return MappingResult.of(messageObject, new TikTokQuestionEvent(messageObject));
});
var container = dependance.build();
return container.find(LiveClient.class);
mapper.forMessage(WebcastLikeMessage.class, roomInfoHandler::handleLike);
mapper.forMessage(WebcastGiftMessage.class, giftHandler::handleGifts);
mapper.forMessage(WebcastSocialMessage.class, socialHandler::handle);
mapper.forMessage(WebcastMemberMessage.class, roomInfoHandler::handleMemberMessage);
//Host Interaction events
mapper.forMessage(WebcastPollMessage.class, commonHandler::handlePollEvent);
mapper.forMessage(WebcastRoomPinMessage.class, commonHandler::handlePinMessage);
mapper.forMessage(WebcastChatMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
return MappingResult.of(messageObject, new TikTokCommentEvent(messageObject));
});
//LinkMic events
// mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
//Rank events
// mapper.webcastObjectToConstructor(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
// mapper.webcastObjectToConstructor(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
// mapper.webcastObjectToConstructor(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
//Others events
// mapper.webcastObjectToConstructor(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
// mapper.webcastObjectToConstructor(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
// mapper.webcastObjectToConstructor(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
// mapper.webcastObjectToConstructor(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
// mapper.webcastObjectToConstructor(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
// mapper.webcastObjectToConstructor(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
// mapper.bytesToEvents(WebcastEnvelopeMessage.class, commonHandler::handleEnvelop);
onCustomMappings.accept(mapper);
return mapper;
}
public LiveClient buildAndConnect() {
var client = build();
client.connect();
@@ -189,365 +275,273 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return build().connectAsync();
}
/**
* To do figure out how to use Annotation processor.
* Goal is to generates methods for all possible events, everytime library is compiled
*/
public TikTokLiveClientBuilder onUnhandledSocial(EventConsumer<TikTokUnhandledSocialEvent> event) {
eventHandler.subscribe(TikTokUnhandledSocialEvent.class, event);
public TikTokLiveClientBuilder onUnhandledSocial(
EventConsumer<TikTokUnhandledSocialEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledSocialEvent.class, event);
return this;
}
// @Override
public LiveClientBuilder onChest(EventConsumer<TikTokChestEvent> event) {
eventHandler.subscribe(TikTokChestEvent.class, event);
tikTokEventHandler.subscribe(TikTokChestEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicFanTicket(EventConsumer<TikTokLinkMicFanTicketEvent> event) {
eventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
public TikTokLiveClientBuilder onLinkMicFanTicket(
EventConsumer<TikTokLinkMicFanTicketEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEnvelope(EventConsumer<TikTokEnvelopeEvent> event) {
eventHandler.subscribe(TikTokEnvelopeEvent.class, event);
tikTokEventHandler.subscribe(TikTokEnvelopeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onShop(EventConsumer<TikTokShopEvent> event) {
eventHandler.subscribe(TikTokShopEvent.class, event);
tikTokEventHandler.subscribe(TikTokShopEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onDetect(EventConsumer<TikTokDetectEvent> event) {
eventHandler.subscribe(TikTokDetectEvent.class, event);
public TikTokLiveClientBuilder onDetect(
EventConsumer<TikTokDetectEvent> event) {
tikTokEventHandler.subscribe(TikTokDetectEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkLayer(EventConsumer<TikTokLinkLayerEvent> event) {
eventHandler.subscribe(TikTokLinkLayerEvent.class, event);
public TikTokLiveClientBuilder onLinkLayer(
EventConsumer<TikTokLinkLayerEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkLayerEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onConnected(EventConsumer<TikTokConnectedEvent> event) {
eventHandler.subscribe(TikTokConnectedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onPreConnection(EventConsumer<TikTokPreConnectionEvent> event) {
eventHandler.subscribe(TikTokPreConnectionEvent.class, event);
tikTokEventHandler.subscribe(TikTokConnectedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onCaption(EventConsumer<TikTokCaptionEvent> event) {
eventHandler.subscribe(TikTokCaptionEvent.class, event);
tikTokEventHandler.subscribe(TikTokCaptionEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onQuestion(EventConsumer<TikTokQuestionEvent> event) {
eventHandler.subscribe(TikTokQuestionEvent.class, event);
tikTokEventHandler.subscribe(TikTokQuestionEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRoomPin(EventConsumer<TikTokRoomPinEvent> event) {
eventHandler.subscribe(TikTokRoomPinEvent.class, event);
public TikTokLiveClientBuilder onRoomPin(
EventConsumer<TikTokRoomPinEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomPinEvent.class, event);
return this;
}
@Override
public <E extends TikTokEvent> LiveClientBuilder onEvent(Class<E> eventClass, EventConsumer<E> event) {
eventHandler.subscribe(eventClass, event);
tikTokEventHandler.subscribe(eventClass, event);
return this;
}
@Override
public TikTokLiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) {
eventHandler.subscribe(TikTokRoomInfoEvent.class, event);
tikTokEventHandler.subscribe(TikTokRoomInfoEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLivePaused(EventConsumer<TikTokLivePausedEvent> event) {
eventHandler.subscribe(TikTokLivePausedEvent.class, event);
tikTokEventHandler.subscribe(TikTokLivePausedEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event) {
eventHandler.subscribe(TikTokLiveUnpausedEvent.class, event);
tikTokEventHandler.subscribe(TikTokLiveUnpausedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLike(EventConsumer<TikTokLikeEvent> event) {
eventHandler.subscribe(TikTokLikeEvent.class, event);
tikTokEventHandler.subscribe(TikTokLikeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLink(EventConsumer<TikTokLinkEvent> event) {
eventHandler.subscribe(TikTokLinkEvent.class, event);
tikTokEventHandler.subscribe(TikTokLinkEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkInvite(EventConsumer<TikTokLinkInviteEvent> event) {
eventHandler.subscribe(TikTokLinkInviteEvent.class, event);
public TikTokLiveClientBuilder onBarrage(
EventConsumer<TikTokBarrageEvent> event) {
tikTokEventHandler.subscribe(TikTokBarrageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkReply(EventConsumer<TikTokLinkReplyEvent> event) {
eventHandler.subscribe(TikTokLinkReplyEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkCreate(EventConsumer<TikTokLinkCreateEvent> event) {
eventHandler.subscribe(TikTokLinkCreateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkClose(EventConsumer<TikTokLinkCloseEvent> event) {
eventHandler.subscribe(TikTokLinkCloseEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkEnter(EventConsumer<TikTokLinkEnterEvent> event) {
eventHandler.subscribe(TikTokLinkEnterEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkLeave(EventConsumer<TikTokLinkLeaveEvent> event) {
eventHandler.subscribe(TikTokLinkLeaveEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkCancel(EventConsumer<TikTokLinkCancelEvent> event) {
eventHandler.subscribe(TikTokLinkCancelEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkKickOut(EventConsumer<TikTokLinkKickOutEvent> event) {
eventHandler.subscribe(TikTokLinkKickOutEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkLinkedListChange(EventConsumer<TikTokLinkLinkedListChangeEvent> event) {
eventHandler.subscribe(TikTokLinkLinkedListChangeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkUpdateUser(EventConsumer<TikTokLinkUpdateUserEvent> event) {
eventHandler.subscribe(TikTokLinkUpdateUserEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkWaitListChange(EventConsumer<TikTokLinkWaitListChangeEvent> event) {
eventHandler.subscribe(TikTokLinkWaitListChangeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMute(EventConsumer<TikTokLinkMuteEvent> event) {
eventHandler.subscribe(TikTokLinkMuteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkRandomMatch(EventConsumer<TikTokLinkRandomMatchEvent> event) {
eventHandler.subscribe(TikTokLinkRandomMatchEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkUpdateUserSettings(EventConsumer<TikTokLinkUpdateUserSettingEvent> event) {
eventHandler.subscribe(TikTokLinkUpdateUserSettingEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicIdxUpdate(EventConsumer<TikTokLinkMicIdxUpdateEvent> event) {
eventHandler.subscribe(TikTokLinkMicIdxUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkListChange(EventConsumer<TikTokLinkListChangeEvent> event) {
eventHandler.subscribe(TikTokLinkListChangeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkCohostListChange(EventConsumer<TikTokLinkCohostListChangeEvent> event) {
eventHandler.subscribe(TikTokLinkCohostListChangeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMediaChange(EventConsumer<TikTokLinkMediaChangeEvent> event) {
eventHandler.subscribe(TikTokLinkMediaChangeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkAcceptNotice(EventConsumer<TikTokLinkAcceptNoticeEvent> event) {
eventHandler.subscribe(TikTokLinkAcceptNoticeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkSysKickOut(EventConsumer<TikTokLinkSysKickOutEvent> event) {
eventHandler.subscribe(TikTokLinkSysKickOutEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkUserToast(EventConsumer<TikTokLinkUserToastEvent> event) {
eventHandler.subscribe(TikTokLinkUserToastEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onBarrage(EventConsumer<TikTokBarrageEvent> event) {
eventHandler.subscribe(TikTokBarrageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onGift(EventConsumer<TikTokGiftEvent> event) {
eventHandler.subscribe(TikTokGiftEvent.class, event);
tikTokEventHandler.subscribe(TikTokGiftEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onGiftCombo(EventConsumer<TikTokGiftComboEvent> event) {
eventHandler.subscribe(TikTokGiftComboEvent.class, event);
tikTokEventHandler.subscribe(TikTokGiftComboEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicArmies(EventConsumer<TikTokLinkMicArmiesEvent> event) {
eventHandler.subscribe(TikTokLinkMicArmiesEvent.class, event);
public TikTokLiveClientBuilder onLinkMicArmies(
EventConsumer<TikTokLinkMicArmiesEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicArmiesEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEmote(EventConsumer<TikTokEmoteEvent> event) {
eventHandler.subscribe(TikTokEmoteEvent.class, event);
tikTokEventHandler.subscribe(TikTokEmoteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnauthorizedMember(EventConsumer<TikTokUnauthorizedMemberEvent> event) {
eventHandler.subscribe(TikTokUnauthorizedMemberEvent.class, event);
public TikTokLiveClientBuilder onUnauthorizedMember(
EventConsumer<TikTokUnauthorizedMemberEvent> event) {
tikTokEventHandler.subscribe(TikTokUnauthorizedMemberEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onInRoomBanner(EventConsumer<TikTokInRoomBannerEvent> event) {
eventHandler.subscribe(TikTokInRoomBannerEvent.class, event);
public TikTokLiveClientBuilder onInRoomBanner(
EventConsumer<TikTokInRoomBannerEvent> event) {
tikTokEventHandler.subscribe(TikTokInRoomBannerEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicMethod(EventConsumer<TikTokLinkMicMethodEvent> event) {
eventHandler.subscribe(TikTokLinkMicMethodEvent.class, event);
public TikTokLiveClientBuilder onLinkMicMethod(
EventConsumer<TikTokLinkMicMethodEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicMethodEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onSubscribe(EventConsumer<TikTokSubscribeEvent> event) {
eventHandler.subscribe(TikTokSubscribeEvent.class, event);
tikTokEventHandler.subscribe(TikTokSubscribeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onPoll(EventConsumer<TikTokPollEvent> event) {
eventHandler.subscribe(TikTokPollEvent.class, event);
tikTokEventHandler.subscribe(TikTokPollEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onFollow(EventConsumer<TikTokFollowEvent> event) {
eventHandler.subscribe(TikTokFollowEvent.class, event);
tikTokEventHandler.subscribe(TikTokFollowEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onComment(EventConsumer<TikTokCommentEvent> event) {
eventHandler.subscribe(TikTokCommentEvent.class, event);
tikTokEventHandler.subscribe(TikTokCommentEvent.class, event);
return this;
}
@Override
public LiveClientBuilder onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action) {
eventHandler.subscribe(TikTokHttpResponseEvent.class, action);
tikTokEventHandler.subscribe(TikTokHttpResponseEvent.class, action);
return this;
}
public TikTokLiveClientBuilder onGoalUpdate(EventConsumer<TikTokGoalUpdateEvent> event) {
eventHandler.subscribe(TikTokGoalUpdateEvent.class, event);
tikTokEventHandler.subscribe(TikTokGoalUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRankUpdate(EventConsumer<TikTokRankUpdateEvent> event) {
eventHandler.subscribe(TikTokRankUpdateEvent.class, event);
tikTokEventHandler.subscribe(TikTokRankUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onIMDelete(EventConsumer<TikTokIMDeleteEvent> event) {
eventHandler.subscribe(TikTokIMDeleteEvent.class, event);
tikTokEventHandler.subscribe(TikTokIMDeleteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLiveEnded(EventConsumer<TikTokLiveEndedEvent> event) {
eventHandler.subscribe(TikTokLiveEndedEvent.class, event);
tikTokEventHandler.subscribe(TikTokLiveEndedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onError(EventConsumer<TikTokErrorEvent> event) {
eventHandler.subscribe(TikTokErrorEvent.class, event);
tikTokEventHandler.subscribe(TikTokErrorEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onJoin(EventConsumer<TikTokJoinEvent> event) {
eventHandler.subscribe(TikTokJoinEvent.class, event);
tikTokEventHandler.subscribe(TikTokJoinEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRankText(EventConsumer<TikTokRankTextEvent> event) {
eventHandler.subscribe(TikTokRankTextEvent.class, event);
tikTokEventHandler.subscribe(TikTokRankTextEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onShare(EventConsumer<TikTokShareEvent> event) {
eventHandler.subscribe(TikTokShareEvent.class, event);
tikTokEventHandler.subscribe(TikTokShareEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnhandledMember(EventConsumer<TikTokUnhandledMemberEvent> event) {
eventHandler.subscribe(TikTokUnhandledMemberEvent.class, event);
public TikTokLiveClientBuilder onUnhandledMember(
EventConsumer<TikTokUnhandledMemberEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledMemberEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onSubNotify(EventConsumer<TikTokSubNotifyEvent> event) {
eventHandler.subscribe(TikTokSubNotifyEvent.class, event);
tikTokEventHandler.subscribe(TikTokSubNotifyEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicBattle(EventConsumer<TikTokLinkMicBattleEvent> event) {
eventHandler.subscribe(TikTokLinkMicBattleEvent.class, event);
public TikTokLiveClientBuilder onLinkMicBattle(
EventConsumer<TikTokLinkMicBattleEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicBattleEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onDisconnected(EventConsumer<TikTokDisconnectedEvent> event) {
eventHandler.subscribe(TikTokDisconnectedEvent.class, event);
public TikTokLiveClientBuilder onDisconnected(
EventConsumer<TikTokDisconnectedEvent> event) {
tikTokEventHandler.subscribe(TikTokDisconnectedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnhandledControl(EventConsumer<TikTokUnhandledControlEvent> event) {
eventHandler.subscribe(TikTokUnhandledControlEvent.class, event);
public TikTokLiveClientBuilder onUnhandledControl(
EventConsumer<TikTokUnhandledControlEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledControlEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEvent(EventConsumer<TikTokEvent> event) {
eventHandler.subscribe(TikTokEvent.class, event);
tikTokEventHandler.subscribe(TikTokEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> event) {
eventHandler.subscribe(TikTokWebsocketResponseEvent.class, event);
tikTokEventHandler.subscribe(TikTokWebsocketResponseEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> event) {
eventHandler.subscribe(TikTokWebsocketMessageEvent.class, event);
tikTokEventHandler.subscribe(TikTokWebsocketMessageEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> event) {
eventHandler.subscribe(TikTokWebsocketUnhandledMessageEvent.class, event);
tikTokEventHandler.subscribe(TikTokWebsocketUnhandledMessageEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onReconnecting(EventConsumer<TikTokReconnectingEvent> event) {
eventHandler.subscribe(TikTokReconnectingEvent.class, event);
tikTokEventHandler.subscribe(TikTokReconnectingEvent.class, event);
return this;
}
}

View File

@@ -26,7 +26,10 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class TikTokLiveEventHandler {
private final Map<Class<?>, Set<EventConsumer>> events;
@@ -36,8 +39,21 @@ public class TikTokLiveEventHandler {
}
public void publish(LiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
Optional.ofNullable(events.get(TikTokEvent.class)).ifPresent(handlers -> handlers.forEach(handler -> handler.onEvent(tikTokLiveClient, tikTokEvent)));
Optional.ofNullable(events.get(tikTokEvent.getClass())).ifPresent(handlers -> handlers.forEach(handler -> handler.onEvent(tikTokLiveClient, tikTokEvent)));
if (events.containsKey(TikTokEvent.class)) {
var handlers = events.get(TikTokEvent.class);
for (var handle : handlers) {
handle.onEvent(tikTokLiveClient, tikTokEvent);
}
}
if (!events.containsKey(tikTokEvent.getClass())) {
return;
}
var handlers = events.get(tikTokEvent.getClass());
for (var handler : handlers) {
handler.onEvent(tikTokLiveClient, tikTokEvent);
}
}
public <T extends TikTokEvent> void subscribe(Class<?> clazz, EventConsumer<T> event) {
@@ -49,10 +65,22 @@ public class TikTokLiveEventHandler {
}
public <T extends TikTokEvent> void unsubscribe(EventConsumer<T> consumer) {
events.forEach((key, value) -> value.remove(consumer));
for (var entry : events.entrySet()) {
entry.getValue().remove(consumer);
}
}
public <T extends TikTokEvent> void unsubscribe(Class<?> clazz, EventConsumer<T> consumer) {
Optional.ofNullable(clazz).map(events::get).ifPresent(consumers -> consumers.remove(consumer));
}
}
if (clazz == null) {
return;
}
if (!events.containsKey(clazz)) {
return;
}
var eventSet = events.get(clazz);
eventSet.remove(consumer);
}
}

View File

@@ -23,100 +23,64 @@
package io.github.jwdeveloper.tiktok;
import com.google.protobuf.InvalidProtocolBufferException;
import io.github.jwdeveloper.dependance.injector.api.annotations.Inject;
import io.github.jwdeveloper.tiktok.common.*;
import io.github.jwdeveloper.tiktok.data.requests.*;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.data.settings.*;
import io.github.jwdeveloper.tiktok.exceptions.*;
import io.github.jwdeveloper.tiktok.http.*;
import io.github.jwdeveloper.tiktok.http.mappers.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.net.http.HttpResponse;
import java.util.function.Consumer;
import java.util.logging.Logger;
import java.util.Optional;
public class TikTokLiveHttpClient implements LiveHttpClient {
public class TikTokLiveHttpClient implements LiveHttpClient
{
/**
* <a href="https://github-wiki-see.page/m/isaackogan/TikTokLive/wiki/All-About-Signatures">Signing API by Isaac Kogan</a>
*/
private static final String TIKTOK_SIGN_API = "https://tiktok.eulerstream.com/webcast/fetch";
* Signing API by Isaac Kogan
* https://github-wiki-see.page/m/isaackogan/TikTokLive/wiki/All-About-Signatures
*/
private static final String TIKTOK_SIGN_API = "https://tiktok.eulerstream.com/webcast/sign_url";
private static final String TIKTOK_URL_WEB = "https://www.tiktok.com/";
private static final String TIKTOK_URL_WEBCAST = "https://webcast.tiktok.com/webcast/";
public static final String TIKTOK_GIFTS_URL = "https://raw.githubusercontent.com/TikTok-LIVE-Private/GiftsGenerator/master/page/public/gifts.json";
public static final String TIKTOK_ROOM_GIFTS_URL = TIKTOK_URL_WEBCAST+"gift/list/";
public static final int TIKTOK_AGE_RESTRICTED_CODE = 4003110;
private final HttpClientFactory httpFactory;
private final LiveClientSettings clientSettings;
private final LiveUserDataMapper liveUserDataMapper;
private final LiveDataMapper liveDataMapper;
private final SignServerResponseMapper signServerResponseMapper;
private final GiftsDataMapper giftsDataMapper;
private final Logger logger;
@Inject
public TikTokLiveHttpClient(HttpClientFactory factory) {
public TikTokLiveHttpClient(HttpClientFactory factory, LiveClientSettings settings) {
this.httpFactory = factory;
this.clientSettings = factory.getLiveClientSettings();
this.logger = LoggerFactory.create("HttpClient-"+hashCode(), clientSettings);
clientSettings = settings;
liveUserDataMapper = new LiveUserDataMapper();
liveDataMapper = new LiveDataMapper();
signServerResponseMapper = new SignServerResponseMapper();
giftsDataMapper = new GiftsDataMapper();
}
public TikTokLiveHttpClient(Consumer<LiveClientSettings> consumer) {
this(new HttpClientFactory(LiveClientSettings.createDefault()));
consumer.accept(clientSettings);
public TikTokLiveHttpClient() {
this(new HttpClientFactory(LiveClientSettings.createDefault()), LiveClientSettings.createDefault());
}
public GiftsData.Response fetchRoomGiftsData(String room_id) {
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
if (proxyClientSettings.isEnabled()) {
while (proxyClientSettings.hasNext()) {
try {
return getRoomGiftsData(room_id);
} catch (TikTokProxyRequestException ignored) {}
}
}
return getRoomGiftsData(room_id);
}
public GiftsData.Response getRoomGiftsData(String room_id) {
var result = httpFactory.client(TIKTOK_ROOM_GIFTS_URL)
.withParam("room_id", room_id)
.build()
.toJsonResponse();
if (result.isFailure())
throw new TikTokLiveRequestException("Unable to fetch gifts information's - "+result);
var json = result.getContent();
return giftsDataMapper.mapRoom(json);
}
public GiftsData.Response fetchGiftsData() {
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
if (proxyClientSettings.isEnabled()) {
while (proxyClientSettings.hasNext()) {
try {
return getGiftsData();
} catch (TikTokProxyRequestException ignored) {}
}
var url = TIKTOK_URL_WEBCAST + "gift/list/";
var optional = httpFactory.client(url)
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokLiveRequestException("Unable to fetch gifts information's");
}
return getGiftsData();
var json = optional.get();
return giftsDataMapper.map(json);
}
public GiftsData.Response getGiftsData() {
var result = httpFactory.client(TIKTOK_GIFTS_URL)
.build()
.toJsonResponse();
if (result.isFailure())
throw new TikTokLiveRequestException("Unable to fetch gifts information's - "+result);
var json = result.getContent();
return giftsDataMapper.map(json);
@Override
public LiveUserData.Response fetchLiveUserData(String userName) {
return fetchLiveUserData(new LiveUserData.Request(userName));
}
@Override
@@ -125,26 +89,40 @@ public class TikTokLiveHttpClient implements LiveHttpClient
if (proxyClientSettings.isEnabled()) {
while (proxyClientSettings.hasNext()) {
try {
return getLiveUserData(request);
var url = TIKTOK_URL_WEB + "api-live/user/room";
var optional = httpFactory.client(url)
.withParam("uniqueId", request.getUserName())
.withParam("sourceType", "54")
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokLiveRequestException("Unable to get information's about user");
}
var json = optional.get();
return liveUserDataMapper.map(json);
} catch (TikTokProxyRequestException ignored) {}
}
}
return getLiveUserData(request);
var url = TIKTOK_URL_WEB + "api-live/user/room";
var optional = httpFactory.client(url)
.withParam("uniqueId", request.getUserName())
.withParam("sourceType", "54")
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokLiveRequestException("Unable to get information's about user");
}
var json = optional.get();
return liveUserDataMapper.map(json);
}
public LiveUserData.Response getLiveUserData(LiveUserData.Request request) {
var url = TIKTOK_URL_WEB + "api-live/user/room";
var result = httpFactory.client(url)
.withParam("uniqueId", request.getUserName())
.withParam("sourceType", "54")
.build()
.toJsonResponse();
if (result.isFailure())
throw new TikTokLiveRequestException("Unable to get information's about user - "+result);
var json = result.getContent();
return liveUserDataMapper.map(json, logger);
@Override
public LiveData.Response fetchLiveData(String roomId) {
return fetchLiveData(new LiveData.Request(roomId));
}
@Override
@@ -153,39 +131,53 @@ public class TikTokLiveHttpClient implements LiveHttpClient
if (proxyClientSettings.isEnabled()) {
while (proxyClientSettings.hasNext()) {
try {
return getLiveData(request);
var url = TIKTOK_URL_WEBCAST + "room/info";
var optional = httpFactory.client(url)
.withParam("room_id", request.getRoomId())
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokLiveRequestException("Unable to get info about live room");
}
var json = optional.get();
return liveDataMapper.map(json);
} catch (TikTokProxyRequestException ignored) {}
}
}
return getLiveData(request);
}
public LiveData.Response getLiveData(LiveData.Request request) {
var url = TIKTOK_URL_WEBCAST + "room/info";
var result = httpFactory.client(url)
.withParam("room_id", request.getRoomId())
.build()
.toJsonResponse();
var optional = httpFactory.client(url)
.withParam("room_id", request.getRoomId())
.build()
.toJsonResponse();
if (result.isFailure())
throw new TikTokLiveRequestException("Unable to get info about live room - "+result);
if (optional.isEmpty()) {
throw new TikTokLiveRequestException("Unable to get info about live room");
}
var json = result.getContent();
var json = optional.get();
return liveDataMapper.map(json);
}
@Override
public LiveConnectionData.Response fetchLiveConnectionData(String roomId) {
return fetchLiveConnectionData(new LiveConnectionData.Request(roomId));
}
@Override
public LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request) {
var result = getStartingPayload(request);
HttpResponse<byte[]> credentialsResponse = result.getContent(); // Always guaranteed to have response
HttpResponse<byte[]> credentialsResponse = getOptionalProxyResponse(request).orElseGet(()-> {
SignServerResponse signServerResponse = getSignedUrl(request.getRoomId());
return getWebsocketCredentialsResponse(signServerResponse.getSignedUrl());
});
try {
var resultHeader = ActionResult.of(credentialsResponse.headers().firstValue("x-set-tt-cookie"));
if (resultHeader.isFailure()) {
logger.warning("Sign Server Headers: "+request.getRoomId()+" - "+credentialsResponse.headers().map());
throw new TikTokSignServerException("Sign server did not return the x-set-tt-cookie header - "+result);
var optionalHeader = credentialsResponse.headers().firstValue("set-cookie");
if (optionalHeader.isEmpty()) {
throw new TikTokSignServerException("Sign server did not return the set-cookie header");
}
var websocketCookie = resultHeader.getContent();
var websocketCookie = optionalHeader.get();
var webcastResponse = WebcastResponse.parseFrom(credentialsResponse.body());
var webSocketUrl = httpFactory
.client(webcastResponse.getPushServer())
@@ -195,40 +187,61 @@ public class TikTokLiveHttpClient implements LiveHttpClient
.withParam("internal_ext", webcastResponse.getInternalExt())
.withParams(webcastResponse.getRouteParamsMapMap())
.build()
.toUri();
.toUrl();
return new LiveConnectionData.Response(websocketCookie, webSocketUrl, webcastResponse);
} catch (InvalidProtocolBufferException e) {
throw new TikTokSignServerException("Unable to parse websocket credentials response to WebcastResponse - "+result);
throw new TikTokSignServerException("Unable to parse websocket credentials response to WebcastResponse");
}
}
private ActionResult<HttpResponse<byte[]>> getStartingPayload(LiveConnectionData.Request request) {
SignServerResponse getSignedUrl(String roomId) {
var urlToSign = httpFactory
.client(TikTokLiveHttpClient.TIKTOK_URL_WEBCAST + "im/fetch")
.withParam("room_id", roomId)
.build()
.toUrl();
var optional = httpFactory
.client(TikTokLiveHttpClient.TIKTOK_SIGN_API)
.withParam("client", "ttlive-java")
.withParam("uuc", "1")
.withParam("url", urlToSign.toString())
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokSignServerException("Unable to sign url: " + urlToSign);
}
var json = optional.get();
return signServerResponseMapper.map(json);
}
HttpResponse<byte[]> getWebsocketCredentialsResponse(String signedUrl) {
var optionalResponse = httpFactory
.clientEmpty(signedUrl)
.build()
.toResponse();
if (optionalResponse.isEmpty()) {
throw new TikTokSignServerException("Unable to get websocket connection credentials");
}
return optionalResponse.get();
}
Optional<HttpResponse<byte[]>> getOptionalProxyResponse(LiveConnectionData.Request request) {
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
if (proxyClientSettings.isEnabled()) {
while (proxyClientSettings.hasNext()) {
try {
return getByteResponse(request.getRoomId());
SignServerResponse signServerResponse = getSignedUrl(request.getRoomId());
HttpResponse<byte[]> credentialsResponse = getWebsocketCredentialsResponse(signServerResponse.getSignedUrl());
clientSettings.getHttpSettings().getProxyClientSettings().rotate();
return Optional.of(credentialsResponse);
} catch (TikTokProxyRequestException | TikTokSignServerException ignored) {}
}
}
return getByteResponse(request.getRoomId());
}
private ActionResult<HttpResponse<byte[]>> getByteResponse(String room_id) {
HttpClientBuilder builder = httpFactory.client(TIKTOK_SIGN_API)
.withParam("client", "ttlive-java")
.withParam("uuc", "1")
.withParam("room_id", room_id);
if (clientSettings.getApiKey() != null)
builder.withParam("apiKey", clientSettings.getApiKey());
var result = builder.build().toResponse();
if (result.isFailure())
throw new TikTokSignServerException("Unable to get websocket connection credentials - "+result);
return result;
return Optional.empty();
}
}

View File

@@ -1,72 +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;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.data.requests.GiftsData;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.net.URI;
import java.util.List;
public class TikTokLiveHttpOfflineClient implements LiveHttpClient {
@Override
public GiftsData.Response fetchGiftsData() {
return new GiftsData.Response("", List.of());
}
@Override
public GiftsData.Response fetchRoomGiftsData(String room_id) {
return new GiftsData.Response("", List.of());
}
@Override
public LiveUserData.Response fetchLiveUserData(LiveUserData.Request request) {
return new LiveUserData.Response("", LiveUserData.UserStatus.Live, "offline_room_id", 0);
}
@Override
public LiveData.Response fetchLiveData(LiveData.Request request) {
return new LiveData.Response("",
LiveData.LiveStatus.HostOnline,
"offline live",
0,
0,
0,
false,
new User(0L, "offline user", new Picture("")),
LiveData.LiveType.SOLO);
}
@Override
public LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request) {
return new LiveConnectionData.Response("",
URI.create("https://example.live"),
WebcastResponse.newBuilder().build());
}
}

View File

@@ -31,7 +31,6 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandl
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.Stopwatch;
@@ -42,9 +41,9 @@ public class TikTokLiveMessageHandler {
private final TikTokLiveEventHandler tikTokEventHandler;
private final TikTokLiveMapper mapper;
public TikTokLiveMessageHandler(TikTokLiveEventHandler tikTokEventHandler, TikTokMapper mapper) {
public TikTokLiveMessageHandler(TikTokLiveEventHandler tikTokEventHandler, TikTokLiveMapper mapper) {
this.tikTokEventHandler = tikTokEventHandler;
this.mapper = (TikTokLiveMapper) mapper;
this.mapper = mapper;
}
public void handle(LiveClient client, WebcastResponse webcastResponse) {
@@ -62,12 +61,10 @@ public class TikTokLiveMessageHandler {
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message)
{
var messageClassName = message.getMethod();
if (!mapper.isRegistered(messageClassName))
{
if (!mapper.isRegistered(messageClassName)) {
tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message));
return;
}
var stopwatch = new Stopwatch();
stopwatch.start();
var events = mapper.handleMapping(messageClassName, message.getPayload().toByteArray());
@@ -79,4 +76,5 @@ public class TikTokLiveMessageHandler {
tikTokEventHandler.publish(client, event);
}
}
}
}

View File

@@ -61,6 +61,11 @@ public class TikTokRoomInfo implements LiveRoomInfo {
return connectionState == state;
}
@Override
public User getHostUser() {
return host;
}
public void updateRanking(List<RankingUser> rankingUsers) {
usersRanking.clear();
usersRanking.addAll(rankingUsers);

View File

@@ -1,135 +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.common;
import com.google.gson.*;
import io.github.jwdeveloper.tiktok.http.mappers.*;
import lombok.Data;
import lombok.experimental.Accessors;
import java.net.http.*;
import java.util.Optional;
import java.util.function.Function;
@Data
public class ActionResult<T> {
private static final Gson gson = new Gson().newBuilder().disableHtmlEscaping()
.registerTypeHierarchyAdapter(HttpResponse.class, new HttpResponseJsonMapper())
.registerTypeHierarchyAdapter(HttpRequest.class, new HttpRequestJsonMapper())
.setPrettyPrinting().create();
private boolean success = true;
private String message;
private T content;
@Accessors(chain = true, fluent = true)
private ActionResult<?> previous;
protected ActionResult(T object) {
this.content = object;
}
protected ActionResult(T object, boolean success) {
this(object);
this.success = success;
}
protected ActionResult(T object, boolean success, String message) {
this(object, success);
this.message = message;
}
public static <T> ActionResultBuilder<T> of(T content) {
return new ActionResultBuilder<>(content);
}
public static <T> ActionResult<T> of(Optional<T> optional) {
return new ActionResult<>(optional.orElse(null), optional.isPresent());
}
public boolean isFailure() {
return !isSuccess();
}
public boolean hasMessage() {
return message != null;
}
public boolean hasPrevious() {
return previous != null;
}
public boolean hasContent() {
return content != null;
}
public <Output> ActionResult<Output> cast(Output output) {
return new ActionResult<>(output, this.isSuccess(), this.getMessage());
}
public <Output> ActionResult<Output> cast() {
return cast(null);
}
public <U> ActionResult<U> map(Function<? super T, ? extends U> mapper) {
return hasContent() ? cast(mapper.apply(content)) : cast();
}
public static <T> ActionResult<T> success(T payload, String message) {
return new ActionResult<>(payload, true, message);
}
public static <T> ActionResult<T> success(T payload) {
return success(payload, null);
}
public static <T> ActionResult<T> success() {
return success(null);
}
public static <T> ActionResult<T> failure(T target, String message) {
return new ActionResult<>(target, false, message);
}
public static <T> ActionResult<T> failure(String message) {
return failure(null, message);
}
public static <T> ActionResult<T> failure() {
return failure(null);
}
public JsonObject toJson() {
JsonObject map = new JsonObject();
map.addProperty("success", success);
map.addProperty("message", message);
map.add("content", gson.toJsonTree(content));
map.add("previous", hasPrevious() ? previous.toJson() : null);
return map;
}
@Override
public String toString() {
return "ActionResult: "+gson.toJson(toJson());
}
}

View File

@@ -1,56 +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.common;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import java.util.logging.*;
public class LoggerFactory
{
public static Logger create(String name, LiveClientSettings settings) {
Logger logger = Logger.getLogger(name);
if (logger.getHandlers().length == 0) {
var handler = new ConsoleHandler();
handler.setFormatter(new Formatter()
{
@Override
public String format(LogRecord record) {
var sb = new StringBuilder();
sb.append(ConsoleColors.GREEN).append("[").append(record.getLoggerName()).append("] ");
sb.append(ConsoleColors.GREEN).append("[").append(record.getLevel()).append("]: ");
sb.append(ConsoleColors.WHITE_BRIGHT).append(record.getMessage());
sb.append(ConsoleColors.RESET).append("\n");
return sb.toString();
}
});
logger.setUseParentHandlers(false);
logger.addHandler(handler);
logger.setLevel(settings.getLogLevel());
if (!settings.isPrintToConsole())
logger.setLevel(Level.OFF);
}
return logger;
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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.gifts;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.live.GiftManager;
import sun.misc.Unsafe;
import java.util.*;
import java.util.logging.Logger;
public class TikTokGiftManager implements GiftManager {
private final Map<Integer, Gift> indexById;
private final Map<String, Gift> indexByName;
private final Logger logger;
public TikTokGiftManager(Logger logger)
{
indexById = new HashMap<>();
indexByName = new HashMap<>();
this.logger = logger;
init();
}
protected void init() {
for (var gift : Gift.values()) {
indexById.put(gift.getId(), gift);
indexByName.put(gift.getName(), gift);
}
}
public Gift registerGift(int id, String name, int diamondCost, Picture picture) {
try {
var constructor = Unsafe.class.getDeclaredConstructors()[0];
constructor.setAccessible(true);
var unsafe = (Unsafe) constructor.newInstance();
Gift enumInstance = (Gift) unsafe.allocateInstance(Gift.class);
var field = Gift.class.getDeclaredField("id");
field.setAccessible(true);
field.set(enumInstance, id);
field = Gift.class.getDeclaredField("name");
field.setAccessible(true);
field.set(enumInstance, name);
// EnumSet
field = Gift.class.getDeclaredField("diamondCost");
field.setAccessible(true);
field.set(enumInstance, diamondCost);
field = Gift.class.getDeclaredField("picture");
field.setAccessible(true);
field.set(enumInstance, picture);
indexById.put(enumInstance.getId(), enumInstance);
indexByName.put(enumInstance.getName(), enumInstance);
return enumInstance;
} catch (Exception e) {
throw new TikTokLiveException("Unable to register gift: " + name + ": " + id);
}
}
public Gift findById(int giftId) {
Gift gift = indexById.get(giftId);
return gift == null ? Gift.UNDEFINED : gift;
}
public Gift findByName(String giftName) {
Gift gift = indexByName.get(giftName);
return gift == null ? Gift.UNDEFINED : gift;
}
@Override
public List<Gift> getGifts() {
return indexById.values().stream().toList();
}
}

View File

@@ -1,80 +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.gifts;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.live.GiftsManager;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
//TODO I should've been called it TikTokGiftsRepository
public class TikTokGiftsManager implements GiftsManager {
private final Map<Integer, Gift> giftsByIdIndex;
public TikTokGiftsManager(List<Gift> giftList)
{
giftsByIdIndex = giftList.stream().collect(Collectors.toConcurrentMap(Gift::getId, Function.identity()));
}
public void attachGift(Gift gift) {
giftsByIdIndex.put(gift.getId(), gift);
}
public void attachGiftsList(List<Gift> gifts) {
gifts.forEach(this::attachGift);
}
public Gift getByName(String name) {
return getByFilter(e -> e.getName().equalsIgnoreCase(name));
}
public Gift getById(int giftId) {
return giftsByIdIndex.getOrDefault(giftId, Gift.UNDEFINED);
}
public Gift getByFilter(Predicate<Gift> filter) {
return giftsByIdIndex.values()
.stream()
.filter(filter)
.findFirst()
.orElse(Gift.UNDEFINED);
}
@Override
public List<Gift> getManyByFilter(Predicate<Gift> filter) {
return giftsByIdIndex.values()
.stream()
.filter(filter)
.toList();
}
public List<Gift> toList() {
return giftsByIdIndex.values().stream().toList();
}
public Map<Integer, Gift> toMap() {
return Collections.unmodifiableMap(giftsByIdIndex);
}
}

View File

@@ -22,7 +22,6 @@
*/
package io.github.jwdeveloper.tiktok.http;
import io.github.jwdeveloper.tiktok.common.ActionResult;
import io.github.jwdeveloper.tiktok.data.settings.HttpClientSettings;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import lombok.AllArgsConstructor;
@@ -30,46 +29,41 @@ import lombok.AllArgsConstructor;
import java.net.*;
import java.net.http.*;
import java.nio.charset.*;
import java.time.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.Collectors;
@AllArgsConstructor
public class HttpClient {
protected final HttpClientSettings httpClientSettings;
protected final String url;
private final Pattern pattern = Pattern.compile("charset=(.*?)(?=&|$)");
public ActionResult<HttpResponse<byte[]>> toResponse() {
public Optional<HttpResponse<byte[]>> toResponse() {
var client = prepareClient();
var request = prepareGetRequest();
try {
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
var result = ActionResult.of(response);
return switch (response.statusCode()) {
case 420 -> result.message("HttpResponse Code:", response.statusCode(), "| IP Cloudflare Blocked.").failure();
case 429 -> {
var wait = response.headers().firstValue("ratelimit-reset");
if (wait.isEmpty())
yield result.message("HttpResponse Code:", response.statusCode(), "| Sign server rate limit reached. Try again later.").failure();
Duration duration = Duration.ofSeconds(Long.parseLong(wait.get()));
yield result.message("HttpResponse Code:", response.statusCode(),
String.format("| Sign server rate limit reached. Try again in %02d:%02d.", duration.toMinutesPart(), duration.toSecondsPart())).failure();
}
case 500, 501, 502, 503 -> result.message("HttpResponse Code:", response.statusCode(), "| Sign server Error. Try again later.").failure();
case 504 -> result.message("HttpResponse Code:", response.statusCode(), "| Sign server Timeout. Try again later.").failure();
case 200 -> result.success();
default -> result.message("HttpResponse Code:", response.statusCode()).failure();
};
} catch (Exception e) {
if (response.statusCode() != 200) {
return Optional.empty();
}
return Optional.of(response);
} catch (Exception e) {
throw new TikTokLiveRequestException(e);
}
}
public ActionResult<String> toJsonResponse() {
return toResponse().map(content -> new String(content.body(), charsetFrom(content.headers())));
public Optional<String> toJsonResponse() {
var optional = toResponse();
if (optional.isEmpty()) {
return Optional.empty();
}
var response = optional.get();
var body = response.body();
var charset = charsetFrom(response.headers());
return Optional.of(new String(body,charset));
}
private Charset charsetFrom(HttpHeaders headers) {
@@ -86,18 +80,23 @@ public class HttpClient {
}
}
public ActionResult<byte[]> toBinaryResponse() {
return toResponse().map(HttpResponse::body);
public Optional<byte[]> toBinaryResponse() {
var optional = toResponse();
if (optional.isEmpty()) {
return Optional.empty();
}
var body = optional.get().body();
return Optional.of(body);
}
public URI toUri() {
public URI toUrl() {
var stringUrl = prepareUrlWithParameters(url, httpClientSettings.getParams());
return URI.create(stringUrl);
}
protected HttpRequest prepareGetRequest() {
var requestBuilder = HttpRequest.newBuilder().GET();
requestBuilder.uri(toUri());
requestBuilder.uri(toUrl());
requestBuilder.timeout(httpClientSettings.getTimeout());
httpClientSettings.getHeaders().forEach(requestBuilder::setHeader);

Some files were not shown because too many files have changed in this diff Show More