mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-28 09:19:40 -05:00
Changes:
Generated new Gifts Json TikTokLive.isLiveOnline() new method for checking if live if online TikTokLive.isLiveOnlineAsync()
This commit is contained in:
@@ -23,12 +23,25 @@
|
||||
package io.github.jwdeveloper.tiktok;
|
||||
|
||||
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokLiveOnlineChecker;
|
||||
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class TikTokLive
|
||||
{
|
||||
public static LiveClientBuilder newClient(String hostName)
|
||||
{
|
||||
return new TikTokLiveClientBuilder(hostName);
|
||||
}
|
||||
|
||||
public static boolean isLiveOnline(String hostName)
|
||||
{
|
||||
return new TikTokLiveOnlineChecker().isOnline(hostName);
|
||||
}
|
||||
|
||||
public static CompletableFuture<Boolean> isLiveOnlineAsync(String hostName)
|
||||
{
|
||||
return new TikTokLiveOnlineChecker().isOnlineAsync(hostName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ package io.github.jwdeveloper.tiktok;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||
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.TikTokGiftEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
|
||||
@@ -135,6 +136,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public LiveClient build() {
|
||||
@@ -148,7 +150,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
|
||||
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
|
||||
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
|
||||
var giftManager = new TikTokGiftManager();
|
||||
var giftManager = new TikTokGiftManager(logger);
|
||||
var eventMapper = new TikTokGenericEventMapper();
|
||||
var giftHandler = new TikTokGiftEventHandler(giftManager);
|
||||
|
||||
@@ -190,6 +192,12 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveClientBuilder onChestOpen(EventConsumer<TikTokChestEvent> event) {
|
||||
tikTokEventHandler.subscribe(TikTokChestEvent.class, event);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TikTokLiveClientBuilder onLinkMicFanTicket(
|
||||
EventConsumer<TikTokLinkMicFanTicketEvent> event) {
|
||||
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
*/
|
||||
package io.github.jwdeveloper.tiktok;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||
import io.github.jwdeveloper.tiktok.messages.data.User;
|
||||
import io.github.jwdeveloper.tiktok.models.ConnectionState;
|
||||
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
|
||||
import lombok.Data;
|
||||
@@ -29,15 +31,20 @@ import lombok.Data;
|
||||
@Data
|
||||
public class TikTokRoomInfo implements LiveRoomInfo
|
||||
{
|
||||
private String roomId;
|
||||
|
||||
private int likesCount;
|
||||
|
||||
private int viewersCount;
|
||||
|
||||
private String roomId;
|
||||
|
||||
private boolean ageRestricted;
|
||||
|
||||
private User host;
|
||||
|
||||
private Picture picture;
|
||||
|
||||
private String description;
|
||||
|
||||
private String hostName;
|
||||
|
||||
private ConnectionState connectionState = ConnectionState.DISCONNECTED;
|
||||
|
||||
@@ -28,18 +28,22 @@ import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class TikTokGiftManager implements GiftManager {
|
||||
|
||||
private final Map<Integer, Gift> indexById;
|
||||
private final Map<String, Gift> indexByName;
|
||||
private final Logger logger;
|
||||
|
||||
public TikTokGiftManager() {
|
||||
public TikTokGiftManager(Logger logger)
|
||||
{
|
||||
indexById = new HashMap<>();
|
||||
indexByName = new HashMap<>();
|
||||
this.logger = logger;
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -66,6 +70,17 @@ public class TikTokGiftManager implements GiftManager {
|
||||
field.set(enumInstance, name);
|
||||
|
||||
|
||||
Arrays.stream(Gift.class.getSuperclass().getDeclaredFields()).toList().forEach(field1 ->
|
||||
{
|
||||
System.out.println(field1.getName()+" ");
|
||||
});
|
||||
|
||||
|
||||
field = Gift.class.getSuperclass().getDeclaredField("name");
|
||||
field.setAccessible(true);
|
||||
field.set(enumInstance,"dupa");
|
||||
|
||||
// EnumSet
|
||||
field = Gift.class.getDeclaredField("diamondCost");
|
||||
field.setAccessible(true);
|
||||
field.set(enumInstance, diamondCost);
|
||||
|
||||
@@ -25,6 +25,7 @@ package io.github.jwdeveloper.tiktok.handlers;
|
||||
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEndEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollStartEvent;
|
||||
@@ -37,12 +38,16 @@ import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokShareEvent;
|
||||
import io.github.jwdeveloper.tiktok.data.models.Text;
|
||||
import io.github.jwdeveloper.tiktok.data.models.chest.Chest;
|
||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
|
||||
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
|
||||
import io.github.jwdeveloper.tiktok.messages.enums.EnvelopeDisplay;
|
||||
import io.github.jwdeveloper.tiktok.messages.webcast.*;
|
||||
import io.github.jwdeveloper.tiktok.models.SocialTypes;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
||||
@@ -106,7 +111,7 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
||||
registerMapping(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
|
||||
registerMapping(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
|
||||
registerMapping(WebcastQuestionNewMessage.class, TikTokQuestionEvent.class);
|
||||
registerMapping(WebcastEnvelopeMessage.class, TikTokEnvelopeEvent.class);
|
||||
registerMappings(WebcastEnvelopeMessage.class, this::handleEnvelop);
|
||||
registerMapping(WebcastSubNotifyMessage.class, TikTokSubNotifyEvent.class);
|
||||
registerMapping(WebcastEmoteChatMessage.class, TikTokEmoteEvent.class);
|
||||
}
|
||||
@@ -148,6 +153,7 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
||||
@SneakyThrows
|
||||
private TikTokEvent handleMemberMessage(byte[] msg) {
|
||||
var message = WebcastMemberMessage.parseFrom(msg);
|
||||
roomInfo.setViewersCount(message.getMemberCount());
|
||||
return switch (message.getAction()) {
|
||||
case JOINED -> new TikTokJoinEvent(message);
|
||||
case SUBSCRIBED -> new TikTokSubscribeEvent(message);
|
||||
@@ -187,5 +193,18 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
||||
};
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private List<TikTokEvent> handleEnvelop(byte[] data) {
|
||||
var msg = WebcastEnvelopeMessage.parseFrom(data);
|
||||
if (msg.getDisplay() != EnvelopeDisplay.EnvelopeDisplayNew) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
var totalDiamonds = msg.getEnvelopeInfo().getDiamondCount();
|
||||
var totalUsers = msg.getEnvelopeInfo().getPeopleCount();
|
||||
var chest = new Chest(totalDiamonds, totalUsers);
|
||||
|
||||
return List.of(new TikTokChestEvent(chest, msg));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
package io.github.jwdeveloper.tiktok.handlers.events;
|
||||
|
||||
public class TikTokChestEventHandler {
|
||||
}
|
||||
@@ -47,6 +47,12 @@ public class TikTokGiftEventHandler {
|
||||
giftsMessages = new HashMap<>();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public List<TikTokEvent> handleGift(byte[] msg) {
|
||||
var currentMessage = WebcastGiftMessage.parseFrom(msg);
|
||||
return handleGift(currentMessage);
|
||||
}
|
||||
|
||||
public List<TikTokEvent> handleGift(WebcastGiftMessage currentMessage)
|
||||
{
|
||||
var userId = currentMessage.getUser().getId();
|
||||
@@ -81,11 +87,6 @@ public class TikTokGiftEventHandler {
|
||||
|
||||
return List.of();
|
||||
}
|
||||
@SneakyThrows
|
||||
public List<TikTokEvent> handleGift(byte[] msg) {
|
||||
var currentMessage = WebcastGiftMessage.parseFrom(msg);
|
||||
return handleGift(currentMessage);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -99,14 +100,17 @@ public class TikTokGiftEventHandler {
|
||||
return new TikTokGiftComboEvent(gift, message, state);
|
||||
}
|
||||
|
||||
private Gift getGiftObject(WebcastGiftMessage giftMessage) {
|
||||
var gift = giftManager.findById((int) giftMessage.getGiftId());
|
||||
private Gift getGiftObject(WebcastGiftMessage giftMessage)
|
||||
{
|
||||
var giftId = (int) giftMessage.getGiftId();
|
||||
var gift = giftManager.findById(giftId);
|
||||
if (gift == Gift.UNDEFINED) {
|
||||
gift = giftManager.findByName(giftMessage.getGift().getName());
|
||||
}
|
||||
if (gift == Gift.UNDEFINED) {
|
||||
if (gift == Gift.UNDEFINED)
|
||||
{
|
||||
gift = giftManager.registerGift(
|
||||
(int) giftMessage.getGift().getId(),
|
||||
giftId,
|
||||
giftMessage.getGift().getName(),
|
||||
giftMessage.getGift().getDiamondCount(),
|
||||
Picture.map(giftMessage.getGift().getImage()));
|
||||
|
||||
@@ -30,7 +30,6 @@ import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
|
||||
import io.github.jwdeveloper.tiktok.mappers.LiveRoomMetaMapper;
|
||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||
|
||||
import javax.script.ScriptEngineManager;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -47,49 +46,34 @@ public class TikTokApiService {
|
||||
}
|
||||
|
||||
|
||||
public void updateSessionId()
|
||||
{
|
||||
if(clientSettings.getSessionId() == null)
|
||||
{
|
||||
public void updateSessionId() {
|
||||
if (clientSettings.getSessionId() == null) {
|
||||
return;
|
||||
}
|
||||
if(clientSettings.getSessionId().isEmpty())
|
||||
{
|
||||
return;
|
||||
if (clientSettings.getSessionId().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
tiktokHttpClient.setSessionId(clientSettings.getSessionId());
|
||||
}
|
||||
|
||||
public boolean sendMessage(String message, String sessionId) {
|
||||
if (sessionId.isEmpty()) {
|
||||
throw new TikTokLiveException("Session ID must not be Empty");
|
||||
}
|
||||
var roomId = clientSettings.getClientParameters().get("room_id");
|
||||
if (roomId == null) {
|
||||
throw new TikTokLiveException("Room ID must not be Empty");
|
||||
}
|
||||
logger.info("Sending message to chat");
|
||||
try {
|
||||
var params = new HashMap<String, Object>(clientSettings.getClientParameters());
|
||||
params.put("content", message);
|
||||
params.put("channel", "tiktok_web");
|
||||
params.remove("cursor");
|
||||
tiktokHttpClient.setSessionId(sessionId);
|
||||
tiktokHttpClient.postMessageToChat(params);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
throw new TikTokLiveRequestException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
|
||||
}
|
||||
public String fetchRoomId(String userName) {
|
||||
var roomId = fetchRoomIdFromTiktokApi(userName);
|
||||
clientSettings.getClientParameters().put("room_id", roomId);
|
||||
logger.info("RoomID -> " + roomId);
|
||||
return roomId;
|
||||
}
|
||||
|
||||
public String fetchRoomId(String userName) {
|
||||
private String fetchRoomIdFromTikTokPage(String userName)
|
||||
{
|
||||
/* var roomId = RequestChain.<String>create()
|
||||
.then(() -> fetchRoomIdFromTikTokPage(userName))
|
||||
.then(() -> fetchRoomIdFromTiktokApi(userName))
|
||||
.run();*/
|
||||
logger.info("Fetching room ID");
|
||||
String html;
|
||||
try {
|
||||
html = tiktokHttpClient.getLivestreamPage(userName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
throw new TikTokLiveRequestException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
|
||||
}
|
||||
|
||||
@@ -112,22 +96,35 @@ public class TikTokApiService {
|
||||
throw new TikTokLiveOfflineHostException("Unable to fetch room ID, live host could be offline or name is misspelled");
|
||||
}
|
||||
|
||||
clientSettings.getClientParameters().put("room_id", id);
|
||||
logger.info("RoomID -> " + id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
private String fetchRoomIdFromTiktokApi(String userName) {
|
||||
|
||||
var params = new HashMap<>(clientSettings.getClientParameters());
|
||||
params.put("uniqueId", userName);
|
||||
params.put("sourceType", 54);
|
||||
var roomData = tiktokHttpClient.getJsonFromTikTokApi("api-live/user/room/", params);
|
||||
|
||||
var data = roomData.getAsJsonObject("data");
|
||||
var user =data.getAsJsonObject("user");
|
||||
var roomId = user.get("roomId").getAsString();
|
||||
|
||||
|
||||
return roomId;
|
||||
}
|
||||
|
||||
|
||||
public LiveRoomMeta fetchRoomInfo() {
|
||||
logger.info("Fetching RoomInfo");
|
||||
try {
|
||||
var response = tiktokHttpClient.getJObjectFromWebcastAPI("room/info/", clientSettings.getClientParameters());
|
||||
var response = tiktokHttpClient.getJsonFromWebcastApi("room/info/", clientSettings.getClientParameters());
|
||||
var mapper = new LiveRoomMetaMapper();
|
||||
var liveRoomMeta = mapper.map(response);
|
||||
logger.info("RoomInfo status -> " + liveRoomMeta.getStatus());
|
||||
return liveRoomMeta;
|
||||
} catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
throw new TikTokLiveRequestException("Failed to fetch room info from WebCast, see stacktrace for more info.", e);
|
||||
}
|
||||
}
|
||||
@@ -136,7 +133,7 @@ public class TikTokApiService {
|
||||
|
||||
logger.info("Fetching ClientData");
|
||||
try {
|
||||
var response = tiktokHttpClient.getSigningServerMessage("im/fetch/", clientSettings.getClientParameters());
|
||||
var response = tiktokHttpClient.getSigningServerResponse("im/fetch/", clientSettings.getClientParameters());
|
||||
clientSettings.getClientParameters().put("cursor", response.getCursor());
|
||||
clientSettings.getClientParameters().put("internal_ext", response.getInternalExt());
|
||||
return response;
|
||||
|
||||
@@ -60,20 +60,22 @@ public class TikTokHttpClient {
|
||||
return get;
|
||||
}
|
||||
|
||||
public String postMessageToChat(Map<String,Object> parameters)
|
||||
public JsonObject getJsonFromTikTokApi(String path, Map<String,Object> params)
|
||||
{
|
||||
var get = postRequest(Constants.TIKTOK_URL_WEBCAST + "room/chat/", parameters);
|
||||
return get;
|
||||
var get = getRequest(Constants.TIKTOK_URL_WEB + path, params);
|
||||
var json = JsonParser.parseString(get);
|
||||
var jsonObject = json.getAsJsonObject();
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
public JsonObject getJObjectFromWebcastAPI(String path, Map<String, Object> parameters) {
|
||||
public JsonObject getJsonFromWebcastApi(String path, Map<String, Object> parameters) {
|
||||
var get = getRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
|
||||
var json = JsonParser.parseString(get);
|
||||
var jsonObject = json.getAsJsonObject();
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
public WebcastResponse getSigningServerMessage(String path, Map<String, Object> parameters) {
|
||||
public WebcastResponse getSigningServerResponse(String path, Map<String, Object> parameters) {
|
||||
var bytes = getSignRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
|
||||
try {
|
||||
return WebcastResponse.parseFrom(bytes);
|
||||
|
||||
@@ -59,22 +59,29 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
@SneakyThrows
|
||||
public String get(String url) {
|
||||
var uri = URI.create(url);
|
||||
var request = HttpRequest.newBuilder().GET();
|
||||
var requestBuilder = HttpRequest.newBuilder().GET();
|
||||
|
||||
for (var header : defaultHeaders.entrySet())
|
||||
{
|
||||
if(header.getKey().equals("Connection") || header.getKey().equals("Accept-Encoding"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
request.setHeader(header.getKey(), header.getValue());
|
||||
requestBuilder.setHeader(header.getKey(), header.getValue());
|
||||
}
|
||||
if (query != null) {
|
||||
var baseUri = uri.toString();
|
||||
var requestUri = URI.create(baseUri + "?" + query);
|
||||
request.uri(requestUri);
|
||||
requestBuilder.uri(requestUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
requestBuilder.uri(uri);
|
||||
}
|
||||
|
||||
return getContent(request.build());
|
||||
var result = requestBuilder.build();
|
||||
|
||||
return getContent(result);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package io.github.jwdeveloper.tiktok.http;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TikTokLiveOnlineChecker
|
||||
{
|
||||
|
||||
public CompletableFuture<Boolean> isOnlineAsync(String hostName) {
|
||||
return CompletableFuture.supplyAsync(() -> isOnline(hostName));
|
||||
}
|
||||
|
||||
public boolean isOnline(String hostName) {
|
||||
var factory = new TikTokHttpRequestFactory(new TikTokCookieJar());
|
||||
var url = getLiveUrl(hostName);
|
||||
try {
|
||||
var response = factory.get(url);
|
||||
var titleContent = extractTitleContent(response);
|
||||
return isTitleLiveOnline(titleContent);
|
||||
} catch (Exception e)
|
||||
{
|
||||
throw new TikTokLiveRequestException("Unable to make check live online request",e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTitleLiveOnline(String title) {
|
||||
return title.contains("is LIVE");
|
||||
}
|
||||
|
||||
private String extractTitleContent(String html) {
|
||||
var regex = "<title\\b[^>]*>(.*?)<\\/title>";
|
||||
var pattern = Pattern.compile(regex);
|
||||
var matcher = pattern.matcher(html);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String getLiveUrl(String hostName) {
|
||||
var sb = new StringBuilder();
|
||||
sb.append("https://www.tiktok.com/@");
|
||||
sb.append(hostName);
|
||||
sb.append("/live");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user