mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-28 09:19:40 -05:00
Compare commits
15 Commits
1.1.2-Rele
...
1.3.0-Rele
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b6e82cd93 | ||
|
|
c93c3144ff | ||
|
|
12c64e1c67 | ||
|
|
5794ff2a57 | ||
|
|
d471e87dd7 | ||
|
|
c89bcad894 | ||
|
|
c9a84c39df | ||
|
|
c1105f1324 | ||
|
|
243ce9bc94 | ||
|
|
4f141edb1a | ||
|
|
359a1508c7 | ||
|
|
bbfa7b410b | ||
|
|
6da40927d0 | ||
|
|
4d97fd9157 | ||
|
|
1ba51476d1 |
@@ -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.1.1-Release</version>
|
<version>1.2.1-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>API</artifactId>
|
<artifactId>API</artifactId>
|
||||||
|
|||||||
@@ -20,16 +20,25 @@
|
|||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.data.requests;
|
package io.github.jwdeveloper.tiktok.data.events.control;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import io.github.jwdeveloper.tiktok.annotations.*;
|
||||||
import lombok.Data;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.requests.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
@Data
|
/**
|
||||||
@AllArgsConstructor
|
* Triggered before the connection is established.
|
||||||
public class SignServerResponse
|
*/
|
||||||
|
@EventMeta(eventType = EventType.Control)
|
||||||
|
public class TikTokPreConnectionEvent extends TikTokLiveClientEvent
|
||||||
{
|
{
|
||||||
private String signedUrl;
|
@Getter private final LiveUserData.Response userData;
|
||||||
|
@Getter private final LiveData.Response roomData;
|
||||||
|
@Getter @Setter boolean cancelConnection = false;
|
||||||
|
|
||||||
private String userAgent;
|
public TikTokPreConnectionEvent(LiveUserData.Response userData, LiveData.Response liveData) {
|
||||||
|
this.userData = userData;
|
||||||
|
this.roomData = liveData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,7 @@ public class LiveData {
|
|||||||
private int totalViewers;
|
private int totalViewers;
|
||||||
private boolean ageRestricted;
|
private boolean ageRestricted;
|
||||||
private User host;
|
private User host;
|
||||||
|
private LiveType liveType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum LiveStatus {
|
public enum LiveStatus {
|
||||||
@@ -51,4 +52,11 @@ public class LiveData {
|
|||||||
HostOnline,
|
HostOnline,
|
||||||
HostOffline,
|
HostOffline,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum LiveType {
|
||||||
|
SOLO,
|
||||||
|
BOX,
|
||||||
|
BATTLE,
|
||||||
|
CO_HOST
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -80,6 +80,11 @@ public class LiveClientSettings {
|
|||||||
*/
|
*/
|
||||||
private String roomId;
|
private String roomId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional: API Key for increased limit to signing server
|
||||||
|
*/
|
||||||
|
private String apiKey;
|
||||||
|
|
||||||
public static LiveClientSettings createDefault()
|
public static LiveClientSettings createDefault()
|
||||||
{
|
{
|
||||||
var httpSettings = new HttpClientSettings();
|
var httpSettings = new HttpClientSettings();
|
||||||
|
|||||||
@@ -33,11 +33,10 @@ import java.util.function.Consumer;
|
|||||||
@Setter
|
@Setter
|
||||||
public class ProxyClientSettings implements Iterator<ProxyData>
|
public class ProxyClientSettings implements Iterator<ProxyData>
|
||||||
{
|
{
|
||||||
private boolean enabled, lastSuccess;
|
private boolean enabled, autoDiscard = true, fallback = true;
|
||||||
private Rotation rotation = Rotation.CONSECUTIVE;
|
private Rotation rotation = Rotation.CONSECUTIVE;
|
||||||
private final List<ProxyData> proxyList = new ArrayList<>();
|
private final List<ProxyData> proxyList = new ArrayList<>();
|
||||||
private int index = 0;
|
private int index = -1;
|
||||||
private boolean autoDiscard = true;
|
|
||||||
private Proxy.Type type = Proxy.Type.DIRECT;
|
private Proxy.Type type = Proxy.Type.DIRECT;
|
||||||
private Consumer<ProxyData> onProxyUpdated = x -> {};
|
private Consumer<ProxyData> onProxyUpdated = x -> {};
|
||||||
|
|
||||||
@@ -64,10 +63,6 @@ public class ProxyClientSettings implements Iterator<ProxyData>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProxyData next() {
|
public ProxyData next() {
|
||||||
return lastSuccess ? proxyList.get(index) : rotate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProxyData rotate() {
|
|
||||||
var nextProxy = switch (rotation)
|
var nextProxy = switch (rotation)
|
||||||
{
|
{
|
||||||
case CONSECUTIVE -> {
|
case CONSECUTIVE -> {
|
||||||
@@ -78,16 +73,18 @@ public class ProxyClientSettings implements Iterator<ProxyData>
|
|||||||
index = new Random().nextInt(proxyList.size());
|
index = new Random().nextInt(proxyList.size());
|
||||||
yield proxyList.get(index).clone();
|
yield proxyList.get(index).clone();
|
||||||
}
|
}
|
||||||
case NONE -> proxyList.get(index).clone();
|
case NONE -> {
|
||||||
|
index = Math.max(index, 0);
|
||||||
|
yield proxyList.get(index).clone();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
onProxyUpdated.accept(nextProxy);
|
onProxyUpdated.accept(nextProxy);
|
||||||
return nextProxy;
|
return nextProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove() {
|
public void remove() {
|
||||||
proxyList.remove(index);
|
proxyList.remove(index);
|
||||||
lastSuccess = false; // index is no longer valid and lastSuccess needs falsified
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIndex(int index) {
|
public void setIndex(int index) {
|
||||||
@@ -99,6 +96,7 @@ public class ProxyClientSettings implements Iterator<ProxyData>
|
|||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProxyClientSettings clone()
|
public ProxyClientSettings clone()
|
||||||
{
|
{
|
||||||
ProxyClientSettings settings = new ProxyClientSettings();
|
ProxyClientSettings settings = new ProxyClientSettings();
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
package io.github.jwdeveloper.tiktok.exceptions;
|
package io.github.jwdeveloper.tiktok.exceptions;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Happens while bad response from Http request to TikTok
|
* Happens while bad response from Http request to TikTok
|
||||||
*/
|
*/
|
||||||
public class TikTokLiveRequestException extends TikTokLiveException
|
public class TikTokLiveRequestException extends TikTokLiveException
|
||||||
|
|||||||
@@ -27,9 +27,8 @@ import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
|
|||||||
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
|
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
|
||||||
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
|
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
|
||||||
|
|
||||||
public interface LiveHttpClient {
|
public interface LiveHttpClient
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return list of gifts that are available in your country
|
* @return list of gifts that are available in your country
|
||||||
*/
|
*/
|
||||||
@@ -37,28 +36,32 @@ public interface LiveHttpClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns information about user that is having a livestream
|
* Returns information about user that is having a livestream
|
||||||
*
|
* @param userName name of user
|
||||||
* @param userName
|
* @return {@link LiveUserData.Response}
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
LiveUserData.Response fetchLiveUserData(String userName);
|
default LiveUserData.Response fetchLiveUserData(String userName) {
|
||||||
|
return fetchLiveUserData(new LiveUserData.Request(userName));
|
||||||
|
}
|
||||||
|
|
||||||
LiveUserData.Response fetchLiveUserData(LiveUserData.Request request);
|
LiveUserData.Response fetchLiveUserData(LiveUserData.Request request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param roomId can be obtained from browsers cookies or by invoked fetchLiveUserData
|
* @param roomId can be obtained from browsers cookies or by invoked fetchLiveUserData
|
||||||
* @return
|
* @return {@link LiveData.Response}
|
||||||
*/
|
*/
|
||||||
LiveData.Response fetchLiveData(String roomId);
|
default LiveData.Response fetchLiveData(String roomId) {
|
||||||
|
return fetchLiveData(new LiveData.Request(roomId));
|
||||||
|
}
|
||||||
|
|
||||||
LiveData.Response fetchLiveData(LiveData.Request request);
|
LiveData.Response fetchLiveData(LiveData.Request request);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param roomId can be obtained from browsers cookies or by invoked fetchLiveUserData
|
* @param roomId can be obtained from browsers cookies or by invoked fetchLiveUserData
|
||||||
* @return
|
* @return {@link LiveConnectionData.Response}
|
||||||
*/
|
*/
|
||||||
LiveConnectionData.Response fetchLiveConnectionData(String roomId);
|
default LiveConnectionData.Response fetchLiveConnectionData(String roomId) {
|
||||||
|
return fetchLiveConnectionData(new LiveConnectionData.Request(roomId));
|
||||||
|
}
|
||||||
|
|
||||||
LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request);
|
LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request);
|
||||||
}
|
}
|
||||||
@@ -24,6 +24,7 @@ package io.github.jwdeveloper.tiktok.live.builder;
|
|||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.control.TikTokPreConnectionEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
|
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
|
||||||
@@ -149,6 +150,13 @@ public interface EventsBuilder<T> {
|
|||||||
*/
|
*/
|
||||||
T onConnected(EventConsumer<TikTokConnectedEvent> action);
|
T onConnected(EventConsumer<TikTokConnectedEvent> action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked before client has been successfully connected to live
|
||||||
|
* @param action
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T onPreConnection(EventConsumer<TikTokPreConnectionEvent> action);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when client tries to reconnect
|
* Invoked when client tries to reconnect
|
||||||
* @param action
|
* @param action
|
||||||
@@ -216,5 +224,3 @@ public interface EventsBuilder<T> {
|
|||||||
|
|
||||||
//T onUnhandledControl(TikTokEventConsumer<TikTokUnhandledControlEvent> event);
|
//T onUnhandledControl(TikTokEventConsumer<TikTokUnhandledControlEvent> event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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.1.1-Release</version>
|
<version>1.2.1-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -26,14 +26,13 @@ import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
|
|||||||
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent;
|
import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.control.TikTokConnectingEvent;
|
import io.github.jwdeveloper.tiktok.data.events.control.*;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent;
|
import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
|
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
|
||||||
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
|
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
|
||||||
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
|
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.exceptions.*;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
|
|
||||||
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
||||||
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
|
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
|
||||||
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
|
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
|
||||||
@@ -127,22 +126,26 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
var userData = httpClient.fetchLiveUserData(userDataRequest);
|
var userData = httpClient.fetchLiveUserData(userDataRequest);
|
||||||
liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp());
|
liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp());
|
||||||
liveRoomInfo.setRoomId(userData.getRoomId());
|
liveRoomInfo.setRoomId(userData.getRoomId());
|
||||||
if (userData.getUserStatus() == LiveUserData.UserStatus.Offline) {
|
|
||||||
throw new TikTokLiveOfflineHostException("User is offline: "+liveRoomInfo.getHostUser());
|
if (userData.getUserStatus() == LiveUserData.UserStatus.Offline)
|
||||||
}
|
throw new TikTokLiveOfflineHostException("User is offline: "+liveRoomInfo.getHostName());
|
||||||
if (userData.getUserStatus() == LiveUserData.UserStatus.NotFound) {
|
|
||||||
throw new TikTokLiveOfflineHostException("User not found: "+liveRoomInfo.getHostUser());
|
if (userData.getUserStatus() == LiveUserData.UserStatus.NotFound)
|
||||||
}
|
throw new TikTokLiveOfflineHostException("User not found: "+liveRoomInfo.getHostName());
|
||||||
|
|
||||||
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.isAgeRestricted())
|
||||||
|
throw new TikTokLiveException("Livestream for "+liveRoomInfo.getHostName()+" is 18+ or age restricted!");
|
||||||
|
|
||||||
|
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound)
|
||||||
|
throw new TikTokLiveOfflineHostException("LiveStream for "+liveRoomInfo.getHostName()+" could not be found.");
|
||||||
|
|
||||||
|
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostOffline)
|
||||||
|
throw new TikTokLiveOfflineHostException("LiveStream for "+liveRoomInfo.getHostName()+" not found, is the Host offline?");
|
||||||
|
|
||||||
tikTokEventHandler.publish(this, new TikTokRoomDataResponseEvent(liveData));
|
tikTokEventHandler.publish(this, new TikTokRoomDataResponseEvent(liveData));
|
||||||
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound) {
|
|
||||||
throw new TikTokLiveOfflineHostException("LiveStream for Host name could not be found.");
|
|
||||||
}
|
|
||||||
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostOffline) {
|
|
||||||
throw new TikTokLiveOfflineHostException("LiveStream for not be found, is the Host offline?");
|
|
||||||
}
|
|
||||||
|
|
||||||
liveRoomInfo.setTitle(liveData.getTitle());
|
liveRoomInfo.setTitle(liveData.getTitle());
|
||||||
liveRoomInfo.setViewersCount(liveData.getViewers());
|
liveRoomInfo.setViewersCount(liveData.getViewers());
|
||||||
@@ -150,6 +153,11 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
liveRoomInfo.setAgeRestricted(liveData.isAgeRestricted());
|
liveRoomInfo.setAgeRestricted(liveData.isAgeRestricted());
|
||||||
liveRoomInfo.setHost(liveData.getHost());
|
liveRoomInfo.setHost(liveData.getHost());
|
||||||
|
|
||||||
|
var preconnectEvent = new TikTokPreConnectionEvent(userData, liveData);
|
||||||
|
tikTokEventHandler.publish(this, preconnectEvent);
|
||||||
|
if (preconnectEvent.isCancelConnection())
|
||||||
|
throw new TikTokLiveException("TikTokPreConnectionEvent cancelled connection!");
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ package io.github.jwdeveloper.tiktok;
|
|||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.control.TikTokPreConnectionEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
|
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
||||||
@@ -98,7 +99,8 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder addListener(TikTokEventListener listener) {
|
public TikTokLiveClientBuilder addListener(TikTokEventListener listener) {
|
||||||
listeners.add(listener);
|
if (listener != null)
|
||||||
|
listeners.add(listener);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,9 +277,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return build().connectAsync();
|
return build().connectAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TikTokLiveClientBuilder onUnhandledSocial(EventConsumer<TikTokUnhandledSocialEvent> event) {
|
||||||
public TikTokLiveClientBuilder onUnhandledSocial(
|
|
||||||
EventConsumer<TikTokUnhandledSocialEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokUnhandledSocialEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokUnhandledSocialEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -289,8 +289,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkMicFanTicket(
|
public TikTokLiveClientBuilder onLinkMicFanTicket(EventConsumer<TikTokLinkMicFanTicketEvent> event) {
|
||||||
EventConsumer<TikTokLinkMicFanTicketEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -305,14 +304,12 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onDetect(
|
public TikTokLiveClientBuilder onDetect(EventConsumer<TikTokDetectEvent> event) {
|
||||||
EventConsumer<TikTokDetectEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokDetectEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokDetectEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkLayer(
|
public TikTokLiveClientBuilder onLinkLayer(EventConsumer<TikTokLinkLayerEvent> event) {
|
||||||
EventConsumer<TikTokLinkLayerEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokLinkLayerEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokLinkLayerEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -322,6 +319,11 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TikTokLiveClientBuilder onPreConnection(EventConsumer<TikTokPreConnectionEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokPreConnectionEvent.class, event);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onCaption(EventConsumer<TikTokCaptionEvent> event) {
|
public TikTokLiveClientBuilder onCaption(EventConsumer<TikTokCaptionEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokCaptionEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokCaptionEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
@@ -332,8 +334,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onRoomPin(
|
public TikTokLiveClientBuilder onRoomPin(EventConsumer<TikTokRoomPinEvent> event) {
|
||||||
EventConsumer<TikTokRoomPinEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokRoomPinEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokRoomPinEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -373,8 +374,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onBarrage(
|
public TikTokLiveClientBuilder onBarrage(EventConsumer<TikTokBarrageEvent> event) {
|
||||||
EventConsumer<TikTokBarrageEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokBarrageEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokBarrageEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -391,8 +391,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkMicArmies(
|
public TikTokLiveClientBuilder onLinkMicArmies(EventConsumer<TikTokLinkMicArmiesEvent> event) {
|
||||||
EventConsumer<TikTokLinkMicArmiesEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokLinkMicArmiesEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokLinkMicArmiesEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -402,20 +401,17 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onUnauthorizedMember(
|
public TikTokLiveClientBuilder onUnauthorizedMember(EventConsumer<TikTokUnauthorizedMemberEvent> event) {
|
||||||
EventConsumer<TikTokUnauthorizedMemberEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokUnauthorizedMemberEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokUnauthorizedMemberEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onInRoomBanner(
|
public TikTokLiveClientBuilder onInRoomBanner(EventConsumer<TikTokInRoomBannerEvent> event) {
|
||||||
EventConsumer<TikTokInRoomBannerEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokInRoomBannerEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokInRoomBannerEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkMicMethod(
|
public TikTokLiveClientBuilder onLinkMicMethod(EventConsumer<TikTokLinkMicMethodEvent> event) {
|
||||||
EventConsumer<TikTokLinkMicMethodEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokLinkMicMethodEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokLinkMicMethodEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -487,8 +483,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onUnhandledMember(
|
public TikTokLiveClientBuilder onUnhandledMember(EventConsumer<TikTokUnhandledMemberEvent> event) {
|
||||||
EventConsumer<TikTokUnhandledMemberEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokUnhandledMemberEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokUnhandledMemberEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -498,20 +493,17 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkMicBattle(
|
public TikTokLiveClientBuilder onLinkMicBattle(EventConsumer<TikTokLinkMicBattleEvent> event) {
|
||||||
EventConsumer<TikTokLinkMicBattleEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokLinkMicBattleEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokLinkMicBattleEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onDisconnected(
|
public TikTokLiveClientBuilder onDisconnected(EventConsumer<TikTokDisconnectedEvent> event) {
|
||||||
EventConsumer<TikTokDisconnectedEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokDisconnectedEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokDisconnectedEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onUnhandledControl(
|
public TikTokLiveClientBuilder onUnhandledControl(EventConsumer<TikTokUnhandledControlEvent> event) {
|
||||||
EventConsumer<TikTokUnhandledControlEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokUnhandledControlEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokUnhandledControlEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,18 +36,17 @@ import java.util.Optional;
|
|||||||
public class TikTokLiveHttpClient implements LiveHttpClient {
|
public class TikTokLiveHttpClient implements LiveHttpClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signing API by Isaac Kogan
|
* <a href="https://github-wiki-see.page/m/isaackogan/TikTokLive/wiki/All-About-Signatures">Signing API by Isaac Kogan</a>
|
||||||
* https://github-wiki-see.page/m/isaackogan/TikTokLive/wiki/All-About-Signatures
|
*/
|
||||||
*/
|
private static final String TIKTOK_SIGN_API = "https://tiktok.eulerstream.com/webcast/fetch";
|
||||||
private static final String TIKTOK_SIGN_API = "https://tiktok.eulerstream.com/webcast/sign_url";
|
|
||||||
private static final String TIKTOK_URL_WEB = "https://www.tiktok.com/";
|
private static final String TIKTOK_URL_WEB = "https://www.tiktok.com/";
|
||||||
private static final String TIKTOK_URL_WEBCAST = "https://webcast.tiktok.com/webcast/";
|
private static final String TIKTOK_URL_WEBCAST = "https://webcast.tiktok.com/webcast/";
|
||||||
|
public static final int TIKTOK_AGE_RESTRICTED_CODE = 4003110;
|
||||||
|
|
||||||
private final HttpClientFactory httpFactory;
|
private final HttpClientFactory httpFactory;
|
||||||
private final LiveClientSettings clientSettings;
|
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 GiftsDataMapper giftsDataMapper;
|
private final GiftsDataMapper giftsDataMapper;
|
||||||
|
|
||||||
public TikTokLiveHttpClient(HttpClientFactory factory, LiveClientSettings settings) {
|
public TikTokLiveHttpClient(HttpClientFactory factory, LiveClientSettings settings) {
|
||||||
@@ -55,7 +54,6 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
clientSettings = settings;
|
clientSettings = settings;
|
||||||
liveUserDataMapper = new LiveUserDataMapper();
|
liveUserDataMapper = new LiveUserDataMapper();
|
||||||
liveDataMapper = new LiveDataMapper();
|
liveDataMapper = new LiveDataMapper();
|
||||||
signServerResponseMapper = new SignServerResponseMapper();
|
|
||||||
giftsDataMapper = new GiftsDataMapper();
|
giftsDataMapper = new GiftsDataMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +64,22 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
|
|
||||||
public GiftsData.Response fetchGiftsData() {
|
public GiftsData.Response fetchGiftsData() {
|
||||||
var url = TIKTOK_URL_WEBCAST + "gift/list/";
|
var url = TIKTOK_URL_WEBCAST + "gift/list/";
|
||||||
|
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
||||||
|
if (proxyClientSettings.isEnabled()) {
|
||||||
|
while (proxyClientSettings.hasNext()) {
|
||||||
|
try {
|
||||||
|
var optional = httpFactory.client(url)
|
||||||
|
.build()
|
||||||
|
.toJsonResponse();
|
||||||
|
|
||||||
|
if (optional.isEmpty()) {
|
||||||
|
throw new TikTokLiveRequestException("Unable to fetch gifts information's");
|
||||||
|
}
|
||||||
|
var json = optional.get();
|
||||||
|
return giftsDataMapper.map(json);
|
||||||
|
} catch (TikTokProxyRequestException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
var optional = httpFactory.client(url)
|
var optional = httpFactory.client(url)
|
||||||
.build()
|
.build()
|
||||||
.toJsonResponse();
|
.toJsonResponse();
|
||||||
@@ -73,23 +87,18 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
if (optional.isEmpty()) {
|
if (optional.isEmpty()) {
|
||||||
throw new TikTokLiveRequestException("Unable to fetch gifts information's");
|
throw new TikTokLiveRequestException("Unable to fetch gifts information's");
|
||||||
}
|
}
|
||||||
|
|
||||||
var json = optional.get();
|
var json = optional.get();
|
||||||
return giftsDataMapper.map(json);
|
return giftsDataMapper.map(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LiveUserData.Response fetchLiveUserData(String userName) {
|
|
||||||
return fetchLiveUserData(new LiveUserData.Request(userName));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiveUserData.Response fetchLiveUserData(LiveUserData.Request request) {
|
public LiveUserData.Response fetchLiveUserData(LiveUserData.Request request) {
|
||||||
|
var url = TIKTOK_URL_WEB + "api-live/user/room";
|
||||||
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
||||||
if (proxyClientSettings.isEnabled()) {
|
if (proxyClientSettings.isEnabled()) {
|
||||||
while (proxyClientSettings.hasNext()) {
|
while (proxyClientSettings.hasNext()) {
|
||||||
try {
|
try {
|
||||||
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())
|
||||||
.withParam("sourceType", "54")
|
.withParam("sourceType", "54")
|
||||||
@@ -105,7 +114,6 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
} catch (TikTokProxyRequestException ignored) {}
|
} catch (TikTokProxyRequestException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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())
|
||||||
.withParam("sourceType", "54")
|
.withParam("sourceType", "54")
|
||||||
@@ -120,18 +128,13 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
return liveUserDataMapper.map(json);
|
return liveUserDataMapper.map(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public LiveData.Response fetchLiveData(String roomId) {
|
|
||||||
return fetchLiveData(new LiveData.Request(roomId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiveData.Response fetchLiveData(LiveData.Request request) {
|
public LiveData.Response fetchLiveData(LiveData.Request request) {
|
||||||
|
var url = TIKTOK_URL_WEBCAST + "room/info";
|
||||||
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
||||||
if (proxyClientSettings.isEnabled()) {
|
if (proxyClientSettings.isEnabled()) {
|
||||||
while (proxyClientSettings.hasNext()) {
|
while (proxyClientSettings.hasNext()) {
|
||||||
try {
|
try {
|
||||||
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())
|
||||||
.build()
|
.build()
|
||||||
@@ -146,7 +149,6 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
} catch (TikTokProxyRequestException ignored) {}
|
} catch (TikTokProxyRequestException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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())
|
||||||
.build()
|
.build()
|
||||||
@@ -160,20 +162,12 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
return liveDataMapper.map(json);
|
return liveDataMapper.map(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public LiveConnectionData.Response fetchLiveConnectionData(String roomId) {
|
|
||||||
return fetchLiveConnectionData(new LiveConnectionData.Request(roomId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request) {
|
public LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request) {
|
||||||
HttpResponse<byte[]> credentialsResponse = getOptionalProxyResponse(request).orElseGet(()-> {
|
HttpResponse<byte[]> credentialsResponse = getOptionalProxyResponse(request).orElseGet(()-> getStarterPayload(request.getRoomId()));
|
||||||
SignServerResponse signServerResponse = getSignedUrl(request.getRoomId());
|
|
||||||
return getWebsocketCredentialsResponse(signServerResponse.getSignedUrl());
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var optionalHeader = credentialsResponse.headers().firstValue("set-cookie");
|
var optionalHeader = credentialsResponse.headers().firstValue("x-set-tt-cookie");
|
||||||
if (optionalHeader.isEmpty()) {
|
if (optionalHeader.isEmpty()) {
|
||||||
throw new TikTokSignServerException("Sign server did not return the set-cookie header");
|
throw new TikTokSignServerException("Sign server did not return the set-cookie header");
|
||||||
}
|
}
|
||||||
@@ -195,39 +189,21 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SignServerResponse getSignedUrl(String roomId) {
|
HttpResponse<byte[]> getStarterPayload(String room_id) {
|
||||||
var urlToSign = httpFactory
|
HttpClientBuilder builder = httpFactory.client(TIKTOK_SIGN_API)
|
||||||
.client(TikTokLiveHttpClient.TIKTOK_URL_WEBCAST + "im/fetch")
|
.withParam("client", "ttlive-java")
|
||||||
.withParam("room_id", roomId)
|
.withParam("uuc", "1")
|
||||||
.build()
|
.withParam("room_id", room_id);
|
||||||
.toUrl();
|
|
||||||
|
|
||||||
|
if (clientSettings.getApiKey() != null)
|
||||||
|
builder.withParam("apiKey", clientSettings.getApiKey());
|
||||||
|
|
||||||
var optional = httpFactory
|
var optional = builder.build().toResponse();
|
||||||
.client(TikTokLiveHttpClient.TIKTOK_SIGN_API)
|
|
||||||
.withParam("client", "ttlive-java")
|
|
||||||
.withParam("uuc", "1")
|
|
||||||
.withParam("url", urlToSign.toString())
|
|
||||||
.build()
|
|
||||||
.toJsonResponse();
|
|
||||||
|
|
||||||
if (optional.isEmpty()) {
|
if (optional.isEmpty()) {
|
||||||
throw new TikTokSignServerException("Unable to sign url: " + urlToSign);
|
|
||||||
}
|
|
||||||
|
|
||||||
var json = optional.get();
|
|
||||||
return signServerResponseMapper.map(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpResponse<byte[]> getWebsocketCredentialsResponse(String signedUrl) {
|
|
||||||
var optionalResponse = httpFactory
|
|
||||||
.clientEmpty(signedUrl)
|
|
||||||
.build()
|
|
||||||
.toResponse();
|
|
||||||
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 optional.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<HttpResponse<byte[]>> getOptionalProxyResponse(LiveConnectionData.Request request) {
|
Optional<HttpResponse<byte[]>> getOptionalProxyResponse(LiveConnectionData.Request request) {
|
||||||
@@ -235,9 +211,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient {
|
|||||||
if (proxyClientSettings.isEnabled()) {
|
if (proxyClientSettings.isEnabled()) {
|
||||||
while (proxyClientSettings.hasNext()) {
|
while (proxyClientSettings.hasNext()) {
|
||||||
try {
|
try {
|
||||||
SignServerResponse signServerResponse = getSignedUrl(request.getRoomId());
|
HttpResponse<byte[]> credentialsResponse = getStarterPayload(request.getRoomId());
|
||||||
HttpResponse<byte[]> credentialsResponse = getWebsocketCredentialsResponse(signServerResponse.getSignedUrl());
|
|
||||||
clientSettings.getHttpSettings().getProxyClientSettings().rotate();
|
|
||||||
return Optional.of(credentialsResponse);
|
return Optional.of(credentialsResponse);
|
||||||
} catch (TikTokProxyRequestException | TikTokSignServerException ignored) {}
|
} catch (TikTokProxyRequestException | TikTokSignServerException ignored) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class HttpClient {
|
|||||||
protected final String url;
|
protected final String url;
|
||||||
private final Pattern pattern = Pattern.compile("charset=(.*?)(?=&|$)");
|
private final Pattern pattern = Pattern.compile("charset=(.*?)(?=&|$)");
|
||||||
|
|
||||||
public Optional<HttpResponse<byte[]>> toResponse() {
|
public Optional<HttpResponse<byte[]>> toResponse() {
|
||||||
var client = prepareClient();
|
var client = prepareClient();
|
||||||
var request = prepareGetRequest();
|
var request = prepareGetRequest();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -67,16 +67,17 @@ public class HttpProxyClient extends HttpClient
|
|||||||
var request = prepareGetRequest();
|
var request = prepareGetRequest();
|
||||||
|
|
||||||
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||||
if (response.statusCode() != 200) {
|
if (response.statusCode() != 200)
|
||||||
proxySettings.setLastSuccess(false);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
proxySettings.setLastSuccess(true);
|
|
||||||
return Optional.of(response);
|
return Optional.of(response);
|
||||||
} catch (HttpConnectTimeoutException | ConnectException e) {
|
} catch (HttpConnectTimeoutException | ConnectException e) {
|
||||||
if (proxySettings.isAutoDiscard())
|
if (proxySettings.isAutoDiscard())
|
||||||
proxySettings.remove();
|
proxySettings.remove();
|
||||||
proxySettings.setLastSuccess(false);
|
throw new TikTokProxyRequestException(e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (e.getMessage().contains("503") && proxySettings.isFallback()) // Indicates proxy protocol is not supported
|
||||||
|
return super.toResponse();
|
||||||
|
throw new TikTokProxyRequestException(e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TikTokLiveRequestException(e);
|
throw new TikTokLiveRequestException(e);
|
||||||
}
|
}
|
||||||
@@ -116,12 +117,12 @@ public class HttpProxyClient extends HttpClient
|
|||||||
|
|
||||||
var response = createHttpResponse(body, toUrl(), responseInfo);
|
var response = createHttpResponse(body, toUrl(), responseInfo);
|
||||||
|
|
||||||
proxySettings.setLastSuccess(true);
|
|
||||||
return Optional.of(response);
|
return Optional.of(response);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
if (e.getMessage().contains("503") && proxySettings.isFallback()) // Indicates proxy protocol is not supported
|
||||||
|
return super.toResponse();
|
||||||
if (proxySettings.isAutoDiscard())
|
if (proxySettings.isAutoDiscard())
|
||||||
proxySettings.remove();
|
proxySettings.remove();
|
||||||
proxySettings.setLastSuccess(false);
|
|
||||||
throw new TikTokProxyRequestException(e);
|
throw new TikTokProxyRequestException(e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TikTokLiveRequestException(e);
|
throw new TikTokLiveRequestException(e);
|
||||||
@@ -130,7 +131,7 @@ public class HttpProxyClient extends HttpClient
|
|||||||
throw new TikTokLiveRequestException("No more proxies available!");
|
throw new TikTokLiveRequestException("No more proxies available!");
|
||||||
} catch (NoSuchAlgorithmException | MalformedURLException | KeyManagementException e) {
|
} catch (NoSuchAlgorithmException | MalformedURLException | KeyManagementException e) {
|
||||||
// Should never be reached!
|
// Should never be reached!
|
||||||
System.out.println("handleSocksProxyRequest()! If you see this message, reach us on discord!");
|
System.out.println("handleSocksProxyRequest: If you see this, message us on discord!");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
} catch (TikTokLiveRequestException e) {
|
} catch (TikTokLiveRequestException e) {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ package io.github.jwdeveloper.tiktok.http.mappers;
|
|||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokLiveHttpClient;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.users.UserAttribute;
|
import io.github.jwdeveloper.tiktok.data.models.users.UserAttribute;
|
||||||
@@ -64,6 +65,9 @@ public class LiveDataMapper {
|
|||||||
default -> LiveData.LiveStatus.HostNotFound;
|
default -> LiveData.LiveStatus.HostNotFound;
|
||||||
};
|
};
|
||||||
response.setLiveStatus(statusValue);
|
response.setLiveStatus(statusValue);
|
||||||
|
} else if (data.has("prompts") && jsonObject.has("status_code") &&
|
||||||
|
data.get("prompts").getAsString().isEmpty() && jsonObject.get("status_code").isJsonPrimitive()) {
|
||||||
|
response.setAgeRestricted(jsonObject.get("status_code").getAsInt() == TikTokLiveHttpClient.TIKTOK_AGE_RESTRICTED_CODE);
|
||||||
} else {
|
} else {
|
||||||
response.setLiveStatus(LiveData.LiveStatus.HostNotFound);
|
response.setLiveStatus(LiveData.LiveStatus.HostNotFound);
|
||||||
}
|
}
|
||||||
@@ -105,6 +109,22 @@ public class LiveDataMapper {
|
|||||||
response.setHost(user);
|
response.setHost(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.has("link_mic")) {
|
||||||
|
var element = data.getAsJsonObject("link_mic");
|
||||||
|
var multi_live = element.get("multi_live_enum").getAsInt();
|
||||||
|
var rival_id = element.get("rival_anchor_id").getAsInt();
|
||||||
|
var battle_scores = element.get("battle_scores").getAsJsonArray();
|
||||||
|
if (multi_live == 1) {
|
||||||
|
if (!battle_scores.isEmpty())
|
||||||
|
response.setLiveType(LiveData.LiveType.BATTLE);
|
||||||
|
else if (rival_id != 0)
|
||||||
|
response.setLiveType(LiveData.LiveType.CO_HOST);
|
||||||
|
else
|
||||||
|
response.setLiveType(LiveData.LiveType.BOX);
|
||||||
|
} else
|
||||||
|
response.setLiveType(LiveData.LiveType.SOLO);
|
||||||
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +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.mappers;
|
|
||||||
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.requests.SignServerResponse;
|
|
||||||
|
|
||||||
public class SignServerResponseMapper {
|
|
||||||
public SignServerResponse map(String json) {
|
|
||||||
var parsedJson = JsonParser.parseString(json);
|
|
||||||
var jsonObject = parsedJson.getAsJsonObject();
|
|
||||||
|
|
||||||
var signUrl = jsonObject.get("signedUrl").getAsString();
|
|
||||||
var userAgent = jsonObject.get("User-Agent").getAsString();
|
|
||||||
return new SignServerResponse(signUrl, userAgent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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.1.1-Release</version>
|
<version>1.2.1-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<artifactId>extension-collector</artifactId>
|
<artifactId>extension-collector</artifactId>
|
||||||
<version>1.1.1-Release</version>
|
<version>1.2.1-Release</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -70,7 +70,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.1.0-Release</version>
|
<version>1.3.0-Release</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -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.1.1-Release</version>
|
<version>1.2.1-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.1.1-Release</version>
|
<version>1.2.1-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.1.1-Release</version>
|
<version>1.2.1-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,10 @@ public class CodeExample {
|
|||||||
//RoomId can be used as an override if you're having issues with HostId.
|
//RoomId can be used as an override if you're having issues with HostId.
|
||||||
//You can find it in the HTML for the livestream-page
|
//You can find it in the HTML for the livestream-page
|
||||||
settings.setRoomId("XXXXXXXXXXXXXXXXX");
|
settings.setRoomId("XXXXXXXXXXXXXXXXX");
|
||||||
|
|
||||||
|
//Optional:
|
||||||
|
//API Key for increased limit to signing server
|
||||||
|
settings.setApiKey("XXXXXXXXXXXXXXXXX");
|
||||||
})
|
})
|
||||||
.buildAndConnect();
|
.buildAndConnect();
|
||||||
// </code>
|
// </code>
|
||||||
|
|||||||
@@ -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.1.1-Release</version>
|
<version>1.2.1-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<artifactId>TikTokLiveJava</artifactId>
|
<artifactId>TikTokLiveJava</artifactId>
|
||||||
<version>1.1.1-Release</version>
|
<version>1.2.1-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<artifactId>API</artifactId>
|
<artifactId>API</artifactId>
|
||||||
<version>1.1.1-Release</version>
|
<version>1.2.1-Release</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -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.1.1-Release</version>
|
<version>1.2.1-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>extension-recorder</artifactId>
|
<artifactId>extension-recorder</artifactId>
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import java.util.function.Consumer;
|
|||||||
|
|
||||||
public class TikTokLiveRecorder
|
public class TikTokLiveRecorder
|
||||||
{
|
{
|
||||||
|
|
||||||
public static LiveRecorder use(Consumer<RecorderSettings> consumer)
|
public static LiveRecorder use(Consumer<RecorderSettings> consumer)
|
||||||
{
|
{
|
||||||
return new RecorderListener(consumer);
|
return new RecorderListener(consumer);
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver;
|
|||||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent;
|
import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
|
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
|
||||||
import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder;
|
import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder;
|
||||||
import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.*;
|
import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.*;
|
||||||
import io.github.jwdeveloper.tiktok.extension.recorder.impl.enums.LiveQuality;
|
import io.github.jwdeveloper.tiktok.extension.recorder.impl.enums.LiveQuality;
|
||||||
@@ -70,16 +69,12 @@ public class RecorderListener implements LiveRecorder {
|
|||||||
var json = event.getLiveData().getJson();
|
var json = event.getLiveData().getJson();
|
||||||
|
|
||||||
liveClient.getLogger().info("Searching for live download url");
|
liveClient.getLogger().info("Searching for live download url");
|
||||||
if (settings.getPrepareDownloadData() != null) {
|
downloadData = settings.getPrepareDownloadData() != null ? settings.getPrepareDownloadData().apply(json) : mapToDownloadData(json);
|
||||||
downloadData = settings.getPrepareDownloadData().apply(json);
|
|
||||||
} else {
|
|
||||||
downloadData = mapToDownloadData(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (downloadData.getDownloadLiveUrl().isEmpty()) {
|
if (downloadData.getDownloadLiveUrl().isEmpty())
|
||||||
throw new TikTokLiveException("Unable to find download live url!");
|
liveClient.getLogger().warning("Unable to find download live url!");
|
||||||
}
|
else
|
||||||
liveClient.getLogger().info("Live download url found!");
|
liveClient.getLogger().info("Live download url found!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TikTokEventObserver
|
@TikTokEventObserver
|
||||||
@@ -88,13 +83,13 @@ public class RecorderListener implements LiveRecorder {
|
|||||||
try {
|
try {
|
||||||
var bufferSize = 1024;
|
var bufferSize = 1024;
|
||||||
var url = new URL(downloadData.getFullUrl());
|
var url = new URL(downloadData.getFullUrl());
|
||||||
HttpsURLConnection socksConnection = (HttpsURLConnection) url.openConnection();
|
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
||||||
var headers = LiveClientSettings.DefaultRequestHeaders();
|
var headers = LiveClientSettings.DefaultRequestHeaders();
|
||||||
for (var entry : headers.entrySet()) {
|
for (var entry : headers.entrySet()) {
|
||||||
socksConnection.setRequestProperty(entry.getKey(), entry.getValue());
|
connection.setRequestProperty(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
var in = new BufferedInputStream(socksConnection.getInputStream());
|
var in = new BufferedInputStream(connection.getInputStream());
|
||||||
var path = settings.getOutputPath() + File.separator + settings.getOutputFileName();
|
var path = settings.getOutputPath() + File.separator + settings.getOutputFileName();
|
||||||
var file = new File(path);
|
var file = new File(path);
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
|
|||||||
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.1.1-Release</version>
|
<version>1.2.1-Release</version>
|
||||||
<modules>
|
<modules>
|
||||||
<module>API</module>
|
<module>API</module>
|
||||||
<module>Client</module>
|
<module>Client</module>
|
||||||
|
|||||||
Reference in New Issue
Block a user