mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-28 17:29:39 -05:00
Compare commits
4 Commits
1.0.17-Rel
...
develop-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46d229869e | ||
|
|
dd417df0ff | ||
|
|
bc24436269 | ||
|
|
2d260dd3f9 |
@@ -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.16-Release</version>
|
<version>1.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>API</artifactId>
|
<artifactId>API</artifactId>
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package io.github.jwdeveloper.tiktok.data.dto;
|
|
||||||
|
|
||||||
import lombok.*;
|
|
||||||
|
|
||||||
import java.net.*;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class ProxyData
|
|
||||||
{
|
|
||||||
private final String address;
|
|
||||||
private final int port;
|
|
||||||
|
|
||||||
public static ProxyData map(String string) {
|
|
||||||
if (string == null || string.isBlank())
|
|
||||||
throw new IllegalArgumentException("Provided address cannot be null or empty!");
|
|
||||||
int portIndex = string.lastIndexOf(':');
|
|
||||||
try {
|
|
||||||
String address = string.substring(0, portIndex);
|
|
||||||
int port = Integer.parseInt(string.substring(portIndex+1));
|
|
||||||
|
|
||||||
// Port validation
|
|
||||||
if (port < 0 || port > 65535)
|
|
||||||
throw new IndexOutOfBoundsException("Port out of range: "+port);
|
|
||||||
|
|
||||||
// IP Validation
|
|
||||||
InetAddress res = InetAddress.getByName(address);
|
|
||||||
|
|
||||||
return new ProxyData(address, port);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new IllegalArgumentException("Port must be a valid integer!");
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
throw new IllegalArgumentException("Address must be valid IPv4, IPv6, or domain name!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProxyData clone() {
|
|
||||||
return new ProxyData(address, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InetSocketAddress toSocketAddress() {
|
|
||||||
return new InetSocketAddress(address, port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,7 +24,7 @@ package io.github.jwdeveloper.tiktok.data.events;
|
|||||||
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
|
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
|
||||||
import io.github.jwdeveloper.tiktok.annotations.EventType;
|
import io.github.jwdeveloper.tiktok.annotations.EventType;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic.
|
* Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic.
|
||||||
@@ -32,12 +32,4 @@ import lombok.Getter;
|
|||||||
*/
|
*/
|
||||||
@EventMeta(eventType = EventType.Control)
|
@EventMeta(eventType = EventType.Control)
|
||||||
public class TikTokDisconnectedEvent extends TikTokLiveClientEvent {
|
public class TikTokDisconnectedEvent extends TikTokLiveClientEvent {
|
||||||
@Getter private final String reason;
|
|
||||||
public TikTokDisconnectedEvent(String reason) {
|
|
||||||
this.reason = reason.isBlank() ? "None" : reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokDisconnectedEvent() {
|
|
||||||
this("None");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,10 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.data.requests;
|
package io.github.jwdeveloper.tiktok.data.requests;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
public class LiveUserData {
|
public class LiveUserData {
|
||||||
|
|
||||||
@@ -35,18 +38,15 @@ public class LiveUserData {
|
|||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public static class Response {
|
public static class Response {
|
||||||
|
|
||||||
private String json;
|
private String json;
|
||||||
|
|
||||||
private UserStatus userStatus;
|
private UserStatus userStatus;
|
||||||
|
|
||||||
private String roomId;
|
private String roomId;
|
||||||
|
|
||||||
|
|
||||||
private long startedAtTimeStamp;
|
private long startedAtTimeStamp;
|
||||||
|
|
||||||
public boolean isLiveOnline() {
|
|
||||||
return userStatus == LiveUserData.UserStatus.Live || userStatus == LiveUserData.UserStatus.LivePaused;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isHostNameValid() {
|
|
||||||
return userStatus != LiveUserData.UserStatus.NotFound;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum UserStatus {
|
public enum UserStatus {
|
||||||
@@ -56,3 +56,5 @@ public class LiveUserData {
|
|||||||
Live,
|
Live,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ public class HttpClientSettings {
|
|||||||
final Map<String, String> cookies;
|
final Map<String, String> cookies;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
|
||||||
ProxyClientSettings proxyClientSettings;
|
ProxyClientSettings proxyClientSettings;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@@ -75,7 +74,7 @@ public class HttpClientSettings {
|
|||||||
* @param consumer Use to configure proxy settings for http client
|
* @param consumer Use to configure proxy settings for http client
|
||||||
*/
|
*/
|
||||||
public void configureProxy(Consumer<ProxyClientSettings> consumer) {
|
public void configureProxy(Consumer<ProxyClientSettings> consumer) {
|
||||||
proxyClientSettings.setEnabled(true);
|
proxyClientSettings.setUseProxy(true);
|
||||||
consumer.accept(proxyClientSettings);
|
consumer.accept(proxyClientSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +104,7 @@ public class HttpClientSettings {
|
|||||||
newSettings.getHeaders().putAll(new TreeMap<>(this.headers));
|
newSettings.getHeaders().putAll(new TreeMap<>(this.headers));
|
||||||
newSettings.getCookies().putAll(new TreeMap<>(this.cookies));
|
newSettings.getCookies().putAll(new TreeMap<>(this.cookies));
|
||||||
newSettings.getParams().putAll(new TreeMap<>(this.params));
|
newSettings.getParams().putAll(new TreeMap<>(this.params));
|
||||||
newSettings.proxyClientSettings = this.proxyClientSettings;
|
newSettings.proxyClientSettings = this.proxyClientSettings.clone();
|
||||||
|
|
||||||
return newSettings;
|
return newSettings;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,101 +22,19 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.data.settings;
|
package io.github.jwdeveloper.tiktok.data.settings;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.dto.ProxyData;
|
import lombok.Getter;
|
||||||
import lombok.*;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.net.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
|
//TODO proxy implementation
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
public class ProxyClientSettings
|
||||||
public class ProxyClientSettings implements Iterator<ProxyData>
|
|
||||||
{
|
{
|
||||||
private boolean enabled, lastSuccess;
|
@Setter
|
||||||
private Rotation rotation = Rotation.CONSECUTIVE;
|
private boolean useProxy;
|
||||||
private final List<ProxyData> proxyList = new ArrayList<>();
|
|
||||||
private int index = 0;
|
|
||||||
private boolean autoDiscard = true;
|
|
||||||
private Proxy.Type type = Proxy.Type.DIRECT;
|
|
||||||
private Consumer<ProxyData> onProxyUpdated = x -> {};
|
|
||||||
|
|
||||||
public boolean addProxy(String addressPort) {
|
|
||||||
return proxyList.add(ProxyData.map(addressPort));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addProxy(String address, int port) {
|
|
||||||
return addProxy(new InetSocketAddress(address, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addProxy(InetSocketAddress inetAddress) {
|
|
||||||
return proxyList.add(new ProxyData(inetAddress.getHostString(), inetAddress.getPort()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addProxies(List<String> list) {
|
|
||||||
list.forEach(this::addProxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
return !proxyList.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ProxyData next() {
|
|
||||||
return lastSuccess ? proxyList.get(index) : rotate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProxyData rotate() {
|
|
||||||
var nextProxy = switch (rotation)
|
|
||||||
{
|
|
||||||
case CONSECUTIVE -> {
|
|
||||||
index = (index+1) % proxyList.size();
|
|
||||||
yield proxyList.get(index).clone();
|
|
||||||
}
|
|
||||||
case RANDOM -> {
|
|
||||||
index = new Random().nextInt(proxyList.size());
|
|
||||||
yield proxyList.get(index).clone();
|
|
||||||
}
|
|
||||||
case NONE -> proxyList.get(index).clone();
|
|
||||||
};
|
|
||||||
onProxyUpdated.accept(nextProxy);
|
|
||||||
return nextProxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove() {
|
|
||||||
proxyList.remove(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIndex(int index) {
|
|
||||||
if (index == 0 && proxyList.isEmpty())
|
|
||||||
this.index = 0;
|
|
||||||
else {
|
|
||||||
if (index < 0 || index >= proxyList.size())
|
|
||||||
throw new IndexOutOfBoundsException("Index " + index + " exceeds list of size: " + proxyList.size());
|
|
||||||
this.index = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public ProxyClientSettings clone()
|
public ProxyClientSettings clone()
|
||||||
{
|
{
|
||||||
ProxyClientSettings settings = new ProxyClientSettings();
|
return new ProxyClientSettings();
|
||||||
settings.setEnabled(enabled);
|
|
||||||
settings.setRotation(rotation);
|
|
||||||
settings.setIndex(index);
|
|
||||||
settings.setType(type);
|
|
||||||
settings.setOnProxyUpdated(onProxyUpdated);
|
|
||||||
proxyList.forEach(proxyData -> settings.addProxy(proxyData.getAddress(), proxyData.getPort()));
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Rotation
|
|
||||||
{
|
|
||||||
/** Rotate addresses consecutively, from proxy 0 -> 1 -> 2 -> ...etc. */
|
|
||||||
CONSECUTIVE,
|
|
||||||
/** Rotate addresses randomly, from proxy 0 -> 69 -> 420 -> 1 -> ...etc. */
|
|
||||||
RANDOM,
|
|
||||||
/** Don't rotate addresses at all, pin to the indexed address. */
|
|
||||||
NONE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package io.github.jwdeveloper.tiktok.exceptions;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Happens while bad response from http proxy request to TikTok
|
|
||||||
*/
|
|
||||||
public class TikTokProxyRequestException extends TikTokLiveException
|
|
||||||
{
|
|
||||||
public TikTokProxyRequestException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokProxyRequestException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokProxyRequestException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokProxyRequestException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokProxyRequestException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
|
||||||
super(message, cause, enableSuppression, writableStackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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.16-Release</version>
|
<version>1.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ package io.github.jwdeveloper.tiktok;
|
|||||||
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
|
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
|
||||||
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
public class TikTokLive {
|
public class TikTokLive {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,50 +37,6 @@ public class TikTokLive {
|
|||||||
return new TikTokLiveClientBuilder(hostName);
|
return new TikTokLiveClientBuilder(hostName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param hostName profile name of Tiktok user could be found in profile link
|
|
||||||
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
|
|
||||||
* @return true if live is Online, false if is offline
|
|
||||||
*/
|
|
||||||
public static boolean isLiveOnline(String hostName)
|
|
||||||
{
|
|
||||||
return requests().fetchLiveUserData(hostName).isLiveOnline();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param hostName profile name of Tiktok user could be found in profile link
|
|
||||||
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
|
|
||||||
* @return true if live is Online, false if is offline
|
|
||||||
*/
|
|
||||||
public static CompletableFuture<Boolean> isLiveOnlineAsync(String hostName)
|
|
||||||
{
|
|
||||||
return CompletableFuture.supplyAsync(()-> isLiveOnline(hostName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param hostName profile name of Tiktok user could be found in profile link
|
|
||||||
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
|
|
||||||
* @return true is hostName name is valid and exists, false if not
|
|
||||||
*/
|
|
||||||
public static boolean isHostNameValid(String hostName)
|
|
||||||
{
|
|
||||||
return requests().fetchLiveUserData(hostName).isHostNameValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param hostName profile name of Tiktok user could be found in profile link
|
|
||||||
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
|
|
||||||
* @return true is hostName name is valid and exists, false if not
|
|
||||||
*/
|
|
||||||
public static CompletableFuture<Boolean> isHostNameValidAsync(String hostName)
|
|
||||||
{
|
|
||||||
return CompletableFuture.supplyAsync(()-> isHostNameValid(hostName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use to get some data from TikTok about users are lives
|
* Use to get some data from TikTok about users are lives
|
||||||
@@ -90,6 +44,9 @@ public class TikTokLive {
|
|||||||
* @return LiveHttpClient
|
* @return LiveHttpClient
|
||||||
*/
|
*/
|
||||||
public static LiveHttpClient requests() {
|
public static LiveHttpClient requests() {
|
||||||
|
|
||||||
|
|
||||||
return new TikTokLiveHttpClient();
|
return new TikTokLiveHttpClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -76,15 +76,19 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
|
|
||||||
|
|
||||||
public void connectAsync(Consumer<LiveClient> onConnection) {
|
public void connectAsync(Consumer<LiveClient> onConnection) {
|
||||||
CompletableFuture.runAsync(() -> {
|
CompletableFuture.supplyAsync(() ->
|
||||||
|
{
|
||||||
connect();
|
connect();
|
||||||
onConnection.accept(this);
|
onConnection.accept(this);
|
||||||
|
return this;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public CompletableFuture<LiveClient> connectAsync() {
|
public CompletableFuture<LiveClient> connectAsync() {
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() ->
|
||||||
|
{
|
||||||
connect();
|
connect();
|
||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
@@ -101,7 +105,8 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
if (e instanceof TikTokLiveOfflineHostException && clientSettings.isRetryOnConnectionFailure()) {
|
if (e instanceof TikTokLiveOfflineHostException && clientSettings.isRetryOnConnectionFailure()) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(clientSettings.getRetryConnectionTimeout().toMillis());
|
Thread.sleep(clientSettings.getRetryConnectionTimeout().toMillis());
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
logger.info("Reconnecting");
|
logger.info("Reconnecting");
|
||||||
tikTokEventHandler.publish(this, new TikTokReconnectingEvent());
|
tikTokEventHandler.publish(this, new TikTokReconnectingEvent());
|
||||||
this.connect();
|
this.connect();
|
||||||
@@ -115,12 +120,14 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void tryConnect() {
|
public void tryConnect() {
|
||||||
if (!liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
|
if (!liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED))
|
||||||
|
{
|
||||||
throw new TikTokLiveException("Already connected");
|
throw new TikTokLiveException("Already connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(ConnectionState.CONNECTING);
|
setState(ConnectionState.CONNECTING);
|
||||||
|
|
||||||
|
|
||||||
var userDataRequest = new LiveUserData.Request(liveRoomInfo.getHostName());
|
var userDataRequest = new LiveUserData.Request(liveRoomInfo.getHostName());
|
||||||
var userData = httpClient.fetchLiveUserData(userDataRequest);
|
var userData = httpClient.fetchLiveUserData(userDataRequest);
|
||||||
liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp());
|
liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp());
|
||||||
@@ -132,6 +139,7 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
throw new TikTokLiveOfflineHostException("User not found: "+liveRoomInfo.getHostUser());
|
throw new TikTokLiveOfflineHostException("User not found: "+liveRoomInfo.getHostUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var liveDataRequest = new LiveData.Request(userData.getRoomId());
|
var liveDataRequest = new LiveData.Request(userData.getRoomId());
|
||||||
var liveData = httpClient.fetchLiveData(liveDataRequest);
|
var liveData = httpClient.fetchLiveData(liveDataRequest);
|
||||||
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound) {
|
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound) {
|
||||||
@@ -147,6 +155,7 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
liveRoomInfo.setAgeRestricted(liveData.isAgeRestricted());
|
liveRoomInfo.setAgeRestricted(liveData.isAgeRestricted());
|
||||||
liveRoomInfo.setHost(liveData.getHost());
|
liveRoomInfo.setHost(liveData.getHost());
|
||||||
|
|
||||||
|
|
||||||
var liveConnectionRequest =new LiveConnectionData.Request(userData.getRoomId());
|
var liveConnectionRequest =new LiveConnectionData.Request(userData.getRoomId());
|
||||||
var liveConnectionData = httpClient.fetchLiveConnectionData(liveConnectionRequest);
|
var liveConnectionData = httpClient.fetchLiveConnectionData(liveConnectionRequest);
|
||||||
webSocketClient.start(liveConnectionData, this);
|
webSocketClient.start(liveConnectionData, this);
|
||||||
@@ -172,6 +181,7 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
tikTokEventHandler.publish(this, event);
|
tikTokEventHandler.publish(this, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public LiveRoomInfo getRoomInfo() {
|
public LiveRoomInfo getRoomInfo() {
|
||||||
return liveRoomInfo;
|
return liveRoomInfo;
|
||||||
}
|
}
|
||||||
@@ -190,4 +200,6 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
public GiftManager getGiftManager() {
|
public GiftManager getGiftManager() {
|
||||||
return tikTokGiftManager;
|
return tikTokGiftManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -156,7 +156,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
|
|
||||||
|
|
||||||
var httpClientFactory = new HttpClientFactory(clientSettings);
|
var httpClientFactory = new HttpClientFactory(clientSettings);
|
||||||
var tikTokLiveHttpClient = new TikTokLiveHttpClient(httpClientFactory, clientSettings);
|
var tikTokLiveHttpClient = new TikTokLiveHttpClient(httpClientFactory);
|
||||||
|
|
||||||
var webSocketClient = new TikTokWebSocketClient(
|
var webSocketClient = new TikTokWebSocketClient(
|
||||||
clientSettings,
|
clientSettings,
|
||||||
@@ -346,7 +346,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TikTokLiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) {
|
public LiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokRoomInfoEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokRoomInfoEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -358,7 +358,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TikTokLiveClientBuilder onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event) {
|
public LiveClientBuilder onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokLiveUnpausedEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokLiveUnpausedEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,14 +24,18 @@ package io.github.jwdeveloper.tiktok;
|
|||||||
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
import io.github.jwdeveloper.tiktok.data.requests.*;
|
import io.github.jwdeveloper.tiktok.data.requests.*;
|
||||||
import io.github.jwdeveloper.tiktok.data.settings.*;
|
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.*;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
import io.github.jwdeveloper.tiktok.http.*;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokSignServerException;
|
||||||
import io.github.jwdeveloper.tiktok.http.mappers.*;
|
import io.github.jwdeveloper.tiktok.http.HttpClientFactory;
|
||||||
|
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
|
||||||
|
import io.github.jwdeveloper.tiktok.http.mappers.GiftsDataMapper;
|
||||||
|
import io.github.jwdeveloper.tiktok.http.mappers.LiveDataMapper;
|
||||||
|
import io.github.jwdeveloper.tiktok.http.mappers.LiveUserDataMapper;
|
||||||
|
import io.github.jwdeveloper.tiktok.http.mappers.SignServerResponseMapper;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
|
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class TikTokLiveHttpClient implements LiveHttpClient {
|
public class TikTokLiveHttpClient implements LiveHttpClient {
|
||||||
|
|
||||||
@@ -44,23 +48,21 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
private static final String TIKTOK_URL_WEBCAST = "https://webcast.tiktok.com/webcast/";
|
private static final String TIKTOK_URL_WEBCAST = "https://webcast.tiktok.com/webcast/";
|
||||||
|
|
||||||
private final HttpClientFactory httpFactory;
|
private final HttpClientFactory httpFactory;
|
||||||
private final LiveClientSettings clientSettings;
|
|
||||||
private final LiveUserDataMapper liveUserDataMapper;
|
private final LiveUserDataMapper liveUserDataMapper;
|
||||||
private final LiveDataMapper liveDataMapper;
|
private final LiveDataMapper liveDataMapper;
|
||||||
private final SignServerResponseMapper signServerResponseMapper;
|
private final SignServerResponseMapper singServerResponseMapper;
|
||||||
private final GiftsDataMapper giftsDataMapper;
|
private final GiftsDataMapper giftsDataMapper;
|
||||||
|
|
||||||
public TikTokLiveHttpClient(HttpClientFactory factory, LiveClientSettings settings) {
|
public TikTokLiveHttpClient(HttpClientFactory factory) {
|
||||||
this.httpFactory = factory;
|
this.httpFactory = factory;
|
||||||
clientSettings = settings;
|
|
||||||
liveUserDataMapper = new LiveUserDataMapper();
|
liveUserDataMapper = new LiveUserDataMapper();
|
||||||
liveDataMapper = new LiveDataMapper();
|
liveDataMapper = new LiveDataMapper();
|
||||||
signServerResponseMapper = new SignServerResponseMapper();
|
singServerResponseMapper = new SignServerResponseMapper();
|
||||||
giftsDataMapper = new GiftsDataMapper();
|
giftsDataMapper = new GiftsDataMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveHttpClient() {
|
public TikTokLiveHttpClient() {
|
||||||
this(new HttpClientFactory(LiveClientSettings.createDefault()), LiveClientSettings.createDefault());
|
this(new HttpClientFactory(LiveClientSettings.createDefault()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -85,26 +87,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiveUserData.Response fetchLiveUserData(LiveUserData.Request request) {
|
public LiveUserData.Response fetchLiveUserData(LiveUserData.Request request) {
|
||||||
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
|
||||||
if (proxyClientSettings.isEnabled()) {
|
|
||||||
while (proxyClientSettings.hasNext()) {
|
|
||||||
try {
|
|
||||||
var url = TIKTOK_URL_WEB + "api-live/user/room";
|
|
||||||
var optional = httpFactory.client(url)
|
|
||||||
.withParam("uniqueId", request.getUserName())
|
|
||||||
.withParam("sourceType", "54")
|
|
||||||
.build()
|
|
||||||
.toJsonResponse();
|
|
||||||
|
|
||||||
if (optional.isEmpty()) {
|
|
||||||
throw new TikTokLiveRequestException("Unable to get information's about user");
|
|
||||||
}
|
|
||||||
|
|
||||||
var json = optional.get();
|
|
||||||
return liveUserDataMapper.map(json);
|
|
||||||
} catch (TikTokProxyRequestException ignored) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var url = TIKTOK_URL_WEB + "api-live/user/room";
|
var url = TIKTOK_URL_WEB + "api-live/user/room";
|
||||||
var optional = httpFactory.client(url)
|
var optional = httpFactory.client(url)
|
||||||
.withParam("uniqueId", request.getUserName())
|
.withParam("uniqueId", request.getUserName())
|
||||||
@@ -127,25 +110,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiveData.Response fetchLiveData(LiveData.Request request) {
|
public LiveData.Response fetchLiveData(LiveData.Request request) {
|
||||||
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
|
||||||
if (proxyClientSettings.isEnabled()) {
|
|
||||||
while (proxyClientSettings.hasNext()) {
|
|
||||||
try {
|
|
||||||
var url = TIKTOK_URL_WEBCAST + "room/info";
|
|
||||||
var optional = httpFactory.client(url)
|
|
||||||
.withParam("room_id", request.getRoomId())
|
|
||||||
.build()
|
|
||||||
.toJsonResponse();
|
|
||||||
|
|
||||||
if (optional.isEmpty()) {
|
|
||||||
throw new TikTokLiveRequestException("Unable to get info about live room");
|
|
||||||
}
|
|
||||||
|
|
||||||
var json = optional.get();
|
|
||||||
return liveDataMapper.map(json);
|
|
||||||
} catch (TikTokProxyRequestException ignored) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var url = TIKTOK_URL_WEBCAST + "room/info";
|
var url = TIKTOK_URL_WEBCAST + "room/info";
|
||||||
var optional = httpFactory.client(url)
|
var optional = httpFactory.client(url)
|
||||||
.withParam("room_id", request.getRoomId())
|
.withParam("room_id", request.getRoomId())
|
||||||
@@ -167,15 +132,14 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request) {
|
public LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request) {
|
||||||
HttpResponse<byte[]> credentialsResponse = getOptionalProxyResponse(request).orElseGet(()-> {
|
|
||||||
SignServerResponse signServerResponse = getSignedUrl(request.getRoomId());
|
var signServerResponse = getSignedUrl(request.getRoomId());
|
||||||
return getWebsocketCredentialsResponse(signServerResponse.getSignedUrl());
|
var credentialsResponse = getWebsocketCredentialsResponse(signServerResponse.getSignedUrl());
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var optionalHeader = credentialsResponse.headers().firstValue("set-cookie");
|
var optionalHeader = credentialsResponse.headers().firstValue("set-cookie");
|
||||||
if (optionalHeader.isEmpty()) {
|
if (optionalHeader.isEmpty()) {
|
||||||
throw new TikTokSignServerException("Sign server did not return the set-cookie header");
|
throw new TikTokSignServerException("Sign server does not returned set-cookie header");
|
||||||
}
|
}
|
||||||
var websocketCookie = optionalHeader.get();
|
var websocketCookie = optionalHeader.get();
|
||||||
var webcastResponse = WebcastResponse.parseFrom(credentialsResponse.body());
|
var webcastResponse = WebcastResponse.parseFrom(credentialsResponse.body());
|
||||||
@@ -216,32 +180,18 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var json = optional.get();
|
var json = optional.get();
|
||||||
return signServerResponseMapper.map(json);
|
return singServerResponseMapper.map(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpResponse<byte[]> getWebsocketCredentialsResponse(String signedUrl) {
|
HttpResponse<byte[]> getWebsocketCredentialsResponse(String signedUrl) {
|
||||||
var optionalResponse = httpFactory
|
var optionalResponse = httpFactory
|
||||||
.clientEmpty(signedUrl)
|
.clientEmpty(signedUrl)
|
||||||
.build()
|
.build()
|
||||||
.toResponse();
|
.toResponse(HttpResponse.BodyHandlers.ofByteArray());
|
||||||
if (optionalResponse.isEmpty()) {
|
if (optionalResponse.isEmpty()) {
|
||||||
throw new TikTokSignServerException("Unable to get websocket connection credentials");
|
throw new TikTokSignServerException("Unable to get websocket connection credentials");
|
||||||
}
|
}
|
||||||
return optionalResponse.get();
|
return optionalResponse.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<HttpResponse<byte[]>> getOptionalProxyResponse(LiveConnectionData.Request request) {
|
|
||||||
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
|
||||||
if (proxyClientSettings.isEnabled()) {
|
|
||||||
while (proxyClientSettings.hasNext()) {
|
|
||||||
try {
|
|
||||||
SignServerResponse signServerResponse = getSignedUrl(request.getRoomId());
|
|
||||||
HttpResponse<byte[]> credentialsResponse = getWebsocketCredentialsResponse(signServerResponse.getSignedUrl());
|
|
||||||
clientSettings.getHttpSettings().getProxyClientSettings().rotate();
|
|
||||||
return Optional.of(credentialsResponse);
|
|
||||||
} catch (TikTokProxyRequestException | TikTokSignServerException ignored) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -26,62 +26,57 @@ import io.github.jwdeveloper.tiktok.data.settings.HttpClientSettings;
|
|||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import java.net.*;
|
import java.net.CookieManager;
|
||||||
import java.net.http.*;
|
import java.net.URI;
|
||||||
import java.nio.charset.*;
|
import java.net.URLEncoder;
|
||||||
import java.util.*;
|
import java.net.http.HttpRequest;
|
||||||
import java.util.regex.*;
|
import java.net.http.HttpResponse;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class HttpClient {
|
public class HttpClient {
|
||||||
protected final HttpClientSettings httpClientSettings;
|
private final HttpClientSettings httpClientSettings;
|
||||||
protected final String url;
|
private final String url;
|
||||||
private final Pattern pattern = Pattern.compile("charset=(.*?)(?=&|$)");
|
|
||||||
|
|
||||||
public Optional<HttpResponse<byte[]>> toResponse() {
|
|
||||||
|
public <T> Optional<HttpResponse<T>> toResponse(HttpResponse.BodyHandler<T> bodyHandler) {
|
||||||
var client = prepareClient();
|
var client = prepareClient();
|
||||||
var request = prepareGetRequest();
|
var request = prepareGetRequest();
|
||||||
try {
|
try
|
||||||
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
{
|
||||||
if (response.statusCode() != 200) {
|
var response = client.send(request, bodyHandler);
|
||||||
|
if(response.statusCode() != 200)
|
||||||
|
{
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return Optional.of(response);
|
return Optional.of(response);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TikTokLiveRequestException(e);
|
throw new TikTokLiveRequestException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Optional<String> toJsonResponse() {
|
public Optional<String> toJsonResponse() {
|
||||||
var optional = toResponse();
|
var optional = toResponse(HttpResponse.BodyHandlers.ofString());
|
||||||
if (optional.isEmpty()) {
|
if (optional.isEmpty()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = optional.get();
|
var response = optional.get();
|
||||||
var body = response.body();
|
|
||||||
var charset = charsetFrom(response.headers());
|
|
||||||
return Optional.of(new String(body,charset));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Charset charsetFrom(HttpHeaders headers) {
|
|
||||||
String type = headers.firstValue("Content-type").orElse("text/html; charset=utf-8");
|
var body = response.body();
|
||||||
int i = type.indexOf(";");
|
return Optional.of(body);
|
||||||
if (i >= 0) type = type.substring(i+1);
|
|
||||||
try {
|
|
||||||
Matcher matcher = pattern.matcher(type);
|
|
||||||
if (!matcher.find())
|
|
||||||
return StandardCharsets.UTF_8;
|
|
||||||
return Charset.forName(matcher.group(1));
|
|
||||||
} catch (Throwable x) {
|
|
||||||
return StandardCharsets.UTF_8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<byte[]> toBinaryResponse() {
|
public Optional<byte[]> toBinaryResponse() {
|
||||||
var optional = toResponse();
|
var optional = toResponse(HttpResponse.BodyHandlers.ofByteArray());
|
||||||
if (optional.isEmpty()) {
|
if (optional.isEmpty()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
@@ -89,12 +84,13 @@ public class HttpClient {
|
|||||||
return Optional.of(body);
|
return Optional.of(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public URI toUrl() {
|
public URI toUrl() {
|
||||||
var stringUrl = prepareUrlWithParameters(url, httpClientSettings.getParams());
|
var stringUrl = prepareUrlWithParameters(url, httpClientSettings.getParams());
|
||||||
return URI.create(stringUrl);
|
return URI.create(stringUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HttpRequest prepareGetRequest() {
|
private HttpRequest prepareGetRequest() {
|
||||||
var requestBuilder = HttpRequest.newBuilder().GET();
|
var requestBuilder = HttpRequest.newBuilder().GET();
|
||||||
requestBuilder.uri(toUrl());
|
requestBuilder.uri(toUrl());
|
||||||
requestBuilder.timeout(httpClientSettings.getTimeout());
|
requestBuilder.timeout(httpClientSettings.getTimeout());
|
||||||
@@ -104,17 +100,18 @@ public class HttpClient {
|
|||||||
return requestBuilder.build();
|
return requestBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected java.net.http.HttpClient prepareClient() {
|
private java.net.http.HttpClient prepareClient() {
|
||||||
var builder = java.net.http.HttpClient.newBuilder()
|
var builder = java.net.http.HttpClient.newBuilder()
|
||||||
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL)
|
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL)
|
||||||
.cookieHandler(new CookieManager())
|
.cookieHandler(new CookieManager())
|
||||||
.connectTimeout(httpClientSettings.getTimeout());
|
.connectTimeout(httpClientSettings.getTimeout());
|
||||||
|
|
||||||
|
|
||||||
httpClientSettings.getOnClientCreating().accept(builder);
|
httpClientSettings.getOnClientCreating().accept(builder);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String prepareUrlWithParameters(String url, Map<String, Object> parameters) {
|
private String prepareUrlWithParameters(String url, Map<String, Object> parameters) {
|
||||||
if (parameters.isEmpty()) {
|
if (parameters.isEmpty()) {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,9 +77,11 @@ public class HttpClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public HttpClient build() {
|
public HttpClient build() {
|
||||||
if (httpClientSettings.getProxyClientSettings().isEnabled())
|
|
||||||
return new HttpProxyClient(httpClientSettings, url);
|
|
||||||
return new HttpClient(httpClientSettings, url);
|
return new HttpClient(httpClientSettings, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.http;
|
package io.github.jwdeveloper.tiktok.http;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.settings.*;
|
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
|
||||||
|
|
||||||
public class HttpClientFactory {
|
public class HttpClientFactory {
|
||||||
private final LiveClientSettings liveClientSettings;
|
private final LiveClientSettings liveClientSettings;
|
||||||
@@ -37,8 +37,6 @@ public class HttpClientFactory {
|
|||||||
|
|
||||||
//Does not contains default httpClientSettings, Params, headers, etd
|
//Does not contains default httpClientSettings, Params, headers, etd
|
||||||
public HttpClientBuilder clientEmpty(String url) {
|
public HttpClientBuilder clientEmpty(String url) {
|
||||||
var settings = new HttpClientSettings();
|
return new HttpClientBuilder(url);
|
||||||
settings.setProxyClientSettings(liveClientSettings.getHttpSettings().getProxyClientSettings());
|
|
||||||
return new HttpClientBuilder(url, settings);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package io.github.jwdeveloper.tiktok.http;
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.settings.*;
|
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.*;
|
|
||||||
|
|
||||||
import javax.net.ssl.*;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.*;
|
|
||||||
import java.net.http.*;
|
|
||||||
import java.net.http.HttpResponse.ResponseInfo;
|
|
||||||
import java.security.*;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class HttpProxyClient extends HttpClient
|
|
||||||
{
|
|
||||||
private final ProxyClientSettings proxySettings;
|
|
||||||
|
|
||||||
public HttpProxyClient(HttpClientSettings httpClientSettings, String url) {
|
|
||||||
super(httpClientSettings, url);
|
|
||||||
this.proxySettings = httpClientSettings.getProxyClientSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<HttpResponse<byte[]>> toResponse() {
|
|
||||||
return switch (proxySettings.getType()) {
|
|
||||||
case HTTP, DIRECT -> handleHttpProxyRequest();
|
|
||||||
default -> handleSocksProxyRequest();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<HttpResponse<byte[]>> handleHttpProxyRequest() {
|
|
||||||
var builder = java.net.http.HttpClient.newBuilder()
|
|
||||||
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL)
|
|
||||||
.cookieHandler(new CookieManager())
|
|
||||||
.connectTimeout(httpClientSettings.getTimeout());
|
|
||||||
|
|
||||||
while (proxySettings.hasNext()) {
|
|
||||||
try {
|
|
||||||
InetSocketAddress address = proxySettings.next().toSocketAddress();
|
|
||||||
builder.proxy(ProxySelector.of(address));
|
|
||||||
|
|
||||||
httpClientSettings.getOnClientCreating().accept(builder);
|
|
||||||
var client = builder.build();
|
|
||||||
var request = prepareGetRequest();
|
|
||||||
|
|
||||||
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
|
||||||
if (response.statusCode() != 200) {
|
|
||||||
proxySettings.setLastSuccess(false);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
proxySettings.setLastSuccess(true);
|
|
||||||
return Optional.of(response);
|
|
||||||
} catch (HttpConnectTimeoutException | ConnectException e) {
|
|
||||||
if (proxySettings.isAutoDiscard())
|
|
||||||
proxySettings.remove();
|
|
||||||
proxySettings.setLastSuccess(false);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new TikTokLiveRequestException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new TikTokLiveRequestException("No more proxies available!");
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<HttpResponse<byte[]>> handleSocksProxyRequest() {
|
|
||||||
try {
|
|
||||||
SSLContext sc = SSLContext.getInstance("SSL");
|
|
||||||
sc.init(null, new TrustManager[]{ new X509TrustManager() {
|
|
||||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}
|
|
||||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}
|
|
||||||
public X509Certificate[] getAcceptedIssuers() { return null; }
|
|
||||||
}}, null);
|
|
||||||
|
|
||||||
URL url = toUrl().toURL();
|
|
||||||
|
|
||||||
if (proxySettings.hasNext()) {
|
|
||||||
try {
|
|
||||||
Proxy proxy = new Proxy(Proxy.Type.SOCKS, proxySettings.next().toSocketAddress());
|
|
||||||
|
|
||||||
System.err.println("Connecting to "+ url);
|
|
||||||
HttpsURLConnection socksConnection = (HttpsURLConnection) url.openConnection(proxy);
|
|
||||||
socksConnection.setSSLSocketFactory(sc.getSocketFactory());
|
|
||||||
socksConnection.setConnectTimeout(httpClientSettings.getTimeout().toMillisPart());
|
|
||||||
socksConnection.setReadTimeout(httpClientSettings.getTimeout().toMillisPart());
|
|
||||||
|
|
||||||
byte[] body = socksConnection.getInputStream().readAllBytes();
|
|
||||||
|
|
||||||
Map<String, List<String>> headers = socksConnection.getHeaderFields()
|
|
||||||
.entrySet()
|
|
||||||
.stream()
|
|
||||||
.filter(entry -> entry.getKey() != null)
|
|
||||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
|
||||||
|
|
||||||
var responseInfo = createResponseInfo(socksConnection.getResponseCode(), headers);
|
|
||||||
|
|
||||||
var response = createHttpResponse(body, toUrl(), responseInfo);
|
|
||||||
|
|
||||||
proxySettings.setLastSuccess(true);
|
|
||||||
return Optional.of(response);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (proxySettings.isAutoDiscard())
|
|
||||||
proxySettings.remove();
|
|
||||||
proxySettings.setLastSuccess(false);
|
|
||||||
throw new TikTokProxyRequestException(e);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new TikTokLiveRequestException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new TikTokLiveRequestException("No more proxies available!");
|
|
||||||
} catch (NoSuchAlgorithmException | MalformedURLException | KeyManagementException e) {
|
|
||||||
// Should never be reached!
|
|
||||||
System.out.println("handleSocksProxyRequest()! If you see this message, reach us on discord!");
|
|
||||||
e.printStackTrace();
|
|
||||||
return Optional.empty();
|
|
||||||
} catch (TikTokLiveRequestException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ResponseInfo createResponseInfo(int code, Map<String, List<String>> headers) {
|
|
||||||
return new ResponseInfo() {
|
|
||||||
@Override
|
|
||||||
public int statusCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpHeaders headers() {
|
|
||||||
return HttpHeaders.of(headers, (s, s1) -> s != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public java.net.http.HttpClient.Version version() {
|
|
||||||
return java.net.http.HttpClient.Version.HTTP_2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpResponse<byte[]> createHttpResponse(byte[] body,
|
|
||||||
URI uri,
|
|
||||||
ResponseInfo info) {
|
|
||||||
return new HttpResponse<>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public int statusCode() {
|
|
||||||
return info.statusCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpRequest request() {
|
|
||||||
throw new UnsupportedOperationException("TODO");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<HttpResponse<byte[]>> previousResponse() {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpHeaders headers() {
|
|
||||||
return info.headers();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] body() {
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<SSLSession> sslSession() {
|
|
||||||
throw new UnsupportedOperationException("TODO");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public URI uri() {
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public java.net.http.HttpClient.Version version() {
|
|
||||||
return info.version();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,10 +26,12 @@ import com.google.gson.JsonParser;
|
|||||||
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
|
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
|
|
||||||
public class LiveUserDataMapper
|
public class LiveUserDataMapper {
|
||||||
{
|
|
||||||
|
|
||||||
public LiveUserData.Response map(String json) {
|
public LiveUserData.Response map(String json) {
|
||||||
var jsonObject = JsonParser.parseString(json).getAsJsonObject();
|
var parsedJson = JsonParser.parseString(json);
|
||||||
|
var jsonObject = parsedJson.getAsJsonObject();
|
||||||
|
|
||||||
var message = jsonObject.get("message").getAsString();
|
var message = jsonObject.get("message").getAsString();
|
||||||
|
|
||||||
@@ -62,5 +64,6 @@ public class LiveUserDataMapper
|
|||||||
};
|
};
|
||||||
|
|
||||||
return new LiveUserData.Response(json, statusEnum, roomId, startTime);
|
return new LiveUserData.Response(json, statusEnum, roomId, startTime);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,17 +23,14 @@
|
|||||||
package io.github.jwdeveloper.tiktok.websocket;
|
package io.github.jwdeveloper.tiktok.websocket;
|
||||||
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.*;
|
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
|
||||||
import io.github.jwdeveloper.tiktok.data.dto.ProxyData;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.settings.*;
|
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLiveEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLiveMessageHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
import org.java_websocket.client.WebSocketClient;
|
import org.java_websocket.client.WebSocketClient;
|
||||||
|
|
||||||
import javax.net.ssl.*;
|
|
||||||
import java.net.Proxy;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class TikTokWebSocketClient implements SocketClient {
|
public class TikTokWebSocketClient implements SocketClient {
|
||||||
@@ -52,10 +49,10 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
this.tikTokEventHandler = tikTokEventHandler;
|
this.tikTokEventHandler = tikTokEventHandler;
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(LiveConnectionData.Response connectionData, LiveClient liveClient)
|
public void start(LiveConnectionData.Response connectionData, LiveClient liveClient)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
@@ -71,15 +68,8 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
tikTokEventHandler,
|
tikTokEventHandler,
|
||||||
liveClient);
|
liveClient);
|
||||||
|
|
||||||
// ProxyClientSettings proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
try
|
||||||
// if (proxyClientSettings.isEnabled())
|
{
|
||||||
// connectProxy(proxyClientSettings);
|
|
||||||
// else
|
|
||||||
connectDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connectDefault() {
|
|
||||||
try {
|
|
||||||
webSocketClient.connect();
|
webSocketClient.connect();
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
} catch (Exception e)
|
} catch (Exception e)
|
||||||
@@ -89,43 +79,12 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connectProxy(ProxyClientSettings proxySettings) {
|
|
||||||
while (proxySettings.hasNext()) {
|
|
||||||
ProxyData proxyData = proxySettings.next();
|
|
||||||
if (!tryProxyConnection(proxySettings, proxyData)) {
|
|
||||||
if (proxySettings.isAutoDiscard())
|
|
||||||
proxySettings.remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
isConnected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!isConnected)
|
|
||||||
throw new TikTokLiveException("Failed to connect to the websocket");
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean tryProxyConnection(ProxyClientSettings proxySettings, ProxyData proxyData) {
|
|
||||||
webSocketClient.setProxy(new Proxy(proxySettings.getType(), proxyData.toSocketAddress()));
|
|
||||||
try {
|
|
||||||
if (proxySettings.getType() == Proxy.Type.SOCKS) {
|
|
||||||
SSLContext sc = SSLContext.getInstance("SSL");
|
|
||||||
sc.init(null, new TrustManager[]{new X509TrustManager() {
|
|
||||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}
|
|
||||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}
|
|
||||||
public X509Certificate[] getAcceptedIssuers() { return null; }
|
|
||||||
}}, null);
|
|
||||||
webSocketClient.setSocketFactory(sc.getSocketFactory());
|
|
||||||
}
|
|
||||||
webSocketClient.connect();
|
|
||||||
return true;
|
|
||||||
} catch (Exception e)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
if (isConnected && webSocketClient != null && webSocketClient.isOpen()) {
|
if (isConnected && webSocketClient != null) {
|
||||||
webSocketClient.closeConnection(0, "");
|
webSocketClient.closeConnection(0, "");
|
||||||
}
|
}
|
||||||
webSocketClient = null;
|
webSocketClient = null;
|
||||||
|
|||||||
@@ -23,18 +23,23 @@
|
|||||||
package io.github.jwdeveloper.tiktok.websocket;
|
package io.github.jwdeveloper.tiktok.websocket;
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import io.github.jwdeveloper.tiktok.*;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokConnectedEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException;
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLiveEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLiveMessageHandler;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.*;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastPushFrame;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
import org.java_websocket.client.WebSocketClient;
|
import org.java_websocket.client.WebSocketClient;
|
||||||
import org.java_websocket.drafts.Draft_6455;
|
import org.java_websocket.drafts.Draft_6455;
|
||||||
import org.java_websocket.handshake.ServerHandshake;
|
import org.java_websocket.handshake.ServerHandshake;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.*;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class TikTokWebSocketListener extends WebSocketClient {
|
public class TikTokWebSocketListener extends WebSocketClient {
|
||||||
|
|
||||||
@@ -87,6 +92,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
|||||||
messageHandler.handle(tikTokLiveClient, webcastResponse);
|
messageHandler.handle(tikTokLiveClient, webcastResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(ServerHandshake serverHandshake) {
|
public void onOpen(ServerHandshake serverHandshake) {
|
||||||
tikTokEventHandler.publish(tikTokLiveClient, new TikTokConnectedEvent());
|
tikTokEventHandler.publish(tikTokLiveClient, new TikTokConnectedEvent());
|
||||||
@@ -95,10 +101,10 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose(int code, String reason, boolean remote) {
|
public void onClose(int i, String s, boolean b) {
|
||||||
tikTokEventHandler.publish(tikTokLiveClient, new TikTokDisconnectedEvent(reason));
|
tikTokEventHandler.publish(tikTokLiveClient, new TikTokDisconnectedEvent());
|
||||||
tikTokLiveClient.disconnect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -109,6 +115,8 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Optional<WebcastPushFrame> getWebcastPushFrame(byte[] buffer) {
|
private Optional<WebcastPushFrame> getWebcastPushFrame(byte[] buffer) {
|
||||||
try {
|
try {
|
||||||
var websocketMessage = WebcastPushFrame.parseFrom(buffer);
|
var websocketMessage = WebcastPushFrame.parseFrom(buffer);
|
||||||
@@ -133,8 +141,9 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
|||||||
return !isClosed() && !isClosing();
|
return !isClosed() && !isClosing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(String s) {
|
public void onMessage(String s) {
|
||||||
// System.err.println(s);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>TikTokLiveJava</artifactId>
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<version>1.0.16-Release</version>
|
<version>1.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package io.github.jwdeveloper.tiktok;
|
|
||||||
|
|
||||||
import java.net.Proxy;
|
|
||||||
|
|
||||||
public class ProxyExample
|
|
||||||
{
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
|
|
||||||
.configure(clientSettings -> {
|
|
||||||
clientSettings.setPrintToConsole(true);
|
|
||||||
clientSettings.getHttpSettings().configureProxy(proxySettings -> {
|
|
||||||
proxySettings.setOnProxyUpdated(proxyData -> System.err.println("Next proxy: " + proxyData.toString()));
|
|
||||||
proxySettings.setType(Proxy.Type.SOCKS);
|
|
||||||
proxySettings.addProxy("localhost", 8080);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.onConnected((liveClient, event) ->
|
|
||||||
liveClient.getLogger().info("Connected "+liveClient.getRoomInfo().getHostName()))
|
|
||||||
.onDisconnected((liveClient, event) ->
|
|
||||||
liveClient.getLogger().info("Disconnect reason: "+event.getReason()))
|
|
||||||
.onLiveEnded((liveClient, event) ->
|
|
||||||
liveClient.getLogger().info("Live Ended"))
|
|
||||||
.onError((liveClient, event) ->
|
|
||||||
event.getException().printStackTrace())
|
|
||||||
.buildAndConnect();
|
|
||||||
System.in.read();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -40,7 +40,6 @@ Join the support [discord](https://discord.gg/e2XwPNTBBr) and visit the `#java-s
|
|||||||
|
|
||||||
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 [@zerodytrash](https://github.com/zerodytrash)
|
- **Node** orginal: [TikTok-Live-Connector](https://github.com/isaackogan/TikTok-Live-Connector) by [@zerodytrash](https://github.com/zerodytrash)
|
||||||
- **Rust** rewrite: [TikTokLiveRust](https://github.com/jwdeveloper/TikTokLiveRust)
|
|
||||||
- **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)
|
||||||
@@ -70,7 +69,7 @@ Maven
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
|
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
|
||||||
<artifactId>Client</artifactId>
|
<artifactId>Client</artifactId>
|
||||||
<version>1.0.16-Release</version>
|
<version>1.0.15-Release</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -87,7 +86,7 @@ dependencyResolutionManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.0.16-Release'
|
implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.0.15-Release'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -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.16-Release</version>
|
<version>1.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -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.16-Release</version>
|
<version>1.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>Tools-EventsWebViewer</artifactId>
|
<artifactId>Tools-EventsWebViewer</artifactId>
|
||||||
|
|||||||
@@ -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.16-Release</version>
|
<version>1.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -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.16-Release</version>
|
<version>1.0.14-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@@ -7,7 +7,7 @@
|
|||||||
<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.16-Release</version>
|
<version>1.0.14-Release</version>
|
||||||
<modules>
|
<modules>
|
||||||
<module>API</module>
|
<module>API</module>
|
||||||
<module>Client</module>
|
<module>Client</module>
|
||||||
|
|||||||
Reference in New Issue
Block a user