Compare commits

..

15 Commits

Author SHA1 Message Date
David Kohler
6b6e82cd93 MINOR 2024-02-15 13:59:36 -05:00
GitHub Action
c93c3144ff Update version in pom.xml 2024-02-15 18:56:11 +00:00
David Kohler
12c64e1c67 MINOR: Merge pull request #57 from jwdeveloper/develop-1.3.0
MINOR: Develop 1.3.0
2024-02-15 13:54:31 -05:00
David Kohler
5794ff2a57 MINOR: Merge pull request #56 from kohlerpop1/fixes-updates
MINOR: Switched to new Signing Server endpoint and more
2024-02-15 13:53:36 -05:00
kohlerpop1
d471e87dd7 Converted magic number to constant AGE_RESTRICTED_CODE 2024-02-15 12:55:45 -05:00
kohlerpop1
c89bcad894 Removed System.out.println of response headers! 2024-02-15 12:13:52 -05:00
kohlerpop1
c9a84c39df Merge remote-tracking branch 'origin/fixes-updates' into fixes-updates 2024-02-15 12:10:52 -05:00
kohlerpop1
c1105f1324 Switched to new Signing Server endpoint and more 2024-02-15 12:10:17 -05:00
kohlerpop1
243ce9bc94 Added PreConnectionEvent with LiveType, made optimizations, and added fallback to default request in proxy class in case proxy protocol is not supported by TikTok or Signing server. 2024-02-15 11:46:13 -05:00
GitHub Action
4f141edb1a Update version in pom.xml 2024-02-15 00:26:07 +00:00
Jacek W
359a1508c7 MINOR 2024-02-15 01:24:26 +01:00
Jacek W
bbfa7b410b Merge pull request #55 from jwdeveloper/develop-1.2.0
Develop 1.2.0
2024-02-15 01:23:56 +01:00
GitHub Action
6da40927d0 Update version in pom.xml 2024-02-15 00:18:41 +00:00
Jacek W
4d97fd9157 Merge pull request #54 from kohlerpop1/fixes-updates
MINOR: Added PreConnectionEvent with LiveType, made optimizations, and more
2024-02-15 01:16:59 +01:00
kohlerpop1
1ba51476d1 Added PreConnectionEvent with LiveType, made optimizations, and added fallback to default request in proxy class in case proxy protocol is not supported by TikTok or Signing server. 2024-02-12 15:24:54 -05:00
28 changed files with 205 additions and 220 deletions

View File

@@ -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>

View File

@@ -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;
}
} }

View File

@@ -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
}
} }

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -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);
} }

View File

@@ -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);
} }

View File

@@ -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>

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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) {}
} }

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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;
} }

View File

@@ -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);
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -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();

View File

@@ -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>