Compare commits

..

100 Commits

Author SHA1 Message Date
Jacek W
5b17c33236 Merge pull request #89 from jwdeveloper/develop-1.8.2
Develop 1.8.2
2024-07-06 17:12:01 +02:00
kohlerpop1
b59373254c Make TikTokLinkMicBattleEvent.is1v1 and is2v2 dynamic based upon team instance
Moved Team1v1 and Team2v2 totalPoints to Team for universal access
2024-07-05 16:21:42 -04:00
jacek.wolniewicz
5524d9f8c4 -- tests improvement 2024-07-05 13:23:56 +02:00
jacek.wolniewicz
aa56f8eaea -- tests improvement 2024-07-05 13:21:59 +02:00
jacek.wolniewicz
e40bde8e7c - clean up code
- rename module Example to examples
2024-07-04 17:40:22 +02:00
jacek.wolniewicz
b769eb9c1f Merge remote-tracking branch 'origin/develop-1.8.2' into develop-1.8.2 2024-07-04 11:52:26 +02:00
jacek.wolniewicz
3e555a502a - add comments next to magic numbers 2024-07-04 11:51:45 +02:00
kohlerpop1
316868818b Renamed Priority.priorityValue to value to follow enum standards
Clarified message in TikTokEventListener
2024-07-03 21:04:44 -04:00
jacek.wolniewicz
36475c2cf6 - change method name from onMapping, to mappings 2024-07-04 00:00:26 +02:00
jacek.wolniewicz
2dbe81278c Merge branch 'refs/heads/master' into develop-1.8.2 2024-07-03 23:45:11 +02:00
jacek.wolniewicz
91fc32b20b Improvement on the ListenersManager 2024-07-03 23:43:23 +02:00
jacek.wolniewicz
fa855fa3aa Improvement on the ListenersManager 2024-07-03 23:40:48 +02:00
jacek.wolniewicz
cfea12dacc Remove descrabble 2024-07-03 22:37:40 +02:00
Jacek W
16cd819aaf Merge pull request #88 from jwdeveloper/develop-1.8.1
Develop 1.8.1
2024-07-03 22:30:18 +02:00
jacek.wolniewicz
290a4970fd Improvement of Listener 2024-07-03 22:29:11 +02:00
jacek.wolniewicz
660cb287e9 Improvement of Listener 2024-07-03 22:27:15 +02:00
kohlerpop1
f5de7720cd Created TikTokLiveUnknownHostException for use inside of TikTokLiveClient! 2024-07-03 14:24:37 -04:00
kohlerpop1
f986efd2d5 Only fetch gifts if no exceptions are thrown to prevent spam to TikTok 2024-07-02 22:08:02 -04:00
kohlerpop1
1054453451 Change parameter names for clarification! 2024-07-02 17:50:37 -04:00
kohlerpop1
7005f58edd Fixed spelling mistake! 2024-07-01 17:38:02 -04:00
jacek.wolniewicz
63672fe9eb - updating customizaton example 2024-07-01 23:32:33 +02:00
jacek.wolniewicz
fed9de3fd0 Due to convention, interfaces should not have TikTok name inside, but they should have prefix Live instead
- rename TikTokMapper to LiveMapper
- rename TikTokLiveMapperHelper to LiveMapperHelper

Create interface:
LiveEventsHandler for TikTokLiveEventHandler
LiveMessagesHandler for TikTokLiveMessageHandler
2024-07-01 23:28:38 +02:00
kohlerpop1
b223651a8f Fixed injection type issue. 2024-07-01 17:22:23 -04:00
kohlerpop1
8d715d4f50 Added javadocs for clarity
Optimized methods in TikTokGiftEventHandler and TikTokGenericEventMapper
2024-07-01 17:02:08 -04:00
jacek.wolniewicz
1736236ccf Due to convention, interfaces should not have TikTok name inside, but they should have prefix Live instead
- rename TikTokMapper to LiveMapper
- rename TikTokLiveMapperHelper to LiveMapperHelper

