mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-27 08:49:40 -05:00
Implement Eulerstream send chat API endpoint!
This commit is contained in:
@@ -26,6 +26,7 @@ import io.github.jwdeveloper.tiktok.data.requests.GiftsData;
|
||||
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
|
||||
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
|
||||
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
|
||||
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
|
||||
|
||||
public interface LiveHttpClient
|
||||
{
|
||||
@@ -64,4 +65,6 @@ public interface LiveHttpClient
|
||||
}
|
||||
|
||||
LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request);
|
||||
|
||||
boolean sendChat(LiveRoomInfo roomInfo, String content);
|
||||
}
|
||||
@@ -36,7 +36,6 @@ public interface LiveClient {
|
||||
*/
|
||||
void connect();
|
||||
|
||||
|
||||
/**
|
||||
* Connects in asynchronous way
|
||||
* When connected Consumer returns instance of LiveClient
|
||||
@@ -48,7 +47,6 @@ public interface LiveClient {
|
||||
*/
|
||||
CompletableFuture<LiveClient> connectAsync();
|
||||
|
||||
|
||||
/**
|
||||
* Disconnects the connection.
|
||||
* @param type
|
||||
@@ -68,7 +66,6 @@ public interface LiveClient {
|
||||
*/
|
||||
void publishEvent(TikTokEvent event);
|
||||
|
||||
|
||||
/**
|
||||
* @param webcastMessageName name of TikTok protocol-buffer message
|
||||
* @param payloadBase64 protocol-buffer message bytes payload
|
||||
@@ -96,4 +93,12 @@ public interface LiveClient {
|
||||
* Logger
|
||||
*/
|
||||
Logger getLogger();
|
||||
|
||||
/**
|
||||
* Send a chat message to the connected room
|
||||
* @return true if successful, otherwise false
|
||||
* @apiNote This is known to return true on some sessionIds despite failing!
|
||||
* <p>We cannot fix this as it is a TikTok issue, not a library issue.
|
||||
*/
|
||||
boolean sendChat(String content);
|
||||
}
|
||||
@@ -183,6 +183,11 @@ public class TikTokLiveClient implements LiveClient
|
||||
messageHandler.handleSingleMessage(this, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendChat(String content) {
|
||||
return httpClient.sendChat(roomInfo, content);
|
||||
}
|
||||
|
||||
public void connectAsync(Consumer<LiveClient> onConnection) {
|
||||
connectAsync().thenAccept(onConnection);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
package io.github.jwdeveloper.tiktok;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import io.github.jwdeveloper.dependance.injector.api.annotations.Inject;
|
||||
import io.github.jwdeveloper.tiktok.common.*;
|
||||
@@ -30,9 +31,10 @@ import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.*;
|
||||
import io.github.jwdeveloper.tiktok.http.*;
|
||||
import io.github.jwdeveloper.tiktok.http.mappers.*;
|
||||
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
|
||||
import io.github.jwdeveloper.tiktok.messages.webcast.ProtoMessageFetchResult;
|
||||
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -42,6 +44,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
|
||||
* <a href="https://github-wiki-see.page/m/isaackogan/TikTokLive/wiki/All-About-Signatures">Signing API by Isaac Kogan</a>
|
||||
*/
|
||||
private static final String TIKTOK_SIGN_API = "https://tiktok.eulerstream.com/webcast/fetch";
|
||||
private static final String TIKTOK_CHAT_URL = "https://tiktok.eulerstream.com/webcast/chat";
|
||||
private static final String TIKTOK_URL_WEB = "https://www.tiktok.com/";
|
||||
private static final String TIKTOK_URL_WEBCAST = "https://webcast.tiktok.com/webcast/";
|
||||
public static final String TIKTOK_ROOM_GIFTS_URL = TIKTOK_URL_WEBCAST+"gift/list/";
|
||||
@@ -182,6 +185,33 @@ public class TikTokLiveHttpClient implements LiveHttpClient
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendChat(LiveRoomInfo roomInfo, String content) {
|
||||
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
||||
if (proxyClientSettings.isEnabled()) {
|
||||
while (proxyClientSettings.hasNext()) {
|
||||
try {
|
||||
return requestSendChat(roomInfo, content);
|
||||
} catch (TikTokProxyRequestException ignored) {}
|
||||
}
|
||||
}
|
||||
return requestSendChat(roomInfo, content);
|
||||
}
|
||||
|
||||
public boolean requestSendChat(LiveRoomInfo roomInfo, String content) {
|
||||
JsonObject body = new JsonObject();
|
||||
body.addProperty("content", content);
|
||||
body.addProperty("sessionId", clientSettings.getSessionId());
|
||||
body.addProperty("ttTargetIdc", clientSettings.getTtTargetIdc());
|
||||
body.addProperty("roomId", roomInfo.getRoomId());
|
||||
var result = httpFactory.client(TIKTOK_CHAT_URL)
|
||||
.withHeader("Content-Type", "application/json")
|
||||
.withBody(HttpRequest.BodyPublishers.ofString(body.toString()))
|
||||
.build()
|
||||
.toJsonResponse();
|
||||
return result.isSuccess();
|
||||
}
|
||||
|
||||
protected ActionResult<HttpResponse<byte[]>> getStartingPayload(LiveConnectionData.Request request) {
|
||||
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
||||
if (proxyClientSettings.isEnabled()) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||
import io.github.jwdeveloper.tiktok.data.requests.*;
|
||||
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
|
||||
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
|
||||
import io.github.jwdeveloper.tiktok.messages.webcast.ProtoMessageFetchResult;
|
||||
|
||||
import java.net.URI;
|
||||
@@ -45,20 +46,26 @@ public class TikTokLiveHttpOfflineClient implements LiveHttpClient {
|
||||
@Override
|
||||
public LiveData.Response fetchLiveData(LiveData.Request request) {
|
||||
return new LiveData.Response("",
|
||||
LiveData.LiveStatus.HostOnline,
|
||||
"offline live",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
new User(0L, "offline user", new Picture("")),
|
||||
LiveData.LiveType.SOLO);
|
||||
LiveData.LiveStatus.HostOnline,
|
||||
"offline live",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
new User(0L, "offline user", new Picture("")),
|
||||
LiveData.LiveType.SOLO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request) {
|
||||
return new LiveConnectionData.Response("",
|
||||
URI.create("https://example.live"),
|
||||
ProtoMessageFetchResult.newBuilder().build());
|
||||
URI.create("https://example.live"),
|
||||
ProtoMessageFetchResult.newBuilder().build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendChat(LiveRoomInfo roomInfo, String content) {
|
||||
// DO NOTHING
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -40,11 +40,12 @@ public class HttpClient {
|
||||
|
||||
protected final HttpClientSettings httpClientSettings;
|
||||
protected final String url;
|
||||
protected final HttpRequest.BodyPublisher bodyPublisher;
|
||||
private final Pattern pattern = Pattern.compile("charset=(.*?)(?=&|$)");
|
||||
|
||||
public <T> ActionResult<HttpResponse<T>> toHttpResponse(HttpResponse.BodyHandler<T> handler) {
|
||||
var client = prepareClient();
|
||||
var request = prepareGetRequest();
|
||||
var request = prepareRequest();
|
||||
try {
|
||||
var response = client.send(request, handler);
|
||||
var result = ActionResult.of(response);
|
||||
@@ -99,8 +100,13 @@ public class HttpClient {
|
||||
return URI.create(stringUrl);
|
||||
}
|
||||
|
||||
protected HttpRequest prepareGetRequest() {
|
||||
var requestBuilder = HttpRequest.newBuilder().GET();
|
||||
/**
|
||||
* @return {@link HttpRequest} with default GET, otherwise POST if {@link #bodyPublisher} is not null
|
||||
*/
|
||||
protected HttpRequest prepareRequest() {
|
||||
var requestBuilder = HttpRequest.newBuilder();
|
||||
if (bodyPublisher != null)
|
||||
requestBuilder.POST(bodyPublisher);
|
||||
requestBuilder.uri(toUri());
|
||||
requestBuilder.timeout(httpClientSettings.getTimeout());
|
||||
if (!httpClientSettings.getCookies().isEmpty()) {
|
||||
@@ -124,12 +130,10 @@ public class HttpClient {
|
||||
}
|
||||
|
||||
protected String prepareUrlWithParameters(String url, Map<String, Object> parameters) {
|
||||
if (parameters.isEmpty()) {
|
||||
return url;
|
||||
}
|
||||
if (parameters.isEmpty())
|
||||
return url;
|
||||
|
||||
return url + "?" + parameters.entrySet().stream().map(entry ->
|
||||
{
|
||||
return url + "?" + parameters.entrySet().stream().map(entry -> {
|
||||
var encodedKey = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8);
|
||||
var encodedValue = URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8);
|
||||
return encodedKey + "=" + encodedValue;
|
||||
|
||||
@@ -24,6 +24,7 @@ package io.github.jwdeveloper.tiktok.http;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.data.settings.HttpClientSettings;
|
||||
|
||||
import java.net.http.HttpRequest;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -31,6 +32,7 @@ public class HttpClientBuilder {
|
||||
|
||||
private final HttpClientSettings httpClientSettings;
|
||||
private String url;
|
||||
private HttpRequest.BodyPublisher bodyPublisher;
|
||||
|
||||
public HttpClientBuilder(String url, HttpClientSettings httpClientSettings) {
|
||||
this.httpClientSettings = httpClientSettings;
|
||||
@@ -78,10 +80,15 @@ public class HttpClientBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpClientBuilder withBody(HttpRequest.BodyPublisher bodyPublisher) {
|
||||
this.bodyPublisher = bodyPublisher;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpClient build() {
|
||||
var proxyClientSettings = httpClientSettings.getProxyClientSettings();
|
||||
if (proxyClientSettings.isEnabled() && proxyClientSettings.hasNext())
|
||||
return new HttpProxyClient(httpClientSettings, url);
|
||||
return new HttpClient(httpClientSettings, url);
|
||||
return new HttpProxyClient(httpClientSettings, url, bodyPublisher);
|
||||
return new HttpClient(httpClientSettings, url, bodyPublisher);
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,8 @@ public class HttpProxyClient extends HttpClient {
|
||||
|
||||
private final ProxyClientSettings proxySettings;
|
||||
|
||||
public HttpProxyClient(HttpClientSettings httpClientSettings, String url) {
|
||||
super(httpClientSettings, url);
|
||||
public HttpProxyClient(HttpClientSettings httpClientSettings, String url, HttpRequest.BodyPublisher bodyPublisher) {
|
||||
super(httpClientSettings, url, bodyPublisher);
|
||||
this.proxySettings = httpClientSettings.getProxyClientSettings();
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class HttpProxyClient extends HttpClient {
|
||||
|
||||
httpClientSettings.getOnClientCreating().accept(builder);
|
||||
var client = builder.build();
|
||||
var request = prepareGetRequest();
|
||||
var request = prepareRequest();
|
||||
|
||||
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||
if (response.statusCode() != 200)
|
||||
|
||||
Reference in New Issue
Block a user