mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-27 08:49:40 -05:00
Establish connection with websocket
This commit is contained in:
@@ -108,14 +108,14 @@ public class Constants {
|
||||
public static Map<String,String> DefaultRequestHeaders() {
|
||||
var headers = new HashMap<String,String>();
|
||||
|
||||
// headers.put("Connection", "keep-alive");
|
||||
headers.put("Connection", "keep-alive");
|
||||
headers.put("Cache-Control", "max-age=0");
|
||||
headers.put("Accept", "text/html,application/json,application/protobuf");
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36");
|
||||
headers.put("Referer", "https://www.tiktok.com/");
|
||||
headers.put("Origin", "https://www.tiktok.com");
|
||||
headers.put("Accept-Language", "en-US,en; q=0.9");
|
||||
// headers.put("Accept-Encoding", "gzip, deflate");
|
||||
headers.put("Accept-Encoding", "gzip, deflate");
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,21 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>2.0.7</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>2.0.7</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.github.jwdeveloper.tiktok;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpApiClient;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||
@@ -85,10 +86,11 @@ public class TikTokClientBuilder {
|
||||
meta.setUserName(userName);
|
||||
|
||||
|
||||
var requestFactory = new TikTokHttpRequestFactory();
|
||||
var apiClient = new TikTokHttpApiClient(clientSettings, requestFactory);
|
||||
var cookieJar = new TikTokCookieJar();
|
||||
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
|
||||
var apiClient = new TikTokHttpApiClient(cookieJar,clientSettings, requestFactory);
|
||||
var apiService = new TikTokApiService(apiClient, logger,clientParameters);
|
||||
var webSocketClient = new TikTokWebsocketClient(logger,clientParameters, clientSettings);
|
||||
var webSocketClient = new TikTokWebsocketClient(logger, cookieJar,clientParameters, requestFactory,clientSettings);
|
||||
var giftManager =new TikTokGiftManager(logger, apiService, clientSettings);
|
||||
return new TikTokLiveClient(meta,apiService, webSocketClient, giftManager, logger);
|
||||
}
|
||||
|
||||
@@ -5,19 +5,11 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class TikTokCookieJar {
|
||||
/// <summary>
|
||||
/// Cookies in Jar
|
||||
/// </summary>
|
||||
private final Map<String, String> cookies;
|
||||
|
||||
/// <summary>
|
||||
/// Create a TikTok cookie jar instance.
|
||||
/// </summary>
|
||||
public TikTokCookieJar() {
|
||||
cookies = new HashMap<>();
|
||||
}
|
||||
|
||||
|
||||
public String get(String key) {
|
||||
return cookies.get(key);
|
||||
}
|
||||
@@ -26,19 +18,17 @@ public class TikTokCookieJar {
|
||||
cookies.put(key, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates Cookies
|
||||
/// </summary>
|
||||
public Set<Map.Entry<String, String>> GetEnumerator() {
|
||||
return cookies.entrySet();
|
||||
}
|
||||
|
||||
/* /// <summary>
|
||||
/// Enumerates Cookies
|
||||
/// </summary>
|
||||
public IEnumerator<string> GetEnumerator()
|
||||
public String parseCookies()
|
||||
{
|
||||
foreach (var cookie in cookies)
|
||||
yield return $"{cookie.Key}={cookie.Value};";
|
||||
}*/
|
||||
var sb = new StringBuilder();
|
||||
for(var entry : cookies.entrySet())
|
||||
{
|
||||
sb.append(entry.getKey()).append("=").append(entry.getValue()).append(";");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,17 +11,21 @@ import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class TikTokHttpApiClient {
|
||||
private final ClientSettings clientSettings;
|
||||
private final TikTokHttpRequestFactory requestFactory;
|
||||
private final TikTokCookieJar tikTokCookieJar;
|
||||
|
||||
public TikTokHttpApiClient(ClientSettings clientSettings, TikTokHttpRequestFactory requestFactory) {
|
||||
|
||||
public TikTokHttpApiClient(TikTokCookieJar tikTokCookieJar, ClientSettings clientSettings, TikTokHttpRequestFactory requestFactory) {
|
||||
this.clientSettings = clientSettings;
|
||||
this.requestFactory = requestFactory;
|
||||
this.tikTokCookieJar = tikTokCookieJar;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +72,18 @@ public class TikTokHttpApiClient {
|
||||
.build();
|
||||
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||
|
||||
var cookies = response.headers().allValues("Set-Cookie");
|
||||
for(var cookie : cookies)
|
||||
{
|
||||
var split = cookie.split(";")[0].split("=");
|
||||
|
||||
|
||||
var key = split[0];
|
||||
var value = split[1];
|
||||
tikTokCookieJar.set(key, value);
|
||||
var i =0;
|
||||
}
|
||||
|
||||
return response.body();
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -80,7 +96,7 @@ public class TikTokHttpApiClient {
|
||||
private String GetSignedUrl(String url, Map<String, Object> parameters) {
|
||||
|
||||
var fullUrl = HttpUtils.parseParameters(url,parameters);
|
||||
var singHeaders = new HashMap<String, Object>();
|
||||
var singHeaders = new TreeMap<String,Object>();
|
||||
singHeaders.put("client", "ttlive-net");
|
||||
singHeaders.put("uuc", 1);
|
||||
singHeaders.put("url", fullUrl);
|
||||
@@ -95,7 +111,6 @@ public class TikTokHttpApiClient {
|
||||
var signedUrl = jsonObject.get("signedUrl").getAsString();
|
||||
var userAgent = jsonObject.get("User-Agent").getAsString();
|
||||
|
||||
//requestFactory.setHeader()
|
||||
requestFactory.setAgent(userAgent);
|
||||
return signedUrl;
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.net.URLEncoder;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.WebSocket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
@@ -29,9 +30,12 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
|
||||
private Boolean sent;
|
||||
private Map<String, String> defaultHeaders;
|
||||
|
||||
public TikTokHttpRequestFactory() {
|
||||
private TikTokCookieJar tikTokCookieJar;
|
||||
|
||||
public TikTokHttpRequestFactory(TikTokCookieJar tikTokCookieJar) {
|
||||
|
||||
cookieManager = new CookieManager();
|
||||
this.tikTokCookieJar = tikTokCookieJar;
|
||||
defaultHeaders = Constants.DefaultRequestHeaders();
|
||||
client = HttpClient.newBuilder()
|
||||
.cookieHandler(cookieManager)
|
||||
@@ -39,6 +43,11 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
|
||||
.build();
|
||||
}
|
||||
|
||||
public WebSocket.Builder openSocket()
|
||||
{
|
||||
return client.newWebSocketBuilder();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public String Get(String url) {
|
||||
var uri = URI.create(url);
|
||||
@@ -124,8 +133,14 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
|
||||
{
|
||||
var split = cookie.split(";")[0].split("=");
|
||||
var uri = request.uri();
|
||||
|
||||
|
||||
var key = split[0];
|
||||
var value = split[1];
|
||||
tikTokCookieJar.set(key, value);
|
||||
|
||||
var map = new HashMap<String,List<String>>();
|
||||
map.put(split[0],List.of(split[1]));
|
||||
map.put(key,List.of(value));
|
||||
cookieManager.put(uri,map);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package io.github.jwdeveloper.tiktok.websocket;
|
||||
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
|
||||
public class Client2 extends WebSocketClient {
|
||||
public Client2(URI serverUri, Map<String, String> httpHeaders) {
|
||||
super(serverUri,httpHeaders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(ServerHandshake serverHandshake) {
|
||||
|
||||
System.out.println("Open");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String s) {
|
||||
System.out.println("MESSAGE");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer bytes) {
|
||||
System.out.println("MESSAGE binary");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int i, String s, boolean b) {
|
||||
System.out.println("Close");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
System.out.println("Error");
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
package io.github.jwdeveloper.tiktok.websocket;
|
||||
|
||||
import java.net.http.WebSocket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
|
||||
public class TikTokWebSocketListener implements java.net.http.WebSocket.Listener {
|
||||
//Insert Body here
|
||||
|
||||
@Override
|
||||
public void onOpen(java.net.http.WebSocket webSocket) {
|
||||
@@ -18,14 +19,31 @@ public class TikTokWebSocketListener implements java.net.http.WebSocket.Listene
|
||||
|
||||
@Override
|
||||
public CompletionStage<?> onText(java.net.http.WebSocket webSocket, CharSequence data, boolean last) {
|
||||
System.out.println("Received message: " + data);
|
||||
System.out.println("Received onText: " + data);
|
||||
return java.net.http.WebSocket.Listener.super.onText(webSocket, data, last);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<?> onPing(WebSocket webSocket, ByteBuffer message) {
|
||||
System.out.println("Received onPing: " );
|
||||
return java.net.http.WebSocket.Listener.super.onPing(webSocket, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<?> onBinary(WebSocket webSocket, ByteBuffer data, boolean last) {
|
||||
System.out.println("Received onBinary: " + data);
|
||||
return java.net.http.WebSocket.Listener.super.onBinary(webSocket, data, last);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<?> onClose(java.net.http.WebSocket webSocket, int statusCode, String reason) {
|
||||
System.out.println("WebSocket closed with status code: " + statusCode + " and reason: " + reason);
|
||||
return java.net.http.WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<?> onPong(WebSocket webSocket, ByteBuffer message) {
|
||||
System.out.println("Received onPong: ");
|
||||
return java.net.http.WebSocket.Listener.super.onPong(webSocket,message);
|
||||
}
|
||||
}
|
||||
@@ -2,46 +2,64 @@ package io.github.jwdeveloper.tiktok.websocket;
|
||||
|
||||
import io.github.jwdeveloper.generated.WebcastResponse;
|
||||
import io.github.jwdeveloper.tiktok.ClientSettings;
|
||||
import io.github.jwdeveloper.tiktok.Constants;
|
||||
import io.github.jwdeveloper.tiktok.TikTokLiveException;
|
||||
import io.github.jwdeveloper.tiktok.http.HttpUtils;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class TikTokWebsocketClient {
|
||||
private final Logger logger;
|
||||
private final Map<String, Object> clientParams;
|
||||
private final ClientSettings clientSettings;
|
||||
private final TikTokCookieJar tikTokCookieJar;
|
||||
private final TikTokHttpRequestFactory factory;
|
||||
|
||||
public TikTokWebsocketClient(Logger logger, Map<String, Object> clientParams, ClientSettings clientSettings) {
|
||||
public TikTokWebsocketClient(Logger logger,
|
||||
TikTokCookieJar tikTokCookieJar,
|
||||
Map<String, Object> clientParams,
|
||||
TikTokHttpRequestFactory factory,
|
||||
ClientSettings clientSettings) {
|
||||
this.logger = logger;
|
||||
this.clientParams = clientParams;
|
||||
this.tikTokCookieJar = tikTokCookieJar;
|
||||
this.clientSettings = clientSettings;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public void start(WebcastResponse webcastResponse) {
|
||||
if (webcastResponse.getWsUrl().isEmpty() || webcastResponse.getWsParam().getAllFields().isEmpty()) {
|
||||
throw new TikTokLiveException("Could not find Room");
|
||||
}
|
||||
try {
|
||||
for (var param : webcastResponse.getWsParam().getAllFields().entrySet()) {
|
||||
var name = param.getKey().getName();
|
||||
var value = param.getValue();
|
||||
clientParams.put(name, value);
|
||||
logger.info("Adding Custom Param" + param.getKey().getName() + " " + param.getValue());
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
|
||||
var params = webcastResponse.getWsParam();
|
||||
var name = params.getName();
|
||||
var value = params.getValue();
|
||||
System.out.println("KEY: " + name + " value: " + value);
|
||||
|
||||
|
||||
var headers = Constants.DefaultRequestHeaders();
|
||||
|
||||
|
||||
var clone = new TreeMap<>(clientParams);
|
||||
// clone.putAll(headers);
|
||||
clone.put(name, value);
|
||||
clone.put("compress", "gzip");
|
||||
|
||||
var url = webcastResponse.getWsUrl();
|
||||
var wsUrl = HttpUtils.parseParametersEncode(url, clientParams);
|
||||
logger.info("Creating Socket with URL " + wsUrl);
|
||||
//socketClient = new TikTokWebSocket(TikTokHttpRequest.CookieJar, token, settings.SocketBufferSize);
|
||||
//connectedSocketUrl = url;
|
||||
//await socketClient.Connect(url);
|
||||
|
||||
var wsUrl = HttpUtils.parseParametersEncode(url, clone);
|
||||
logger.info("Starting Socket-Threads");
|
||||
//runningTask = Task.Run(WebSocketLoop, token);
|
||||
//pollingTask = Task.Run(PingLoop, token);
|
||||
@@ -51,28 +69,44 @@ public class TikTokWebsocketClient {
|
||||
}
|
||||
if (clientSettings.isHandleExistingMessagesOnConnect()) {
|
||||
try {
|
||||
// HandleWebcastMessages(webcastResponse);
|
||||
// HandleWebcastMessages(webcastResponse);
|
||||
} catch (Exception e) {
|
||||
throw new TikTokLiveException("Error Handling Initial Messages", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startWS(String url)
|
||||
{
|
||||
public void startWS(String url) {
|
||||
try {
|
||||
var cookie = tikTokCookieJar.parseCookies();
|
||||
logger.info("WssIP: " + url);
|
||||
logger.info("Cookie: " + cookie);
|
||||
|
||||
var cookie = "tt_csrf_token=Fh92faHZ-fVnWZ8CG58Wb_kIC1hb-QzizkRM;ttwid=1%7CergNdYee4w-v_96VkhyDxkJ8NIavveA-NvCEdWF68Ik%7C1691076950%7C154533521f698b079ff5300fbd058e85e81a8ef64c41349f1d218124aa74a6db;";
|
||||
// var url = "wss://webcast16-ws-useast1a.tiktok.com/webcast/im/push/?aid=1988&app_language=en-US&app_name=tiktok_web&browser_language=en&browser_name=Mozilla&browser_online=True&browser_platform=Win32&browser_version=5.0+(Windows+NT+10.0%3b+Win64%3b+x64)+AppleWebKit%2f537.36+(KHTML%2c+like+Gecko)+Chrome%2f102.0.5005.63+Safari%2f537.36&cookie_enabled=True&cursor=1691242057374_7263829320139870326_1_1_0_0&internal_ext=fetch_time%3a1691242057374%7cstart_time%3a0%7cack_ids%3a%2c%7cflag%3a0%7cseq%3a1%7cnext_cursor%3a1691242057374_7263829320139870326_1_1_0_0%7cwss_info%3a0-1691242057374-0-0&device_platform=web&focus_state=True&from_page=user&history_len=4&is_fullscreen=False&is_page_visible=True&did_rule=3&fetch_rule=1&identity=audience&last_rtt=0&live_id=12&resp_content_type=protobuf&screen_height=1152&screen_width=2048&tz_name=Europe%2fBerlin&referer=https%2c+%2f%2fwww.tiktok.com%2f&root_referer=https%2c+%2f%2fwww.tiktok.com%2f&msToken=&version_code=180800&webcast_sdk_version=1.3.0&update_version_code=1.3.0&webcast_language=en-US&room_id=7263759223213132577&imprp=u65Ja_b3czc3iEAb4x6oLXindKyTO";
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
var ws = client.newWebSocketBuilder()
|
||||
var map = new HashMap<String, String>();
|
||||
map.put("Cookie", cookie);
|
||||
|
||||
//var cluent2 = new Client2(URI.create(url), map);
|
||||
var builder = HttpClient.newHttpClient().newWebSocketBuilder();
|
||||
var ws = builder
|
||||
.subprotocols("echo-protocol")
|
||||
.connectTimeout(Duration.ofSeconds(15))
|
||||
.header("cookie",cookie)
|
||||
.buildAsync(URI.create(url),new TikTokWebSocketListener()).get();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
.header("Cookie", cookie)
|
||||
.buildAsync(URI.create(url), new TikTokWebSocketListener()).get();
|
||||
|
||||
|
||||
|
||||
var i =0;
|
||||
while (true) {
|
||||
byte[] message = new byte[]{58, 2, 104, 98};
|
||||
ByteBuffer buffer = ByteBuffer.wrap(message);
|
||||
while (buffer.hasRemaining()) {
|
||||
ws.sendPing(buffer);
|
||||
}
|
||||
buffer.clear();
|
||||
Thread.sleep(10);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.io.IOException;
|
||||
|
||||
public class TikTokLiveTest
|
||||
{
|
||||
public static String TEST_USER_SUBJECT = "moniczkka";
|
||||
public static String TEST_USER_SUBJECT = "erwin_winki";
|
||||
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user