Create interface:
LiveEventsHandler for TikTokLiveEventHandler
LiveMessagesHandler for TikTokLiveMessageHandler
2024-07-01 22:19:07 +02:00
jacek.wolniewicz
85d99ce4f1 TikTokLive client sevices customization 2024-07-01 21:57:07 +02:00
jacek.wolniewicz
87727070e9 Move all events documentation to the 'EventsBuilder' 2024-07-01 21:33:04 +02:00
jacek.wolniewicz
71f744cf49 Merge remote-tracking branch 'origin/develop-1.8.1' into develop-1.8.1 2024-07-01 21:26:10 +02:00
jacek.wolniewicz
046d5f1756 Simplify adding events to TikTok Builder,
checkout `EventsBuilder`
2024-07-01 21:25:30 +02:00
kohlerpop1
c36b0f1f62 Fixed spelling mistake! 2024-07-01 15:04:05 -04:00
GitHub Action
a2082ebee3 Update version in pom.xml 2024-07-01 00:35:28 +00:00
David Kohler
412c72c119 MINOR 2024-06-30 20:33:51 -04:00
GitHub Action
6728fd9963 Update version in pom.xml 2024-07-01 00:32:46 +00:00
David Kohler
47493d4955 MINOR - Develop 1.8
Develop 1.8
2024-06-30 20:30:54 -04:00
jacek.wolniewicz
4d4317d96c Clean up code 2024-06-30 07:28:50 +02:00
jacek.wolniewicz
b1954a708c Fix issue: no events where triggered 2024-06-30 06:59:26 +02:00
kohlerpop1
14317337e9 Optimized TikTokLiveEventHandler 2024-06-29 23:57:53 -04:00
kohlerpop1
947c9c49a2 Improve addProxy(String addressPort) in ProxyClientSettings
Added @param action description and return values
Optimized methods in TikTokLiveMapper
Optimized Thread in TikTokWebSocketPingingTask
Optimized TikTokLiveEventHandler and TikTokLiveMessageHandler methods
2024-06-29 23:28:49 -04:00
jacek.wolniewicz
f2bd07377b Introduce dependecy injection container
- TikTokLiveClientBuilder this class has been higly modify to support DI container
2024-06-29 23:23:48 +02:00
jacek.wolniewicz
3f268f3a1a Introduce dependecy injection container
- TikTokLiveClientBuilder this class has been higly modify to support DI container
2024-06-29 23:12:24 +02:00
jacek.wolniewicz
55fcf83870 Introduce dependecy injection container
- TikTokLiveClientBuilder this class has been higly modify to support DI container
2024-06-29 23:07:50 +02:00
jacek.wolniewicz
8d3828cca8 Introduce dependecy injection container
- TikTokLiveClientBuilder this class has been higly modify to support DI container
2024-06-29 23:04:53 +02:00
jacek.wolniewicz
1c88491b8c Merge branch 'refs/heads/dev-dependecy-injection' into develop-1.7.3
# Conflicts:
#	API/src/main/java/io/github/jwdeveloper/tiktok/data/settings/ProxyClientSettings.java
#	Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClientBuilder.java
2024-06-29 22:57:56 +02:00
jacek.wolniewicz
47b050d0ba Introduce dependecy injection container
- TikTokLiveClientBuilder this class has been higly modify to support DI container
2024-06-29 22:52:39 +02:00
kohlerpop1
cfef082d3b Updated ProxyData exceptions to include previous exception to finish stacktrace
Updated LiveUserData.Request to throw an IllegalArgumentException when a null or blank username is provided
Updated HttpClientSettings to use setProxyClientSettings instead of direct access
Fixed ProxyRotation bug starting at index 1 instead of 0 and made methods default to synchronized in case concurrency is used in implementors code
Changed HttpClient#toUrl to toUri
Added @Getter to HttpClientFactory for liveClientSettings
Added consumer to TikTokLive#requests so that way proxies can be used when calling the fetch methods
Changed LiveUserData.Response#startTime to clarify the variable name
2024-06-28 23:07:10 -04:00
GitHub Action
34ddc74189 Update version in pom.xml 2024-06-24 14:16:40 +00:00
Jacek W
9a66d240bc Merge pull request #85 from jwdeveloper/develop-1.7.2
Develop 1.7.2
2024-06-24 08:38:22 +02:00
kohlerpop1
d825803187 Added while loop condition so it does not exit when getConnectionState returns Disconnected and stopOnDisconnect is false! 2024-06-23 23:06:05 -04:00
kohlerpop1
77c9cd6b52 Converted Consumer to BiConsumer to also accept liveClient! 2024-06-20 16:51:42 -04:00
kohlerpop1
0329d3cfeb Removed useless imports and altered logger message! 2024-06-18 22:01:47 -04:00
kohlerpop1
26659bb37d Removed not needed/used RecorderSettings#startOnConnected 2024-06-18 15:36:03 -04:00
kohlerpop1
0b9852c4d4 Moved ActionResult#message to top of toJson() for easier reading
Change Recording settings to accept an output file instead of directory and filename
2024-06-18 15:21:05 -04:00
GitHub Action
31618a16ba Update version in pom.xml 2024-06-07 10:55:14 +00:00
GitHub Action
243791f6b8 Update version in pom.xml 2024-06-02 20:11:19 +00:00
David Kohler
4f74a0f1b7 MINOR 2024-06-02 16:09:45 -04:00
GitHub Action
d1eec34fca Update version in pom.xml 2024-06-02 20:07:58 +00:00
David Kohler
82196ef8e3 MINOR: Merge pull request #84 from jwdeveloper/develop-1.6.4
Develop 1.6.4
2024-06-02 16:06:24 -04:00
kohlerpop1
8685d96ccf Moved roomId declaration to RoomInfoEvent as it is always null during onConnecting event!
Made other improvements for readability and altered createdAt field.
2024-06-01 22:36:43 -04:00
kohlerpop1
69f1d5b5c2 Fixed proto file type names, created TikTokEventListenerBase with all events, created ListUser with additional information, and created all events for TikTokLink individual events 2024-06-01 22:18:43 -04:00
kohlerpop1
6f322b2a46 Fixed custom listener manager checks. Previous implementation allowed incorrect parameter types! 2024-05-29 15:38:06 -04:00
kohlerpop1
73c4c09ea1 Moved ActionResult message above content to make it easier to read in json print out!
Added status code 420 for IP cloudflare block
2024-05-29 14:11:27 -04:00
kohlerpop1
95e357af92 Updated HTTP response code messages
General optimization of classes and removal of no longer needed classes
Removed unused imports
2024-05-29 14:00:20 -04:00
Jacek W
6b31ec7d80 Merge pull request #80 from htliang128/master
Update of Socks Proxy adding headers
2024-05-26 22:46:43 +02:00
htliang128
919554bbc8 Update of Socks Proxy adding headers 2024-05-25 12:22:31 +08:00
htliang128
bd0a1f0d01 Update of Socks Proxy adding headers 2024-05-25 12:20:57 +08:00
htliang128
f48479a92c Update of Socks Proxy adding headers 2024-05-25 12:17:46 +08:00
GitHub Action
68a86f3dbd Update version in pom.xml 2024-05-24 01:34:38 +00:00
David Kohler
c3a7a27948 Merge pull request #78 from jwdeveloper/develop-1.6.3
Develop-1.6.3
2024-05-23 21:31:48 -04:00
kohlerpop1
af52e15a45 Removal of shared cookie parameter cookie in TikTokWebSocketClient!
Privatized objects in HttpClientSettings so getters are used!
2024-05-23 21:29:03 -04:00
GitHub Action
5577df7c9c Update version in pom.xml 2024-05-23 22:45:49 +00:00
David Kohler
2c68fe3421 Merge pull request #77 from jwdeveloper/develop-1.6.2
Develop 1.6.2
2024-05-23 18:42:15 -04:00
kohlerpop1
5abfd95c89 Update of Lombok
Fixed headers being passed to Websocket. Huge thanks to @isaackogan - https://github.com/isaackogan
2024-05-23 18:32:55 -04:00
kohlerpop1
5c715bfd52 Changed Picture#Empty to Picture#empty to follow Java standards
Updated descriptions in LiveClientSettings
Added new LiveHttpClient#fetchRoomGiftsData(String room_id) to fetch gifts for this specific room/livestream and altered GiftsDataMapper to reflect the new fetchRoomGiftsData and other TikTokLive client and http client classes
2024-05-13 21:14:03 -04:00
GitHub Action
b153afb332 Update version in pom.xml 2024-05-13 00:55:24 +00:00
David Kohler
d2ea00bcae Merge pull request #72 from jwdeveloper/develop-1.6.1
Develop 1.6.1
2024-05-12 20:52:28 -04:00
kohlerpop1
4297af1349 Simplify LiveDataMapper#map 2024-05-12 20:47:13 -04:00
kohlerpop1
d09c90ef54 Added append live username option to FileStorage and now support connection to 18+ age restricted! 2024-05-10 16:44:42 -04:00
kohlerpop1
9c96c8899a Added option to use File Locking as through testing, some events occur simultaneously causing the file to become overlapped or corrupted. 2024-05-04 15:21:34 -04:00
kohlerpop1
301df6392d More updated to TikTokLinkMicBattleEvent, updated Gift since its no longer enum we do not need to use Unsafe, and added default mappings for WebcastLinkMicBattle and WebcastLinkMicArmies 2024-04-19 13:41:07 -04:00
kohlerpop1
fb9fc04ee5 Revert "More updated to TikTokLinkMicBattleEvent, updated Gift since its no longer enum we do not need to use Unsafe, and added default mappings for WebcastLinkMicBattle and WebcastLinkMicArmies"
This reverts commit 43a8ba4225.
2024-04-19 13:33:49 -04:00
kohlerpop1
43a8ba4225 More updated to TikTokLinkMicBattleEvent, updated Gift since its no longer enum we do not need to use Unsafe, and added default mappings for WebcastLinkMicBattle and WebcastLinkMicArmies 2024-04-19 13:28:10 -04:00
David Kohler
dffccf1f0b Update README.md 2024-04-10 12:08:46 -04:00
GitHub Action
6dcccccb78 Update version in pom.xml 2024-04-10 16:07:17 +00:00
David Kohler
0d467d79c3 Update TikTokGiftEventHandlerTest.java
Fixed minor issue with Client compilation
2024-04-10 12:05:20 -04:00
David Kohler
33c98508c0 MINOR
Merge pull request #70 from jwdeveloper/develop-1.6.0
2024-04-10 12:01:00 -04:00
kohlerpop1
67948b14cc Changed isNotClosing to isOpen because if isOpen is false inside of any of the using methods, it throws an exception. 2024-04-10 11:54:35 -04:00
kohlerpop1
22e11a7822 Removed TikTokRoomInfo.getHostUser() in favor of TikTokRoomInfo.getHost().
Major rework of TikTokLinkMicBattleEvent and proto to support it.
Addition changes to other files to support!
2024-04-09 21:38:04 -04:00
GitHub Action
4545503441 Update version in pom.xml 2024-04-02 02:28:56 +00:00
David Kohler
498d34a90b Merge pull request #69 from jwdeveloper/develop-1.5.4
Changed isNotClosing to isOpen
2024-04-01 22:27:09 -04:00
kohlerpop1
103ed7e3ed Changed isNotClosing to isOpen because if isOpen is false inside of any of the using methods, it throws an exception. 2024-03-31 20:19:24 -04:00
GitHub Action
67e70c34bc Update version in pom.xml 2024-03-03 21:42:11 +00:00
JW
786c24d267 Merge remote-tracking branch 'origin/master' 2024-03-03 22:40:11 +01:00
JW
966d2f65d8 - improve recorder 2024-03-03 22:39:44 +01:00
GitHub Action
7ba7143f5a Update version in pom.xml 2024-03-02 09:57:33 +00:00
JW
92fde03f2b - improve collector 2024-03-02 10:55:44 +01:00
GitHub Action
e058290118 Update version in pom.xml 2024-03-01 23:17:33 +00:00
David Kohler
d25741b229 Merge pull request #67 from jwdeveloper/develop-1.5.1
Fix for mapping of HttpResponse & HttpRequest and more!
2024-03-01 18:15:41 -05:00
GitHub Action
6178bc25cf Update version in pom.xml 2024-03-01 01:54:49 +00:00
Jacek W
48d1138754 MINOR 2024-03-01 02:53:04 +01:00
Jacek W
a5320db820 Merge pull request #63 from jwdeveloper/develop-1.5.0
Develop 1.5.0
2024-03-01 02:51:35 +01:00
173 changed files with 3613 additions and 3035 deletions

View File

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

View File

@@ -0,0 +1,18 @@
package io.github.jwdeveloper.tiktok.annotations;
/**
* HIGHEST 1
* HIGH 2
* NORMAL 3
* LOW 4
* LOWEST 5
*/
public enum Priority {
LOWEST(2), LOW(1), NORMAL(0), HIGH(-1), HIGHEST(-2);
public final int value;
Priority(int value) {
this.value = value;
}
}

View File

@@ -28,5 +28,14 @@ import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface TikTokEventObserver
{
/**
* When more than one method listen for certain Event, you can specify the method priority
* @see Priority
*/
Priority priority() default Priority.NORMAL;
/**
* When true, action is invoked on a thread, from the threads pool
*/
boolean async() default false;
}

View File

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

View File

@@ -38,8 +38,7 @@ public class TikTokBarrageEvent extends TikTokHeaderEvent {
private final Picture rightIcon;
private final String eventName;
private final int duration;
private BarrageParam barrageParam;
private final BarrageParam barrageParam;
public TikTokBarrageEvent(WebcastBarrageMessage msg) {
super(msg.getCommon());
@@ -49,6 +48,5 @@ 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

@@ -32,15 +32,13 @@ import lombok.Getter;
import java.util.List;
/**
* Triggered every time a new chat comment arrives.
*/
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokCommentEvent extends TikTokHeaderEvent {
private final User user;
private final String text;
private final String getUserLanguage;
private final String userLanguage;
private final User mentionedUser;
private final List<Picture> pictures;
private final boolean visibleToSender;
@@ -50,7 +48,7 @@ public class TikTokCommentEvent extends TikTokHeaderEvent {
user = User.map(msg.getUser(), msg.getUserIdentity());
text = msg.getContent();
visibleToSender = msg.getVisibleToSender();
getUserLanguage = msg.getContentLanguage();
userLanguage = msg.getContentLanguage();
mentionedUser = User.map(msg.getAtUser());
pictures = msg.getEmotesListList().stream().map(e -> Picture.map(e.getEmote().getImage())).toList();
}
@@ -66,4 +64,4 @@ public class TikTokCommentEvent extends TikTokHeaderEvent {
builder.setContent(message);
return new TikTokCommentEvent(builder.build());
}
}
}

View File

@@ -25,9 +25,6 @@ import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
/**
* Triggered when the connection is successfully established.
*/
@EventMeta(eventType = EventType.Control)
public class TikTokConnectedEvent extends TikTokLiveClientEvent
{

View File

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

View File

@@ -26,13 +26,12 @@ import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
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 {
@Getter private final String reason;
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

@@ -28,9 +28,6 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* General error event. You should handle this.
*/
@Getter
@AllArgsConstructor
@EventMeta(eventType = EventType.Control)

View File

@@ -34,9 +34,10 @@ import java.util.List;
@EventMeta(eventType = EventType.Message)
public class TikTokIMDeleteEvent extends TikTokHeaderEvent {
List<Long> userIds;
private final List<Long> msgIds, 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

@@ -33,11 +33,7 @@ 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,8 +40,10 @@ import java.util.List;
@EventMeta(eventType = EventType.Message)
public class TikTokLinkMicArmiesEvent extends TikTokHeaderEvent {
private final Long battleId;
private final Integer battleStatus;
/**
true if battle is finished otherwise false
*/
private final boolean finished;
private final Picture picture;
@@ -52,6 +54,6 @@ public class TikTokLinkMicArmiesEvent extends TikTokHeaderEvent {
battleId = msg.getId();
armies = msg.getBattleItemsList().stream().map(LinkMicArmy::new).toList();
picture = Picture.map(msg.getImage());
battleStatus = msg.getBattleStatus();
finished = msg.getBattleStatus() == LinkMicBattleStatus.ARMY_FINISHED;
}
}
}

View File

@@ -22,29 +22,62 @@
*/
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.annotations.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.LinkMicBattleTeam;
import io.github.jwdeveloper.tiktok.data.models.battles.*;
import io.github.jwdeveloper.tiktok.messages.enums.LinkMicBattleStatus;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter;
import lombok.*;
import java.util.List;
import java.util.*;
/**
* Triggered every time a battle starts.
* Triggered every time a battle starts & ends
*/
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent {
private final Long battleId;
private final List<LinkMicBattleTeam> team1;
private final List<LinkMicBattleTeam> team2;
public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent
{
private final Long battleId;
/**
true if battle is finished otherwise false
*/
private final boolean finished;
private final List<Team> teams;
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();
}
}
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));
} 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));
}
}
// 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 teams.get(0) instanceof Team1v1;
}
public boolean is2v2() {
return teams.get(0) instanceof Team2v2;
}
public boolean isTie() {
return isFinished() && teams.get(0).getTotalPoints() == teams.get(1).getTotalPoints();
}
}

