mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-27 16:59:39 -05:00
Compare commits
10 Commits
0.0.12-Rel
...
0.0.14-Rel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e9244aa67 | ||
|
|
fadb1ab267 | ||
|
|
4273375eb9 | ||
|
|
3daeee6316 | ||
|
|
cde38df1b3 | ||
|
|
15d6351d65 | ||
|
|
44ba999b83 | ||
|
|
5cf0d30962 | ||
|
|
71ebc6e05e | ||
|
|
c6d09927a0 |
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>0.0.11-Release</version>
|
||||
<version>0.0.13-Release</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>API</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>0.0.11-Release</version>
|
||||
<version>0.0.13-Release</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -29,6 +29,23 @@
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>3.24.1</version>
|
||||
</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>
|
||||
|
||||
|
||||
|
||||
@@ -70,7 +70,6 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
|
||||
var tiktokRoomInfo = new TikTokRoomInfo();
|
||||
tiktokRoomInfo.setUserName(clientSettings.getHostName());
|
||||
|
||||
|
||||
var cookieJar = new TikTokCookieJar();
|
||||
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
|
||||
var apiClient = new TikTokHttpApiClient(cookieJar, requestFactory);
|
||||
@@ -79,7 +78,6 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
|
||||
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler, clientSettings, logger, giftManager, tiktokRoomInfo);
|
||||
var webSocketClient = new TikTokWebSocketClient(logger,
|
||||
cookieJar,
|
||||
requestFactory,
|
||||
clientSettings,
|
||||
webResponseHandler,
|
||||
tikTokEventHandler);
|
||||
|
||||
@@ -105,16 +105,18 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
||||
private TikTokEvent handleSocialMedia(WebcastResponse.Message msg) {
|
||||
var message = WebcastSocialMessage.parseFrom(msg.getBinary());
|
||||
|
||||
String type = message.getHeader().getSocialData().getType();
|
||||
Pattern pattern = Pattern.compile("\\d+");
|
||||
Matcher matcher = pattern.matcher(type);
|
||||
if (matcher.find()) {
|
||||
var socialType = message.getHeader().getSocialData().getType();
|
||||
var pattern = Pattern.compile("pm_mt_guidance_viewer_([0-9]+)_share");
|
||||
var matcher = pattern.matcher(socialType);
|
||||
|
||||
if (matcher.find())
|
||||
{
|
||||
var value = matcher.group(0);
|
||||
var number = Integer.parseInt(value);
|
||||
return new TikTokShareEvent(message, number);
|
||||
}
|
||||
|
||||
var socialType = message.getHeader().getSocialData().getType();
|
||||
|
||||
return switch (socialType) {
|
||||
case SocialTypes.LikeType -> new TikTokLikeEvent(message);
|
||||
case SocialTypes.FollowType -> new TikTokFollowEvent(message);
|
||||
|
||||
@@ -90,7 +90,7 @@ public class TikTokHttpApiClient {
|
||||
|
||||
var fullUrl = HttpUtils.parseParameters(url,parameters);
|
||||
var singHeaders = new TreeMap<String,Object>();
|
||||
singHeaders.put("client", "ttlive-net");
|
||||
singHeaders.put("client", "ttlive-java");
|
||||
singHeaders.put("uuc", 1);
|
||||
singHeaders.put("url", fullUrl);
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ import io.github.jwdeveloper.tiktok.http.HttpUtils;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.WebSocket;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Logger;
|
||||
@@ -23,24 +23,21 @@ public class TikTokWebSocketClient {
|
||||
private final Logger logger;
|
||||
private final ClientSettings clientSettings;
|
||||
private final TikTokCookieJar tikTokCookieJar;
|
||||
private final TikTokHttpRequestFactory factory;
|
||||
private final TikTokMessageHandlerRegistration webResponseHandler;
|
||||
private final TikTokEventHandler tikTokEventHandler;
|
||||
|
||||
private WebSocket webSocket;
|
||||
private WebSocketClient webSocketClient;
|
||||
private boolean isConnected;
|
||||
private TikTokLiveClient tikTokLiveClient;
|
||||
|
||||
public TikTokWebSocketClient(Logger logger,
|
||||
TikTokCookieJar tikTokCookieJar,
|
||||
TikTokHttpRequestFactory factory,
|
||||
ClientSettings clientSettings,
|
||||
TikTokMessageHandlerRegistration webResponseHandler,
|
||||
TikTokEventHandler tikTokEventHandler) {
|
||||
this.logger = logger;
|
||||
this.tikTokCookieJar = tikTokCookieJar;
|
||||
this.clientSettings = clientSettings;
|
||||
this.factory = factory;
|
||||
this.webResponseHandler = webResponseHandler;
|
||||
this.tikTokEventHandler = tikTokEventHandler;
|
||||
isConnected = false;
|
||||
@@ -56,12 +53,12 @@ public class TikTokWebSocketClient {
|
||||
}
|
||||
try {
|
||||
var url = getWebSocketUrl(webcastResponse);
|
||||
if (clientSettings.isHandleExistingMessagesOnConnect())
|
||||
{
|
||||
if (clientSettings.isHandleExistingMessagesOnConnect()) {
|
||||
logger.info("Handling existing messages");
|
||||
webResponseHandler.handle(tikTokLiveClient, webcastResponse);
|
||||
}
|
||||
webSocket = startWebSocket(url);
|
||||
webSocketClient = startWebSocket(url);
|
||||
webSocketClient.connect();
|
||||
} catch (Exception e) {
|
||||
throw new TikTokLiveException("Failed to connect to the websocket", e);
|
||||
}
|
||||
@@ -82,20 +79,19 @@ public class TikTokWebSocketClient {
|
||||
return HttpUtils.parseParametersEncode(url, clone);
|
||||
}
|
||||
|
||||
private WebSocket startWebSocket(String url) throws Exception {
|
||||
private WebSocketClient startWebSocket(String url) {
|
||||
var cookie = tikTokCookieJar.parseCookies();
|
||||
var map = new HashMap<String, String>();
|
||||
map.put("Cookie", cookie);
|
||||
return factory.openSocket()
|
||||
.subprotocols("echo-protocol")
|
||||
.connectTimeout(Duration.ofSeconds(15))
|
||||
.header("Cookie", cookie)
|
||||
.buildAsync(URI.create(url), new TikTokWebSocketListener(webResponseHandler, tikTokEventHandler, tikTokLiveClient)).get();
|
||||
|
||||
return new TikTokWebSocketListener(URI.create(url), map, 3000, webResponseHandler, tikTokEventHandler, tikTokLiveClient);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void stop() {
|
||||
if (isConnected && webSocket != null) {
|
||||
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
|
||||
if (isConnected && webSocketClient != null) {
|
||||
webSocketClient.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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;
|
||||
@@ -12,71 +11,71 @@ import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||
import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketAck;
|
||||
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.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
public class TikTokWebSocketListener extends WebSocketClient {
|
||||
|
||||
public class TikTokWebSocketListener implements java.net.http.WebSocket.Listener {
|
||||
|
||||
private final ByteArrayOutputStream accumulatedData = new ByteArrayOutputStream();
|
||||
private final TikTokMessageHandlerRegistration webResponseHandler;
|
||||
private final TikTokEventHandler tikTokEventHandler;
|
||||
private final TikTokLiveClient tikTokLiveClient;
|
||||
|
||||
public TikTokWebSocketListener(TikTokMessageHandlerRegistration webResponseHandler,
|
||||
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.tikTokEventHandler = tikTokEventHandler;
|
||||
this.tikTokLiveClient = tikTokLiveClient;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompletionStage<?> onBinary(WebSocket webSocket, ByteBuffer data, boolean last) {
|
||||
try {
|
||||
var bytes = new byte[data.remaining()];
|
||||
data.get(bytes);
|
||||
accumulatedData.write(bytes);
|
||||
if (last) {
|
||||
handleBinary(webSocket, accumulatedData.toByteArray());
|
||||
accumulatedData.reset();
|
||||
public void onOpen(ServerHandshake serverHandshake) {
|
||||
tikTokEventHandler.publish(tikTokLiveClient,new TikTokConnectedEvent());
|
||||
sendPing();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer bytes)
|
||||
{
|
||||
try {
|
||||
handleBinary(bytes.array());
|
||||
} catch (Exception e) {
|
||||
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e));
|
||||
}
|
||||
webSocket.request(1);
|
||||
return null;
|
||||
sendPing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(java.net.http.WebSocket webSocket) {
|
||||
tikTokEventHandler.publish(tikTokLiveClient,new TikTokConnectedEvent());
|
||||
webSocket.request(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(java.net.http.WebSocket webSocket, Throwable error) {
|
||||
tikTokEventHandler.publish(tikTokLiveClient,new TikTokErrorEvent(error));
|
||||
webSocket.request(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<?> onClose(java.net.http.WebSocket webSocket, int statusCode, String reason) {
|
||||
public void onClose(int i, String s, boolean b) {
|
||||
tikTokEventHandler.publish(tikTokLiveClient,new TikTokDisconnectedEvent());
|
||||
return java.net.http.WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
|
||||
}
|
||||
|
||||
private void handleBinary(WebSocket webSocket, byte[] buffer) {
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
tikTokEventHandler.publish(tikTokLiveClient,new TikTokErrorEvent(error));
|
||||
sendPing();
|
||||
}
|
||||
|
||||
private void handleBinary(byte[] buffer) {
|
||||
var websocketMessageOptional = getWebcastWebsocketMessage(buffer);
|
||||
if (websocketMessageOptional.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
var websocketMessage = websocketMessageOptional.get();
|
||||
sendAckId(webSocket, websocketMessage.getId());
|
||||
sendAckId(websocketMessage.getId());
|
||||
|
||||
var webResponse = getWebResponseMessage(websocketMessage.getBinary());
|
||||
webResponseHandler.handle(tikTokLiveClient, webResponse);
|
||||
@@ -114,13 +113,19 @@ public class TikTokWebSocketListener implements java.net.http.WebSocket.Listener
|
||||
}
|
||||
}
|
||||
|
||||
private void sendAckId(WebSocket webSocket, long id) {
|
||||
private void sendAckId(long id) {
|
||||
var serverInfo = WebcastWebsocketAck
|
||||
.newBuilder()
|
||||
.setType("ack")
|
||||
.setId(id)
|
||||
.build();
|
||||
webSocket.sendBinary(serverInfo.toByteString().asReadOnlyByteBuffer(), true);
|
||||
send(serverInfo.toByteString().asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onMessage(String s) {
|
||||
|
||||
}
|
||||
}
|
||||
56
README.md
56
README.md
@@ -37,22 +37,16 @@ Do you prefer other programming languages?
|
||||
```xml
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>3.24.1</version>
|
||||
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
|
||||
<artifactId>Client</artifactId>
|
||||
<version>0.0.13-Release</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.jwdeveloper</groupId>
|
||||
<artifactId>TikTok-Live-Java</artifactId>
|
||||
<version>0.0.11-Release</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
@@ -65,23 +59,28 @@ Do you prefer other programming languages?
|
||||
var tiktokUsername = "jwdevtiktok";
|
||||
|
||||
TikTokLive.newClient(tiktokUsername)
|
||||
.onConnected(event ->
|
||||
.onConnected((client, event) ->
|
||||
{
|
||||
System.out.println("Connected");
|
||||
})
|
||||
.onJoin(event ->
|
||||
.onJoin((client, event) ->
|
||||
{
|
||||
System.out.println("User joined -> " + event.getUser().getNickName());
|
||||
})
|
||||
.onComment(event ->
|
||||
.onComment((client, event) ->
|
||||
{
|
||||
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();
|
||||
})
|
||||
.buildAndRun();
|
||||
System.in.read();
|
||||
}
|
||||
```
|
||||
## Configuration
|
||||
@@ -90,35 +89,36 @@ Do you prefer other programming languages?
|
||||
public class ConfigurationExample
|
||||
{
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
TikTokLive.newClient("jwdevtiktok")
|
||||
var tiktokUsername = "jwdevtiktok";
|
||||
TikTokLive.newClient(tiktokUsername)
|
||||
.configure(clientSettings ->
|
||||
{
|
||||
clientSettings.setHostName("jwdevtiktok"); //tiktok user
|
||||
clientSettings.setClientLanguage("en"); //language
|
||||
clientSettings.setTimeout(Duration.ofSeconds(2)); //connection timeout
|
||||
clientSettings.setLogLevel(Level.ALL); //log level
|
||||
clientSettings.setDownloadGiftInfo(true); //TODO
|
||||
clientSettings.setCheckForUnparsedData(true); //TODO
|
||||
clientSettings.setPollingInterval(Duration.ofSeconds(1)); //TODO
|
||||
clientSettings.setPrintMessageData(true); //TODO
|
||||
clientSettings.setPrintToConsole(true); //TODO
|
||||
clientSettings.setHandleExistingMessagesOnConnect(true); //TODO
|
||||
clientSettings.setRetryOnConnectionFailure(true); //TODO
|
||||
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
|
||||
A `TikTokLive` object contains the following methods.
|
||||
A `client (LiveClient)` object contains the following methods.
|
||||
|
||||
| Method Name | Description |
|
||||
| ----------- | ----------- |
|
||||
| connect | Connects to the live stream chat.<br>Returns a `Promise` which will be resolved when the connection is successfully established. |
|
||||
| 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. |
|
||||
|
||||
## Events
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>0.0.11-Release</version>
|
||||
<version>0.0.13-Release</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.io.IOException;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static String TEST_TIKTOK_USER = "vadimpyrography";
|
||||
public static String TEST_TIKTOK_USER = "kitovskyyy";
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
var client = TikTokLive.newClient(TEST_TIKTOK_USER)
|
||||
|
||||
@@ -6,10 +6,15 @@ public class SimpleExample {
|
||||
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((client, event) ->
|
||||
{
|
||||
System.out.println("Connected");
|
||||
})
|
||||
|
||||
.onJoin((client, event) ->
|
||||
{
|
||||
System.out.println("User joined -> " + event.getUser().getNickName());
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<version>0.0.11-Release</version>
|
||||
<version>0.0.13-Release</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
7
pom.xml
7
pom.xml
@@ -7,7 +7,7 @@
|
||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||
<artifactId>TikTokLiveJava</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.0.11-Release</version>
|
||||
<version>0.0.13-Release</version>
|
||||
<modules>
|
||||
<module>API</module>
|
||||
<module>Client</module>
|
||||
@@ -54,6 +54,7 @@
|
||||
<configuration>
|
||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||
<shadedClassifierName>all</shadedClassifierName>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
@@ -64,8 +65,6 @@
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>**/proto/**</exclude>
|
||||
<exclude>**/google/**</exclude>
|
||||
<exclude>**/tiktokSchema.proto/**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
@@ -99,6 +98,8 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
Reference in New Issue
Block a user