mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-27 16:59:39 -05:00
Compare commits
51 Commits
0.0.8-Rele
...
0.0.15-Rel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
818c4cb364 | ||
|
|
911e2b12a5 | ||
|
|
1aff710523 | ||
|
|
c0f8e6d904 | ||
|
|
b059afd621 | ||
|
|
1275878822 | ||
|
|
761f3ab633 | ||
|
|
66def92316 | ||
|
|
cc85d7c124 | ||
|
|
384cfade5a | ||
|
|
483dceadcf | ||
|
|
5f8cba5126 | ||
|
|
f9966c9a5f | ||
|
|
48a79736ad | ||
|
|
eb82d0df78 | ||
|
|
4ed821925d | ||
|
|
6e9244aa67 | ||
|
|
fadb1ab267 | ||
|
|
4273375eb9 | ||
|
|
3daeee6316 | ||
|
|
cde38df1b3 | ||
|
|
15d6351d65 | ||
|
|
44ba999b83 | ||
|
|
5cf0d30962 | ||
|
|
71ebc6e05e | ||
|
|
c6d09927a0 | ||
|
|
f03cb14262 | ||
|
|
d9ef60ccad | ||
|
|
6fb89e72d4 | ||
|
|
230764ed6a | ||
|
|
b9a4fb193e | ||
|
|
af209fc2ca | ||
|
|
74bfe0b9e7 | ||
|
|
3545167873 | ||
|
|
c22483043d | ||
|
|
8155d49366 | ||
|
|
321b7c0eda | ||
|
|
26c7db8f99 | ||
|
|
5f7ead2f05 | ||
|
|
dffae3a521 | ||
|
|
6254443755 | ||
|
|
c001eacbce | ||
|
|
1bbb704d14 | ||
|
|
8c3a5c6627 | ||
|
|
470b154c5e | ||
|
|
2391b12598 | ||
|
|
cb68050e24 | ||
|
|
a9e347b8da | ||
|
|
73823c82ea | ||
|
|
e0542d39af | ||
|
|
d33dab0a98 |
2
.github/workflows/maven-publish.yml
vendored
2
.github/workflows/maven-publish.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Publish Artifacts
|
name: Publish New Version
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|||||||
81
.gitignore
vendored
81
.gitignore
vendored
@@ -1,3 +1,82 @@
|
|||||||
# Project exclude paths
|
# Project exclude paths
|
||||||
/API/target/
|
/API/target/
|
||||||
/Client/target/
|
/Client/target/
|
||||||
|
*.db
|
||||||
|
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>TikTokLiveJava</artifactId>
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<version>1.0.0</version>
|
<version>0.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>API</artifactId>
|
<artifactId>API</artifactId>
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package io.github.jwdeveloper.tiktok;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -10,62 +12,58 @@ public class ClientSettings {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Timeout for Connections
|
/// Timeout for Connections
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
private Duration timeout;
|
||||||
private Duration Timeout;
|
|
||||||
/// <summary>
|
|
||||||
/// Polling-Interval for Socket-Connection
|
|
||||||
/// </summary
|
|
||||||
|
|
||||||
private Duration PollingInterval;
|
|
||||||
/// <summary>
|
|
||||||
/// Proxy for Connection
|
|
||||||
/// </summary>
|
|
||||||
|
|
||||||
// public RotatingProxy Proxy;
|
// public RotatingProxy Proxy;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ISO-Language for Client
|
/// ISO-Language for Client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
private String ClientLanguage;
|
private String clientLanguage;
|
||||||
/// <summary>
|
|
||||||
/// Size for Buffer for Socket-Connection
|
|
||||||
/// </summary>
|
|
||||||
|
|
||||||
private int SocketBufferSize;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to Retry if Connection Fails
|
/// Whether to Retry if Connection Fails
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private boolean RetryOnConnectionFailure;
|
private boolean retryOnConnectionFailure;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait to connect again for selected amount of time
|
||||||
|
/// </summary>
|
||||||
|
private Duration retryConnectionTimeout;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to handle Messages received from Room when Connecting
|
/// Whether to handle Messages received from Room when Connecting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private boolean HandleExistingMessagesOnConnect;
|
private boolean handleExistingMessagesOnConnect;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to download List of Gifts for Room when Connecting
|
/// Whether to download List of Gifts for Room when Connecting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private boolean DownloadGiftInfo;
|
private boolean downloadGiftInfo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to print Logs to Console
|
/// Whether to print Logs to Console
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
private boolean PrintToConsole;
|
private boolean printToConsole;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// LoggingLevel for Logs
|
/// LoggingLevel for Logs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Level LogLevel;
|
private Level logLevel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to print Base64-Data for Messages to Console
|
/// Whether to print Base64-Data for Messages to Console
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private boolean PrintMessageData;
|
private boolean printMessageData;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to check Messages for Unparsed Data
|
/// Tiktok user name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private boolean CheckForUnparsedData;
|
private String hostName;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameters used in requests to tiktok api
|
||||||
|
/// </summary>
|
||||||
|
private Map<String, Object> clientParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,18 +39,16 @@ public class Constants {
|
|||||||
|
|
||||||
public static ClientSettings DefaultClientSettings() {
|
public static ClientSettings DefaultClientSettings() {
|
||||||
var clientSettings = new ClientSettings();
|
var clientSettings = new ClientSettings();
|
||||||
|
|
||||||
clientSettings.setTimeout(Duration.ofSeconds(DEFAULT_TIMEOUT));
|
clientSettings.setTimeout(Duration.ofSeconds(DEFAULT_TIMEOUT));
|
||||||
clientSettings.setPollingInterval(Duration.ofSeconds(DEFAULT_POLLTIME));
|
|
||||||
clientSettings.setClientLanguage("en-US");
|
clientSettings.setClientLanguage("en-US");
|
||||||
clientSettings.setHandleExistingMessagesOnConnect(true);
|
clientSettings.setHandleExistingMessagesOnConnect(true);
|
||||||
clientSettings.setDownloadGiftInfo(true);
|
clientSettings.setDownloadGiftInfo(true);
|
||||||
clientSettings.setRetryOnConnectionFailure(true);
|
clientSettings.setRetryOnConnectionFailure(false);
|
||||||
clientSettings.setSocketBufferSize(500_000);
|
clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1));
|
||||||
clientSettings.setPrintToConsole(true);
|
clientSettings.setPrintToConsole(false);
|
||||||
clientSettings.setLogLevel(Level.ALL);
|
clientSettings.setLogLevel(Level.ALL);
|
||||||
clientSettings.setCheckForUnparsedData(false);
|
|
||||||
clientSettings.setPrintMessageData(false);
|
clientSettings.setPrintMessageData(false);
|
||||||
|
clientSettings.setClientParameters(Constants.DefaultClientParams());
|
||||||
return clientSettings;
|
return clientSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,94 +2,94 @@ package io.github.jwdeveloper.tiktok.events;
|
|||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.events.messages.*;
|
import io.github.jwdeveloper.tiktok.events.messages.*;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public interface TikTokEventBuilder<T> {
|
public interface TikTokEventBuilder<T> {
|
||||||
T onUnhandledSocial(Consumer<TikTokUnhandledSocialEvent> event);
|
T onUnhandledSocial(TikTokEventConsumer<TikTokUnhandledSocialEvent> event);
|
||||||
|
|
||||||
T onLinkMicFanTicket(Consumer<TikTokLinkMicFanTicketEvent> event);
|
T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);
|
||||||
|
|
||||||
T onEnvelope(Consumer<TikTokEnvelopeEvent> event);
|
T onEnvelope(TikTokEventConsumer<TikTokEnvelopeEvent> event);
|
||||||
|
|
||||||
T onShopMessage(Consumer<TikTokShopMessageEvent> event);
|
T onShopMessage(TikTokEventConsumer<TikTokShopMessageEvent> event);
|
||||||
|
|
||||||
T onDetectMessage(Consumer<TikTokDetectMessageEvent> event);
|
T onDetectMessage(TikTokEventConsumer<TikTokDetectMessageEvent> event);
|
||||||
|
|
||||||
T onLinkLayerMessage(Consumer<TikTokLinkLayerMessageEvent> event);
|
T onLinkLayerMessage(TikTokEventConsumer<TikTokLinkLayerMessageEvent> event);
|
||||||
|
|
||||||
T onConnected(Consumer<TikTokConnectedEvent> event);
|
T onConnected(TikTokEventConsumer<TikTokConnectedEvent> event);
|
||||||
|
|
||||||
T onCaption(Consumer<TikTokCaptionEvent> event);
|
T onCaption(TikTokEventConsumer<TikTokCaptionEvent> event);
|
||||||
|
|
||||||
T onQuestion(Consumer<TikTokQuestionEvent> event);
|
T onQuestion(TikTokEventConsumer<TikTokQuestionEvent> event);
|
||||||
|
|
||||||
T onRoomPinMessage(Consumer<TikTokRoomPinMessageEvent> event);
|
T onRoomPinMessage(TikTokEventConsumer<TikTokRoomPinMessageEvent> event);
|
||||||
|
|
||||||
T onRoomMessage(Consumer<TikTokRoomMessageEvent> event);
|
T onRoomMessage(TikTokEventConsumer<TikTokRoomMessageEvent> event);
|
||||||
|
|
||||||
T onLivePaused(Consumer<TikTokLivePausedEvent> event);
|
T onLivePaused(TikTokEventConsumer<TikTokLivePausedEvent> event);
|
||||||
|
|
||||||
T onLike(Consumer<TikTokLikeEvent> event);
|
T onLike(TikTokEventConsumer<TikTokLikeEvent> event);
|
||||||
|
|
||||||
T onLinkMessage(Consumer<TikTokLinkMessageEvent> event);
|
T onLinkMessage(TikTokEventConsumer<TikTokLinkMessageEvent> event);
|
||||||
|
|
||||||
T onBarrageMessage(Consumer<TikTokBarrageMessageEvent> event);
|
T onBarrageMessage(TikTokEventConsumer<TikTokBarrageMessageEvent> event);
|
||||||
|
|
||||||
T onGiftMessage(Consumer<TikTokGiftMessageEvent> event);
|
T onGiftMessage(TikTokEventConsumer<TikTokGiftMessageEvent> event);
|
||||||
|
|
||||||
T onLinkMicArmies(Consumer<TikTokLinkMicArmiesEvent> event);
|
T onLinkMicArmies(TikTokEventConsumer<TikTokLinkMicArmiesEvent> event);
|
||||||
|
|
||||||
T onEmote(Consumer<TikTokEmoteEvent> event);
|
T onEmote(TikTokEventConsumer<TikTokEmoteEvent> event);
|
||||||
|
|
||||||
T onUnauthorizedMember(Consumer<TikTokUnauthorizedMemberEvent> event);
|
T onUnauthorizedMember(TikTokEventConsumer<TikTokUnauthorizedMemberEvent> event);
|
||||||
|
|
||||||
T onInRoomBanner(Consumer<TikTokInRoomBannerEvent> event);
|
T onInRoomBanner(TikTokEventConsumer<TikTokInRoomBannerEvent> event);
|
||||||
|
|
||||||
T onLinkMicMethod(Consumer<TikTokLinkMicMethodEvent> event);
|
T onLinkMicMethod(TikTokEventConsumer<TikTokLinkMicMethodEvent> event);
|
||||||
|
|
||||||
T onSubscribe(Consumer<TikTokSubscribeEvent> event);
|
T onSubscribe(TikTokEventConsumer<TikTokSubscribeEvent> event);
|
||||||
|
|
||||||
T onPollMessage(Consumer<TikTokPollMessageEvent> event);
|
T onPollMessage(TikTokEventConsumer<TikTokPollMessageEvent> event);
|
||||||
|
|
||||||
T onFollow(Consumer<TikTokFollowEvent> event);
|
T onFollow(TikTokEventConsumer<TikTokFollowEvent> event);
|
||||||
|
|
||||||
T onRoomViewerData(Consumer<TikTokRoomViewerDataEvent> event);
|
T onRoomViewerData(TikTokEventConsumer<TikTokRoomViewerDataEvent> event);
|
||||||
|
|
||||||
T onGoalUpdate(Consumer<TikTokGoalUpdateEvent> event);
|
T onGoalUpdate(TikTokEventConsumer<TikTokGoalUpdateEvent> event);
|
||||||
|
|
||||||
T onComment(Consumer<TikTokCommentEvent> event);
|
T onComment(TikTokEventConsumer<TikTokCommentEvent> event);
|
||||||
|
|
||||||
T onRankUpdate(Consumer<TikTokRankUpdateEvent> event);
|
T onRankUpdate(TikTokEventConsumer<TikTokRankUpdateEvent> event);
|
||||||
|
|
||||||
T onIMDelete(Consumer<TikTokIMDeleteEvent> event);
|
T onIMDelete(TikTokEventConsumer<TikTokIMDeleteEvent> event);
|
||||||
|
|
||||||
T onLiveEnded(Consumer<TikTokLiveEndedEvent> event);
|
T onLiveEnded(TikTokEventConsumer<TikTokLiveEndedEvent> event);
|
||||||
|
|
||||||
T onError(Consumer<TikTokErrorEvent> event);
|
T onError(TikTokEventConsumer<TikTokErrorEvent> event);
|
||||||
|
|
||||||
T onUnhandled(Consumer<TikTokUnhandledEvent> event);
|
T onUnhandled(TikTokEventConsumer<TikTokUnhandledEvent> event);
|
||||||
|
|
||||||
T onJoin(Consumer<TikTokJoinEvent> event);
|
T onJoin(TikTokEventConsumer<TikTokJoinEvent> event);
|
||||||
|
|
||||||
T onRankText(Consumer<TikTokRankTextEvent> event);
|
T onRankText(TikTokEventConsumer<TikTokRankTextEvent> event);
|
||||||
|
|
||||||
T onShare(Consumer<TikTokShareEvent> event);
|
T onShare(TikTokEventConsumer<TikTokShareEvent> event);
|
||||||
|
|
||||||
T onUnhandledMember(Consumer<TikTokUnhandledMemberEvent> event);
|
T onUnhandledMember(TikTokEventConsumer<TikTokUnhandledMemberEvent> event);
|
||||||
|
|
||||||
T onSubNotify(Consumer<TikTokSubNotifyEvent> event);
|
T onSubNotify(TikTokEventConsumer<TikTokSubNotifyEvent> event);
|
||||||
|
|
||||||
T onLinkMicBattle(Consumer<TikTokLinkMicBattleEvent> event);
|
T onLinkMicBattle(TikTokEventConsumer<TikTokLinkMicBattleEvent> event);
|
||||||
|
|
||||||
T onDisconnected(Consumer<TikTokDisconnectedEvent> event);
|
T onDisconnected(TikTokEventConsumer<TikTokDisconnectedEvent> event);
|
||||||
|
|
||||||
T onGiftBroadcast(Consumer<TikTokGiftBroadcastEvent> event);
|
T onGiftBroadcast(TikTokEventConsumer<TikTokGiftBroadcastEvent> event);
|
||||||
|
|
||||||
T onUnhandledControl(Consumer<TikTokUnhandledControlEvent> event);
|
T onUnhandledControl(TikTokEventConsumer<TikTokUnhandledControlEvent> event);
|
||||||
|
|
||||||
|
T onEvent(TikTokEventConsumer<TikTokEvent> event);
|
||||||
|
|
||||||
|
T onWebsocketMessage(TikTokEventConsumer<TikTokWebsocketMessageEvent> event);
|
||||||
|
|
||||||
T onEvent(Consumer<TikTokEvent> event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package io.github.jwdeveloper.tiktok.events;
|
|||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
|
|
||||||
public interface TikTokLiveEvent<T extends TikTokEvent>
|
public interface TikTokEventConsumer<T extends TikTokEvent>
|
||||||
{
|
{
|
||||||
void onEvent(LiveClient liveClient, T event);
|
void onEvent(LiveClient liveClient, T event);
|
||||||
}
|
}
|
||||||
@@ -3,38 +3,39 @@ package io.github.jwdeveloper.tiktok.events.messages;
|
|||||||
import io.github.jwdeveloper.tiktok.annotations.Nullable;
|
import io.github.jwdeveloper.tiktok.annotations.Nullable;
|
||||||
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.events.objects.Gift;
|
import io.github.jwdeveloper.tiktok.events.objects.Gift;
|
||||||
|
import io.github.jwdeveloper.tiktok.events.objects.TikTokGift;
|
||||||
import io.github.jwdeveloper.tiktok.events.objects.User;
|
import io.github.jwdeveloper.tiktok.events.objects.User;
|
||||||
import io.github.jwdeveloper.tiktok.messages.WebcastGiftMessage;
|
import io.github.jwdeveloper.tiktok.messages.WebcastGiftMessage;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class TikTokGiftMessageEvent extends TikTokEvent {
|
public class TikTokGiftMessageEvent extends TikTokEvent {
|
||||||
private final Gift gift;
|
|
||||||
|
|
||||||
@Nullable
|
private final Gift gift;
|
||||||
private User sender;
|
|
||||||
|
|
||||||
private final String purchaseId;
|
@Nullable
|
||||||
|
private User sender;
|
||||||
|
|
||||||
private final String receipt;
|
private final String purchaseId;
|
||||||
|
|
||||||
private final Integer amount;
|
private final String receipt;
|
||||||
|
|
||||||
private final Boolean streakFinished;
|
private final Integer amount;
|
||||||
|
|
||||||
private final Integer streakIndex;
|
private final Boolean streakFinished;
|
||||||
|
|
||||||
public TikTokGiftMessageEvent(WebcastGiftMessage msg) {
|
private final Integer streakIndex;
|
||||||
super(msg.getHeader());;
|
|
||||||
gift = new Gift(msg.getGiftDetails());
|
public TikTokGiftMessageEvent(WebcastGiftMessage msg) {
|
||||||
if(msg.hasSender())
|
super(msg.getHeader());
|
||||||
{
|
gift = new Gift(msg.getGiftDetails());
|
||||||
sender = new User(msg.getSender());
|
if (msg.hasSender()) {
|
||||||
|
sender = new User(msg.getSender());
|
||||||
|
}
|
||||||
|
purchaseId = msg.getLogId();
|
||||||
|
receipt = msg.getReceiptJson();
|
||||||
|
amount = msg.getAmount();
|
||||||
|
streakFinished = msg.getRepeatEnd();
|
||||||
|
streakIndex = msg.getRepeatCount();
|
||||||
}
|
}
|
||||||
purchaseId = msg.getLogId();
|
|
||||||
receipt = msg.getReceiptJson();
|
|
||||||
amount = msg.getAmount();
|
|
||||||
streakFinished = msg.getRepeatEnd();
|
|
||||||
streakIndex = msg.getRepeatCount();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,10 @@ import lombok.Getter;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class TikTokIMDeleteEvent extends TikTokEvent {
|
public class TikTokIMDeleteEvent extends TikTokEvent {
|
||||||
private final String data1;
|
private final byte[] data;
|
||||||
private final String data2;
|
|
||||||
|
|
||||||
public TikTokIMDeleteEvent(WebcastImDeleteMessage msg) {
|
public TikTokIMDeleteEvent(WebcastImDeleteMessage msg) {
|
||||||
super(msg.getHeader());;
|
super(msg.getHeader());
|
||||||
data1 = msg.getData1();
|
data = msg.getData().toByteArray();
|
||||||
data2 = msg.getData2();
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,15 @@ public class TikTokRankUpdateEvent extends TikTokEvent {
|
|||||||
var rankData = msg.getData().getRankings();
|
var rankData = msg.getData().getRankings();
|
||||||
eventType = rankData.getType();
|
eventType = rankData.getType();
|
||||||
label = rankData.getLabel();
|
label = rankData.getLabel();
|
||||||
rank = rankData.getDetails(0).getLabel();
|
if(rankData.getDetailsList().isEmpty())
|
||||||
|
{
|
||||||
|
rank = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rank = rankData.getDetails(0).getLabel();
|
||||||
|
}
|
||||||
color = rankData.getColor().getColor();
|
color = rankData.getColor().getColor();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokRankUpdateEvent(WebcastRankUpdateMessage msg) {
|
public TikTokRankUpdateEvent(WebcastRankUpdateMessage msg) {
|
||||||
@@ -31,7 +36,14 @@ public class TikTokRankUpdateEvent extends TikTokEvent {
|
|||||||
var rankData = msg.getData().getRankData();
|
var rankData = msg.getData().getRankData();
|
||||||
eventType = rankData.getType();
|
eventType = rankData.getType();
|
||||||
label = rankData.getLabel();
|
label = rankData.getLabel();
|
||||||
rank = rankData.getDetails(0).getLabel();
|
if(rankData.getDetailsList().isEmpty())
|
||||||
|
{
|
||||||
|
rank = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rank = rankData.getDetails(0).getLabel();
|
||||||
|
}
|
||||||
color = rankData.getColor().getColor();
|
color = rankData.getColor().getColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.events.messages;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Happens when TikTok websocket receive message from server
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class TikTokWebsocketMessageEvent extends TikTokEvent
|
||||||
|
{
|
||||||
|
private TikTokEvent event;
|
||||||
|
|
||||||
|
private WebcastResponse.Message message;
|
||||||
|
}
|
||||||
@@ -7,14 +7,14 @@ import java.util.List;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class Badge {
|
public class Badge {
|
||||||
private final ComboBadge comboBadges;
|
private ComboBadge comboBadges;
|
||||||
private final List<TextBadge> textBadges;
|
private final List<TextBadge> textBadges;
|
||||||
private final List<ImageBadge> imageBadges;
|
private final List<ImageBadge> imageBadges;
|
||||||
|
|
||||||
public Badge(io.github.jwdeveloper.tiktok.messages.Badge badge) {
|
public Badge(io.github.jwdeveloper.tiktok.messages.Badge badge) {
|
||||||
textBadges = badge.getTextBadgesList().stream().map(b -> new TextBadge(b.getType(), b.getName())).toList();
|
textBadges = badge.getTextBadgesList().stream().map(b -> new TextBadge(b.getType(), b.getName())).toList();
|
||||||
imageBadges = badge.getImageBadgesList().stream().map(b -> new ImageBadge(b.getDisplayType(), new Picture(b.getImage()))).toList();
|
imageBadges = badge.getImageBadgesList().stream().map(b -> new ImageBadge(b.getDisplayType(), new Picture(b.getImage()))).toList();
|
||||||
comboBadges = new ComboBadge(new Picture(badge.getComplexBadge().getImageUrl()), badge.getComplexBadge().getData());
|
comboBadges = new ComboBadge(new Picture("badge.getComplexBadge().getImageUrl()"), badge.getComplexBadge().getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.exceptions;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class TikTokLiveMessageException extends TikTokLiveException {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final WebcastResponse.Message webcastMessage;
|
||||||
|
@Getter
|
||||||
|
private final WebcastResponse webcastResponse;
|
||||||
|
|
||||||
|
|
||||||
|
public TikTokLiveMessageException(WebcastResponse.Message message,
|
||||||
|
WebcastResponse webcastResponse,
|
||||||
|
Throwable cause) {
|
||||||
|
super("Error while handling Message: " + message.getType() + ": \n", cause);
|
||||||
|
this.webcastMessage = message;
|
||||||
|
this.webcastResponse = webcastResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String messageName()
|
||||||
|
{
|
||||||
|
return webcastMessage.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String messageToBase64()
|
||||||
|
{
|
||||||
|
return Base64.getEncoder().encodeToString(webcastMessage.getBinary().toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String webcastResponseToBase64()
|
||||||
|
{
|
||||||
|
return Base64.getEncoder().encodeToString(webcastResponse.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package io.github.jwdeveloper.tiktok.exceptions;
|
|
||||||
|
|
||||||
public class TikTokLiveMessageParsingException extends TikTokLiveException
|
|
||||||
{
|
|
||||||
public TikTokLiveMessageParsingException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokLiveMessageParsingException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokLiveMessageParsingException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokLiveMessageParsingException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokLiveMessageParsingException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
|
||||||
super(message, cause, enableSuppression, writableStackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.exceptions;
|
||||||
|
|
||||||
|
public class TikTokLiveOfflineHostException extends TikTokLiveException
|
||||||
|
{
|
||||||
|
public TikTokLiveOfflineHostException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.exceptions;
|
||||||
|
|
||||||
|
public class TikTokLiveRequestException extends TikTokLiveException
|
||||||
|
{
|
||||||
|
public TikTokLiveRequestException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public TikTokLiveRequestException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TikTokLiveRequestException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TikTokLiveRequestException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TikTokLiveRequestException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.exceptions;
|
||||||
|
|
||||||
|
|
||||||
|
public class TikTokMessageMappingException extends TikTokLiveException
|
||||||
|
{
|
||||||
|
public TikTokMessageMappingException(Class<?> inputClazz, Class<?> outputClass, Throwable throwable)
|
||||||
|
{
|
||||||
|
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + " to class " + outputClass.getSimpleName(),throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TikTokMessageMappingException(Class<?> inputClazz, Class<?> outputClass, String message)
|
||||||
|
{
|
||||||
|
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + " to class " + outputClass.getSimpleName()+": "+message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.exceptions;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public class TikTokProtocolBufferException extends TikTokLiveException
|
||||||
|
{
|
||||||
|
@Getter
|
||||||
|
private final byte[] bytes;
|
||||||
|
|
||||||
|
public TikTokProtocolBufferException(String message, byte[] bytes, Throwable cause)
|
||||||
|
{
|
||||||
|
super(message, cause);
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.handler;
|
||||||
|
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||||
|
|
||||||
|
public interface TikTokMessageHandler
|
||||||
|
{
|
||||||
|
TikTokEvent handle(WebcastResponse.Message message) throws Exception;
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package io.github.jwdeveloper.tiktok.http.Resource;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class ClientFetchDataResponse {
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.live;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.events.objects.TikTokGift;
|
||||||
|
import io.github.jwdeveloper.tiktok.models.GiftId;
|
||||||
|
import io.github.jwdeveloper.tiktok.models.gifts.TikTokGiftInfo;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface GiftManager
|
||||||
|
{
|
||||||
|
Map<Integer, TikTokGiftInfo> getGiftsInfo();
|
||||||
|
|
||||||
|
Map<GiftId, TikTokGift> getActiveGifts();
|
||||||
|
}
|
||||||
@@ -6,5 +6,6 @@ public interface LiveClient {
|
|||||||
|
|
||||||
void disconnect();
|
void disconnect();
|
||||||
|
|
||||||
|
GiftManager getGiftManager();
|
||||||
LiveRoomInfo getRoomInfo();
|
LiveRoomInfo getRoomInfo();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package io.github.jwdeveloper.tiktok.live;
|
|||||||
public interface LiveRoomInfo
|
public interface LiveRoomInfo
|
||||||
{
|
{
|
||||||
int getViewersCount();
|
int getViewersCount();
|
||||||
|
|
||||||
String getRoomId();
|
String getRoomId();
|
||||||
String getUserName();
|
String getUserName();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import lombok.Data;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GiftId
|
public class GiftId
|
||||||
{
|
{
|
||||||
public long Gift;
|
private long giftId;
|
||||||
|
|
||||||
public String UserName;
|
private String userName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.models;
|
||||||
|
|
||||||
|
public enum GiftStrike
|
||||||
|
{
|
||||||
|
BEGIN, UPDATE, ENDED
|
||||||
|
}
|
||||||
@@ -3,14 +3,13 @@ package io.github.jwdeveloper.tiktok.models.gifts;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class DefaultFormat
|
public class DefaultFormat {
|
||||||
{
|
private boolean bold;
|
||||||
private boolean bold ;
|
private String color;
|
||||||
private String color ;
|
private int font_size;
|
||||||
private int font_size ;
|
private boolean italic;
|
||||||
private boolean italic ;
|
private int italic_angle;
|
||||||
private int italic_angle ;
|
private boolean use_highlight_color;
|
||||||
private boolean use_highlight_color ;
|
private boolean use_remote_color;
|
||||||
private boolean use_remote_color ;
|
private int weight;
|
||||||
private int weight ;
|
|
||||||
}
|
}
|
||||||
@@ -5,10 +5,9 @@ import lombok.Data;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class DisplayText
|
public class DisplayText {
|
||||||
{
|
private DefaultFormat default_format;
|
||||||
private DefaultFormat default_format ;
|
private String default_pattern;
|
||||||
private String default_pattern ;
|
private String key;
|
||||||
private String key ;
|
private List<Object> pieces;
|
||||||
private List<Object> pieces ;
|
|
||||||
}
|
}
|
||||||
@@ -5,14 +5,13 @@ import lombok.Data;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class GiftLabelIcon
|
public class GiftLabelIcon {
|
||||||
{
|
private String avg_color;
|
||||||
private String avg_color ;
|
private int height;
|
||||||
private int height ;
|
private int image_type;
|
||||||
private int image_type ;
|
private boolean is_animated;
|
||||||
private boolean is_animated ;
|
private String open_web_url;
|
||||||
private String open_web_url ;
|
private String uri;
|
||||||
private String uri ;
|
private List<String> url_list;
|
||||||
private List<String> url_list ;
|
private int width;
|
||||||
private int width ;
|
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,9 @@ import java.util.List;
|
|||||||
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class GiftPanelBanner
|
public class GiftPanelBanner {
|
||||||
{
|
private List<Object> bg_color_values;
|
||||||
private List<Object> bg_color_values ;
|
private DisplayText display_text;
|
||||||
private DisplayText display_text ;
|
private LeftIcon left_icon;
|
||||||
private LeftIcon left_icon ;
|
private String schema_url;
|
||||||
private String schema_url ;
|
|
||||||
}
|
}
|
||||||
@@ -5,14 +5,13 @@ import lombok.Data;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class Image
|
public class Image {
|
||||||
{
|
private String avg_color;
|
||||||
private String avg_color ;
|
private int height;
|
||||||
private int height ;
|
private int image_type;
|
||||||
private int image_type ;
|
private boolean is_animated;
|
||||||
private boolean is_animated ;
|
private String open_web_url;
|
||||||
private String open_web_url ;
|
private String uri;
|
||||||
private String uri ;
|
private List<String> url_list;
|
||||||
private List<String> url_list ;
|
private int width;
|
||||||
private int width ;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,15 @@ import lombok.Data;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class LeftIcon
|
public class LeftIcon {
|
||||||
{
|
private String avg_color;
|
||||||
private String avg_color ;
|
private int height;
|
||||||
private int height ;
|
private int image_type;
|
||||||
private int image_type ;
|
private boolean is_animated;
|
||||||
private boolean is_animated ;
|
private String open_web_url;
|
||||||
private String open_web_url ;
|
private String uri;
|
||||||
private String uri ;
|
private List<String> url_list;
|
||||||
private List<String> url_list ;
|
private int width;
|
||||||
private int width ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package io.github.jwdeveloper.tiktok.models.gifts;
|
package io.github.jwdeveloper.tiktok.models.gifts;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
public class LockInfo
|
public class LockInfo
|
||||||
{
|
{
|
||||||
public int lock_type;
|
private int lock_type;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import lombok.Data;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TikTokGift
|
public class TikTokGiftInfo
|
||||||
{
|
{
|
||||||
private int action_type;
|
private int action_type;
|
||||||
private int app_id;
|
private int app_id;
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.utils;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
|
|
||||||
|
public class CancelationToken
|
||||||
|
{
|
||||||
|
private boolean isCanceled =false;
|
||||||
|
|
||||||
|
public void cancel()
|
||||||
|
{
|
||||||
|
isCanceled =true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCancel()
|
||||||
|
{
|
||||||
|
|
||||||
|
return isCanceled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void throwIfCancel()
|
||||||
|
{
|
||||||
|
if(!isCanceled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new TikTokLiveException("Token requested cancelation");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNotCancel()
|
||||||
|
{
|
||||||
|
return !isCancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CancelationToken create()
|
||||||
|
{
|
||||||
|
return new CancelationToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -186,7 +186,7 @@ message Badge {
|
|||||||
|
|
||||||
message BadgeComplex {
|
message BadgeComplex {
|
||||||
uint32 data1 = 1;
|
uint32 data1 = 1;
|
||||||
string imageUrl = 2;
|
//string imageUrl = 2; Protocol message had invalid UTF-8
|
||||||
string data = 4;
|
string data = 4;
|
||||||
DataContainer detail1 = 5;
|
DataContainer detail1 = 5;
|
||||||
string data2 = 6;
|
string data2 = 6;
|
||||||
@@ -377,7 +377,7 @@ message RankTextMessage {
|
|||||||
// Links to Image-Files on the TikTok CDN
|
// Links to Image-Files on the TikTok CDN
|
||||||
message Picture {
|
message Picture {
|
||||||
repeated string urls = 1; // Usually has 3 different urls with different sizes/extensions
|
repeated string urls = 1; // Usually has 3 different urls with different sizes/extensions
|
||||||
string prefix = 2; // uri
|
// string prefix = 2; // uri not working
|
||||||
uint32 data1 = 3;
|
uint32 data1 = 3;
|
||||||
uint32 data2 = 4;
|
uint32 data2 = 4;
|
||||||
string color = 5;
|
string color = 5;
|
||||||
@@ -414,13 +414,16 @@ message User {
|
|||||||
Picture profilePicture = 9; // Avatar
|
Picture profilePicture = 9; // Avatar
|
||||||
Picture picture720 = 10; // 720p
|
Picture picture720 = 10; // 720p
|
||||||
Picture picture1080 = 11; // 1080p
|
Picture picture1080 = 11; // 1080p
|
||||||
uint32 data2 = 15;
|
int32 status = 15;
|
||||||
uint64 data3 = 16;
|
int64 createTime = 16;
|
||||||
|
int64 modifyTime = 17;
|
||||||
|
int32 secret = 18;
|
||||||
|
string shareQrcodeUri = 19;
|
||||||
repeated Picture additionalPictures = 21;
|
repeated Picture additionalPictures = 21;
|
||||||
FollowerData followerData = 22;
|
FollowerData followerData = 22;
|
||||||
string userString1 = 23;
|
// string userString1 = 23;
|
||||||
UserRanking userRank1 = 25;
|
UserRanking userRank1 = 25;
|
||||||
string userString2 = 32;
|
// string userString2 = 32;
|
||||||
uint64 data4 = 37;
|
uint64 data4 = 37;
|
||||||
string uniqueId = 38; // @-ID for user
|
string uniqueId = 38; // @-ID for user
|
||||||
string data5 = 46;
|
string data5 = 46;
|
||||||
@@ -681,7 +684,7 @@ message WebcastGiftMessage {
|
|||||||
uint32 data11 = 34;
|
uint32 data11 = 34;
|
||||||
|
|
||||||
message GiftData1 {
|
message GiftData1 {
|
||||||
string data1 = 1;
|
// string data1 = 1; not working
|
||||||
uint32 data2 = 2;
|
uint32 data2 = 2;
|
||||||
uint32 data3 = 3;
|
uint32 data3 = 3;
|
||||||
}
|
}
|
||||||
@@ -749,8 +752,7 @@ message WebcastHourlyRankMessage {
|
|||||||
// Message related to Chat-moderation?
|
// Message related to Chat-moderation?
|
||||||
message WebcastImDeleteMessage {
|
message WebcastImDeleteMessage {
|
||||||
MessageHeader header = 1;
|
MessageHeader header = 1;
|
||||||
string data1 = 2;
|
bytes data = 3;
|
||||||
string data2 = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message WebcastInRoomBannerMessage {
|
message WebcastInRoomBannerMessage {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>TikTokLiveJava</artifactId>
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<version>1.0.0</version>
|
<version>0.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@@ -29,6 +29,23 @@
|
|||||||
<artifactId>protobuf-java</artifactId>
|
<artifactId>protobuf-java</artifactId>
|
||||||
<version>3.24.1</version>
|
<version>3.24.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>2.0.7</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.java-websocket</groupId>
|
||||||
|
<artifactId>Java-WebSocket</artifactId>
|
||||||
|
<version>1.5.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>2.0.7</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,45 +1,47 @@
|
|||||||
package io.github.jwdeveloper.tiktok;
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.events.objects.TikTokGift;
|
import io.github.jwdeveloper.tiktok.events.objects.TikTokGift;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.WebcastGiftMessage;
|
||||||
import io.github.jwdeveloper.tiktok.models.GiftId;
|
import io.github.jwdeveloper.tiktok.models.GiftId;
|
||||||
|
import io.github.jwdeveloper.tiktok.models.gifts.TikTokGiftInfo;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
public class TikTokGiftManager {
|
public class TikTokGiftManager implements GiftManager {
|
||||||
private Logger logger;
|
|
||||||
private ClientSettings clientSettings;
|
|
||||||
private TikTokApiService apiService;
|
|
||||||
private Map<Integer, TikTokGift> gifts;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private Map<GiftId, TikTokGift> activeGifts;
|
private final Map<Integer, TikTokGiftInfo> giftsInfo;
|
||||||
|
@Getter
|
||||||
|
private final Map<GiftId, TikTokGift> activeGifts;
|
||||||
|
|
||||||
public TikTokGiftManager(Logger logger, TikTokApiService apiService, ClientSettings clientSettings) {
|
public TikTokGiftManager() {
|
||||||
this.logger = logger;
|
giftsInfo = new HashMap<>();
|
||||||
this.clientSettings = clientSettings;
|
|
||||||
this.apiService = apiService;
|
|
||||||
this.gifts = new HashMap<>();
|
|
||||||
activeGifts = new HashMap<>();
|
activeGifts = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadGifts() {
|
public TikTokGift updateActiveGift(WebcastGiftMessage giftMessage) {
|
||||||
if (!clientSettings.isDownloadGiftInfo()) {
|
var giftId = new GiftId(giftMessage.getGiftId(), giftMessage.getSender().getUniqueId());
|
||||||
return;
|
if (activeGifts.containsKey(giftId)) {
|
||||||
|
var gift = activeGifts.get(giftId);
|
||||||
|
gift.setAmount(giftMessage.getAmount());
|
||||||
|
} else {
|
||||||
|
var newGift = new TikTokGift(giftMessage);
|
||||||
|
activeGifts.put(giftId, newGift);
|
||||||
}
|
}
|
||||||
logger.info("Fetching gifts");
|
|
||||||
//TODO gifts =apiService.fetchAvailableGifts();
|
var gift = activeGifts.get(giftId);
|
||||||
|
|
||||||
|
if (giftMessage.getRepeatEnd()) {
|
||||||
|
gift.setStreakFinished(true);
|
||||||
|
activeGifts.remove(giftId);
|
||||||
|
}
|
||||||
|
return gift;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TikTokGift> getGifts()
|
public void loadGifsInfo(Map<Integer, TikTokGiftInfo> gifts) {
|
||||||
{
|
this.giftsInfo.putAll(gifts);
|
||||||
return gifts.values().stream().toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,4 @@ public class TikTokLive
|
|||||||
{
|
{
|
||||||
return new TikTokLiveClientBuilder(userName);
|
return new TikTokLiveClientBuilder(userName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +1,70 @@
|
|||||||
package io.github.jwdeveloper.tiktok;
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.events.messages.TikTokDisconnectedEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
||||||
import io.github.jwdeveloper.tiktok.live.ConnectionState;
|
import io.github.jwdeveloper.tiktok.live.ConnectionState;
|
||||||
|
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
|
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
|
||||||
import io.github.jwdeveloper.tiktok.live.TikTokRoomInfo;
|
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
|
||||||
import io.github.jwdeveloper.tiktok.websocket.TikTokWebsocketClient;
|
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class TikTokLiveClient implements LiveClient {
|
public class TikTokLiveClient implements LiveClient {
|
||||||
private final TikTokRoomInfo meta;
|
private final TikTokRoomInfo liveRoomInfo;
|
||||||
private final TikTokGiftManager giftManager;
|
private final TikTokGiftManager tikTokGiftManager;
|
||||||
private final TikTokApiService apiClient;
|
private final TikTokApiService apiClient;
|
||||||
private final TikTokWebsocketClient webSocketClient;
|
private final TikTokWebSocketClient webSocketClient;
|
||||||
private final TikTokEventHandler tikTokEventHandler;
|
private final TikTokEventHandler tikTokEventHandler;
|
||||||
|
private final ClientSettings clientSettings;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
|
|
||||||
|
|
||||||
public TikTokLiveClient(TikTokRoomInfo tikTokLiveMeta,
|
public TikTokLiveClient(TikTokRoomInfo tikTokLiveMeta,
|
||||||
TikTokApiService tikTokApiService,
|
TikTokApiService tikTokApiService,
|
||||||
TikTokWebsocketClient webSocketClient,
|
TikTokWebSocketClient webSocketClient,
|
||||||
TikTokGiftManager tikTokGiftManager,
|
TikTokGiftManager tikTokGiftManager,
|
||||||
TikTokEventHandler tikTokEventHandler,
|
TikTokEventHandler tikTokEventHandler,
|
||||||
|
ClientSettings clientSettings,
|
||||||
Logger logger) {
|
Logger logger) {
|
||||||
this.meta = tikTokLiveMeta;
|
this.liveRoomInfo = tikTokLiveMeta;
|
||||||
this.giftManager = tikTokGiftManager;
|
this.tikTokGiftManager = tikTokGiftManager;
|
||||||
this.apiClient = tikTokApiService;
|
this.apiClient = tikTokApiService;
|
||||||
this.webSocketClient = webSocketClient;
|
this.webSocketClient = webSocketClient;
|
||||||
this.logger = logger;
|
|
||||||
this.tikTokEventHandler = tikTokEventHandler;
|
this.tikTokEventHandler = tikTokEventHandler;
|
||||||
|
this.clientSettings = clientSettings;
|
||||||
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void connect() {
|
public void connect() {
|
||||||
try {
|
try {
|
||||||
tryConnect();
|
tryConnect();
|
||||||
} catch (Exception e) {
|
}
|
||||||
e.printStackTrace();
|
catch (TikTokLiveException e)
|
||||||
|
{
|
||||||
setState(ConnectionState.DISCONNECTED);
|
setState(ConnectionState.DISCONNECTED);
|
||||||
|
tikTokEventHandler.publish(this, new TikTokErrorEvent(e));
|
||||||
|
tikTokEventHandler.publish(this, new TikTokDisconnectedEvent());
|
||||||
|
|
||||||
|
if(e instanceof TikTokLiveOfflineHostException && clientSettings.isRetryOnConnectionFailure())
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Thread.sleep(clientSettings.getRetryConnectionTimeout().toMillis());
|
||||||
|
}
|
||||||
|
catch (Exception ignored){}
|
||||||
|
logger.info("Reconnecting");
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
if (!meta.hasConnectionState(ConnectionState.CONNECTED)) {
|
if (!liveRoomInfo.hasConnectionState(ConnectionState.CONNECTED)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
webSocketClient.stop();
|
webSocketClient.stop();
|
||||||
@@ -55,40 +72,48 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void tryConnect() {
|
public void tryConnect() {
|
||||||
if (meta.hasConnectionState(ConnectionState.CONNECTED))
|
if (liveRoomInfo.hasConnectionState(ConnectionState.CONNECTED))
|
||||||
throw new RuntimeException("Already connected");
|
throw new TikTokLiveException("Already connected");
|
||||||
if (meta.hasConnectionState(ConnectionState.CONNECTING))
|
if (liveRoomInfo.hasConnectionState(ConnectionState.CONNECTING))
|
||||||
throw new RuntimeException("Already connecting");
|
throw new TikTokLiveException("Already connecting");
|
||||||
|
|
||||||
logger.info("Connecting");
|
logger.info("Connecting");
|
||||||
setState(ConnectionState.CONNECTING);
|
setState(ConnectionState.CONNECTING);
|
||||||
|
|
||||||
var roomId = apiClient.fetchRoomId(meta.getUserName());
|
var roomId = apiClient.fetchRoomId(liveRoomInfo.getUserName());
|
||||||
meta.setRoomId(roomId);
|
liveRoomInfo.setRoomId(roomId);
|
||||||
var roomData =apiClient.fetchRoomInfo();
|
var roomData = apiClient.fetchRoomInfo();
|
||||||
if (roomData.getStatus() == 0 || roomData.getStatus() == 4)
|
if (roomData.getStatus() == 0 || roomData.getStatus() == 4) {
|
||||||
{
|
throw new TikTokLiveOfflineHostException("LiveStream for HostID could not be found. Is the Host online?");
|
||||||
throw new TikTokLiveException("LiveStream for HostID could not be found. Is the Host online?");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// giftManager.loadGifts();
|
if (clientSettings.isDownloadGiftInfo())
|
||||||
|
{
|
||||||
|
logger.info("Fetch Gift info");
|
||||||
|
var gifts = apiClient.fetchAvailableGifts();
|
||||||
|
tikTokGiftManager.loadGifsInfo(gifts);
|
||||||
|
}
|
||||||
var clientData = apiClient.fetchClientData();
|
var clientData = apiClient.fetchClientData();
|
||||||
webSocketClient.start(clientData);
|
webSocketClient.start(clientData, this);
|
||||||
setState(ConnectionState.CONNECTED);
|
setState(ConnectionState.CONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public LiveRoomInfo getRoomInfo() {
|
public LiveRoomInfo getRoomInfo() {
|
||||||
return meta;
|
return liveRoomInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GiftManager getGiftManager() {
|
||||||
|
return tikTokGiftManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void setState(ConnectionState connectionState) {
|
private void setState(ConnectionState connectionState) {
|
||||||
logger.info("TikTokLive client state: " + connectionState.name());
|
logger.info("TikTokLive client state: " + connectionState.name());
|
||||||
meta.setConnectionState(connectionState);
|
liveRoomInfo.setConnectionState(connectionState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,114 +2,88 @@ package io.github.jwdeveloper.tiktok;
|
|||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.events.TikTokEventBuilder;
|
import io.github.jwdeveloper.tiktok.events.TikTokEventBuilder;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
import io.github.jwdeveloper.tiktok.events.TikTokEventConsumer;
|
||||||
import io.github.jwdeveloper.tiktok.events.messages.*;
|
import io.github.jwdeveloper.tiktok.events.messages.*;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.WebResponseHandler;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpApiClient;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpApiClient;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.live.TikTokRoomInfo;
|
import io.github.jwdeveloper.tiktok.utils.CancelationToken;
|
||||||
import io.github.jwdeveloper.tiktok.websocket.TikTokWebsocketClient;
|
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveClientBuilder> {
|
public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveClientBuilder> {
|
||||||
private String userName;
|
|
||||||
private final ClientSettings clientSettings;
|
private final ClientSettings clientSettings;
|
||||||
private Map<String, Object> clientParameters;
|
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final TikTokEventHandler tikTokEventHandler;
|
private final TikTokEventHandler tikTokEventHandler;
|
||||||
|
|
||||||
public TikTokLiveClientBuilder(String userName) {
|
public TikTokLiveClientBuilder(String userName) {
|
||||||
this.tikTokEventHandler = new TikTokEventHandler();
|
this.tikTokEventHandler = new TikTokEventHandler();
|
||||||
this.userName = userName;
|
|
||||||
this.clientSettings = Constants.DefaultClientSettings();
|
this.clientSettings = Constants.DefaultClientSettings();
|
||||||
this.clientParameters = Constants.DefaultClientParams();
|
this.clientSettings.setHostName(userName);
|
||||||
this.logger = Logger.getLogger(TikTokLive.class.getName());
|
this.logger = Logger.getLogger(TikTokLive.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> consumer) {
|
||||||
|
|
||||||
|
|
||||||
public TikTokLiveClientBuilder clientSettings(Consumer<ClientSettings> consumer) {
|
|
||||||
consumer.accept(clientSettings);
|
consumer.accept(clientSettings);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder hostUserName(String userName) {
|
|
||||||
this.userName = userName;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokLiveClientBuilder clientParameters(Map<String, Object> clientParameters) {
|
|
||||||
this.clientParameters = clientParameters;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokLiveClientBuilder addClientParameters(String key, Object value) {
|
|
||||||
this.clientParameters.put(key, value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validate() {
|
private void validate() {
|
||||||
|
|
||||||
if (clientSettings.getTimeout() == null) {
|
if (clientSettings.getTimeout() == null) {
|
||||||
clientSettings.setTimeout(Duration.ofSeconds(Constants.DEFAULT_TIMEOUT));
|
clientSettings.setTimeout(Duration.ofSeconds(Constants.DEFAULT_TIMEOUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientSettings.getPollingInterval() == null) {
|
|
||||||
clientSettings.setPollingInterval(Duration.ofSeconds(Constants.DEFAULT_POLLTIME));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clientSettings.getClientLanguage() == null || clientSettings.getClientLanguage().equals("")) {
|
if (clientSettings.getClientLanguage() == null || clientSettings.getClientLanguage().equals("")) {
|
||||||
clientSettings.setClientLanguage(Constants.DefaultClientSettings().getClientLanguage());
|
clientSettings.setClientLanguage(Constants.DefaultClientSettings().getClientLanguage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientSettings.getSocketBufferSize() < 500_000) {
|
|
||||||
clientSettings.setSocketBufferSize(Constants.DefaultClientSettings().getSocketBufferSize());
|
if (clientSettings.getHostName() == null || clientSettings.getHostName().equals("")) {
|
||||||
|
throw new TikTokLiveException("HostName can not be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var params = clientSettings.getClientParameters();
|
||||||
|
params.put("app_language", clientSettings.getClientLanguage());
|
||||||
|
params.put("webcast_language", clientSettings.getClientLanguage());
|
||||||
|
|
||||||
if (userName == null || userName.equals("")) {
|
logger.setLevel(clientSettings.getLogLevel());
|
||||||
throw new RuntimeException("UserName can not be null");
|
|
||||||
|
if(clientSettings.isPrintToConsole() && clientSettings.getLogLevel() == Level.OFF)
|
||||||
|
{
|
||||||
|
logger.setLevel(Level.ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientParameters == null) {
|
|
||||||
clientParameters = Constants.DefaultClientParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
clientParameters.put("app_language", clientSettings.getClientLanguage());
|
|
||||||
clientParameters.put("webcast_language", clientSettings.getClientLanguage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveClient build() {
|
public LiveClient build() {
|
||||||
validate();
|
validate();
|
||||||
|
|
||||||
|
|
||||||
var meta = new TikTokRoomInfo();
|
var tiktokRoomInfo = new TikTokRoomInfo();
|
||||||
meta.setUserName(userName);
|
tiktokRoomInfo.setUserName(clientSettings.getHostName());
|
||||||
|
|
||||||
|
|
||||||
var cookieJar = new TikTokCookieJar();
|
var cookieJar = new TikTokCookieJar();
|
||||||
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
|
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
|
||||||
var apiClient = new TikTokHttpApiClient(cookieJar, clientSettings, requestFactory);
|
var apiClient = new TikTokHttpApiClient(cookieJar, requestFactory);
|
||||||
var apiService = new TikTokApiService(apiClient, logger, clientParameters);
|
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
|
||||||
var giftManager = new TikTokGiftManager(logger, apiService, clientSettings);
|
var giftManager = new TikTokGiftManager();
|
||||||
var webResponseHandler = new WebResponseHandler(tikTokEventHandler,giftManager);
|
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler, clientSettings, logger, giftManager, tiktokRoomInfo);
|
||||||
var webSocketClient = new TikTokWebsocketClient(logger,
|
var webSocketClient = new TikTokWebSocketClient(logger,
|
||||||
cookieJar,
|
cookieJar,
|
||||||
clientParameters,
|
|
||||||
requestFactory,
|
|
||||||
clientSettings,
|
clientSettings,
|
||||||
webResponseHandler,
|
webResponseHandler,
|
||||||
tikTokEventHandler);
|
tikTokEventHandler);
|
||||||
|
|
||||||
return new TikTokLiveClient(meta, apiService, webSocketClient, giftManager, tikTokEventHandler, logger);
|
return new TikTokLiveClient(tiktokRoomInfo, apiService, webSocketClient, giftManager, tikTokEventHandler, clientSettings, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveClient buildAndRun() {
|
public LiveClient buildAndRun() {
|
||||||
@@ -118,214 +92,236 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onUnhandledSocial(Consumer<TikTokUnhandledSocialEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokUnhandledSocialEvent.class,event);
|
public TikTokLiveClientBuilder onUnhandledSocial(
|
||||||
|
TikTokEventConsumer<TikTokUnhandledSocialEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokUnhandledSocialEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkMicFanTicket(Consumer<TikTokLinkMicFanTicketEvent> event) {
|
public TikTokLiveClientBuilder onLinkMicFanTicket(
|
||||||
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class,event);
|
TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onEnvelope(Consumer<TikTokEnvelopeEvent> event) {
|
public TikTokLiveClientBuilder onEnvelope(TikTokEventConsumer<TikTokEnvelopeEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokEnvelopeEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokEnvelopeEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onShopMessage(Consumer<TikTokShopMessageEvent> event) {
|
public TikTokLiveClientBuilder onShopMessage(TikTokEventConsumer<TikTokShopMessageEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokShopMessageEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokShopMessageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onDetectMessage(Consumer<TikTokDetectMessageEvent> event) {
|
public TikTokLiveClientBuilder onDetectMessage(
|
||||||
tikTokEventHandler.subscribe(TikTokDetectMessageEvent.class,event);
|
TikTokEventConsumer<TikTokDetectMessageEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokDetectMessageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkLayerMessage(Consumer<TikTokLinkLayerMessageEvent> event) {
|
public TikTokLiveClientBuilder onLinkLayerMessage(
|
||||||
tikTokEventHandler.subscribe(TikTokLinkLayerMessageEvent.class,event);
|
TikTokEventConsumer<TikTokLinkLayerMessageEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokLinkLayerMessageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onConnected(Consumer<TikTokConnectedEvent> event) {
|
public TikTokLiveClientBuilder onConnected(TikTokEventConsumer<TikTokConnectedEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokConnectedEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokConnectedEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onCaption(Consumer<TikTokCaptionEvent> event) {
|
public TikTokLiveClientBuilder onCaption(TikTokEventConsumer<TikTokCaptionEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokCaptionEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokCaptionEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onQuestion(Consumer<TikTokQuestionEvent> event) {
|
public TikTokLiveClientBuilder onQuestion(TikTokEventConsumer<TikTokQuestionEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokQuestionEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokQuestionEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onRoomPinMessage(Consumer<TikTokRoomPinMessageEvent> event) {
|
public TikTokLiveClientBuilder onRoomPinMessage(
|
||||||
tikTokEventHandler.subscribe(TikTokRoomPinMessageEvent.class,event);
|
TikTokEventConsumer<TikTokRoomPinMessageEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokRoomPinMessageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onRoomMessage(Consumer<TikTokRoomMessageEvent> event) {
|
public TikTokLiveClientBuilder onRoomMessage(TikTokEventConsumer<TikTokRoomMessageEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokRoomMessageEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokRoomMessageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLivePaused(Consumer<TikTokLivePausedEvent> event) {
|
public TikTokLiveClientBuilder onLivePaused(TikTokEventConsumer<TikTokLivePausedEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokLivePausedEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokLivePausedEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLike(Consumer<TikTokLikeEvent> event) {
|
public TikTokLiveClientBuilder onLike(TikTokEventConsumer<TikTokLikeEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokLikeEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokLikeEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkMessage(Consumer<TikTokLinkMessageEvent> event) {
|
public TikTokLiveClientBuilder onLinkMessage(TikTokEventConsumer<TikTokLinkMessageEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokLinkMessageEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokLinkMessageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onBarrageMessage(Consumer<TikTokBarrageMessageEvent> event) {
|
public TikTokLiveClientBuilder onBarrageMessage(
|
||||||
tikTokEventHandler.subscribe(TikTokBarrageMessageEvent.class,event);
|
TikTokEventConsumer<TikTokBarrageMessageEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokBarrageMessageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onGiftMessage(Consumer<TikTokGiftMessageEvent> event) {
|
public TikTokLiveClientBuilder onGiftMessage(TikTokEventConsumer<TikTokGiftMessageEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokGiftMessageEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokGiftMessageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkMicArmies(Consumer<TikTokLinkMicArmiesEvent> event) {
|
public TikTokLiveClientBuilder onLinkMicArmies(
|
||||||
tikTokEventHandler.subscribe(TikTokLinkMicArmiesEvent.class,event);
|
TikTokEventConsumer<TikTokLinkMicArmiesEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokLinkMicArmiesEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onEmote(Consumer<TikTokEmoteEvent> event) {
|
public TikTokLiveClientBuilder onEmote(TikTokEventConsumer<TikTokEmoteEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokEmoteEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokEmoteEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onUnauthorizedMember(
|
public TikTokLiveClientBuilder onUnauthorizedMember(
|
||||||
Consumer<TikTokUnauthorizedMemberEvent> event) {
|
TikTokEventConsumer<TikTokUnauthorizedMemberEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokUnauthorizedMemberEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokUnauthorizedMemberEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onInRoomBanner(Consumer<TikTokInRoomBannerEvent> event) {
|
public TikTokLiveClientBuilder onInRoomBanner(
|
||||||
tikTokEventHandler.subscribe(TikTokInRoomBannerEvent.class,event);
|
TikTokEventConsumer<TikTokInRoomBannerEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokInRoomBannerEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkMicMethod(Consumer<TikTokLinkMicMethodEvent> event) {
|
public TikTokLiveClientBuilder onLinkMicMethod(
|
||||||
tikTokEventHandler.subscribe(TikTokLinkMicMethodEvent.class,event);
|
TikTokEventConsumer<TikTokLinkMicMethodEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokLinkMicMethodEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onSubscribe(Consumer<TikTokSubscribeEvent> event) {
|
public TikTokLiveClientBuilder onSubscribe(TikTokEventConsumer<TikTokSubscribeEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokSubscribeEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokSubscribeEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onPollMessage(Consumer<TikTokPollMessageEvent> event) {
|
public TikTokLiveClientBuilder onPollMessage(TikTokEventConsumer<TikTokPollMessageEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokPollMessageEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokPollMessageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onFollow(Consumer<TikTokFollowEvent> event) {
|
public TikTokLiveClientBuilder onFollow(TikTokEventConsumer<TikTokFollowEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokFollowEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokFollowEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onRoomViewerData(Consumer<TikTokRoomViewerDataEvent> event) {
|
public TikTokLiveClientBuilder onRoomViewerData(
|
||||||
tikTokEventHandler.subscribe(TikTokRoomViewerDataEvent.class,event);
|
TikTokEventConsumer<TikTokRoomViewerDataEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokRoomViewerDataEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onGoalUpdate(Consumer<TikTokGoalUpdateEvent> event) {
|
public TikTokLiveClientBuilder onGoalUpdate(TikTokEventConsumer<TikTokGoalUpdateEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokGoalUpdateEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokGoalUpdateEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onComment(Consumer<TikTokCommentEvent> event) {
|
public TikTokLiveClientBuilder onComment(TikTokEventConsumer<TikTokCommentEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokCommentEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokCommentEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onRankUpdate(Consumer<TikTokRankUpdateEvent> event) {
|
public TikTokLiveClientBuilder onRankUpdate(TikTokEventConsumer<TikTokRankUpdateEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokRankUpdateEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokRankUpdateEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onIMDelete(Consumer<TikTokIMDeleteEvent> event) {
|
public TikTokLiveClientBuilder onIMDelete(TikTokEventConsumer<TikTokIMDeleteEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokIMDeleteEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokIMDeleteEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLiveEnded(Consumer<TikTokLiveEndedEvent> event) {
|
public TikTokLiveClientBuilder onLiveEnded(TikTokEventConsumer<TikTokLiveEndedEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokLiveEndedEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokLiveEndedEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onError(Consumer<TikTokErrorEvent> event) {
|
public TikTokLiveClientBuilder onError(TikTokEventConsumer<TikTokErrorEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokErrorEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokErrorEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onUnhandled(Consumer<TikTokUnhandledEvent> event) {
|
public TikTokLiveClientBuilder onUnhandled(TikTokEventConsumer<TikTokUnhandledEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokUnhandledEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokUnhandledEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onJoin(Consumer<TikTokJoinEvent> event) {
|
public TikTokLiveClientBuilder onJoin(TikTokEventConsumer<TikTokJoinEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokJoinEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokJoinEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onRankText(Consumer<TikTokRankTextEvent> event) {
|
public TikTokLiveClientBuilder onRankText(TikTokEventConsumer<TikTokRankTextEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokRankTextEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokRankTextEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onShare(Consumer<TikTokShareEvent> event) {
|
public TikTokLiveClientBuilder onShare(TikTokEventConsumer<TikTokShareEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokShareEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokShareEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onUnhandledMember(Consumer<TikTokUnhandledMemberEvent> event) {
|
public TikTokLiveClientBuilder onUnhandledMember(
|
||||||
tikTokEventHandler.subscribe(TikTokUnhandledMemberEvent.class,event);
|
TikTokEventConsumer<TikTokUnhandledMemberEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokUnhandledMemberEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onSubNotify(Consumer<TikTokSubNotifyEvent> event) {
|
public TikTokLiveClientBuilder onSubNotify(TikTokEventConsumer<TikTokSubNotifyEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokSubNotifyEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokSubNotifyEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkMicBattle(Consumer<TikTokLinkMicBattleEvent> event) {
|
public TikTokLiveClientBuilder onLinkMicBattle(
|
||||||
tikTokEventHandler.subscribe(TikTokLinkMicBattleEvent.class,event);
|
TikTokEventConsumer<TikTokLinkMicBattleEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokLinkMicBattleEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onDisconnected(Consumer<TikTokDisconnectedEvent> event) {
|
public TikTokLiveClientBuilder onDisconnected(
|
||||||
tikTokEventHandler.subscribe(TikTokDisconnectedEvent.class,event);
|
TikTokEventConsumer<TikTokDisconnectedEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokDisconnectedEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onGiftBroadcast(Consumer<TikTokGiftBroadcastEvent> event) {
|
public TikTokLiveClientBuilder onGiftBroadcast(
|
||||||
tikTokEventHandler.subscribe(TikTokGiftBroadcastEvent.class,event);
|
TikTokEventConsumer<TikTokGiftBroadcastEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokGiftBroadcastEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onUnhandledControl(Consumer<TikTokUnhandledControlEvent> event) {
|
public TikTokLiveClientBuilder onUnhandledControl(
|
||||||
tikTokEventHandler.subscribe(TikTokUnhandledControlEvent.class,event);
|
TikTokEventConsumer<TikTokUnhandledControlEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokUnhandledControlEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onEvent(Consumer<TikTokEvent> event) {
|
public TikTokLiveClientBuilder onEvent(TikTokEventConsumer<TikTokEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokEvent.class,event);
|
tikTokEventHandler.subscribe(TikTokEvent.class, event);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TikTokLiveClientBuilder onWebsocketMessage(TikTokEventConsumer<TikTokWebsocketMessageEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokWebsocketMessageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,3 +329,6 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package io.github.jwdeveloper.tiktok.live;
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.live.ConnectionState;
|
||||||
|
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -1,40 +1,38 @@
|
|||||||
package io.github.jwdeveloper.tiktok.handlers;
|
package io.github.jwdeveloper.tiktok.handlers;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.events.TikTokEventConsumer;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class TikTokEventHandler {
|
public class TikTokEventHandler {
|
||||||
private final Map<String, Consumer> events;
|
private final Map<String, TikTokEventConsumer> events;
|
||||||
|
|
||||||
public TikTokEventHandler()
|
public TikTokEventHandler() {
|
||||||
{
|
|
||||||
events = new HashMap<>();
|
events = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void publish(TikTokEvent tikTokEvent)
|
public void publish(TikTokLiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
|
||||||
{
|
if (events.containsKey(TikTokEvent.class.getSimpleName())) {
|
||||||
if(events.containsKey(TikTokEvent.class.getSimpleName()))
|
|
||||||
{
|
|
||||||
var handler = events.get(TikTokEvent.class.getSimpleName());
|
var handler = events.get(TikTokEvent.class.getSimpleName());
|
||||||
handler.accept(tikTokEvent);
|
handler.onEvent(tikTokLiveClient, tikTokEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = tikTokEvent.getClass().getSimpleName();
|
var name = tikTokEvent.getClass().getSimpleName();
|
||||||
if(!events.containsKey(name))
|
if (!events.containsKey(name)) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var handler = events.get(name);
|
var handler = events.get(name);
|
||||||
handler.accept(tikTokEvent);
|
handler.onEvent(tikTokLiveClient, tikTokEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends TikTokEvent> void subscribe(Class<?> clazz, Consumer<T> event)
|
public <T extends TikTokEvent> void subscribe(Class<?> clazz, TikTokEventConsumer<T> event) {
|
||||||
{
|
events.put(clazz.getSimpleName(), event);
|
||||||
events.put(clazz.getSimpleName(),event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T extends TikTokEvent> void unsubscribe(Class<?> clazz) {
|
||||||
|
events.remove(clazz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,99 @@
|
|||||||
package io.github.jwdeveloper.tiktok.handlers;
|
package io.github.jwdeveloper.tiktok.handlers;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.protobuf.ByteString;
|
||||||
|
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.events.messages.TikTokWebsocketMessageEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.events.messages.TikTokUnhandledEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
|
||||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||||
|
|
||||||
public interface TikTokMessageHandler<T>
|
import java.util.Arrays;
|
||||||
{
|
import java.util.Base64;
|
||||||
Class<T> getHandleClazz();
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
TikTokEvent handle(WebcastResponse.Message message) throws Exception;
|
|
||||||
|
public abstract class TikTokMessageHandler {
|
||||||
|
|
||||||
|
private final Map<String, io.github.jwdeveloper.tiktok.handler.TikTokMessageHandler> handlers;
|
||||||
|
private final TikTokEventHandler tikTokEventHandler;
|
||||||
|
private final ClientSettings clientSettings;
|
||||||
|
protected final Logger logger;
|
||||||
|
|
||||||
|
public TikTokMessageHandler(TikTokEventHandler tikTokEventHandler,ClientSettings clientSettings, Logger logger) {
|
||||||
|
handlers = new HashMap<>();
|
||||||
|
this.tikTokEventHandler = tikTokEventHandler;
|
||||||
|
this.clientSettings = clientSettings;
|
||||||
|
this.logger = logger;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void init();
|
||||||
|
|
||||||
|
public void register(Class<?> clazz, Function<WebcastResponse.Message, TikTokEvent> func) {
|
||||||
|
handlers.put(clazz.getSimpleName(), func::apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(Class<?> input, Class<?> output) {
|
||||||
|
register(input, (e) -> mapMessageToEvent(input, output, e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(TikTokLiveClient client, WebcastResponse webcastResponse) {
|
||||||
|
for (var message : webcastResponse.getMessagesList()) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(clientSettings.isPrintMessageData())
|
||||||
|
{
|
||||||
|
var type= message.getType();
|
||||||
|
var base64 = Base64.getEncoder().encodeToString(message.getBinary().toByteArray());
|
||||||
|
logger.info(type+": \n "+base64);
|
||||||
|
}
|
||||||
|
handleSingleMessage(client, message);
|
||||||
|
} catch (Exception e) {
|
||||||
|
var exception = new TikTokLiveMessageException(message, webcastResponse, e);
|
||||||
|
tikTokEventHandler.publish(client, new TikTokErrorEvent(exception));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSingleMessage(TikTokLiveClient client, WebcastResponse.Message message) throws Exception {
|
||||||
|
if (!handlers.containsKey(message.getType())) {
|
||||||
|
tikTokEventHandler.publish(client, new TikTokUnhandledEvent(message));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var handler = handlers.get(message.getType());
|
||||||
|
var tiktokEvent = handler.handle(message);
|
||||||
|
tikTokEventHandler.publish(client, new TikTokWebsocketMessageEvent(tiktokEvent, message));
|
||||||
|
tikTokEventHandler.publish(client, tiktokEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TikTokEvent mapMessageToEvent(Class<?> inputClazz, Class<?> outputClass, WebcastResponse.Message message) {
|
||||||
|
try {
|
||||||
|
var parseMethod = inputClazz.getDeclaredMethod("parseFrom", ByteString.class);
|
||||||
|
var deserialized = parseMethod.invoke(null, message.getBinary());
|
||||||
|
|
||||||
|
var constructors = Arrays.stream(outputClass.getConstructors())
|
||||||
|
.filter(ea -> Arrays.stream(ea.getParameterTypes())
|
||||||
|
.toList()
|
||||||
|
.contains(inputClazz))
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if(constructors.isEmpty())
|
||||||
|
{
|
||||||
|
throw new TikTokMessageMappingException(inputClazz, outputClass, "Unable to find constructor with input class type");
|
||||||
|
}
|
||||||
|
|
||||||
|
var tiktokEvent = constructors.get().newInstance(deserialized);
|
||||||
|
return (TikTokEvent) tiktokEvent;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new TikTokMessageMappingException(inputClazz, outputClass, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package io.github.jwdeveloper.tiktok.handlers;
|
package io.github.jwdeveloper.tiktok.handlers;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||||
import io.github.jwdeveloper.tiktok.TikTokGiftManager;
|
import io.github.jwdeveloper.tiktok.TikTokGiftManager;
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||||
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.events.messages.*;
|
import io.github.jwdeveloper.tiktok.events.messages.*;
|
||||||
import io.github.jwdeveloper.tiktok.events.objects.TikTokGift;
|
import io.github.jwdeveloper.tiktok.events.objects.TikTokGift;
|
||||||
@@ -9,28 +11,35 @@ import io.github.jwdeveloper.tiktok.models.GiftId;
|
|||||||
import io.github.jwdeveloper.tiktok.models.SocialTypes;
|
import io.github.jwdeveloper.tiktok.models.SocialTypes;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class WebResponseHandler extends WebResponseHandlerBase {
|
public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
||||||
private final TikTokGiftManager giftManager;
|
private final TikTokGiftManager giftManager;
|
||||||
|
private final TikTokRoomInfo roomInfo;
|
||||||
|
|
||||||
public WebResponseHandler(TikTokEventHandler tikTokEventHandler, TikTokGiftManager giftManager) {
|
public TikTokMessageHandlerRegistration(TikTokEventHandler tikTokEventHandler,
|
||||||
super(tikTokEventHandler);
|
ClientSettings clientSettings,
|
||||||
|
Logger logger,
|
||||||
|
TikTokGiftManager giftManager,
|
||||||
|
TikTokRoomInfo roomInfo) {
|
||||||
|
super(tikTokEventHandler, clientSettings, logger);
|
||||||
this.giftManager = giftManager;
|
this.giftManager = giftManager;
|
||||||
|
this.roomInfo = roomInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
||||||
//ConnectionEvents events
|
//ConnectionEvents events
|
||||||
register(WebcastControlMessage.class, TikTokRoomMessageEvent.class);
|
register(WebcastControlMessage.class, this::handleWebcastControlMessage);
|
||||||
register(SystemMessage.class, this::handleWebcastControlMessage);
|
register(SystemMessage.class,TikTokRoomMessageEvent.class);
|
||||||
|
|
||||||
|
|
||||||
//Room status events
|
//Room status events
|
||||||
register(WebcastLiveIntroMessage.class, TikTokRoomMessageEvent.class);
|
register(WebcastLiveIntroMessage.class, TikTokRoomMessageEvent.class);
|
||||||
register(WebcastRoomUserSeqMessage.class, TikTokRoomViewerDataEvent.class); //TODO update viewer count ViewerCount = userSeqMessage.ViewerCount;
|
register(WebcastRoomUserSeqMessage.class, this::handleRoomUserSeqMessage);
|
||||||
register(RoomMessage.class, TikTokRoomMessageEvent.class);
|
register(RoomMessage.class, TikTokRoomMessageEvent.class);
|
||||||
register(WebcastRoomMessage.class, TikTokRoomMessageEvent.class);
|
register(WebcastRoomMessage.class, TikTokRoomMessageEvent.class);
|
||||||
register(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
|
register(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
|
||||||
@@ -74,9 +83,9 @@ public class WebResponseHandler extends WebResponseHandlerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private TikTokEvent handleWebcastControlMessage(WebcastResponse.Message msg)
|
private TikTokEvent handleWebcastControlMessage(WebcastResponse.Message msg) {
|
||||||
{
|
|
||||||
var message = WebcastControlMessage.parseFrom(msg.getBinary());
|
var message = WebcastControlMessage.parseFrom(msg.getBinary());
|
||||||
return switch (message.getAction()) {
|
return switch (message.getAction()) {
|
||||||
case STREAM_PAUSED -> new TikTokLivePausedEvent();
|
case STREAM_PAUSED -> new TikTokLivePausedEvent();
|
||||||
@@ -88,29 +97,7 @@ public class WebResponseHandler extends WebResponseHandlerBase {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private TikTokEvent handleGift(WebcastResponse.Message msg) {
|
private TikTokEvent handleGift(WebcastResponse.Message msg) {
|
||||||
var giftMessage = WebcastGiftMessage.parseFrom(msg.getBinary());
|
var giftMessage = WebcastGiftMessage.parseFrom(msg.getBinary());
|
||||||
var giftId = new GiftId(giftMessage.getGiftId(), giftMessage.getSender().getUniqueId());
|
giftManager.updateActiveGift(giftMessage);
|
||||||
|
|
||||||
var activeGifts = giftManager.getActiveGifts();
|
|
||||||
if (activeGifts.containsKey(giftId)) {
|
|
||||||
// Debug.Log($"Updating Gift[{giftId.Gift}]Amount[{message.Amount}]");
|
|
||||||
var gift = activeGifts.get(giftId);
|
|
||||||
gift.setAmount(giftMessage.getAmount());
|
|
||||||
} else {
|
|
||||||
TikTokGift newGift = new TikTokGift(giftMessage);
|
|
||||||
activeGifts.put(giftId, newGift);
|
|
||||||
// Debug.Log($"New Gift[{giftId.Gift}]Amount[{message.Amount}]");
|
|
||||||
// RunEvent(OnGift, newGift);
|
|
||||||
}
|
|
||||||
if (giftMessage.getRepeatEnd()) {
|
|
||||||
//if (ShouldLog(LogLevel.Verbose))
|
|
||||||
// Debug.Log($"GiftStreak Ended: [{giftId.Gift}] Amount[{message.Amount}]")
|
|
||||||
var gift = activeGifts.get(giftId);
|
|
||||||
gift.setStreakFinished(true);
|
|
||||||
activeGifts.remove(gift);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug.Log($"Handling GiftMessage");
|
|
||||||
|
|
||||||
return new TikTokGiftMessageEvent(giftMessage);
|
return new TikTokGiftMessageEvent(giftMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,16 +105,18 @@ public class WebResponseHandler extends WebResponseHandlerBase {
|
|||||||
private TikTokEvent handleSocialMedia(WebcastResponse.Message msg) {
|
private TikTokEvent handleSocialMedia(WebcastResponse.Message msg) {
|
||||||
var message = WebcastSocialMessage.parseFrom(msg.getBinary());
|
var message = WebcastSocialMessage.parseFrom(msg.getBinary());
|
||||||
|
|
||||||
String type = message.getHeader().getSocialData().getType();
|
var socialType = message.getHeader().getSocialData().getType();
|
||||||
Pattern pattern = Pattern.compile("pm_mt_guidance_viewer_([0-9]+)_share");
|
var pattern = Pattern.compile("pm_mt_guidance_viewer_([0-9]+)_share");
|
||||||
Matcher matcher = pattern.matcher(type);
|
var matcher = pattern.matcher(socialType);
|
||||||
if (matcher.find()) {
|
|
||||||
|
if (matcher.find())
|
||||||
|
{
|
||||||
var value = matcher.group(0);
|
var value = matcher.group(0);
|
||||||
var number = Integer.parseInt(value);
|
var number = Integer.parseInt(value);
|
||||||
return new TikTokShareEvent(message, number);
|
return new TikTokShareEvent(message, number);
|
||||||
}
|
}
|
||||||
|
|
||||||
var socialType = message.getHeader().getSocialData().getType();
|
|
||||||
return switch (socialType) {
|
return switch (socialType) {
|
||||||
case SocialTypes.LikeType -> new TikTokLikeEvent(message);
|
case SocialTypes.LikeType -> new TikTokLikeEvent(message);
|
||||||
case SocialTypes.FollowType -> new TikTokFollowEvent(message);
|
case SocialTypes.FollowType -> new TikTokFollowEvent(message);
|
||||||
@@ -146,4 +135,11 @@ public class WebResponseHandler extends WebResponseHandlerBase {
|
|||||||
default -> new TikTokUnhandledMemberEvent(message);
|
default -> new TikTokUnhandledMemberEvent(message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TikTokEvent handleRoomUserSeqMessage(WebcastResponse.Message msg)
|
||||||
|
{
|
||||||
|
var event = (TikTokRoomViewerDataEvent)mapMessageToEvent(WebcastRoomUserSeqMessage.class, TikTokRoomViewerDataEvent.class, msg);
|
||||||
|
roomInfo.setViewersCount(event.getViewerCount());
|
||||||
|
return event;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
package io.github.jwdeveloper.tiktok.handlers;
|
|
||||||
|
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
|
||||||
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.events.messages.TikTokUnhandledEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageParsingException;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class WebResponseHandlerBase {
|
|
||||||
|
|
||||||
private final Map<String, TikTokMessageHandler> handlers;
|
|
||||||
private final TikTokEventHandler tikTokEventHandler;
|
|
||||||
|
|
||||||
public WebResponseHandlerBase(TikTokEventHandler tikTokEventHandler) {
|
|
||||||
handlers = new HashMap<>();
|
|
||||||
this.tikTokEventHandler = tikTokEventHandler;
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void init();
|
|
||||||
|
|
||||||
public void register(Class<?> input, Class<?> output) {
|
|
||||||
register(input, (e) ->
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
var parseMethod = input.getDeclaredMethod("parseFrom", ByteString.class);
|
|
||||||
var deserialized = parseMethod.invoke(null, e.getBinary());
|
|
||||||
|
|
||||||
var constructors = Arrays.stream(output.getConstructors()).filter(ea -> Arrays.stream(ea.getParameterTypes()).toList().contains(input)).findFirst();
|
|
||||||
|
|
||||||
var tiktokEvent = constructors.get().newInstance(deserialized);
|
|
||||||
return (TikTokEvent)tiktokEvent;
|
|
||||||
} catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new TikTokLiveMessageParsingException("Unable to handle parsing from class: " + input.getSimpleName() + " to class " + output.getSimpleName(), ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> void register(Class clazz, Function<WebcastResponse.Message, TikTokEvent> func) {
|
|
||||||
var haandler = new TikTokMessageHandler<T>() {
|
|
||||||
@Override
|
|
||||||
public Class<T> getHandleClazz() {
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TikTokEvent handle(WebcastResponse.Message message) throws Exception {
|
|
||||||
return func.apply(message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handlers.put(haandler.getHandleClazz().getSimpleName(), haandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handle(WebcastResponse webcastResponse) {
|
|
||||||
for (var message : webcastResponse.getMessagesList()) {
|
|
||||||
try {
|
|
||||||
handleSingleMessage(message);
|
|
||||||
} catch (Exception e)
|
|
||||||
{
|
|
||||||
var decoded = Base64.getEncoder().encodeToString(message.getBinary().toByteArray());
|
|
||||||
|
|
||||||
var exception = new TikTokLiveException("Error whilst Handling Message. Stopping Client. Final Message: \n"+decoded, e);
|
|
||||||
tikTokEventHandler.publish(new TikTokErrorEvent(exception));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleSingleMessage(WebcastResponse.Message message) throws Exception {
|
|
||||||
if (!handlers.containsKey(message.getType())) {
|
|
||||||
tikTokEventHandler.publish(new TikTokUnhandledEvent(message));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var handler = handlers.get(message.getType());
|
|
||||||
var tiktokEvent = handler.handle(message);
|
|
||||||
tikTokEventHandler.publish(tiktokEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -44,8 +44,8 @@ public class HttpUtils
|
|||||||
builder.append("&");
|
builder.append("&");
|
||||||
}
|
}
|
||||||
|
|
||||||
final String encodedKey = URLEncoder.encode(param.getKey().toString(), StandardCharsets.UTF_8.toString());
|
final String encodedKey = URLEncoder.encode(param.getKey(), StandardCharsets.UTF_8);
|
||||||
final String encodedValue = URLEncoder.encode(param.getValue().toString(), StandardCharsets.UTF_8.toString());
|
final String encodedValue = URLEncoder.encode(param.getValue().toString(), StandardCharsets.UTF_8);
|
||||||
builder.append(encodedKey).append("=").append(encodedValue);
|
builder.append(encodedKey).append("=").append(encodedValue);
|
||||||
first = true;
|
first = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package io.github.jwdeveloper.tiktok.http;
|
package io.github.jwdeveloper.tiktok.http;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
|
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
|
||||||
import io.github.jwdeveloper.tiktok.models.gifts.TikTokGift;
|
import io.github.jwdeveloper.tiktok.models.gifts.TikTokGiftInfo;
|
||||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -15,12 +17,12 @@ import java.util.regex.Pattern;
|
|||||||
public class TikTokApiService {
|
public class TikTokApiService {
|
||||||
private final TikTokHttpApiClient apiClient;
|
private final TikTokHttpApiClient apiClient;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final Map<String, Object> clientParams;
|
private final ClientSettings clientSettings;
|
||||||
|
|
||||||
public TikTokApiService(TikTokHttpApiClient apiClient, Logger logger, Map<String, Object> clientParams) {
|
public TikTokApiService(TikTokHttpApiClient apiClient, Logger logger, ClientSettings clientSettings) {
|
||||||
this.apiClient = apiClient;
|
this.apiClient = apiClient;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.clientParams = clientParams;
|
this.clientSettings = clientSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String fetchRoomId(String userName) {
|
public String fetchRoomId(String userName) {
|
||||||
@@ -29,7 +31,7 @@ public class TikTokApiService {
|
|||||||
try {
|
try {
|
||||||
html = apiClient.GetLivestreamPage(userName);
|
html = apiClient.GetLivestreamPage(userName);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
|
throw new TikTokLiveRequestException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern firstPattern = Pattern.compile("room_id=([0-9]*)");
|
Pattern firstPattern = Pattern.compile("room_id=([0-9]*)");
|
||||||
@@ -48,10 +50,10 @@ public class TikTokApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (id.isEmpty()) {
|
if (id.isEmpty()) {
|
||||||
throw new TikTokLiveException("Unable to fetch room ID");
|
throw new TikTokLiveOfflineHostException("Unable to fetch room ID, live host could be offline or name is misspelled");
|
||||||
}
|
}
|
||||||
|
|
||||||
clientParams.put("room_id", id);
|
clientSettings.getClientParameters().put("room_id", id);
|
||||||
logger.info("RoomID -> "+id);
|
logger.info("RoomID -> "+id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@@ -60,7 +62,7 @@ public class TikTokApiService {
|
|||||||
public LiveRoomMeta fetchRoomInfo() {
|
public LiveRoomMeta fetchRoomInfo() {
|
||||||
logger.info("Fetch RoomInfo");
|
logger.info("Fetch RoomInfo");
|
||||||
try {
|
try {
|
||||||
var response = apiClient.GetJObjectFromWebcastAPI("room/info/", clientParams);
|
var response = apiClient.GetJObjectFromWebcastAPI("room/info/", clientSettings.getClientParameters());
|
||||||
if (!response.has("data")) {
|
if (!response.has("data")) {
|
||||||
return new LiveRoomMeta();
|
return new LiveRoomMeta();
|
||||||
}
|
}
|
||||||
@@ -78,7 +80,7 @@ public class TikTokApiService {
|
|||||||
logger.info("RoomInfo status -> "+info.getStatus());
|
logger.info("RoomInfo status -> "+info.getStatus());
|
||||||
return info;
|
return info;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TikTokLiveException("Failed to fetch room info from WebCast, see stacktrace for more info.", e);
|
throw new TikTokLiveRequestException("Failed to fetch room info from WebCast, see stacktrace for more info.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,20 +88,20 @@ public class TikTokApiService {
|
|||||||
{
|
{
|
||||||
logger.info("Fetch ClientData");
|
logger.info("Fetch ClientData");
|
||||||
try {
|
try {
|
||||||
var response = apiClient.GetDeserializedMessage("im/fetch/", clientParams);
|
var response = apiClient.GetDeserializedMessage("im/fetch/", clientSettings.getClientParameters());
|
||||||
clientParams.put("cursor",response.getCursor());
|
clientSettings.getClientParameters().put("cursor",response.getCursor());
|
||||||
clientParams.put("internal_ext", response.getAckIds());
|
clientSettings.getClientParameters().put("internal_ext", response.getAckIds());
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
throw new TikTokLiveException("Failed to fetch client data", e);
|
throw new TikTokLiveRequestException("Failed to fetch client data", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, TikTokGift> fetchAvailableGifts() {
|
public Map<Integer, TikTokGiftInfo> fetchAvailableGifts() {
|
||||||
try {
|
try {
|
||||||
var response = apiClient.GetJObjectFromWebcastAPI("gift/list/", clientParams);
|
var response = apiClient.GetJObjectFromWebcastAPI("gift/list/", clientSettings.getClientParameters());
|
||||||
if(!response.has("data"))
|
if(!response.has("data"))
|
||||||
{
|
{
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
@@ -110,17 +112,17 @@ public class TikTokApiService {
|
|||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
}
|
}
|
||||||
var giftsJsonList = dataJson.get("gifts").getAsJsonArray();
|
var giftsJsonList = dataJson.get("gifts").getAsJsonArray();
|
||||||
var gifts = new HashMap<Integer, TikTokGift>();
|
var gifts = new HashMap<Integer, TikTokGiftInfo>();
|
||||||
var gson = new Gson();
|
var gson = new Gson();
|
||||||
for(var jsonGift : giftsJsonList)
|
for(var jsonGift : giftsJsonList)
|
||||||
{
|
{
|
||||||
var gift = gson.fromJson(jsonGift, TikTokGift.class);
|
var gift = gson.fromJson(jsonGift, TikTokGiftInfo.class);
|
||||||
logger.info("Found Available Gift "+ gift.getName()+ " with ID "+gift.getId());
|
logger.info("Found Available Gift "+ gift.getName()+ " with ID "+gift.getId());
|
||||||
gifts.put(gift.getId(),gift);
|
gifts.put(gift.getId(),gift);
|
||||||
}
|
}
|
||||||
return gifts;
|
return gifts;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TikTokLiveException("Failed to fetch giftTokens from WebCast, see stacktrace for more info.", e);
|
throw new TikTokLiveRequestException("Failed to fetch giftTokens from WebCast, see stacktrace for more info.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import com.google.gson.JsonObject;
|
|||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import io.github.jwdeveloper.tiktok.ClientSettings;
|
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||||
import io.github.jwdeveloper.tiktok.Constants;
|
import io.github.jwdeveloper.tiktok.Constants;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@@ -16,27 +16,23 @@ import java.util.Map;
|
|||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
public class TikTokHttpApiClient {
|
public class TikTokHttpApiClient {
|
||||||
private final ClientSettings clientSettings;
|
|
||||||
private final TikTokHttpRequestFactory requestFactory;
|
private final TikTokHttpRequestFactory requestFactory;
|
||||||
private final TikTokCookieJar tikTokCookieJar;
|
private final TikTokCookieJar tikTokCookieJar;
|
||||||
|
|
||||||
|
public TikTokHttpApiClient(TikTokCookieJar tikTokCookieJar, TikTokHttpRequestFactory requestFactory) {
|
||||||
public TikTokHttpApiClient(TikTokCookieJar tikTokCookieJar, ClientSettings clientSettings, TikTokHttpRequestFactory requestFactory) {
|
|
||||||
this.clientSettings = clientSettings;
|
|
||||||
this.requestFactory = requestFactory;
|
this.requestFactory = requestFactory;
|
||||||
this.tikTokCookieJar = tikTokCookieJar;
|
this.tikTokCookieJar = tikTokCookieJar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String GetLivestreamPage(String userName) {
|
public String GetLivestreamPage(String userName) {
|
||||||
|
|
||||||
var url = Constants.TIKTOK_URL_WEB + "@" + userName + "/live/";
|
var url = Constants.TIKTOK_URL_WEB + "@" + userName + "/live/";
|
||||||
var get = getRequest(url, null, false);
|
var get = getRequest(url, null);
|
||||||
return get;
|
return get;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonObject GetJObjectFromWebcastAPI(String path, Map<String, Object> parameters) {
|
public JsonObject GetJObjectFromWebcastAPI(String path, Map<String, Object> parameters) {
|
||||||
var get = getRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters, false);
|
var get = getRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
|
||||||
var json = JsonParser.parseString(get);
|
var json = JsonParser.parseString(get);
|
||||||
var jsonObject = json.getAsJsonObject();
|
var jsonObject = json.getAsJsonObject();
|
||||||
return jsonObject;
|
return jsonObject;
|
||||||
@@ -49,12 +45,11 @@ public class TikTokHttpApiClient {
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
throw new TikTokLiveException("Unable to deserialize message: "+path,e);
|
throw new TikTokLiveRequestException("Unable to deserialize message: "+path,e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getRequest(String url, Map<String, Object> parameters) {
|
||||||
private String getRequest(String url, Map<String, Object> parameters, boolean signURL) {
|
|
||||||
if (parameters == null) {
|
if (parameters == null) {
|
||||||
parameters = new HashMap<>();
|
parameters = new HashMap<>();
|
||||||
}
|
}
|
||||||
@@ -86,7 +81,7 @@ public class TikTokHttpApiClient {
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
throw new TikTokLiveException("unabel to send signature");
|
throw new TikTokLiveRequestException("Unable to send signature");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +90,7 @@ public class TikTokHttpApiClient {
|
|||||||
|
|
||||||
var fullUrl = HttpUtils.parseParameters(url,parameters);
|
var fullUrl = HttpUtils.parseParameters(url,parameters);
|
||||||
var singHeaders = new TreeMap<String,Object>();
|
var singHeaders = new TreeMap<String,Object>();
|
||||||
singHeaders.put("client", "ttlive-net");
|
singHeaders.put("client", "ttlive-java");
|
||||||
singHeaders.put("uuc", 1);
|
singHeaders.put("uuc", 1);
|
||||||
singHeaders.put("url", fullUrl);
|
singHeaders.put("url", fullUrl);
|
||||||
|
|
||||||
@@ -112,7 +107,7 @@ public class TikTokHttpApiClient {
|
|||||||
requestFactory.setAgent(userAgent);
|
requestFactory.setAgent(userAgent);
|
||||||
return signedUrl;
|
return signedUrl;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TikTokLiveException("Insufficent values have been supplied for signing. Likely due to an update. Post an issue on GitHub.", e);
|
throw new TikTokLiveRequestException("Insufficient values have been supplied for signing. Likely due to an update. Post an issue on GitHub.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package io.github.jwdeveloper.tiktok.http;
|
|||||||
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.Constants;
|
import io.github.jwdeveloper.tiktok.Constants;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import java.net.CookieManager;
|
import java.net.CookieManager;
|
||||||
import java.net.ProxySelector;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
@@ -18,24 +18,16 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class TikTokHttpRequestFactory implements TikTokHttpRequest
|
public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||||
{
|
private final CookieManager cookieManager;
|
||||||
private CookieManager cookieManager;
|
private final Map<String, String> defaultHeaders;
|
||||||
private HttpClient client;
|
private final TikTokCookieJar tikTokCookieJar;
|
||||||
|
private final HttpClient client;
|
||||||
private Duration timeout;
|
|
||||||
|
|
||||||
private ProxySelector webProxy;
|
|
||||||
private String query;
|
private String query;
|
||||||
private Boolean sent;
|
|
||||||
private Map<String, String> defaultHeaders;
|
|
||||||
|
|
||||||
private TikTokCookieJar tikTokCookieJar;
|
|
||||||
|
|
||||||
public TikTokHttpRequestFactory(TikTokCookieJar tikTokCookieJar) {
|
public TikTokHttpRequestFactory(TikTokCookieJar tikTokCookieJar) {
|
||||||
|
|
||||||
cookieManager = new CookieManager();
|
|
||||||
this.tikTokCookieJar = tikTokCookieJar;
|
this.tikTokCookieJar = tikTokCookieJar;
|
||||||
|
this.cookieManager = new CookieManager();
|
||||||
defaultHeaders = Constants.DefaultRequestHeaders();
|
defaultHeaders = Constants.DefaultRequestHeaders();
|
||||||
client = HttpClient.newBuilder()
|
client = HttpClient.newBuilder()
|
||||||
.cookieHandler(cookieManager)
|
.cookieHandler(cookieManager)
|
||||||
@@ -43,8 +35,7 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebSocket.Builder openSocket()
|
public WebSocket.Builder openSocket() {
|
||||||
{
|
|
||||||
return client.newWebSocketBuilder();
|
return client.newWebSocketBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,26 +43,21 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
|
|||||||
public String Get(String url) {
|
public String Get(String url) {
|
||||||
var uri = URI.create(url);
|
var uri = URI.create(url);
|
||||||
var request = HttpRequest.newBuilder().GET();
|
var request = HttpRequest.newBuilder().GET();
|
||||||
for(var header : defaultHeaders.entrySet())
|
|
||||||
{
|
|
||||||
//request.setHeader(header.getKey(),header.getValue());
|
|
||||||
}
|
|
||||||
if (query != null) {
|
if (query != null) {
|
||||||
var baseUri = uri.toString();
|
var baseUri = uri.toString();
|
||||||
var requestUri = URI.create(baseUri + "?" + query);
|
var requestUri = URI.create(baseUri + "?" + query);
|
||||||
request.uri(requestUri);
|
request.uri(requestUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetContent(request.build());
|
return GetContent(request.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String Post(String url, HttpRequest.BodyPublisher data) {
|
public String Post(String url, HttpRequest.BodyPublisher data) {
|
||||||
var uri = URI.create(url);
|
var uri = URI.create(url);
|
||||||
var request = HttpRequest.newBuilder().POST(data);
|
var request = HttpRequest.newBuilder().POST(data);
|
||||||
for(var header : defaultHeaders.entrySet())
|
for (var header : defaultHeaders.entrySet()) {
|
||||||
{
|
request.setHeader(header.getKey(), header.getValue());
|
||||||
request.setHeader(header.getKey(),header.getValue());
|
|
||||||
}
|
}
|
||||||
if (query != null) {
|
if (query != null) {
|
||||||
var baseUri = uri.toString();
|
var baseUri = uri.toString();
|
||||||
@@ -81,14 +67,12 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
|
|||||||
return GetContent(request.build());
|
return GetContent(request.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokHttpRequest setHeader(String key, String value)
|
public TikTokHttpRequest setHeader(String key, String value) {
|
||||||
{
|
defaultHeaders.put(key, value);
|
||||||
defaultHeaders.put(key,value);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokHttpRequest setAgent( String value)
|
public TikTokHttpRequest setAgent(String value) {
|
||||||
{
|
|
||||||
defaultHeaders.put("User-Agent", value);
|
defaultHeaders.put("User-Agent", value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -111,26 +95,18 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private String GetContent(HttpRequest request) throws Exception {
|
private String GetContent(HttpRequest request) throws Exception {
|
||||||
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
sent = true;
|
if (response.statusCode() == 404) {
|
||||||
if (response.statusCode() == 404)
|
throw new TikTokLiveRequestException("Request responded with 404 NOT_FOUND");
|
||||||
{
|
|
||||||
throw new RuntimeException("Request responded with 404 NOT_FOUND");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(response.statusCode() != 200)
|
if (response.statusCode() != 200) {
|
||||||
{
|
throw new TikTokLiveRequestException("Request was unsuccessful " + response.statusCode());
|
||||||
throw new RuntimeException("Request was unsuccessful "+response.statusCode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var cookies = response.headers().allValues("Set-Cookie");
|
var cookies = response.headers().allValues("Set-Cookie");
|
||||||
for(var cookie : cookies)
|
for (var cookie : cookies) {
|
||||||
{
|
|
||||||
var split = cookie.split(";")[0].split("=");
|
var split = cookie.split(";")[0].split("=");
|
||||||
var uri = request.uri();
|
var uri = request.uri();
|
||||||
|
|
||||||
@@ -139,9 +115,9 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
|
|||||||
var value = split[1];
|
var value = split[1];
|
||||||
tikTokCookieJar.set(key, value);
|
tikTokCookieJar.set(key, value);
|
||||||
|
|
||||||
var map = new HashMap<String,List<String>>();
|
var map = new HashMap<String, List<String>>();
|
||||||
map.put(key,List.of(value));
|
map.put(key, List.of(value));
|
||||||
cookieManager.put(uri,map);
|
cookieManager.put(uri, map);
|
||||||
|
|
||||||
}
|
}
|
||||||
return response.body();
|
return response.body();
|
||||||
|
|||||||
@@ -3,69 +3,69 @@ package io.github.jwdeveloper.tiktok.websocket;
|
|||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.ClientSettings;
|
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||||
import io.github.jwdeveloper.tiktok.Constants;
|
import io.github.jwdeveloper.tiktok.Constants;
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.WebResponseHandler;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
||||||
import io.github.jwdeveloper.tiktok.http.HttpUtils;
|
import io.github.jwdeveloper.tiktok.http.HttpUtils;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||||
|
import org.java_websocket.client.WebSocketClient;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.http.WebSocket;
|
import java.net.http.WebSocket;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class TikTokWebsocketClient {
|
public class TikTokWebSocketClient {
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final Map<String, Object> clientParams;
|
|
||||||
private final ClientSettings clientSettings;
|
private final ClientSettings clientSettings;
|
||||||
private final TikTokCookieJar tikTokCookieJar;
|
private final TikTokCookieJar tikTokCookieJar;
|
||||||
private final TikTokHttpRequestFactory factory;
|
private final TikTokMessageHandlerRegistration webResponseHandler;
|
||||||
private final WebResponseHandler webResponseHandler;
|
|
||||||
private final TikTokEventHandler tikTokEventHandler;
|
private final TikTokEventHandler tikTokEventHandler;
|
||||||
|
private WebSocketClient webSocketClient;
|
||||||
private WebSocket webSocket;
|
private TikTokLiveClient tikTokLiveClient;
|
||||||
|
private TikTokWebSocketPingingTask pingingTask;
|
||||||
private boolean isConnected;
|
private boolean isConnected;
|
||||||
|
|
||||||
public TikTokWebsocketClient(Logger logger,
|
public TikTokWebSocketClient(Logger logger,
|
||||||
TikTokCookieJar tikTokCookieJar,
|
TikTokCookieJar tikTokCookieJar,
|
||||||
Map<String, Object> clientParams,
|
|
||||||
TikTokHttpRequestFactory factory,
|
|
||||||
ClientSettings clientSettings,
|
ClientSettings clientSettings,
|
||||||
WebResponseHandler webResponseHandler,
|
TikTokMessageHandlerRegistration webResponseHandler,
|
||||||
TikTokEventHandler tikTokEventHandler) {
|
TikTokEventHandler tikTokEventHandler) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.clientParams = clientParams;
|
|
||||||
this.tikTokCookieJar = tikTokCookieJar;
|
this.tikTokCookieJar = tikTokCookieJar;
|
||||||
this.clientSettings = clientSettings;
|
this.clientSettings = clientSettings;
|
||||||
this.factory = factory;
|
|
||||||
this.webResponseHandler = webResponseHandler;
|
this.webResponseHandler = webResponseHandler;
|
||||||
this.tikTokEventHandler = tikTokEventHandler;
|
this.tikTokEventHandler = tikTokEventHandler;
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(WebcastResponse webcastResponse)
|
public void start(WebcastResponse webcastResponse, TikTokLiveClient tikTokLiveClient) {
|
||||||
{
|
this.tikTokLiveClient = tikTokLiveClient;
|
||||||
if(isConnected)
|
if (isConnected) {
|
||||||
{
|
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
if (webcastResponse.getSocketUrl().isEmpty() || webcastResponse.getSocketParamsList().isEmpty()) {
|
if (webcastResponse.getSocketUrl().isEmpty() || webcastResponse.getSocketParamsList().isEmpty()) {
|
||||||
throw new TikTokLiveException("Could not find Room");
|
throw new TikTokLiveException("Could not find Room");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
var url =getWebSocketUrl(webcastResponse);
|
var url = getWebSocketUrl(webcastResponse);
|
||||||
webSocket =startWebSocket(url);
|
|
||||||
if (clientSettings.isHandleExistingMessagesOnConnect()) {
|
if (clientSettings.isHandleExistingMessagesOnConnect()) {
|
||||||
// HandleWebcastMessages(webcastResponse);
|
logger.info("Handling existing messages");
|
||||||
|
webResponseHandler.handle(tikTokLiveClient, webcastResponse);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
webSocketClient = startWebSocket(url);
|
||||||
|
webSocketClient.connect();
|
||||||
|
|
||||||
|
pingingTask = new TikTokWebSocketPingingTask();
|
||||||
|
pingingTask.run(webSocketClient);
|
||||||
|
isConnected = true;
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
isConnected =false;
|
||||||
throw new TikTokLiveException("Failed to connect to the websocket", e);
|
throw new TikTokLiveException("Failed to connect to the websocket", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,33 +78,34 @@ public class TikTokWebsocketClient {
|
|||||||
var headers = Constants.DefaultRequestHeaders();
|
var headers = Constants.DefaultRequestHeaders();
|
||||||
|
|
||||||
|
|
||||||
var clone = new TreeMap<>(clientParams);
|
var clone = new TreeMap<>(clientSettings.getClientParameters());
|
||||||
clone.putAll(headers);
|
clone.putAll(headers);
|
||||||
clone.put(name, value);
|
clone.put(name, value);
|
||||||
var url = webcastResponse.getSocketUrl();
|
var url = webcastResponse.getSocketUrl();
|
||||||
return HttpUtils.parseParametersEncode(url, clone);
|
return HttpUtils.parseParametersEncode(url, clone);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WebSocket startWebSocket(String url) throws Exception {
|
private WebSocketClient startWebSocket(String url) {
|
||||||
var cookie = tikTokCookieJar.parseCookies();
|
var cookie = tikTokCookieJar.parseCookies();
|
||||||
// System.out.println("WssIP: " + url);
|
|
||||||
// System.out.println("Cookie: " + cookie);
|
|
||||||
|
|
||||||
var map = new HashMap<String, String>();
|
var map = new HashMap<String, String>();
|
||||||
map.put("Cookie", cookie);
|
map.put("Cookie", cookie);
|
||||||
|
return new TikTokWebSocketListener(URI.create(url),
|
||||||
return factory.openSocket()
|
map,
|
||||||
.subprotocols("echo-protocol")
|
3000,
|
||||||
.connectTimeout(Duration.ofSeconds(15))
|
webResponseHandler,
|
||||||
.header("Cookie", cookie)
|
tikTokEventHandler,
|
||||||
.buildAsync(URI.create(url), new TikTokWebSocketListener(webResponseHandler, tikTokEventHandler)).get();
|
tikTokLiveClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
if(isConnected && webSocket != null)
|
public void stop()
|
||||||
{
|
{
|
||||||
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
|
if (isConnected && webSocketClient != null) {
|
||||||
|
webSocketClient.close(1);
|
||||||
}
|
}
|
||||||
|
webSocketClient = null;
|
||||||
|
pingingTask = null;
|
||||||
|
isConnected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,106 +1,121 @@
|
|||||||
package io.github.jwdeveloper.tiktok.websocket;
|
package io.github.jwdeveloper.tiktok.websocket;
|
||||||
|
|
||||||
|
import com.google.protobuf.ByteString;
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.events.messages.TikTokConnectedEvent;
|
import io.github.jwdeveloper.tiktok.events.messages.TikTokConnectedEvent;
|
||||||
import io.github.jwdeveloper.tiktok.events.messages.TikTokDisconnectedEvent;
|
import io.github.jwdeveloper.tiktok.events.messages.TikTokDisconnectedEvent;
|
||||||
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
|
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageParsingException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.WebResponseHandler;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
||||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||||
import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketAck;
|
import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketAck;
|
||||||
import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketMessage;
|
import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketMessage;
|
||||||
|
import org.java_websocket.client.WebSocketClient;
|
||||||
|
import org.java_websocket.drafts.Draft_6455;
|
||||||
|
import org.java_websocket.handshake.ServerHandshake;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.net.URI;
|
||||||
import java.net.http.WebSocket;
|
import java.net.http.WebSocket;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.concurrent.CompletionStage;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class TikTokWebSocketListener extends WebSocketClient {
|
||||||
|
|
||||||
public class TikTokWebSocketListener implements java.net.http.WebSocket.Listener {
|
private final TikTokMessageHandlerRegistration webResponseHandler;
|
||||||
|
|
||||||
private final ByteArrayOutputStream accumulatedData = new ByteArrayOutputStream();
|
|
||||||
private final WebResponseHandler webResponseHandler;
|
|
||||||
private final TikTokEventHandler tikTokEventHandler;
|
private final TikTokEventHandler tikTokEventHandler;
|
||||||
|
private final TikTokLiveClient tikTokLiveClient;
|
||||||
|
|
||||||
public TikTokWebSocketListener(WebResponseHandler webResponseHandler, TikTokEventHandler tikTokEventHandler) {
|
public TikTokWebSocketListener(URI serverUri,
|
||||||
|
Map<String, String> httpHeaders,
|
||||||
|
int connectTimeout,
|
||||||
|
TikTokMessageHandlerRegistration webResponseHandler,
|
||||||
|
TikTokEventHandler tikTokEventHandler,
|
||||||
|
TikTokLiveClient tikTokLiveClient) {
|
||||||
|
super(serverUri, new Draft_6455(), httpHeaders,connectTimeout);
|
||||||
this.webResponseHandler = webResponseHandler;
|
this.webResponseHandler = webResponseHandler;
|
||||||
this.tikTokEventHandler = tikTokEventHandler;
|
this.tikTokEventHandler = tikTokEventHandler;
|
||||||
|
this.tikTokLiveClient = tikTokLiveClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletionStage<?> onBinary(WebSocket webSocket, ByteBuffer data, boolean last) {
|
public void onOpen(ServerHandshake serverHandshake) {
|
||||||
|
tikTokEventHandler.publish(tikTokLiveClient,new TikTokConnectedEvent());
|
||||||
|
sendPing();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(ByteBuffer bytes)
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
var bytes = new byte[data.remaining()];
|
handleBinary(bytes.array());
|
||||||
data.get(bytes);
|
|
||||||
accumulatedData.write(bytes);
|
|
||||||
if (last) {
|
|
||||||
handleBinary(webSocket, accumulatedData.toByteArray());
|
|
||||||
accumulatedData.reset();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
tikTokEventHandler.publish(new TikTokErrorEvent(e));
|
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e));
|
||||||
}
|
}
|
||||||
webSocket.request(1);
|
sendPing();
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(java.net.http.WebSocket webSocket) {
|
public void onClose(int i, String s, boolean b) {
|
||||||
tikTokEventHandler.publish(new TikTokConnectedEvent());
|
tikTokEventHandler.publish(tikTokLiveClient,new TikTokDisconnectedEvent());
|
||||||
webSocket.request(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(java.net.http.WebSocket webSocket, Throwable error) {
|
public void onError(Exception error) {
|
||||||
tikTokEventHandler.publish(new TikTokErrorEvent(error));
|
tikTokEventHandler.publish(tikTokLiveClient,new TikTokErrorEvent(error));
|
||||||
webSocket.request(1);
|
sendPing();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void handleBinary(byte[] buffer) {
|
||||||
public CompletionStage<?> onClose(java.net.http.WebSocket webSocket, int statusCode, String reason) {
|
var websocketMessageOptional = getWebcastWebsocketMessage(buffer);
|
||||||
tikTokEventHandler.publish(new TikTokDisconnectedEvent());
|
if (websocketMessageOptional.isEmpty()) {
|
||||||
return java.net.http.WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
|
return;
|
||||||
|
}
|
||||||
|
var websocketMessage = websocketMessageOptional.get();
|
||||||
|
sendAckId(websocketMessage.getId());
|
||||||
|
|
||||||
|
var webResponse = getWebResponseMessage(websocketMessage.getBinary());
|
||||||
|
webResponseHandler.handle(tikTokLiveClient, webResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleBinary(WebSocket webSocket, byte[] buffer) {
|
private Optional<WebcastWebsocketMessage> getWebcastWebsocketMessage(byte[] buffer) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
var websocketMessage = WebcastWebsocketMessage.parseFrom(buffer);
|
var websocketMessage = WebcastWebsocketMessage.parseFrom(buffer);
|
||||||
if (websocketMessage.getBinary().isEmpty()) {
|
if (websocketMessage.getBinary().isEmpty()) {
|
||||||
return;
|
return Optional.empty();
|
||||||
}
|
|
||||||
sendAckId(webSocket, websocketMessage.getId());
|
|
||||||
try {
|
|
||||||
var response = WebcastResponse.parseFrom(websocketMessage.getBinary());
|
|
||||||
webResponseHandler.handle(response);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new TikTokLiveMessageParsingException("Unable to read WebcastResponse", e);
|
|
||||||
}
|
}
|
||||||
|
return Optional.of(websocketMessage);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TikTokLiveMessageParsingException("Unable to read WebcastWebsocketMessage", e);
|
throw new TikTokProtocolBufferException("Unable to parse WebcastWebsocketMessage", buffer, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pingTask(WebSocket webSocket) throws InterruptedException {
|
private WebcastResponse getWebResponseMessage(ByteString buffer) {
|
||||||
while (true) {
|
try {
|
||||||
byte[] message = new byte[]{58, 2, 104, 98};
|
return WebcastResponse.parseFrom(buffer);
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(message);
|
} catch (Exception e) {
|
||||||
while (buffer.hasRemaining()) {
|
throw new TikTokProtocolBufferException("Unable to parse WebcastResponse", buffer.toByteArray(), e);
|
||||||
webSocket.sendPing(buffer);
|
|
||||||
}
|
|
||||||
buffer.clear();
|
|
||||||
Thread.sleep(10);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendAckId(WebSocket webSocket, long id) {
|
|
||||||
|
|
||||||
|
private void sendAckId(long id) {
|
||||||
var serverInfo = WebcastWebsocketAck
|
var serverInfo = WebcastWebsocketAck
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setType("ack")
|
.setType("ack")
|
||||||
.setId(id)
|
.setId(id)
|
||||||
.build();
|
.build();
|
||||||
webSocket.sendBinary(serverInfo.toByteString().asReadOnlyByteBuffer(), true);
|
send(serverInfo.toByteString().asReadOnlyByteBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(String s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.websocket;
|
||||||
|
|
||||||
|
import org.java_websocket.WebSocket;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class TikTokWebSocketPingingTask
|
||||||
|
{
|
||||||
|
private Thread thread;
|
||||||
|
|
||||||
|
private boolean isRunning = false;
|
||||||
|
private final int MIN_TIMEOUT = 5;
|
||||||
|
private final int MAX_TIMEOUT = 100;
|
||||||
|
|
||||||
|
|
||||||
|
public void run(WebSocket webSocket)
|
||||||
|
{
|
||||||
|
var thread = new Thread(() ->
|
||||||
|
{
|
||||||
|
pingTask(webSocket);
|
||||||
|
});
|
||||||
|
isRunning =true;
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop()
|
||||||
|
{
|
||||||
|
if(thread != null)
|
||||||
|
{
|
||||||
|
thread.interrupt();
|
||||||
|
}
|
||||||
|
isRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void pingTask(WebSocket webSocket)
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
while (isRunning)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!webSocket.isOpen())
|
||||||
|
{
|
||||||
|
Thread.sleep(100);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
webSocket.sendPing();
|
||||||
|
var timeout = random.nextInt(MAX_TIMEOUT)+MIN_TIMEOUT;
|
||||||
|
Thread.sleep(timeout);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
isRunning = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
import io.github.jwdeveloper.tiktok.common.TikTokBaseTest;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class ParseMessagesTests extends TikTokBaseTest
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ShouldParseMessageWebcastLikeMessage() throws InvalidProtocolBufferException {
|
||||||
|
var bytes = getFileBytesUtf("LikeMessage.bin");
|
||||||
|
var message = WebcastLikeMessage.parseFrom(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ShouldParseMessageWebcastGiftMessage() throws InvalidProtocolBufferException {
|
||||||
|
var bytes = getFileBytesUtf("MessageWebcastGiftMessage.bin");
|
||||||
|
var message = WebcastGiftMessage.parseFrom(bytes);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void ShouldParseMessageWebcastChatMessage() throws InvalidProtocolBufferException {
|
||||||
|
var bytes = getFileBytesUtf("MessageWebcastChatMessage.bin");
|
||||||
|
var message = WebcastChatMessage.parseFrom(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ShouldParseMessageWebcastImDeleteMessage() throws InvalidProtocolBufferException {
|
||||||
|
var bytes = getFileBytesUtf("MessageWebcastImDeleteMessage.bin");
|
||||||
|
var message = WebcastImDeleteMessage.parseFrom(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ShouldParseMessageWebcastSocialMessage() throws InvalidProtocolBufferException {
|
||||||
|
var bytes = getFileBytesUtf("MessageWebcastSocialMessage.bin");
|
||||||
|
var message = WebcastSocialMessage.parseFrom(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ShouldParseMessageWebcastMemberMessage() throws InvalidProtocolBufferException {
|
||||||
|
var bytes = getFileBytesUtf("WebcastMemberMessage.bin");
|
||||||
|
var message = WebcastMemberMessage.parseFrom(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package io.github.jwdeveloper.tiktok;
|
|
||||||
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketMessage;
|
|
||||||
import org.junit.Test;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class SerializeWebMessageTest
|
|
||||||
{
|
|
||||||
@Test
|
|
||||||
public void WebcastWebsocketMessage()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
try (var str = getClass().getClassLoader().getResourceAsStream("WebcastWebsocketMessage.bin"))
|
|
||||||
{
|
|
||||||
var bytes = str.readAllBytes();
|
|
||||||
var person = WebcastWebsocketMessage.parseFrom(bytes);
|
|
||||||
System.out.println("id: " + person.getId());
|
|
||||||
System.out.println("type: " + person.getType());
|
|
||||||
System.out.println("binary: " + person.getBinary().size());
|
|
||||||
// System.out.println("Email: " + person.getEmail());
|
|
||||||
} catch (InvalidProtocolBufferException e) {
|
|
||||||
System.out.println("Error parsing the protobuf message: " + e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("Error reading the file: " + e.getMessage());
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.common.TikTokBaseTest;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
public class WebResponseHandlerTests extends TikTokBaseTest {
|
||||||
|
public static TikTokMessageHandlerRegistration sut;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
var mockEventHandler = mock(TikTokEventHandler.class);
|
||||||
|
var mockGiftManager = mock(TikTokGiftManager.class);
|
||||||
|
var mockRoomInfo = mock(TikTokRoomInfo.class);
|
||||||
|
var mockClientSettings = mock(ClientSettings.class);
|
||||||
|
var mockLogger = mock(Logger.class);
|
||||||
|
sut = new TikTokMessageHandlerRegistration(mockEventHandler,mockClientSettings,mockLogger, mockGiftManager, mockRoomInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.common;
|
||||||
|
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketMessage;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
Client/src/test/resources/LikeMessage.bin
Normal file
1
Client/src/test/resources/LikeMessage.bin
Normal file
File diff suppressed because one or more lines are too long
1
Client/src/test/resources/MessageWebcastChatMessage.bin
Normal file
1
Client/src/test/resources/MessageWebcastChatMessage.bin
Normal file
File diff suppressed because one or more lines are too long
1
Client/src/test/resources/MessageWebcastGiftMessage.bin
Normal file
1
Client/src/test/resources/MessageWebcastGiftMessage.bin
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
|||||||
|
CjUKFldlYmNhc3RJbURlbGV0ZU1lc3NhZ2UQhZab+vyKvvJkGJKWhYz+o7DxZCC0sajzoTEwARoJhojH2ojIjaBk
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
CskHMAFChgcaDgoJI2ZmZmZmZmZmIJADIp8GCAsSDgoJI2ZmZmZmZmZmIJADqgGJBgqGBgiFiNKIpZnf0WIaCm1yIEEuTC5GLkFK/wQKxgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzkxODE3OWQ4MzQ0YWZiYjk3OTAzYjYyMGQwOTg1ZGEzfnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNjkyOTAwMDAwJngtc2lnbmF0dXJlPUE0RmtOWDMlMkIxNiUyRjlxeENvR1JReEczNFRnRUUlM0QKtAFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzkxODE3OWQ4MzQ0YWZiYjk3OTAzYjYyMGQwOTg1ZGEzfmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTY5MjkwMDAwMCZ4LXNpZ25hdHVyZT1EOHlYQUhNVGxGeUR5N3dqT3BXRllrUlBBWnclM0QKtgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzkxODE3OWQ4MzQ0YWZiYjk3OTAzYjYyMGQwOTg1ZGEzfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTY5MjkwMDAwMCZ4LXNpZ25hdHVyZT1IYkIwNk00N2Y0JTJGT29jUWxla0gwREdDdkY3MCUzRBJEMTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvOTE4MTc5ZDgzNDRhZmJiOTc5MDNiNjIwZDA5ODVkYTOyAQgI9h8Qmw0YAboBAIICALICCy56YXBpc3l3YW5l8gJMTVM0d0xqQUJBQUFBYXdVMzNGbnBIYllkMHdra1djeC1DTnBzeDdXT0lqOXdtOTBwQ2tRUmZPekJuZVdZczdXT0plSm5GVU5kdFh0MwoecG1fbXRfZ3VpZGFuY2Vfdmlld2VyXzEwX3NoYXJlEjJ7MDp1c2VyfSBzaGFyZWQgdGhlIExJVkUgd2l0aCBtb3JlIHRoYW4gMTAgZnJpZW5kc1ACsAEFwAECChRXZWJjYXN0U29jaWFsTWVzc2FnZRCglsC+2OG+8mQYoJaZxvrevPJkIOTf0vOhMUgBuAECEoYGSv8ECsYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC85MTgxNzlkODM0NGFmYmI5NzkwM2I2MjBkMDk4NWRhM350cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTY5MjkwMDAwMCZ4LXNpZ25hdHVyZT1BNEZrTlgzJTJCMTYlMkY5cXhDb0dSUXhHMzRUZ0VFJTNECrQBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC85MTgxNzlkODM0NGFmYmI5NzkwM2I2MjBkMDk4NWRhM35jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE2OTI5MDAwMDAmeC1zaWduYXR1cmU9RDh5WEFITVRsRnlEeTd3ak9wV0ZZa1JQQVp3JTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC85MTgxNzlkODM0NGFmYmI5NzkwM2I2MjBkMDk4NWRhM35jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE2OTI5MDAwMDAmeC1zaWduYXR1cmU9SGJCMDZNNDdmNCUyRk9vY1FsZWtIMERHQ3ZGNzAlM0QSRDEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzkxODE3OWQ4MzQ0YWZiYjk3OTAzYjYyMGQwOTg1ZGEzsgEIEJsNGAEI9h+6AQCCAgCyAgsuemFwaXN5d2FuZfICTE1TNHdMakFCQUFBQWF3VTMzRm5wSGJZZDB3a2tXY3gtQ05wc3g3V09Jajl3bTkwcENrUVJmT3pCbmVXWXM3V09KZUpuRlVOZHRYdDMIhYjSiKWZ39FiGgptciBBLkwuRi5BGAEgAyoCLTFAGQ==
|
||||||
1
Client/src/test/resources/WebcastMemberMessage.bin
Normal file
1
Client/src/test/resources/WebcastMemberMessage.bin
Normal file
File diff suppressed because one or more lines are too long
@@ -1,32 +0,0 @@
|
|||||||
ŔĆł»›„ÖF¸E *
|
|
||||||
|
|
||||||
compress_typenone2pb:msgBš
|
|
||||||
Ű
|
|
||||||
WebcastLikeMessageş
|
|
||||||
|
|
||||||
WebcastLikeMessageˇ–¤ŚöÍííd –żÚřęëíd0BŔ
|
|
||||||
pm_mt_msg_viewer{0:user} liked the LIVE
|
|
||||||
#ffffffff "‚
|
|
||||||
Ş}
|
|
||||||
{ ”‚•ÉÔëdhulajnoga czek˛hulajnoga.czek5ňLMS4wLjABAAAAx4-lIrRjH0pMT0D3laROVsnU-4u6P1tN4td82AQTCHjKZ-CHaF_DluNSFQQp1s4DHP°¸Ŕ ĆЂҟ1†q*Ü ”‚•ÉÔëdhulajnoga czek˛ş ˛hulajnoga.czek5J˙
|
|
||||||
Čhttps://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-euttp/26aa68e29831ff0c9d4fb37875efffdd~tplv-tiktok-shrink:72:72.webp?x-expires=1692291600&x-signature=Z2ZM2T%2FckIxKSj%2BJY%2BONoypyMwo%3D
|
|
||||||
´https://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-euttp/26aa68e29831ff0c9d4fb37875efffdd~c5_100x100.webp?x-expires=1692291600&x-signature=gJgrVHIZWnVCif4Z6gXuhnl1pn8%3D
|
|
||||||
´https://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-euttp/26aa68e29831ff0c9d4fb37875efffdd~c5_100x100.jpeg?x-expires=1692291600&x-signature=ITqTLj6v7UVl12HeeGa6a6FYNpc%3DD100x100/tos-useast2a-avt-0068-euttp/26aa68e29831ff0c9d4fb37875efffddŞ0‚ ňLMS4wLjABAAAAx4-lIrRjH0pMT0D3laROVsnU-4u6P1tN4td82AQTCHjKZ-CHaF_DluNSFQQp1s4D‚îR„sslocal://webcast_webview_popup?gravity=bottom&show_mask=1&url=https%3A%2F%2Flf16-web.tiktokcdn.com%2Fobj%2Fies-hotsoon-draft-sg%2Ftiktok-live-faq%2Ftiktok_live_revenue_new_gifter_details.html&web_bg_color=FFFFFF&height=60%25&mask_bg_color=000000b3&use_spark=1b:"10000037267585271263611681*0
|
|
||||||
271541203697319145231Ş pm_mt_live_ng_im
|
|
||||||
New gifter( ‚Ü Résslocal://webcast_lynxview_popup?use_spark=1&url=https%3A%2F%2Flf16-gecko-source.tiktokcdn.com%2Fobj%2Fbyte-gurd-source-sg%2Ftiktok%2Ffe%2Flive%2Ftiktok_live_revenue_user_level_main%2Fsrc%2Fpages%2Fprivilege%2Fpanel%2Ftemplate.js&hide_status_bar=0&hide_nav_bar=1&container_bg_color=00000000&height=90%25&bdhm_bid=tiktok_live_revenue_user_level_main&use_forest=1XbN
|
|
||||||
271383811767874578280".mock_fix_width_transparent_7138381176787457828*2ş’Ő+webcast-va/grade_badge_icon_lite_lv1_v1.png:ésslocal://webcast_lynxview_popup?use_spark=1&url=https%3A%2F%2Flf16-gecko-source.tiktokcdn.com%2Fobj%2Fbyte-gurd-source-sg%2Ftiktok%2Ffe%2Flive%2Ftiktok_live_revenue_user_level_main%2Fsrc%2Fpages%2Fprivilege%2Fpanel%2Ftemplate.js&hide_status_bar=0&hide_nav_bar=1&container_bg_color=00000000&height=90%25&bdhm_bid=tiktok_live_revenue_user_level_main&use_forest=1
|
|
||||||
\https://p16-webcast.tiktokcdn.com/webcast-va/grade_badge_icon_lite_lv1_v1.png~tplv-obj.image
|
|
||||||
\https://p19-webcast.tiktokcdn.com/webcast-va/grade_badge_icon_lite_lv1_v1.png~tplv-obj.image"2* b
|
|
||||||
#99789EE7x2 : " Z
|
|
||||||
#99789EE7€‚÷( R„sslocal://webcast_webview_popup?gravity=bottom&show_mask=1&url=https%3A%2F%2Flf16-web.tiktokcdn.com%2Fobj%2Fies-hotsoon-draft-sg%2Ftiktok-live-faq%2Ftiktok_live_revenue_new_gifter_details.html&web_bg_color=FFFFFF&height=60%25&mask_bg_color=000000b3&use_spark=1Xb:
|
|
||||||
271541203697319145231"10000037267585271263611681*0ş¦x€Ű 0:„sslocal://webcast_webview_popup?gravity=bottom&show_mask=1&url=https%3A%2F%2Flf16-web.tiktokcdn.com%2Fobj%2Fies-hotsoon-draft-sg%2Ftiktok-live-faq%2Ftiktok_live_revenue_new_gifter_details.html&web_bg_color=FFFFFF&height=60%25&mask_bg_color=000000b3&use_spark=1
|
|
||||||
Shttps://p16-webcast.tiktokcdn.com/webcast-va/new_gifter_badge_v3.png~tplv-obj.image
|
|
||||||
Shttps://p19-webcast.tiktokcdn.com/webcast-va/new_gifter_badge_v3.png~tplv-obj.image"webcast-va/new_gifter_badge_v3.png
|
|
||||||
pm_mt_live_ng_im
|
|
||||||
New gifterZ
|
|
||||||
#803F3F3Fb
|
|
||||||
#803F3F3FBÍ†Ë”Ź¨Á‚cŔ
|
|
||||||
pm_mt_msg_viewer{0:user} liked the LIVE
|
|
||||||
#ffffffff "‚
|
|
||||||
Ş}
|
|
||||||
{˛hulajnoga.czek5ňLMS4wLjABAAAAx4-lIrRjH0pMT0D3laROVsnU-4u6P1tN4td82AQTCHjKZ-CHaF_DluNSFQQp1s4D ”‚•ÉÔëdhulajnoga czekHˇ–¤ŚöÍííd)1692120689751_7267603020139989890_1_1_0_0č ×؂ҟ1*-@H
|
|
||||||
90
README.md
90
README.md
@@ -1,9 +1,13 @@
|
|||||||
# TikTok-Live-Java
|
[](https://jitpack.io/#jwdeveloper/TikTok-Live-Java)
|
||||||
A Java library based on [TikTok-Connector](https://github.com/isaackogan/TikTok-Live-Connector) and [TikTokLiveSharp](https://github.com/sebheron/TikTokLiveSharp). Use it to receive live stream events such as comments and gifts in realtime from [TikTok LIVE](https://www.tiktok.com/live) by connecting to TikTok's internal WebCast push service. The package includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers. No credentials are required. Besides [Chat Comments](#chat), other events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked. You can also send [automatic messages](#send-chat-messages) into the chat by providing your Session ID.
|
|
||||||
|
|
||||||
|
|
||||||
|
# TikTokLive Java
|
||||||
|
A Java library based on [TikTokLive](https://github.com/isaackogan/TikTokLive) and [TikTokLiveSharp](https://github.com/sebheron/TikTokLiveSharp). Use it to receive live stream events such as comments and gifts in realtime from [TikTok LIVE](https://www.tiktok.com/live) by connecting to TikTok's internal WebCast push service. The package includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers. No credentials are required. Besides [Chat Comments](#chat), other events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked. You can also send [automatic messages](#send-chat-messages) into the chat by providing your Session ID.
|
||||||
|
|
||||||
|
Join the support [discord](https://discord.gg/e2XwPNTBBr) and visit the `#java-support` channel for questions, contributions and ideas. Feel free to make pull requests with missing/new features, fixes, etc
|
||||||
|
|
||||||
Do you prefer other programming languages?
|
Do you prefer other programming languages?
|
||||||
- **Node** orginal: [TikTok-Live-Connector](https://github.com/isaackogan/TikTok-Live-Connector) by [@isaackogan](https://github.com/isaackogan)
|
- **Node** orginal: [TikTok-Live-Connector](https://github.com/isaackogan/TikTok-Live-Connector) by [@zerodytrash](https://github.com/zerodytrash)
|
||||||
- **Python** rewrite: [TikTokLive](https://github.com/isaackogan/TikTokLive) by [@isaackogan](https://github.com/isaackogan)
|
- **Python** rewrite: [TikTokLive](https://github.com/isaackogan/TikTokLive) by [@isaackogan](https://github.com/isaackogan)
|
||||||
- **Go** rewrite: [GoTikTokLive](https://github.com/Davincible/gotiktoklive) by [@Davincible](https://github.com/Davincible)
|
- **Go** rewrite: [GoTikTokLive](https://github.com/Davincible/gotiktoklive) by [@Davincible](https://github.com/Davincible)
|
||||||
- **C#** rewrite: [TikTokLiveSharp](https://github.com/frankvHoof93/TikTokLiveSharp) by [@frankvHoof93](https://github.com/frankvHoof93)
|
- **C#** rewrite: [TikTokLiveSharp](https://github.com/frankvHoof93/TikTokLiveSharp) by [@frankvHoof93](https://github.com/frankvHoof93)
|
||||||
@@ -12,15 +16,14 @@ Do you prefer other programming languages?
|
|||||||
|
|
||||||
#### Overview
|
#### Overview
|
||||||
- [Getting started](#getting-started)
|
- [Getting started](#getting-started)
|
||||||
- [Params and options](#params-and-options)
|
- [Configuration](#configuration)
|
||||||
- [Methods](#methods)
|
- [Methods](#methods)
|
||||||
- [Events](#events)
|
- [Events](#events)
|
||||||
- [Examples](#examples)
|
|
||||||
- [Contributing](#contributing)
|
- [Contributing](#contributing)
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
1. Install the package via Maven (dependecies will be simplify in future)
|
1. Install the package via Maven
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<repositories>
|
<repositories>
|
||||||
@@ -29,32 +32,20 @@ Do you prefer other programming languages?
|
|||||||
<url>https://jitpack.io</url>
|
<url>https://jitpack.io</url>
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
```
|
|
||||||
|
|
||||||
```xml
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.protobuf</groupId>
|
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
|
||||||
<artifactId>protobuf-java</artifactId>
|
<artifactId>Client</artifactId>
|
||||||
<version>3.24.1</version>
|
<version>0.0.14-Release</version>
|
||||||
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
<version>2.10.1</version>
|
<version>2.10.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
|
|
||||||
<artifactId>API</artifactId>
|
|
||||||
<version>0.0.4-Release</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
|
|
||||||
<artifactId>Client</artifactId>
|
|
||||||
<version>0.0.4-Release</version>
|
|
||||||
</dependency>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Create your first chat connection
|
2. Create your first chat connection
|
||||||
@@ -63,36 +54,69 @@ Do you prefer other programming languages?
|
|||||||
public static void main(String[] args)
|
public static void main(String[] args)
|
||||||
{
|
{
|
||||||
// Username of someone who is currently live
|
// Username of someone who is currently live
|
||||||
var tiktokUsername = "officialgeilegisela";
|
var tiktokUsername = "jwdevtiktok";
|
||||||
|
|
||||||
TikTokLive.newClient(tiktokUsername)
|
TikTokLive.newClient(tiktokUsername)
|
||||||
.onConnected(event ->
|
.onConnected((client, event) ->
|
||||||
{
|
{
|
||||||
System.out.println("Connected");
|
System.out.println("Connected");
|
||||||
})
|
})
|
||||||
.onJoin(event ->
|
.onJoin((client, event) ->
|
||||||
{
|
{
|
||||||
System.out.println("User joined -> " + event.getUser().getNickName());
|
System.out.println("User joined -> " + event.getUser().getNickName());
|
||||||
})
|
})
|
||||||
.onComment(event ->
|
.onComment((client, event) ->
|
||||||
{
|
{
|
||||||
System.out.println(event.getUser().getUniqueId() + ": " + event.getText());
|
System.out.println(event.getUser().getUniqueId() + ": " + event.getText());
|
||||||
})
|
})
|
||||||
.onError(event ->
|
.onEvent((client, event) ->
|
||||||
|
{
|
||||||
|
System.out.println("Viewers count: "+client.getRoomInfo().getViewersCount());
|
||||||
|
})
|
||||||
|
.onError((client, event) ->
|
||||||
{
|
{
|
||||||
event.getException().printStackTrace();
|
event.getException().printStackTrace();
|
||||||
})
|
})
|
||||||
.buildAndRun();
|
.buildAndRun();
|
||||||
|
System.in.read();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class ConfigurationExample
|
||||||
|
{
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
var tiktokUsername = "jwdevtiktok";
|
||||||
|
TikTokLive.newClient(tiktokUsername)
|
||||||
|
.configure(clientSettings ->
|
||||||
|
{
|
||||||
|
clientSettings.setHostName(Main.TEST_TIKTOK_USER); // TikTok user name
|
||||||
|
clientSettings.setClientLanguage("en"); // Language
|
||||||
|
clientSettings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
|
||||||
|
clientSettings.setLogLevel(Level.ALL); // Log level
|
||||||
|
clientSettings.setDownloadGiftInfo(true); // Downloading meta information about gifts. You can access it by client.getGiftManager().getGiftsInfo();
|
||||||
|
clientSettings.setPrintMessageData(true); // Printing TikTok Protocol buffer messages in Base64 format
|
||||||
|
clientSettings.setPrintToConsole(true); // Printing all logs to console even if log level is Level.OFF
|
||||||
|
clientSettings.setHandleExistingMessagesOnConnect(true); // Invokes all TikTok events that had occurred before connection
|
||||||
|
clientSettings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
|
||||||
|
clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
|
||||||
|
})
|
||||||
|
.buildAndRun();
|
||||||
|
System.in.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
A `TikTokLive` object contains the following methods.
|
A `client (LiveClient)` object contains the following methods.
|
||||||
|
|
||||||
| Method Name | Description |
|
| Method Name | Description |
|
||||||
| ----------- | ----------- |
|
| ----------- | ----------- |
|
||||||
| connect | Connects to the live stream chat.<br>Returns a `Promise` which will be resolved when the connection is successfully established. |
|
| connect | Connects to the live stream. |
|
||||||
| disconnect | Disconnects the connection. |
|
| disconnect | Disconnects the connection. |
|
||||||
|
| getGiftManager | Gets the meta informations about all gifts. |
|
||||||
| getRoomInfo | Gets the current room info from TikTok API including streamer info, room status and statistics. |
|
| getRoomInfo | Gets the current room info from TikTok API including streamer info, room status and statistics. |
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|||||||
@@ -2,11 +2,48 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<!-- READ ME
|
||||||
|
This POM file is configured to run only inside TikTokLiveJava project
|
||||||
|
In case you have copied it follows this stets to fix console errors
|
||||||
|
|
||||||
|
1. Remember to remove
|
||||||
|
<parent>
|
||||||
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<version>0.0.13-Release</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
2. Paste
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jitpack.io</id>
|
||||||
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
|
||||||
|
<artifactId>Client</artifactId>
|
||||||
|
<version>0.0.14-Release</version> <- Change with latest version of TikTokJava
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.10.1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
I hope it will help you :)
|
||||||
|
-->
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>TikTokLiveJava</artifactId>
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<version>1.0.0</version>
|
<version>0.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>TestApplication</artifactId>
|
<artifactId>TestApplication</artifactId>
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public class ConfigurationExample {
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
|
||||||
|
TikTokLive.newClient(Main.TEST_TIKTOK_USER)
|
||||||
|
.configure(clientSettings ->
|
||||||
|
{
|
||||||
|
clientSettings.setHostName(Main.TEST_TIKTOK_USER); // TikTok user name
|
||||||
|
clientSettings.setClientLanguage("en"); // Language
|
||||||
|
clientSettings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
|
||||||
|
clientSettings.setLogLevel(Level.ALL); // Log level
|
||||||
|
clientSettings.setDownloadGiftInfo(true); // Downloading meta information about gifts. You can access it by client.getGiftManager().getGiftsInfo();
|
||||||
|
clientSettings.setPrintMessageData(true); // Printing TikTok Protocol buffer messages in Base64 format
|
||||||
|
clientSettings.setPrintToConsole(true); // Printing all logs to console even if log level is Level.OFF
|
||||||
|
clientSettings.setHandleExistingMessagesOnConnect(true); // Invokes all TikTok events that had occurred before connection
|
||||||
|
clientSettings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
|
||||||
|
clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
|
||||||
|
})
|
||||||
|
.buildAndRun();
|
||||||
|
System.in.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,22 @@
|
|||||||
package io.github.jwdeveloper.tiktok;
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.events.messages.*;
|
import io.github.jwdeveloper.tiktok.events.messages.*;
|
||||||
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
public static String TEST_USER_SUBJECT = "stiflerhub";
|
public static String TEST_TIKTOK_USER = "olchik.m1";
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
var client = TikTokLive.newClient(TEST_USER_SUBJECT)
|
var client = TikTokLive.newClient(TEST_TIKTOK_USER)
|
||||||
|
.configure(clientSettings ->
|
||||||
|
{
|
||||||
|
clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(5));
|
||||||
|
clientSettings.setRetryOnConnectionFailure(true);
|
||||||
|
})
|
||||||
.onConnected(Main::onConnected)
|
.onConnected(Main::onConnected)
|
||||||
.onDisconnected(Main::onDisconnected)
|
.onDisconnected(Main::onDisconnected)
|
||||||
.onRoomViewerData(Main::onViewerData)
|
.onRoomViewerData(Main::onViewerData)
|
||||||
@@ -21,60 +28,63 @@ public class Main {
|
|||||||
.onLike(Main::onLike)
|
.onLike(Main::onLike)
|
||||||
.onGiftMessage(Main::onGiftMessage)
|
.onGiftMessage(Main::onGiftMessage)
|
||||||
.onEmote(Main::onEmote)
|
.onEmote(Main::onEmote)
|
||||||
.onError(tikTokErrorEvent ->
|
.onError((_client, error) ->
|
||||||
{
|
{
|
||||||
// tikTokErrorEvent.getException().printStackTrace();
|
error.getException().printStackTrace();
|
||||||
|
})
|
||||||
|
.onEvent((liveClient, event) ->
|
||||||
|
{
|
||||||
|
var viewers = liveClient.getRoomInfo().getViewersCount();
|
||||||
})
|
})
|
||||||
.buildAndRun();
|
.buildAndRun();
|
||||||
|
|
||||||
|
|
||||||
var viewers = client.getRoomInfo().getViewersCount();
|
|
||||||
System.in.read();
|
System.in.read();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onConnected(TikTokConnectedEvent e) {
|
private static void onConnected(LiveClient tikTokLive, TikTokConnectedEvent e) {
|
||||||
print("Connected");
|
print("Connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onDisconnected(TikTokDisconnectedEvent e) {
|
private static void onDisconnected(LiveClient tikTokLive, TikTokDisconnectedEvent e) {
|
||||||
print("Disconnected");
|
print("Disconnected");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onViewerData(TikTokRoomViewerDataEvent e) {
|
private static void onViewerData(LiveClient tikTokLive, TikTokRoomViewerDataEvent e) {
|
||||||
print("Viewer count is:", e.getViewerCount());
|
print("Viewer count is:", e.getViewerCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onJoin(TikTokJoinEvent e) {
|
private static void onJoin(LiveClient tikTokLive, TikTokJoinEvent e) {
|
||||||
print(e.getUser().getUniqueId(), "joined!");
|
print(e.getUser().getUniqueId(), "joined!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onComment(TikTokCommentEvent e) {
|
private static void onComment(LiveClient tikTokLive, TikTokCommentEvent e) {
|
||||||
print("DUPA: "+e.getText());
|
print(e.getUser().getUniqueId(), e.getText());
|
||||||
// print(e.getUser().getUniqueId(), e.getText());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onFollow(TikTokFollowEvent e) {
|
private static void onFollow(LiveClient tikTokLive, TikTokFollowEvent e) {
|
||||||
print(e.getNewFollower().getUniqueId(), "followed!");
|
print(e.getNewFollower().getUniqueId(), "followed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onShare(TikTokShareEvent e) {
|
private static void onShare(LiveClient tikTokLive, TikTokShareEvent e) {
|
||||||
print(e.getUser().getUniqueId(), "shared!");
|
print(e.getUser().getUniqueId(), "shared!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onSubscribe(TikTokSubscribeEvent e) {
|
private static void onSubscribe(LiveClient tikTokLive, TikTokSubscribeEvent e) {
|
||||||
print(e.getNewSubscriber().getUniqueId(), "subscribed!");
|
print(e.getNewSubscriber().getUniqueId(), "subscribed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onLike(TikTokLikeEvent e) {
|
private static void onLike(LiveClient tikTokLive, TikTokLikeEvent e) {
|
||||||
|
|
||||||
print(e.getSender().getUniqueId(), "liked!");
|
print(e.getSender().getUniqueId(), "liked!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onGiftMessage(TikTokGiftMessageEvent e) {
|
private static void onGiftMessage(LiveClient tikTokLive, TikTokGiftMessageEvent e)
|
||||||
|
{
|
||||||
print(e.getSender().getUniqueId(), "sent", e.getAmount(), "x", e.getGift().getName());
|
print(e.getSender().getUniqueId(), "sent", e.getAmount(), "x", e.getGift().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onEmote(TikTokEmoteEvent e) {
|
private static void onEmote(LiveClient tikTokLive, TikTokEmoteEvent e) {
|
||||||
print(e.getUser().getUniqueId(), "sent", e.getEmoteId());
|
print(e.getUser().getUniqueId(), "sent", e.getEmoteId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +93,6 @@ public class Main {
|
|||||||
for (var message : messages) {
|
for (var message : messages) {
|
||||||
sb.append(message).append(" ");
|
sb.append(message).append(" ");
|
||||||
}
|
}
|
||||||
System.out.println(sb.toString());
|
System.out.println(sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,30 +1,37 @@
|
|||||||
package io.github.jwdeveloper.tiktok;
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
public class SimpleExample {
|
import java.io.IOException;
|
||||||
public static void main(String[] args) {
|
|
||||||
// Username of someone who is currently live
|
|
||||||
var tiktokUsername = "officialgeilegisela";
|
|
||||||
|
|
||||||
TikTokLive.newClient(tiktokUsername)
|
public class SimpleExample {
|
||||||
.clientSettings(settings ->
|
public static void main(String[] args) throws IOException {
|
||||||
|
|
||||||
|
TikTokLive.newClient(Main.TEST_TIKTOK_USER)
|
||||||
|
.onFollow((liveClient, event) ->
|
||||||
{
|
{
|
||||||
|
System.out.println("Follow joined -> " + event.getNewFollower().getNickName());
|
||||||
})
|
})
|
||||||
.onConnected(event ->
|
.onConnected((client, event) ->
|
||||||
{
|
{
|
||||||
System.out.println("Connected");
|
System.out.println("Connected");
|
||||||
})
|
})
|
||||||
.onJoin(event ->
|
|
||||||
|
.onJoin((client, event) ->
|
||||||
{
|
{
|
||||||
System.out.println("User joined -> " + event.getUser().getNickName());
|
System.out.println("User joined -> " + event.getUser().getNickName());
|
||||||
})
|
})
|
||||||
.onComment(event ->
|
.onComment((client, event) ->
|
||||||
{
|
{
|
||||||
System.out.println(event.getUser().getUniqueId() + ": " + event.getText());
|
System.out.println(event.getUser().getUniqueId() + ": " + event.getText());
|
||||||
})
|
})
|
||||||
.onError(event ->
|
.onEvent((client, event) ->
|
||||||
|
{
|
||||||
|
System.out.println("Viewers count: "+client.getRoomInfo().getViewersCount());
|
||||||
|
})
|
||||||
|
.onError((client, event) ->
|
||||||
{
|
{
|
||||||
event.getException().printStackTrace();
|
event.getException().printStackTrace();
|
||||||
})
|
})
|
||||||
.buildAndRun();
|
.buildAndRun();
|
||||||
|
System.in.read();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
50
Tools-EventsCollector/pom.xml
Normal file
50
Tools-EventsCollector/pom.xml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<version>0.0.14-Release</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>Tools-EventsCollector</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xerial</groupId>
|
||||||
|
<artifactId>sqlite-jdbc</artifactId>
|
||||||
|
<version>3.34.0</version> <!-- Use the latest version available -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jdbi</groupId>
|
||||||
|
<artifactId>jdbi3-core</artifactId>
|
||||||
|
<version>3.23.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jdbi</groupId>
|
||||||
|
<artifactId>jdbi3-sqlobject</artifactId>
|
||||||
|
<version>3.23.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>1.7.32</version> <!-- Use the latest version available -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
|
<artifactId>Client</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.tools.collector;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLive;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.db.TikTokDatabase;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.tables.ExceptionInfoModel;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
//https://protobuf-decoder.netlify.app/
|
||||||
|
/*
|
||||||
|
mia_tattoo
|
||||||
|
moniczkka
|
||||||
|
besin1276
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static List<String> ignoredEvents;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws SQLException {
|
||||||
|
|
||||||
|
ignoredEvents = List.of("TikTokJoinEvent","TikTokLikeEvent");
|
||||||
|
|
||||||
|
var db = new TikTokDatabase("test");
|
||||||
|
db.init();
|
||||||
|
|
||||||
|
var users = new ArrayList<String>();
|
||||||
|
users.add("mia_tattoo");
|
||||||
|
users.add("moniczkka");
|
||||||
|
users.add("besin1276");
|
||||||
|
|
||||||
|
for(var user : users)
|
||||||
|
{
|
||||||
|
runTikTokLiveInstance(user, db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void runTikTokLiveInstance(String tiktokUser, TikTokDatabase tikTokDatabase)
|
||||||
|
{
|
||||||
|
|
||||||
|
TikTokLive.newClient(tiktokUser)
|
||||||
|
.onWebsocketMessage((liveClient, event) ->
|
||||||
|
{
|
||||||
|
var eventName = event.getEvent().getClass().getSimpleName();
|
||||||
|
|
||||||
|
if(ignoredEvents.contains(eventName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var binary = Base64.getEncoder().encodeToString(event.getMessage().getBinary().toByteArray());
|
||||||
|
var model = TikTokMessageModel.builder()
|
||||||
|
.type("message")
|
||||||
|
.hostName(tiktokUser)
|
||||||
|
.eventName(eventName)
|
||||||
|
.eventContent(binary)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
tikTokDatabase.insertMessage(model);
|
||||||
|
System.out.println("EVENT: ["+tiktokUser+"] " + eventName);
|
||||||
|
})
|
||||||
|
.onError((liveClient, event) ->
|
||||||
|
{
|
||||||
|
var exception = event.getException();
|
||||||
|
var exceptionContent = ExceptionInfoModel.getStackTraceAsString(exception);
|
||||||
|
var builder = TikTokErrorModel.builder();
|
||||||
|
if (exception instanceof TikTokLiveMessageException ex) {
|
||||||
|
builder.hostName(tiktokUser)
|
||||||
|
.errorName(ex.messageName())
|
||||||
|
.errorType("error-message")
|
||||||
|
.exceptionContent(exceptionContent)
|
||||||
|
.message(ex.messageToBase64())
|
||||||
|
.response(ex.webcastResponseToBase64());
|
||||||
|
} else {
|
||||||
|
builder.hostName(tiktokUser)
|
||||||
|
.errorName(exception.getClass().getSimpleName())
|
||||||
|
.errorType("error-system")
|
||||||
|
.exceptionContent(exceptionContent)
|
||||||
|
.message("")
|
||||||
|
.response("");
|
||||||
|
}
|
||||||
|
|
||||||
|
var error = builder.build();
|
||||||
|
tikTokDatabase.insertError(error);
|
||||||
|
System.out.println("ERROR: "+error.getErrorName());
|
||||||
|
exception.printStackTrace();
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.tools.collector.db;
|
||||||
|
|
||||||
|
public class SqlConsts
|
||||||
|
{
|
||||||
|
public static String CREATE_MESSAGES_TABLE = """
|
||||||
|
CREATE TABLE IF NOT EXISTS TikTokMessageModel (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
hostName TEXT,
|
||||||
|
type TEXT,
|
||||||
|
eventName TEXT,
|
||||||
|
eventContent TEXT,
|
||||||
|
createdAt TEXT
|
||||||
|
);
|
||||||
|
""";
|
||||||
|
|
||||||
|
public static String CREATE_ERROR_TABLE = """
|
||||||
|
CREATE TABLE IF NOT EXISTS TikTokErrorModel (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
hostName VARCHAR(255),
|
||||||
|
errorName VARCHAR(255),
|
||||||
|
errorType VARCHAR(255),
|
||||||
|
exceptionContent TEXT,
|
||||||
|
message TEXT,
|
||||||
|
response TEXT,
|
||||||
|
createdAt DATETIME
|
||||||
|
);
|
||||||
|
""";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.tools.collector.db;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
|
||||||
|
import org.jdbi.v3.core.Jdbi;
|
||||||
|
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class TikTokDatabase
|
||||||
|
{
|
||||||
|
private final String database;
|
||||||
|
private TikTokMessageModelDAO messagesTable;
|
||||||
|
private TikTokErrorModelDAO errorTable;
|
||||||
|
|
||||||
|
public TikTokDatabase(String database) {
|
||||||
|
this.database =database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() throws SQLException {
|
||||||
|
var jdbcUrl ="jdbc:sqlite:"+database+".db";
|
||||||
|
var connection = DriverManager.getConnection(jdbcUrl);
|
||||||
|
Jdbi jdbi = Jdbi.create(jdbcUrl)
|
||||||
|
.installPlugin(new SqlObjectPlugin());
|
||||||
|
jdbi.useHandle(handle -> {
|
||||||
|
handle.execute(SqlConsts.CREATE_MESSAGES_TABLE);
|
||||||
|
handle.execute(SqlConsts.CREATE_ERROR_TABLE);
|
||||||
|
});
|
||||||
|
messagesTable = jdbi.onDemand(TikTokMessageModelDAO.class);
|
||||||
|
errorTable = jdbi.onDemand(TikTokErrorModelDAO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertMessage(TikTokMessageModel message)
|
||||||
|
{
|
||||||
|
var dateFormat = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS");
|
||||||
|
message.setCreatedAt(dateFormat.format(new Date()));
|
||||||
|
messagesTable.insertTikTokMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertError(TikTokErrorModel message)
|
||||||
|
{
|
||||||
|
var dateFormat = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS");
|
||||||
|
message.setCreatedAt(dateFormat.format(new Date()));
|
||||||
|
errorTable.insertTikTokMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.tools.collector.db;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
|
||||||
|
|
||||||
|
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
||||||
|
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||||
|
|
||||||
|
public interface TikTokErrorModelDAO
|
||||||
|
{
|
||||||
|
@SqlUpdate("INSERT INTO TikTokErrorModel (hostName, errorName, errorType, exceptionContent, message, response, createdAt) " +
|
||||||
|
"VALUES (:hostName, :errorName, :errorType, :exceptionContent, :message, :response, :createdAt)")
|
||||||
|
void insertTikTokMessage(@BindBean TikTokErrorModel message);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.tools.collector.db;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
|
||||||
|
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
||||||
|
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||||
|
|
||||||
|
public interface TikTokMessageModelDAO
|
||||||
|
{
|
||||||
|
@SqlUpdate("INSERT INTO TikTokMessageModel (hostName, eventName,type, eventContent, createdAt) " +
|
||||||
|
"VALUES (:hostName, :eventName, :type, :eventContent, :createdAt)")
|
||||||
|
void insertTikTokMessage(@BindBean TikTokMessageModel message);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.tools.collector.tables;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
public class ExceptionInfoModel
|
||||||
|
{
|
||||||
|
private String message;
|
||||||
|
private String stackTrace;
|
||||||
|
|
||||||
|
public ExceptionInfoModel(Throwable throwable) {
|
||||||
|
this.message = throwable.getMessage();
|
||||||
|
this.stackTrace = getStackTraceAsString(throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getStackTraceAsString(Throwable throwable) {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
throwable.printStackTrace(pw);
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters for message and stackTrace
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStackTrace() {
|
||||||
|
return stackTrace;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.tools.collector.tables;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class TikTokErrorModel
|
||||||
|
{
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String hostName;
|
||||||
|
|
||||||
|
private String errorName;
|
||||||
|
|
||||||
|
private String errorType;
|
||||||
|
|
||||||
|
private String exceptionContent;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private String response;
|
||||||
|
|
||||||
|
private String createdAt;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.tools.collector.tables;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class TikTokMessageModel
|
||||||
|
{
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String hostName;
|
||||||
|
|
||||||
|
private String eventName;
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
private String eventContent;
|
||||||
|
|
||||||
|
private String createdAt;
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>TikTokLiveJava</artifactId>
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<version>1.0.0</version>
|
<version>0.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@@ -33,6 +33,11 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jsoup</groupId>
|
||||||
|
<artifactId>jsoup</artifactId>
|
||||||
|
<version>1.13.1</version> <!-- Check for the latest version -->
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<artifactId>Client</artifactId>
|
<artifactId>Client</artifactId>
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package io.github.jwdeveloper.tiktok.events_generator;
|
package io.github.jwdeveloper.tiktok.events_generator;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.FilesUtility;
|
import io.github.jwdeveloper.tiktok.utils.FilesUtility;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class EventsGenerator
|
public class EventsGenerator
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,16 +20,16 @@ public class EventsInterfaceGenerator {
|
|||||||
// System.out.println(clazz.getName());
|
// System.out.println(clazz.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
//var result = generateInterface("io.github.jwdeveloper.tiktok.events", classes);System.out.println(result);
|
// var result = generateInterface("io.github.jwdeveloper.tiktok.events", classes);System.out.println(result);
|
||||||
|
|
||||||
|
|
||||||
var result = getBuilderImplementation("x",classes); System.out.println(result);
|
var result = getBuilderImplementation("x",classes); System.out.println(result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateInterface(String packageName, Set<Class<? extends TikTokEvent>> eventsClasses) {
|
public String generateInterface(String packageName, Set<Class<? extends TikTokEvent>> eventsClasses) {
|
||||||
|
|
||||||
TypeSpec.Builder classBuilder = TypeSpec.interfaceBuilder("TikTokEvents");
|
TypeSpec.Builder classBuilder = TypeSpec.interfaceBuilder("TikTokEventBuilder");
|
||||||
classBuilder.addModifiers(Modifier.PUBLIC);
|
classBuilder.addModifiers(Modifier.PUBLIC);
|
||||||
classBuilder.addTypeVariable(TypeVariableName.get("T"));
|
classBuilder.addTypeVariable(TypeVariableName.get("T"));
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ public class EventsInterfaceGenerator {
|
|||||||
MethodSpec.Builder constructorBuilder = MethodSpec.methodBuilder("on" + methodName);
|
MethodSpec.Builder constructorBuilder = MethodSpec.methodBuilder("on" + methodName);
|
||||||
|
|
||||||
|
|
||||||
var name = "Consumer<" + clazzName + ">";
|
var name = "TikTokEventConsumer<" + clazzName + ">";
|
||||||
constructorBuilder.addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC);
|
constructorBuilder.addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC);
|
||||||
constructorBuilder.addParameter(ClassName.bestGuess(name), "event");
|
constructorBuilder.addParameter(ClassName.bestGuess(name), "event");
|
||||||
constructorBuilder.returns(TypeVariableName.get("T"));
|
constructorBuilder.returns(TypeVariableName.get("T"));
|
||||||
@@ -91,7 +91,7 @@ public class EventsInterfaceGenerator {
|
|||||||
MethodSpec.Builder constructorBuilder = MethodSpec.methodBuilder( methodName);
|
MethodSpec.Builder constructorBuilder = MethodSpec.methodBuilder( methodName);
|
||||||
|
|
||||||
|
|
||||||
var name = "Consumer<" + clazzName + ">";
|
var name = "TikTokEventConsumer<" + clazzName + ">";
|
||||||
constructorBuilder.addModifiers( Modifier.PUBLIC);
|
constructorBuilder.addModifiers( Modifier.PUBLIC);
|
||||||
constructorBuilder.addParameter(ClassName.bestGuess(name), "event");
|
constructorBuilder.addParameter(ClassName.bestGuess(name), "event");
|
||||||
constructorBuilder.addStatement("tikTokEventHandler.subscribe("+clazzName+".class,event)");
|
constructorBuilder.addStatement("tikTokEventHandler.subscribe("+clazzName+".class,event)");
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.protocol;
|
||||||
|
|
||||||
|
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class ProtocolGenerator
|
||||||
|
{
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Path to the HTML file
|
||||||
|
File htmlFile = new File("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\page.html");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Parse the HTML file with Jsoup
|
||||||
|
var doc = Jsoup.parse(htmlFile, "UTF-8");
|
||||||
|
|
||||||
|
// Find all script tags
|
||||||
|
var scriptTags = doc.select("script");
|
||||||
|
|
||||||
|
// Display all script tags
|
||||||
|
int counter = 1;
|
||||||
|
for (var scriptTag : scriptTags) {
|
||||||
|
String srcValue = scriptTag.attr("src");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(!srcValue.contains("tiktok/webapp/main/webapp-live/"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Only print those script tags which have a 'src' attribute
|
||||||
|
if (!srcValue.isEmpty()) {
|
||||||
|
System.out.println("Script Tag " + counter + " src attribute: " + srcValue);
|
||||||
|
}
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.github.jwdeveloper.tiktok;
|
package io.github.jwdeveloper.tiktok.utils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
8
pom.xml
8
pom.xml
@@ -7,12 +7,13 @@
|
|||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<artifactId>TikTokLiveJava</artifactId>
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>1.0.0</version>
|
<version>0.0.14-Release</version>
|
||||||
<modules>
|
<modules>
|
||||||
<module>API</module>
|
<module>API</module>
|
||||||
<module>Client</module>
|
<module>Client</module>
|
||||||
<module>Tools</module>
|
<module>Tools</module>
|
||||||
<module>TestApplication</module>
|
<module>TestApplication</module>
|
||||||
|
<module>Tools-EventsCollector</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -54,6 +55,7 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||||
<shadedClassifierName>all</shadedClassifierName>
|
<shadedClassifierName>all</shadedClassifierName>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
<minimizeJar>true</minimizeJar>
|
<minimizeJar>true</minimizeJar>
|
||||||
<artifactSet>
|
<artifactSet>
|
||||||
<includes>
|
<includes>
|
||||||
@@ -64,8 +66,6 @@
|
|||||||
<filter>
|
<filter>
|
||||||
<artifact>*:*</artifact>
|
<artifact>*:*</artifact>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>**/proto/**</exclude>
|
|
||||||
<exclude>**/google/**</exclude>
|
|
||||||
<exclude>**/tiktokSchema.proto/**</exclude>
|
<exclude>**/tiktokSchema.proto/**</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
</filter>
|
</filter>
|
||||||
@@ -99,6 +99,8 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
Reference in New Issue
Block a user