View File

@@ -32,10 +32,8 @@ 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

@@ -26,9 +26,7 @@ import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
/**
* Triggered when the live stream gets terminated by the host. Will also trigger the TikTokDisconnectedEvent event.
*/
@EventMeta(eventType = EventType.Message)
public class TikTokLiveEndedEvent extends TikTokEvent {
}

View File

@@ -29,9 +29,7 @@ import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastQuestionNewMessage;
import lombok.Getter;
/*
Triggered every time someone asks a new question via the question feature.
*/
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokQuestionEvent extends TikTokHeaderEvent {

View File

@@ -32,15 +32,14 @@ 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,13 +33,11 @@ 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,25 +32,24 @@ 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

@@ -31,9 +31,7 @@ import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSubNotifyMessage;
import lombok.Getter;
/**
* Triggers when a user creates a subscription.
*/
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokSubscribeEvent extends TikTokHeaderEvent {

View File

@@ -26,9 +26,6 @@ package io.github.jwdeveloper.tiktok.data.events.common;
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import lombok.Getter;
/**
* Base class for all events
*/
@Getter
public abstract class TikTokEvent {

View File

@@ -27,15 +27,14 @@ 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
{
@Getter private final LiveUserData.Response userData;
@Getter private final LiveData.Response roomData;
@Getter @Setter boolean cancelConnection = false;
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;

View File

@@ -29,20 +29,6 @@ import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import lombok.Getter;
/**
* Triggered every time gift is sent
*
* @see GiftComboStateType it has 3 states
*
* <p>Example when user sends gift with combo</p>
* <p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
* <p>Combo: 4 -> comboState = GiftSendType.Active</p>
* <p>Combo: 8 -> comboState = GiftSendType.Active</p>
* <p>Combo: 12 -> comboState = GiftSendType.Finsihed</p>
* <p>
* Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
*/
@EventMeta(eventType = EventType.Message)
@Getter
public class TikTokGiftComboEvent extends TikTokGiftEvent {
@@ -55,12 +41,9 @@ public class TikTokGiftComboEvent extends TikTokGiftEvent {
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);
gift,
new User(0L, "Test", new Picture("")),
WebcastGiftMessage.newBuilder().setComboCount(combo).build(),
comboState);
}
}

View File

@@ -22,7 +22,6 @@
*/
package io.github.jwdeveloper.tiktok.data.events.gift;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.Picture;
@@ -31,12 +30,6 @@ import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import lombok.Getter;
/**
* Triggered when user sends gifts that has
* no combo (most of expensive gifts)
* or if combo has finished
*/
@EventMeta(eventType = EventType.Message)
@Getter
public class TikTokGiftEvent extends TikTokHeaderEvent {

View File

@@ -0,0 +1,45 @@
/*
* 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

@@ -20,18 +20,17 @@
* 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;
package io.github.jwdeveloper.tiktok.data.events.link;
import lombok.Value;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Value
public class EnumValue
{
public int value;
public String name;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkApplyEvent extends TikTokLinkEvent {
public static EnumValue Map(Enum<?> _enum)
{
return new EnumValue(_enum.ordinal() ,_enum.name());
public TikTokLinkApplyEvent(WebcastLinkMessage msg) {
super(msg);
}
}
}

View File

@@ -20,36 +20,27 @@
* 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;
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 {
import java.io.IOException;
import java.util.Base64;
private final long fromUserId, toUserId, cancelType, actionId;
public class TikTokBaseTest
{
public byte[] getFileBytes(String path)
{
try {
var stream = getClass().getClassLoader().getResourceAsStream(path);
var bytes= stream.readAllBytes();
stream.close();
return bytes;
} catch (IOException e) {
throw new RuntimeException(e);
}
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();
}
public byte[] getFileBytesUtf(String path)
{
try {
var stream = getClass().getClassLoader().getResourceAsStream(path);
var bytes= stream.readAllBytes();
stream.close();
return Base64.getDecoder().decode(bytes);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -20,24 +20,20 @@
* 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.GiftOld;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class TikTokGiftManagerTest {
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

@@ -0,0 +1,39 @@
/*
* 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

@@ -0,0 +1,44 @@
/*
* 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

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

@@ -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;
package io.github.jwdeveloper.tiktok.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.annotations.*;
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

@@ -0,0 +1,46 @@
/*
* 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

@@ -0,0 +1,55 @@
/*
* 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

@@ -0,0 +1,47 @@
/*
* 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

@@ -0,0 +1,39 @@
/*
* 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

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

@@ -0,0 +1,47 @@
/*
* 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

@@ -20,24 +20,20 @@
* 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;
package io.github.jwdeveloper.tiktok.data.events.link;
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.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import lombok.Data;
@Data
@Getter
@EventMeta(eventType = EventType.Message)
public class CustomEvent extends TikTokHeaderEvent {
private final User user;
private final String title;
public class TikTokLinkMicIdxUpdateEvent extends TikTokLinkEvent {
public CustomEvent(User user, String title) {
this.user = user;
this.title = title;
public TikTokLinkMicIdxUpdateEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasMicIdxUpdateContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Mic Idx Update Content!");
// Proto Empty
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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

@@ -0,0 +1,50 @@
/*
* 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

@@ -0,0 +1,47 @@
/*
* 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

@@ -0,0 +1,45 @@
/*
* 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

@@ -0,0 +1,44 @@
/*
* 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

@@ -0,0 +1,39 @@
/*
* 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

@@ -0,0 +1,47 @@
/*
* 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

@@ -0,0 +1,39 @@
/*
* 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,13 +30,11 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/*
Triggered when LiveRoomInfo got updated such as likes, viewers, ranking ....
*/
@Getter
@AllArgsConstructor
@EventMeta(eventType = EventType.Message)
public class TikTokRoomInfoEvent extends TikTokEvent
{
LiveRoomInfo roomInfo;
}
}

View File

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

View File

@@ -24,35 +24,31 @@ package io.github.jwdeveloper.tiktok.data.events.social;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
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.WebcastMemberMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Value;
/**
* Triggers when a user follows the streamer. Based on social event.
*/
@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());
.setUser(io.github.jwdeveloper.tiktok.messages.data.User.newBuilder()
.setNickname(userName)
.build())
.build());
}
}
}

View File

@@ -31,9 +31,7 @@ import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Getter;
/**
* Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
*/
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLikeEvent extends TikTokHeaderEvent

View File

@@ -29,25 +29,22 @@ import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Getter;
/**
* Triggers when a user shares the stream. Based on social event.
*/
@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

@@ -35,10 +35,7 @@ import lombok.Value;
import java.time.Duration;
/**
* Triggered every time TikTok sends data. Data incoming as protobuf message.
* You can deserialize the binary object depending on the use case.
*/
@Getter
@AllArgsConstructor
@EventMeta(eventType = EventType.Debug)

View File

@@ -29,9 +29,7 @@ import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import lombok.Getter;
/**
* Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
*/
@Getter
@EventMeta(eventType = EventType.Debug)
public class TikTokWebsocketUnhandledMessageEvent extends TikTokUnhandledEvent<WebcastResponse.Message>

View File

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

View File

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

@@ -0,0 +1,74 @@
/*
* 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 lombok.Getter;
public abstract class Team {
/** Value >= 0 when finished otherwise -1 */
@Getter protected int totalPoints;
/**
* 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

@@ -0,0 +1,45 @@
/*
* 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 {
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

@@ -0,0 +1,50 @@
/*
* 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 {
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

@@ -20,22 +20,20 @@
* 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;
package io.github.jwdeveloper.tiktok.data.models.battles;
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.Value;
import lombok.Getter;
import java.util.List;
@Getter
public class Viewer {
private final User user;
private final int points;
@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();
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();
}
}
}

View File

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

View File

@@ -22,11 +22,10 @@
*/
package io.github.jwdeveloper.tiktok.data.models.gifts;
//TODO it should be called GiftComboStateType
public enum GiftComboStateType {
Finished,
Begin,
Active;
Active,
Finished;
public static GiftComboStateType fromNumber(long number) {
return switch ((int) number) {

View File

@@ -0,0 +1,56 @@
/*
* 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

@@ -22,16 +22,12 @@
*/
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.WebcastEnvelopeMessage;
import lombok.AccessLevel;
import lombok.Getter;
import io.github.jwdeveloper.tiktok.data.models.badges.Badge;
import io.github.jwdeveloper.tiktok.messages.webcast.*;
import lombok.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
@Getter
public class User {
@@ -49,12 +45,12 @@ public class User {
return attributes.stream().toList();
}
public boolean hasAttribute(UserAttribute userFlag) {
return attributes.contains(userFlag);
public boolean hasAttribute(UserAttribute attribute) {
return attributes.contains(attribute);
}
public void addAttribute(UserAttribute... flags) {
this.attributes.addAll(Arrays.stream(flags).toList());
public void addAttribute(UserAttribute... attributes) {
this.attributes.addAll(List.of(attributes));
}
public boolean isGiftGiver() {
@@ -136,6 +132,14 @@ 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();
@@ -159,13 +163,12 @@ public class User {
}
}
public static User EMPTY = new User(0L,
"",
Picture.Empty(),
0,
0,
List.of(Badge.empty()));
"",
Picture.empty(),
0,
0,
List.of(Badge.empty()));
public static User map(io.github.jwdeveloper.tiktok.messages.data.User user) {
return new User(user);
@@ -202,11 +205,25 @@ public class User {
public static User map(WebcastEnvelopeMessage.EnvelopeInfo envelopeInfo) {
return new User(0L,
//envelopeInfo.getSendUserId(),
envelopeInfo.getSendUserName(),
Picture.map(envelopeInfo.getSendUserAvatar()),
0,
0,
List.of(Badge.empty()));
//envelopeInfo.getSendUserId(),
envelopeInfo.getSendUserName(),
Picture.map(envelopeInfo.getSendUserAvatar()),
0,
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,20 +23,12 @@
package io.github.jwdeveloper.tiktok.data.requests;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.*;
import java.util.List;
public class GiftsData
{
@Getter
public final class Request
{
}
@Getter
@AllArgsConstructor
public static final class Response
@@ -44,5 +36,4 @@ public class GiftsData
private String json;
private List<Gift> gifts;
}
}
}

View File

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

View File

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

View File

@@ -33,20 +33,15 @@ import java.util.logging.Level;
@Data
public class LiveClientSettings {
/**
* TODO: give better description
* <p>
* sets client in the offline mode, so it do not connects to TikTok servers
* it makes sense to use it when you are testing client with your custom events
* Sets client to offline mode, prohibits connection to TikTok servers
* @apiNote Useful when testing client with custom events
*/
private boolean offline;
/**
* TODO: give better description
* <p>
* Determines if gifts data is downloaded before TikTokLive starts,
* when `false` then client.giftManager() does not contain initial gifts
* Fetch and download gifts data before TikTokLive starts
* @apiNote If `false`, client.giftManager() does not contain initial gifts
*/
private boolean fetchGifts = true;
@@ -91,6 +86,9 @@ public class LiveClientSettings {
*/
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>
@@ -180,6 +178,4 @@ public class LiveClientSettings {
headers.put("Accept-Language", "en-US,en; q=0.9");
return headers;
}
}

View File

@@ -31,17 +31,17 @@ import java.util.function.Consumer;
@Getter
@Setter
public class ProxyClientSettings implements Iterator<ProxyData>
public class ProxyClientSettings implements Iterator<ProxyData>, Iterable<ProxyData>
{
private boolean enabled, autoDiscard = true, fallback = true;
private Rotation rotation = Rotation.CONSECUTIVE;
private final List<ProxyData> proxyList = new ArrayList<>();
private int index = -1;
private int index;
private Proxy.Type type = Proxy.Type.DIRECT;
private Consumer<ProxyData> onProxyUpdated = x -> {};
public boolean addProxy(String addressPort) {
return proxyList.add(ProxyData.map(addressPort));
return addProxy(ProxyData.map(addressPort).toSocketAddress());
}
public boolean addProxy(String address, int port) {
@@ -57,33 +57,27 @@ public class ProxyClientSettings implements Iterator<ProxyData>
}
@Override
public boolean hasNext() {
public synchronized boolean hasNext() {
return !proxyList.isEmpty();
}
@Override
public ProxyData next() {
var nextProxy = switch (rotation)
{
case CONSECUTIVE -> {
index = (index+1) % proxyList.size();
yield proxyList.get(index).clone();
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);
}
case RANDOM -> {
index = new Random().nextInt(proxyList.size());
yield proxyList.get(index).clone();
}
case NONE -> {
index = Math.max(index, 0);
yield proxyList.get(index).clone();
}
};
onProxyUpdated.accept(nextProxy);
return nextProxy;
}
}
}
@Override
public void remove() {
public synchronized void remove() {
proxyList.remove(index);
}
@@ -97,8 +91,8 @@ public class ProxyClientSettings implements Iterator<ProxyData>
}
}
public ProxyClientSettings clone()
{
@Override
public ProxyClientSettings clone() {
ProxyClientSettings settings = new ProxyClientSettings();
settings.setEnabled(enabled);
settings.setRotation(rotation);
@@ -109,6 +103,27 @@ public class ProxyClientSettings implements Iterator<ProxyData>
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

@@ -20,7 +20,11 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.mappers.handlers;
package io.github.jwdeveloper.tiktok.exceptions;
public class TikTokChestEventHandler {
}
public class TikTokLiveUnknownHostException extends TikTokLiveException
{
public TikTokLiveUnknownHostException(String message) {
super(message);
}
}

View File

@@ -30,10 +30,14 @@ import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
public interface LiveHttpClient
{
/**
* @return list of gifts that are available in your country
* @return {@link GiftsData.Response} list of gifts that are compiled and available on github
*/
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

View File

@@ -25,15 +25,13 @@ package io.github.jwdeveloper.tiktok.listener;
import java.util.List;
/**
* You can dynamically add or removing TikTokEventListener
*
* @see TikTokEventListener
*
* Manage events listeners objects
*/
public interface ListenersManager
{
List<TikTokEventListener> getListeners();
void addListener(TikTokEventListener listener);
List<Object> getListeners();
void removeListener(TikTokEventListener listener);
void addListener(Object listener);
void removeListener(Object listener);
}

View File

@@ -22,53 +22,54 @@
*/
package io.github.jwdeveloper.tiktok.listener;
import io.github.jwdeveloper.tiktok.live.LiveClient;
/**
*
* @see ListenersManager
*
* ListenersManager
* <p>
* 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());
* }
*
* TikTokLive.newClient("someuser").addListener(listener)
* @TikTokEventObserver
* public void onCommentMessage(LiveClient liveClient, TikTokCommentEvent event)
* {
* System.out.println(event.getText());
* }
*
* 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 onGiftMessage(LiveClient liveClient, TikTokGiftMessageEvent event)
* {
* System.out.println(event.getGift().getDescription());
* }
*
* @TikTokEventObserver
* public void onAnyEvent(LiveClient liveClient, TikTokEvent event)
* {
* System.out.println(event.getClass().getSimpleName());
* }
* }
* }
* </pre>
*/
public interface TikTokEventListener
{
//TODO I think this interface can be removed, since we are using,
//annotation @TikTokEventHandler to check methods that are events
@Deprecated(forRemoval = true, since = "1.8.1 (This interface is not longer needed, please remove it from your class)")
public interface TikTokEventListener {
}
}

View File

@@ -0,0 +1,156 @@
/*
* 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

@@ -0,0 +1,19 @@
package io.github.jwdeveloper.tiktok.live;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import java.util.HashSet;
import java.util.Optional;
public interface LiveEventsHandler {
void publish(LiveClient tikTokLiveClient, TikTokEvent tikTokEvent);
<T extends TikTokEvent> void subscribe(Class<?> clazz, EventConsumer<T> event);
<T extends TikTokEvent> void unsubscribeAll(Class<?> clazz);
<T extends TikTokEvent> void unsubscribe(EventConsumer<T> consumer);
<T extends TikTokEvent> void unsubscribe(Class<?> clazz, EventConsumer<T> consumer);
}

View File

@@ -0,0 +1,18 @@
package io.github.jwdeveloper.tiktok.live;
import io.github.jwdeveloper.tiktok.data.dto.MessageMetaData;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
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.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.Stopwatch;
import java.time.Duration;
public interface LiveMessagesHandler {
void handle(LiveClient client, WebcastResponse webcastResponse);
void handleSingleMessage(LiveClient client, WebcastResponse.Message message);
}

View File

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

View File

@@ -25,7 +25,13 @@ 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

@@ -22,8 +22,8 @@
*/
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.common.TikTokEvent;
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;
@@ -36,6 +36,7 @@ import io.github.jwdeveloper.tiktok.data.events.social.TikTokShareEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent;
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftComboStateType;
public interface EventsBuilder<T> {
@@ -52,131 +53,257 @@ public interface EventsBuilder<T> {
/**
* Invoked whenever any event is triggered
*
* @param action
* @return
* @param action consumable action
* @return self instance
*/
T onEvent(EventConsumer<TikTokEvent> action);
default T onEvent(EventConsumer<TikTokEvent> action) {
return onEvent(TikTokEvent.class, action);
}
/**
* Invoked when information about room (live) got updated such as viewer count, etc..
*
* @param action
* @return
* @param action consumable action
* @return self instance
*/
T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> action);
default T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> action) {
return onEvent(TikTokRoomInfoEvent.class, action);
}
/**
* Invoked when someone send message to chat
*
* @param action
* @return
* @param action consumable action
* @return self instance
*/
T onComment(EventConsumer<TikTokCommentEvent> action);
default T onComment(EventConsumer<TikTokCommentEvent> action) {
return onEvent(TikTokCommentEvent.class, action);
}
/**
* Invoked when TikTokLiveJava makes http request and getting response
*
* @param action
* @return
* @param action consumable action
* @return self instance
*/
T onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action);
default T onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action) {
return onEvent(TikTokHttpResponseEvent.class, action);
}
/**
* Invoked when TikTok protocolBuffer data "message" was successfully mapped to event
* events contains protocol-buffer "Message" and TikTokLiveJava "Event"
*
* @param action
* @return
* @param action consumable action
* @return self instance
*/
T onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> action);
default T onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> action) {
return onEvent(TikTokWebsocketMessageEvent.class, action);
}
/**
* Invoked when there was not found event mapper for TikTok protocolBuffer data "message"
* Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
*
* @param action
* @return
* @param action consumable action
* @return self instance
*/
T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> action);
default T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> action) {
return onEvent(TikTokWebsocketUnhandledMessageEvent.class, action);
}
/**
* Invoked every time TikTok sends protocolBuffer data to websocket
* Response contains list of messages that are later mapped to events
* @param action
* @return
*
* @param action consumable action
* @return self instance
*/
T onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> action);
default T onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> action) {
return onEvent(TikTokWebsocketResponseEvent.class, action);
}
/**
* Invoked for gifts that has no combo, or when combo finishes
* @param action
* @return
* Triggers for these different reasons:
* <ol>
* <li>User sends gifts that have no combo (most of expensive gifts)</li>
* <li>{@link TikTokGiftComboEvent} has combaState = {@link GiftComboStateType#Finished}</li>
* </ol>
* @param action consumable action
* @return self instance
*/
T onGift(EventConsumer<TikTokGiftEvent> action);
default T onGift(EventConsumer<TikTokGiftEvent> action) {
return onEvent(TikTokGiftEvent.class, action);
}
/**
* Invoked for gifts that has combo options such as roses
* @param action
* @return
* Triggered every time a gift is sent
* <p>Example when user sends gift with combo</p>
* <ul>
* <li>Combo: 1 -> comboState = {@link GiftComboStateType#Begin}</li>
* <li>Combo: 4 -> comboState = {@link GiftComboStateType#Active}</li>
* <li>Combo: 8 -> comboState = {@link GiftComboStateType#Active}</li>
* <li>Combo: 12 -> comboState = {@link GiftComboStateType#Finished}</li>
* </ul>
* Both {@link TikTokGiftComboEvent} and {@link TikTokGiftEvent} events are triggered when comboState is Finished
*
* @apiNote {@link GiftComboStateType} has 3 states: {@link GiftComboStateType#Begin Begin}, {@link GiftComboStateType#Active Active}, & {@link GiftComboStateType#Finished Finished}
* @param action consumable action
* @return self instance
*/
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> action);
default T onGiftCombo(EventConsumer<TikTokGiftComboEvent> action) {
return onEvent(TikTokGiftComboEvent.class, action);
}
/**
* Triggered every time someone asks a new question via the question feature.
*
* @param action consumable action
* @return self instance
*/
default T onQuestion(EventConsumer<TikTokQuestionEvent> action) {
return onEvent(TikTokQuestionEvent.class, action);
}
T onQuestion(EventConsumer<TikTokQuestionEvent> action);
/**
* Triggers when a user subscribe the streamer.
*
* @param action consumable action
* @return self instance
*/
default T onSubscribe(EventConsumer<TikTokSubscribeEvent> action) {
return onEvent(TikTokSubscribeEvent.class, action);
}
T onSubscribe(EventConsumer<TikTokSubscribeEvent> action);
/**
* Triggers when a user follows the streamer. Based on social event.
*
* @param action consumable action
* @return self instance
*/
default T onFollow(EventConsumer<TikTokFollowEvent> action) {
return onEvent(TikTokFollowEvent.class, action);
}
T onFollow(EventConsumer<TikTokFollowEvent> action);
/**
* Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
*
* @param action consumable action
* @return self instance
*/
default T onLike(EventConsumer<TikTokLikeEvent> action) {
return onEvent(TikTokLikeEvent.class, action);
}
T onLike(EventConsumer<TikTokLikeEvent> action);
/**
* Triggers when a user sends emote
*
* @param action consumable action
* @return self instance
*/
default T onEmote(EventConsumer<TikTokEmoteEvent> action) {
return onEvent(TikTokEmoteEvent.class, action);
}
T onEmote(EventConsumer<TikTokEmoteEvent> action);
/**
* Triggers when a user joins to the live
*
* @param action consumable action
* @return self instance
*/
default T onJoin(EventConsumer<TikTokJoinEvent> action) {
return onEvent(TikTokJoinEvent.class, action);
}
T onJoin(EventConsumer<TikTokJoinEvent> action);
/**
* Triggers when a user shares the stream.
*
* @param action consumable action
* @return self instance
*/
default T onShare(EventConsumer<TikTokShareEvent> action) {
return onEvent(TikTokShareEvent.class, action);
}
T onShare(EventConsumer<TikTokShareEvent> action);
/**
* Triggered when the live stream gets paused
*
* @param action consumable action
* @return self instance
*/
default T onLivePaused(EventConsumer<TikTokLivePausedEvent> action) {
return onEvent(TikTokLivePausedEvent.class, action);
}
T onLivePaused(EventConsumer<TikTokLivePausedEvent> action);
/**
* Triggered when the live stream gets unpaused
*
* @param action consumable action
* @return self instance
*/
default T onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> action) {
return onEvent(TikTokLiveUnpausedEvent.class, action);
}
T onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> action);
T onLiveEnded(EventConsumer<TikTokLiveEndedEvent> action);
/**
* Triggered when the live stream gets terminated by the host. Will also trigger the TikTokDisconnectedEvent event.
*
* @param action consumable action
* @return self instance
*/
default T onLiveEnded(EventConsumer<TikTokLiveEndedEvent> action) {
return onEvent(TikTokLiveEndedEvent.class, action);
}
/**
* Invoked when client has been successfully connected to live
* @param action
* @return
*
* @param action consumable action
* @return self instance
*/
T onConnected(EventConsumer<TikTokConnectedEvent> action);
default T onConnected(EventConsumer<TikTokConnectedEvent> action) {
return onEvent(TikTokConnectedEvent.class, action);
}
/**
* Invoked before client has been successfully connected to live
* @param action
* @return
*
* @param action consumable action
* @return self instance
*/
T onPreConnection(EventConsumer<TikTokPreConnectionEvent> action);
default T onPreConnection(EventConsumer<TikTokPreConnectionEvent> action) {
return onEvent(TikTokPreConnectionEvent.class, action);
}
/**
* Invoked when client tries to reconnect
* @param action
* @return
*
* @param action consumable action
* @return self instance
*/
T onReconnecting(EventConsumer<TikTokReconnectingEvent> action);
default T onReconnecting(EventConsumer<TikTokReconnectingEvent> action) {
return onEvent(TikTokReconnectingEvent.class, action);
}
/**
* Invoked when client disconnected
* @param action
* @return
* 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 avoid being rate-limited.
*
* @param action consumable action
* @return self instance
*/
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> action);
default T onDisconnected(EventConsumer<TikTokDisconnectedEvent> action) {
return onEvent(TikTokDisconnectedEvent.class, action);
}
/**
* Invoked when exception was throed inside client or event handler
* @param action
* @return
*
* @param action consumable action
* @return self instance
*/
T onError(EventConsumer<TikTokErrorEvent> action);
default T onError(EventConsumer<TikTokErrorEvent> action) {
return onEvent(TikTokErrorEvent.class, action);
}
// TODO Figure out how those events works
@@ -223,4 +350,10 @@ public interface EventsBuilder<T> {
//T onLinkMicBattle(TikTokEventConsumer<TikTokLinkMicBattleEvent> event);
//T onUnhandledControl(TikTokEventConsumer<TikTokUnhandledControlEvent> event);
/**
* To do figure out how to use Annotation processor.
* Goal is to generates methods for all possible events, everytime library is compiled
*/
}

View File

@@ -22,58 +22,73 @@
*/
package io.github.jwdeveloper.tiktok.live.builder;
import io.github.jwdeveloper.dependance.implementation.DependanceContainerBuilder;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
import io.github.jwdeveloper.tiktok.mappers.LiveMapper;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
/**
* This method is triggered after default mappings are registered
* It could be used to OVERRIDE behaviour of mappings and implement custom behaviour
*
* <p>
* Be aware if for example you override WebcastGiftEvent, onGiftEvent() will not be working
*
* @param onCustomMappings lambda method
* @return
*/
LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings);
LiveClientBuilder mappings(Consumer<LiveMapper> onCustomMappings);
@Deprecated(forRemoval = true, since = "1.8.2 use `mappings` method instead")
LiveClientBuilder onMappings(Consumer<LiveMapper> onCustomMappings);
/**
* Configuration of client settings
* @see LiveClientSettings
*
* @param onConfigure
* @return
* @see LiveClientSettings
*/
LiveClientBuilder configure(Consumer<LiveClientSettings> onConfigure);
/**
* @see TikTokEventListener
* Adding events listener class, its fancy way to register events without using lamda method
* but actual method in class that implements TikTokEventListener
*
* @return
*/
LiveClientBuilder addListener(TikTokEventListener listener);
LiveClientBuilder addListener(Object listener);
/**
* Allows you to use own implementation of internal TikTokLive dependencies,
* when the default implementation does not meet your needs
*
* @param onCustomizeDependencies access to dependency container
* @return
*/
LiveClientBuilder customize(Consumer<DependanceContainerBuilder> onCustomizeDependencies);
/**
* Builds new instance of the LiveClient
*
* @return LiveClient object
*/
LiveClient build();
/**
* Builds new instance of the LiveClient and connects to live
*
* @return LiveClient object and connects to TikTok live
* @return LiveClient object
*/
LiveClient buildAndConnect();
/**
*
* @return LiveClient object and connects to TikTok live asynchronously
*/
CompletableFuture<LiveClient> buildAndConnectAsync();

View File

@@ -27,18 +27,23 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.mappers.data.MappingAction;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
import java.util.List;
import java.util.function.Function;
public interface TikTokMapper {
public interface LiveMapper {
/**
* * if mapper is not found for messageName, TikTokLiveException is thrown
* when 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);
@@ -49,10 +54,9 @@ public interface TikTokMapper {
TikTokMapperModel forAnyMessage();
List<TikTokEvent> handleMapping(String messageName, byte[] bytes);
boolean isRegistered(String mapperName);
<T extends GeneratedMessageV3> boolean isRegistered(Class<T> mapperName);
}

View File

@@ -26,7 +26,7 @@ import com.google.protobuf.GeneratedMessageV3;
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
import io.github.jwdeveloper.tiktok.utils.ProtoBufferObject;
public interface TikTokMapperHelper {
public interface LiveMapperHelper {
/**
* @param bytes protocol buffer data bytes

View File

@@ -22,7 +22,7 @@
*/
package io.github.jwdeveloper.tiktok.mappers.data;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapperHelper;
import io.github.jwdeveloper.tiktok.mappers.LiveMapperHelper;
@FunctionalInterface
public interface MappingAction<T> {
@@ -33,6 +33,6 @@ public interface MappingAction<T> {
* @param mapperHelper utils and helper methods that can be use to debbug/display/deserialize protocol buffer data
* @return
*/
T onMapping(byte[] inputBytes, String messageName, TikTokMapperHelper mapperHelper);
T onMapping(byte[] inputBytes, String messageName, LiveMapperHelper mapperHelper);
}

View File

@@ -24,9 +24,8 @@ package io.github.jwdeveloper.tiktok.websocket;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
public interface SocketClient {
public interface LiveSocketClient {
void start(LiveConnectionData.Response webcastResponse, LiveClient tikTokLiveClient);
void stop();
}

View File

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

View File

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

View File

@@ -521,7 +521,7 @@ message WebcastLinkMicArmies {
uint64 id2 = 4;
uint64 timeStamp1 = 5;
uint64 timeStamp2 = 6;
int32 battleStatus = 7; // SHOULD BE AN ENUM
LinkMicBattleStatus battleStatus = 7;
uint64 data1 = 8;
uint64 data2 = 9;
uint32 data3 = 10;
@@ -574,11 +574,26 @@ message WebcastLinkMicBattle {
Common common = 1;
uint64 id = 2;
LinkMicBattleConfig battleConfig = 3;
uint32 data2 = 4;
LinkMicBattleStatus battleStatus = 4;
repeated LinkMicBattleDetails details = 5;
repeated LinkMicBattleTeam teams1 = 9;
repeated LinkMicBattleTeam teams2 = 10;
repeated LinkMicBattleTopViewers viewerTeam = 9;
repeated LinkMicBattleHost hostTeam = 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;
@@ -586,29 +601,69 @@ 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 data2 = 3;
uint32 winStreak = 3;
uint32 data3 = 5;
string url = 6;
}
message LinkMicBattleDetails {
uint64 id = 1;
LinkMicBattleData details = 2;
LinkMicBattleDetailsSummary summary = 2;
message LinkMicBattleDetailsSummary {
uint64 id = 1;
uint32 unknownData2 = 2;
uint32 points = 3;
}
}
message LinkMicBattleTeam {
message LinkMicBattleTopViewers {
uint64 id = 1;
repeated User users = 2;
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;
}
}
}
message LinkMicBattleTeamData {
uint64 teamId = 1;
LinkMicBattleData data = 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;
}
}
}
}
@@ -750,7 +805,7 @@ message WebcastLinkMessage {
LinkerListChangeContent ListChangeContent = 20;
CohostListChangeContent CohostListChangeContent = 21;
LinkerMediaChangeContent MediaChangeContent = 22;
LinkerAcceptNoticeContent ReplyAcceptNoticeContent = 23;
LinkerAcceptNoticeContent AcceptNoticeContent = 23;
LinkerSysKickOutContent SysKickOutContent = 101;
LinkmicUserToastContent UserToastContent = 102;
string extra = 200;
@@ -792,6 +847,4 @@ message RoomVerifyMessage {
string content = 3;
int64 noticeType = 4;
bool closeRoom = 5;
}
}

View File

@@ -5,13 +5,14 @@
<parent>
<artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.4.0-Release</version>
<version>1.8.0-Release</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Client</artifactId>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>

View File

@@ -23,19 +23,21 @@
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
* @return LiveClientBuilder
*/
public static LiveClientBuilder newClient(String hostName) {
@@ -45,7 +47,7 @@ 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
* @return true if live is Online, false if is offline
*/
public static boolean isLiveOnline(String hostName) {
@@ -55,7 +57,7 @@ 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
* @return true if live is Online, false if is offline
*/
public static CompletableFuture<Boolean> isLiveOnlineAsync(String hostName) {
@@ -65,7 +67,7 @@ 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
* @return true is hostName name is valid and exists, false if not
*/
public static boolean isHostNameValid(String hostName) {
@@ -75,7 +77,7 @@ 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
* @return true is hostName name is valid and exists, false if not
*/
public static CompletableFuture<Boolean> isHostNameValidAsync(String hostName) {
@@ -87,12 +89,19 @@ public class TikTokLive {
*
* @return LiveHttpClient
*/
public static LiveHttpClient requests() {
return new TikTokLiveHttpClient();
public static LiveHttpClient requests(Consumer<LiveClientSettings> consumer) {
return new TikTokLiveHttpClient(consumer);
}
/**
* Use to get some data from TikTok about users are lives
*
* @return LiveHttpClient
*/
public static LiveHttpClient requests() {
return requests(liveClientSettings -> {});
}
//I don't like it, but it is reasonable for now
private static GiftsManager giftsManager;
/**
@@ -108,6 +117,4 @@ public class TikTokLive {
}
return giftsManager;
}
}

View File

@@ -23,57 +23,53 @@
package io.github.jwdeveloper.tiktok;
import com.google.protobuf.ByteString;
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.*;
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.LiveConnectionData;
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
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.ListenersManager;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
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.models.ConnectionState;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import io.github.jwdeveloper.tiktok.websocket.LiveSocketClient;
import lombok.Getter;
import java.util.Base64;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.logging.Logger;
public class TikTokLiveClient implements LiveClient {
private final TikTokRoomInfo liveRoomInfo;
@Getter
public class TikTokLiveClient implements LiveClient
{
private final TikTokRoomInfo roomInfo;
private final LiveHttpClient httpClient;
private final SocketClient webSocketClient;
private final TikTokLiveEventHandler tikTokEventHandler;
private final LiveSocketClient webSocketClient;
private final LiveEventsHandler tikTokEventHandler;
private final LiveClientSettings clientSettings;
private final TikTokListenersManager listenersManager;
private final ListenersManager listenersManager;
private final Logger logger;
private final GiftsManager giftsManager;
private final TikTokLiveMessageHandler messageHandler;
private final GiftsManager giftManager;
private final LiveMessagesHandler messageHandler;
public TikTokLiveClient(
TikTokLiveMessageHandler messageHandler,
LiveMessagesHandler messageHandler,
GiftsManager giftsManager,
TikTokRoomInfo tikTokLiveMeta,
LiveHttpClient tiktokHttpClient,
SocketClient webSocketClient,
TikTokLiveEventHandler tikTokEventHandler,
LiveSocketClient webSocketClient,
LiveEventsHandler tikTokEventHandler,
LiveClientSettings clientSettings,
TikTokListenersManager listenersManager,
ListenersManager listenersManager,
Logger logger) {
this.messageHandler = messageHandler;
this.giftsManager = giftsManager;
this.liveRoomInfo = tikTokLiveMeta;
this.giftManager = giftsManager;
this.roomInfo = tikTokLiveMeta;
this.httpClient = tiktokHttpClient;
this.webSocketClient = webSocketClient;
this.tikTokEventHandler = tikTokEventHandler;
@@ -82,22 +78,6 @@ public class TikTokLiveClient implements LiveClient {
this.logger = logger;
}
public void connectAsync(Consumer<LiveClient> onConnection) {
CompletableFuture.runAsync(() -> {
connect();
onConnection.accept(this);
});
}
public CompletableFuture<LiveClient> connectAsync() {
return CompletableFuture.supplyAsync(() -> {
connect();
return this;
});
}
public void connect() {
try {
tryConnect();
@@ -124,58 +104,61 @@ public class TikTokLiveClient implements LiveClient {
}
public void tryConnect() {
if (!liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
if (!roomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
throw new TikTokLiveException("Already connected");
}
setState(ConnectionState.CONNECTING);
tikTokEventHandler.publish(this, new TikTokConnectingEvent());
var userDataRequest = new LiveUserData.Request(liveRoomInfo.getHostName());
var userDataRequest = new LiveUserData.Request(roomInfo.getHostName());
var userData = httpClient.fetchLiveUserData(userDataRequest);
liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp());
liveRoomInfo.setRoomId(userData.getRoomId());
roomInfo.setStartTime(userData.getStartTime());
roomInfo.setRoomId(userData.getRoomId());
if (userData.getUserStatus() == LiveUserData.UserStatus.Offline)
throw new TikTokLiveOfflineHostException("User is offline: " + liveRoomInfo.getHostName());
throw new TikTokLiveOfflineHostException("User is offline: " + roomInfo.getHostName());
if (userData.getUserStatus() == LiveUserData.UserStatus.NotFound)
throw new TikTokLiveOfflineHostException("User not found: " + liveRoomInfo.getHostName());
throw new TikTokLiveUnknownHostException("User not found: " + roomInfo.getHostName());
var liveDataRequest = new LiveData.Request(userData.getRoomId());
var liveData = httpClient.fetchLiveData(liveDataRequest);
if (liveData.isAgeRestricted())
throw new TikTokLiveException("Livestream for " + liveRoomInfo.getHostName() + " is 18+ or age restricted!");
if (liveData.isAgeRestricted() && clientSettings.isThrowOnAgeRestriction())
throw new TikTokLiveException("Livestream for " + roomInfo.getHostName() + " is 18+ or age restricted!");
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound)
throw new TikTokLiveOfflineHostException("LiveStream for " + liveRoomInfo.getHostName() + " could not be found.");
throw new TikTokLiveUnknownHostException("LiveStream for " + roomInfo.getHostName() + " could not be found.");
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostOffline)
throw new TikTokLiveOfflineHostException("LiveStream for " + liveRoomInfo.getHostName() + " not found, is the Host offline?");
throw new TikTokLiveOfflineHostException("LiveStream for " + roomInfo.getHostName() + " not found, is the Host offline?");
tikTokEventHandler.publish(this, new TikTokRoomDataResponseEvent(liveData));
liveRoomInfo.setTitle(liveData.getTitle());
liveRoomInfo.setViewersCount(liveData.getViewers());
liveRoomInfo.setTotalViewersCount(liveData.getTotalViewers());
liveRoomInfo.setAgeRestricted(liveData.isAgeRestricted());
liveRoomInfo.setHost(liveData.getHost());
roomInfo.setTitle(liveData.getTitle());
roomInfo.setViewersCount(liveData.getViewers());
roomInfo.setTotalViewersCount(liveData.getTotalViewers());
roomInfo.setAgeRestricted(liveData.isAgeRestricted());
roomInfo.setHost(liveData.getHost());
var preconnectEvent = new TikTokPreConnectionEvent(userData, liveData);
tikTokEventHandler.publish(this, preconnectEvent);
if (preconnectEvent.isCancelConnection())
throw new TikTokLiveException("TikTokPreConnectionEvent cancelled connection!");
if (clientSettings.isFetchGifts())
giftManager.attachGiftsList(httpClient.fetchRoomGiftsData(userData.getRoomId()).getGifts());
var liveConnectionRequest = new LiveConnectionData.Request(userData.getRoomId());
var liveConnectionData = httpClient.fetchLiveConnectionData(liveConnectionRequest);
webSocketClient.start(liveConnectionData, this);
setState(ConnectionState.CONNECTED);
tikTokEventHandler.publish(this, new TikTokRoomInfoEvent(liveRoomInfo));
tikTokEventHandler.publish(this, new TikTokRoomInfoEvent(roomInfo));
}
public void disconnect() {
if (liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
if (roomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
return;
}
setState(ConnectionState.DISCONNECTED);
@@ -184,7 +167,7 @@ public class TikTokLiveClient implements LiveClient {
private void setState(ConnectionState connectionState) {
logger.info("TikTokLive client state: " + connectionState.name());
liveRoomInfo.setConnectionState(connectionState);
roomInfo.setConnectionState(connectionState);
}
public void publishEvent(TikTokEvent event) {
@@ -205,22 +188,15 @@ public class TikTokLiveClient implements LiveClient {
messageHandler.handleSingleMessage(this, message);
}
@Override
public GiftsManager getGiftManager() {
return giftsManager;
public void connectAsync(Consumer<LiveClient> onConnection) {
connectAsync().thenAccept(onConnection);
}
public LiveRoomInfo getRoomInfo() {
return liveRoomInfo;
}
@Override
public ListenersManager getListenersManager() {
return listenersManager;
}
@Override
public Logger getLogger() {
return logger;
public CompletableFuture<LiveClient> connectAsync() {
return CompletableFuture.supplyAsync(() -> {
connect();
return this;
});
}
}

View File

@@ -22,30 +22,26 @@
*/
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.dependance.Dependance;
import io.github.jwdeveloper.dependance.api.DependanceContainer;
import io.github.jwdeveloper.dependance.implementation.DependanceContainerBuilder;
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.http.TikTokHttpResponseEvent;
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.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftsManager;
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.mappers.data.MappingResult;
import io.github.jwdeveloper.tiktok.mappers.handlers.*;
import io.github.jwdeveloper.tiktok.messages.webcast.*;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketOfflineClient;
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 java.util.*;
import java.util.concurrent.CompletableFuture;
@@ -55,23 +51,28 @@ import java.util.logging.Logger;
public class TikTokLiveClientBuilder implements LiveClientBuilder {
protected final LiveClientSettings clientSettings;
protected final TikTokLiveEventHandler eventHandler;
protected final List<TikTokEventListener> listeners;
protected Consumer<TikTokMapper> onCustomMappings;
protected Logger logger;
protected GiftsManager giftsManager;
protected final LiveEventsHandler eventHandler;
protected final List<Object> listeners;
protected final List<Consumer<LiveMapper>> onCustomMappings;
protected final List<Consumer<DependanceContainerBuilder>> onCustomDependencies;
public TikTokLiveClientBuilder(String userName) {
this.clientSettings = LiveClientSettings.createDefault();
this.clientSettings.setHostName(userName);
this.eventHandler = new TikTokLiveEventHandler();
this.listeners = new ArrayList<>();
this.onCustomMappings = (e) -> {
};
this.onCustomMappings = new ArrayList<>();
this.onCustomDependencies = new ArrayList<>();
}
public LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings) {
this.onCustomMappings = onCustomMappings;
public LiveClientBuilder mappings(Consumer<LiveMapper> consumer) {
this.onCustomMappings.add(consumer);
return this;
}
@Override
public LiveClientBuilder onMappings(Consumer<LiveMapper> onCustomMappings) {
mappings(onCustomMappings);
return this;
}
@@ -80,12 +81,18 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return this;
}
public TikTokLiveClientBuilder addListener(TikTokEventListener listener) {
public TikTokLiveClientBuilder addListener(Object listener) {
if (listener != null)
listeners.add(listener);
return this;
}
@Override
public LiveClientBuilder customize(Consumer<DependanceContainerBuilder> onCustomizeDependencies) {
this.onCustomDependencies.add(onCustomizeDependencies);
return this;
}
protected void validate() {
if (clientSettings.getClientLanguage() == null || clientSettings.getClientLanguage().isEmpty())
clientSettings.setClientLanguage("en");
@@ -96,142 +103,92 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
if (clientSettings.getHostName().startsWith("@"))
clientSettings.setHostName(clientSettings.getHostName().substring(1));
//TODO 250 Magic number
if (clientSettings.getPingInterval() < 250)
throw new TikTokLiveException("Minimum allowed ping interval is 250 millseconds");
throw new TikTokLiveException("Minimum allowed ping interval is 250 milliseconds");
var httpSettings = clientSettings.getHttpSettings();
httpSettings.getParams().put("app_language", clientSettings.getClientLanguage());
httpSettings.getParams().put("webcast_language", clientSettings.getClientLanguage());
this.logger = LoggerFactory.create(clientSettings.getHostName(), clientSettings);
this.giftsManager = clientSettings.isFetchGifts() ? TikTokLive.gifts() : new TikTokGiftsManager(List.of());
}
//TODO each class registered to container should implement own interface,
public LiveClient build() {
validate();
var tiktokRoomInfo = new TikTokRoomInfo();
tiktokRoomInfo.setHostName(clientSettings.getHostName());
//Docs: https://github.com/jwdeveloper/DepenDance?tab=readme-ov-file#01-basic
var dependance = Dependance.newContainer();
var listenerManager = new TikTokListenersManager(listeners, eventHandler);
//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 httpClientFactory = new HttpClientFactory(clientSettings);
//messages
dependance.registerSingleton(LiveEventsHandler.class, eventHandler);
dependance.registerSingleton(LiveMessagesHandler.class, TikTokLiveMessageHandler.class);
var liveHttpClient = clientSettings.isOffline() ?
new TikTokLiveHttpOfflineClient() :
new TikTokLiveHttpClient(httpClientFactory, clientSettings);
//listeners
dependance.registerSingleton(ListenersManager.class, TikTokListenersManager.class);
var eventsMapper = createMapper(giftsManager, tiktokRoomInfo);
var messageHandler = new TikTokLiveMessageHandler(eventHandler, eventsMapper);
//networking
dependance.registerSingleton(HttpClientFactory.class);
dependance.registerSingleton(TikTokWebSocketPingingTask.class);
if (clientSettings.isOffline()) {
dependance.registerSingleton(LiveSocketClient.class, TikTokWebSocketOfflineClient.class);
dependance.registerSingleton(LiveHttpClient.class, TikTokLiveHttpOfflineClient.class);
} else {
dependance.registerSingleton(LiveSocketClient.class, TikTokWebSocketClient.class);
dependance.registerSingleton(LiveHttpClient.class, TikTokLiveHttpClient.class);
}
var webSocketClient = clientSettings.isOffline() ?
new TikTokWebSocketOfflineClient(eventHandler) :
new TikTokWebSocketClient(
clientSettings,
messageHandler,
eventHandler);
/* 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);
*/
return new TikTokLiveClient(
messageHandler,
giftsManager,
tiktokRoomInfo,
liveHttpClient,
webSocketClient,
eventHandler,
clientSettings,
listenerManager,
logger);
//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(LiveMapperHelper.class, TikTokLiveMapperHelper.class);
dependance.registerSingleton(LiveMapper.class, (container) ->
{
var dependace = (DependanceContainer) container.find(DependanceContainer.class);
var mapper = MessagesMapperFactory.create(dependace);
onCustomMappings.forEach(action -> action.accept(mapper));
return mapper;
});
//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);
onCustomDependencies.forEach(action -> action.accept(dependance));
var container = dependance.build();
var listenerManager = container.find(ListenersManager.class);
listeners.forEach(listenerManager::addListener);
return container.find(LiveClient.class);
}
public TikTokLiveMapper createMapper(GiftsManager giftsManager, TikTokRoomInfo roomInfo) {
var eventMapper = new TikTokGenericEventMapper();
var mapper = new TikTokLiveMapper(new TikTokLiveMapperHelper(eventMapper));
//ConnectionEvents events
var commonHandler = new TikTokCommonEventHandler();
var giftHandler = new TikTokGiftEventHandler(giftsManager, 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 messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastCaptionMessage.class);
return MappingResult.of(messageObject, new TikTokCaptionEvent(messageObject));
});
//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));
});
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();
@@ -242,256 +199,9 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return build().connectAsync();
}
public TikTokLiveClientBuilder onUnhandledSocial(EventConsumer<TikTokUnhandledSocialEvent> event) {
eventHandler.subscribe(TikTokUnhandledSocialEvent.class, event);
return this;
}
public LiveClientBuilder onChest(EventConsumer<TikTokChestEvent> event) {
eventHandler.subscribe(TikTokChestEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicFanTicket(EventConsumer<TikTokLinkMicFanTicketEvent> event) {
eventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEnvelope(EventConsumer<TikTokEnvelopeEvent> event) {
eventHandler.subscribe(TikTokEnvelopeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onShop(EventConsumer<TikTokShopEvent> event) {
eventHandler.subscribe(TikTokShopEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onDetect(EventConsumer<TikTokDetectEvent> event) {
eventHandler.subscribe(TikTokDetectEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkLayer(EventConsumer<TikTokLinkLayerEvent> event) {
eventHandler.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);
return this;
}
public TikTokLiveClientBuilder onCaption(EventConsumer<TikTokCaptionEvent> event) {
eventHandler.subscribe(TikTokCaptionEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onQuestion(EventConsumer<TikTokQuestionEvent> event) {
eventHandler.subscribe(TikTokQuestionEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRoomPin(EventConsumer<TikTokRoomPinEvent> event) {
eventHandler.subscribe(TikTokRoomPinEvent.class, event);
return this;
}
@Override
public <E extends TikTokEvent> LiveClientBuilder onEvent(Class<E> eventClass, EventConsumer<E> event) {
eventHandler.subscribe(eventClass, event);
return this;
}
@Override
public TikTokLiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) {
eventHandler.subscribe(TikTokRoomInfoEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLivePaused(EventConsumer<TikTokLivePausedEvent> event) {
eventHandler.subscribe(TikTokLivePausedEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event) {
eventHandler.subscribe(TikTokLiveUnpausedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLike(EventConsumer<TikTokLikeEvent> event) {
eventHandler.subscribe(TikTokLikeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLink(EventConsumer<TikTokLinkEvent> event) {
eventHandler.subscribe(TikTokLinkEvent.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);
return this;
}
public TikTokLiveClientBuilder onGiftCombo(EventConsumer<TikTokGiftComboEvent> event) {
eventHandler.subscribe(TikTokGiftComboEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicArmies(EventConsumer<TikTokLinkMicArmiesEvent> event) {
eventHandler.subscribe(TikTokLinkMicArmiesEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEmote(EventConsumer<TikTokEmoteEvent> event) {
eventHandler.subscribe(TikTokEmoteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnauthorizedMember(EventConsumer<TikTokUnauthorizedMemberEvent> event) {
eventHandler.subscribe(TikTokUnauthorizedMemberEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onInRoomBanner(EventConsumer<TikTokInRoomBannerEvent> event) {
eventHandler.subscribe(TikTokInRoomBannerEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicMethod(EventConsumer<TikTokLinkMicMethodEvent> event) {
eventHandler.subscribe(TikTokLinkMicMethodEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onSubscribe(EventConsumer<TikTokSubscribeEvent> event) {
eventHandler.subscribe(TikTokSubscribeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onPoll(EventConsumer<TikTokPollEvent> event) {
eventHandler.subscribe(TikTokPollEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onFollow(EventConsumer<TikTokFollowEvent> event) {
eventHandler.subscribe(TikTokFollowEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onComment(EventConsumer<TikTokCommentEvent> event) {
eventHandler.subscribe(TikTokCommentEvent.class, event);
return this;
}
@Override
public LiveClientBuilder onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action) {
eventHandler.subscribe(TikTokHttpResponseEvent.class, action);
return this;
}
public TikTokLiveClientBuilder onGoalUpdate(EventConsumer<TikTokGoalUpdateEvent> event) {
eventHandler.subscribe(TikTokGoalUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRankUpdate(EventConsumer<TikTokRankUpdateEvent> event) {
eventHandler.subscribe(TikTokRankUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onIMDelete(EventConsumer<TikTokIMDeleteEvent> event) {
eventHandler.subscribe(TikTokIMDeleteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLiveEnded(EventConsumer<TikTokLiveEndedEvent> event) {
eventHandler.subscribe(TikTokLiveEndedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onError(EventConsumer<TikTokErrorEvent> event) {
eventHandler.subscribe(TikTokErrorEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onJoin(EventConsumer<TikTokJoinEvent> event) {
eventHandler.subscribe(TikTokJoinEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRankText(EventConsumer<TikTokRankTextEvent> event) {
eventHandler.subscribe(TikTokRankTextEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onShare(EventConsumer<TikTokShareEvent> event) {
eventHandler.subscribe(TikTokShareEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnhandledMember(EventConsumer<TikTokUnhandledMemberEvent> event) {
eventHandler.subscribe(TikTokUnhandledMemberEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onSubNotify(EventConsumer<TikTokSubNotifyEvent> event) {
eventHandler.subscribe(TikTokSubNotifyEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicBattle(EventConsumer<TikTokLinkMicBattleEvent> event) {
eventHandler.subscribe(TikTokLinkMicBattleEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onDisconnected(EventConsumer<TikTokDisconnectedEvent> event) {
eventHandler.subscribe(TikTokDisconnectedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnhandledControl(EventConsumer<TikTokUnhandledControlEvent> event) {
eventHandler.subscribe(TikTokUnhandledControlEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEvent(EventConsumer<TikTokEvent> event) {
eventHandler.subscribe(TikTokEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> event) {
eventHandler.subscribe(TikTokWebsocketResponseEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> event) {
eventHandler.subscribe(TikTokWebsocketMessageEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> event) {
eventHandler.subscribe(TikTokWebsocketUnhandledMessageEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onReconnecting(EventConsumer<TikTokReconnectingEvent> event) {
eventHandler.subscribe(TikTokReconnectingEvent.class, event);
public <E extends TikTokEvent> LiveClientBuilder onEvent(Class<E> eventClass, EventConsumer<E> action) {
eventHandler.subscribe(eventClass, action);
return this;
}
}

View File

@@ -23,15 +23,13 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.LiveEventsHandler;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
public class TikTokLiveEventHandler {
public class TikTokLiveEventHandler implements LiveEventsHandler {
private final Map<Class<?>, Set<EventConsumer>> events;
public TikTokLiveEventHandler() {
@@ -39,21 +37,8 @@ public class TikTokLiveEventHandler {
}
public void publish(LiveClient tikTokLiveClient, TikTokEvent 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);
}
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)));
}
public <T extends TikTokEvent> void subscribe(Class<?> clazz, EventConsumer<T> event) {
@@ -65,22 +50,10 @@ public class TikTokLiveEventHandler {
}
public <T extends TikTokEvent> void unsubscribe(EventConsumer<T> consumer) {
for (var entry : events.entrySet()) {
entry.getValue().remove(consumer);
}
events.forEach((key, value) -> value.remove(consumer));
}
public <T extends TikTokEvent> void unsubscribe(Class<?> clazz, EventConsumer<T> consumer) {
if (clazz == null) {
return;
}
if (!events.containsKey(clazz)) {
return;
}
var eventSet = events.get(clazz);
eventSet.remove(consumer);
}
}
Optional.ofNullable(clazz).map(events::get).ifPresent(consumers -> consumers.remove(consumer));
}
}

View File

@@ -23,6 +23,7 @@
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;
@@ -32,6 +33,7 @@ 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;
public class TikTokLiveHttpClient implements LiveHttpClient
@@ -43,6 +45,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
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;
@@ -52,17 +55,44 @@ public class TikTokLiveHttpClient implements LiveHttpClient
private final GiftsDataMapper giftsDataMapper;
private final Logger logger;
public TikTokLiveHttpClient(HttpClientFactory factory, LiveClientSettings settings) {
@Inject
public TikTokLiveHttpClient(HttpClientFactory factory) {
this.httpFactory = factory;
this.clientSettings = settings;
this.logger = LoggerFactory.create("HttpClient", clientSettings);
this.clientSettings = factory.getLiveClientSettings();
this.logger = LoggerFactory.create("HttpClient-"+hashCode(), clientSettings);
liveUserDataMapper = new LiveUserDataMapper();
liveDataMapper = new LiveDataMapper();
giftsDataMapper = new GiftsDataMapper();
}
public TikTokLiveHttpClient() {
this(new HttpClientFactory(LiveClientSettings.createDefault()), LiveClientSettings.createDefault());
public TikTokLiveHttpClient(Consumer<LiveClientSettings> consumer) {
this(new HttpClientFactory(LiveClientSettings.createDefault()));
consumer.accept(clientSettings);
}
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() {
@@ -106,7 +136,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
var url = TIKTOK_URL_WEB + "api-live/user/room";
var result = httpFactory.client(url)
.withParam("uniqueId", request.getUserName())
.withParam("sourceType", "54")
.withParam("sourceType", "54") //MAGIC NUMBER, WHAT 54 means?
.build()
.toJsonResponse();
@@ -152,7 +182,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
try {
var resultHeader = ActionResult.of(credentialsResponse.headers().firstValue("x-set-tt-cookie"));
if (resultHeader.isFailure()) {
logger.warning("SignServer Headers: "+request.getRoomId()+" - "+credentialsResponse.headers().map());
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 websocketCookie = resultHeader.getContent();
@@ -165,7 +195,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
.withParam("internal_ext", webcastResponse.getInternalExt())
.withParams(webcastResponse.getRouteParamsMapMap())
.build()
.toUrl();
.toUri();
return new LiveConnectionData.Response(websocketCookie, webSocketUrl, webcastResponse);
} catch (InvalidProtocolBufferException e) {
@@ -188,7 +218,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
private ActionResult<HttpResponse<byte[]>> getByteResponse(String room_id) {
HttpClientBuilder builder = httpFactory.client(TIKTOK_SIGN_API)
.withParam("client", "ttlive-java")
.withParam("uuc", "1")
.withParam("uuc", "1") //MAGIC NUMBER!
.withParam("room_id", room_id);
if (clientSettings.getApiKey() != null)

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.models.Picture;
@@ -18,6 +40,11 @@ public class TikTokLiveHttpOfflineClient implements LiveHttpClient {
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);
@@ -42,4 +69,4 @@ public class TikTokLiveHttpOfflineClient implements LiveHttpClient {
URI.create("https://example.live"),
WebcastResponse.newBuilder().build());
}
}
}

View File

@@ -30,18 +30,20 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketRespons
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent;
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.live.LiveEventsHandler;
import io.github.jwdeveloper.tiktok.live.LiveMessagesHandler;
import io.github.jwdeveloper.tiktok.mappers.LiveMapper;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.Stopwatch;
import java.time.Duration;
public class TikTokLiveMessageHandler {
public class TikTokLiveMessageHandler implements LiveMessagesHandler {
private final TikTokLiveEventHandler tikTokEventHandler;
private final TikTokLiveMapper mapper;
private final LiveEventsHandler tikTokEventHandler;
private final LiveMapper mapper;
public TikTokLiveMessageHandler(TikTokLiveEventHandler tikTokEventHandler, TikTokLiveMapper mapper) {
public TikTokLiveMessageHandler(LiveEventsHandler tikTokEventHandler, LiveMapper mapper) {
this.tikTokEventHandler = tikTokEventHandler;
this.mapper = mapper;
}
@@ -58,13 +60,13 @@ public class TikTokLiveMessageHandler {
}
}
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message)
{
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message) {
var messageClassName = message.getMethod();
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());
@@ -76,5 +78,4 @@ public class TikTokLiveMessageHandler {
tikTokEventHandler.publish(client, event);
}
}
}
}

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