Changed Picture#Empty to Picture#empty to follow Java standards

Updated descriptions in LiveClientSettings
Added new LiveHttpClient#fetchRoomGiftsData(String room_id) to fetch gifts for this specific room/livestream and altered GiftsDataMapper to reflect the new fetchRoomGiftsData and other TikTokLive client and http client classes
This commit is contained in:
kohlerpop1
2024-05-13 21:14:03 -04:00
parent b153afb332
commit 5c715bfd52
9 changed files with 82 additions and 20 deletions

View File

@@ -93,7 +93,7 @@ public class Picture {
} }
} }
public static Picture Empty() { public static Picture empty() {
return new Picture(""); return new Picture("");
} }

View File

@@ -169,7 +169,7 @@ public class User {
public static User EMPTY = new User(0L, public static User EMPTY = new User(0L,
"", "",
Picture.Empty(), Picture.empty(),
0, 0,
0, 0,
List.of(Badge.empty())); List.of(Badge.empty()));

View File

@@ -33,20 +33,15 @@ import java.util.logging.Level;
@Data @Data
public class LiveClientSettings { public class LiveClientSettings {
/** /**
* TODO: give better description * Sets client to offline mode, prohibits connection to TikTok servers
* <p> * @apiNote Useful when testing client with custom events
* sets client in the offline mode, so it do not connects to TikTok servers
* it makes sense to use it when you are testing client with your custom events
*/ */
private boolean offline; private boolean offline;
/** /**
* TODO: give better description * Fetch and download gifts data before TikTokLive starts
* <p> * @apiNote If `false`, client.giftManager() does not contain initial gifts
* Determines if gifts data is downloaded before TikTokLive starts,
* when `false` then client.giftManager() does not contain initial gifts
*/ */
private boolean fetchGifts = true; private boolean fetchGifts = true;

View File

@@ -30,10 +30,14 @@ 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 {@link GiftsData.Response} list of gifts that are compiled and available on github
*/ */
GiftsData.Response fetchGiftsData(); GiftsData.Response fetchGiftsData();
/**
* @return {@link GiftsData.Response} list of gifts that are available in your region / livestream
*/
GiftsData.Response fetchRoomGiftsData(String room_id);
/** /**
* Returns information about user that is having a livestream * Returns information about user that is having a livestream

View File

@@ -128,6 +128,9 @@ public class TikTokLiveClient implements LiveClient {
liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp()); liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp());
liveRoomInfo.setRoomId(userData.getRoomId()); liveRoomInfo.setRoomId(userData.getRoomId());
if (clientSettings.isFetchGifts())
giftsManager.attachGiftsList(httpClient.fetchRoomGiftsData(userData.getRoomId()).getGifts());
if (userData.getUserStatus() == LiveUserData.UserStatus.Offline) if (userData.getUserStatus() == LiveUserData.UserStatus.Offline)
throw new TikTokLiveOfflineHostException("User is offline: " + liveRoomInfo.getHostName()); throw new TikTokLiveOfflineHostException("User is offline: " + liveRoomInfo.getHostName());

View File

@@ -43,6 +43,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
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 String TIKTOK_GIFTS_URL = "https://raw.githubusercontent.com/TikTok-LIVE-Private/GiftsGenerator/master/page/public/gifts.json"; public static final String TIKTOK_GIFTS_URL = "https://raw.githubusercontent.com/TikTok-LIVE-Private/GiftsGenerator/master/page/public/gifts.json";
public static final String TIKTOK_ROOM_GIFTS_URL = TIKTOK_URL_WEBCAST+"gift/list/";
public static final int TIKTOK_AGE_RESTRICTED_CODE = 4003110; public static final int TIKTOK_AGE_RESTRICTED_CODE = 4003110;
private final HttpClientFactory httpFactory; private final HttpClientFactory httpFactory;
@@ -65,6 +66,31 @@ public class TikTokLiveHttpClient implements LiveHttpClient
this(new HttpClientFactory(LiveClientSettings.createDefault()), LiveClientSettings.createDefault()); this(new HttpClientFactory(LiveClientSettings.createDefault()), LiveClientSettings.createDefault());
} }
public GiftsData.Response fetchRoomGiftsData(String room_id) {
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
if (proxyClientSettings.isEnabled()) {
while (proxyClientSettings.hasNext()) {
try {
return getRoomGiftsData(room_id);
} catch (TikTokProxyRequestException ignored) {}
}
}
return getRoomGiftsData(room_id);
}
public GiftsData.Response getRoomGiftsData(String room_id) {
var result = httpFactory.client(TIKTOK_ROOM_GIFTS_URL)
.withParam("room_id", room_id)
.build()
.toJsonResponse();
if (result.isFailure())
throw new TikTokLiveRequestException("Unable to fetch gifts information's - "+result);
var json = result.getContent();
return giftsDataMapper.mapRoom(json);
}
public GiftsData.Response fetchGiftsData() { public GiftsData.Response fetchGiftsData() {
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings(); var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
if (proxyClientSettings.isEnabled()) { if (proxyClientSettings.isEnabled()) {

View File

@@ -18,6 +18,11 @@ public class TikTokLiveHttpOfflineClient implements LiveHttpClient {
return new GiftsData.Response("", List.of()); return new GiftsData.Response("", List.of());
} }
@Override
public GiftsData.Response fetchRoomGiftsData(String room_id) {
return new GiftsData.Response("", List.of());
}
@Override @Override
public LiveUserData.Response fetchLiveUserData(LiveUserData.Request request) { public LiveUserData.Response fetchLiveUserData(LiveUserData.Request request) {
return new LiveUserData.Response("", LiveUserData.UserStatus.Live, "offline_room_id", 0); return new LiveUserData.Response("", LiveUserData.UserStatus.Live, "offline_room_id", 0);
@@ -42,4 +47,4 @@ public class TikTokLiveHttpOfflineClient implements LiveHttpClient {
URI.create("https://example.live"), URI.create("https://example.live"),
WebcastResponse.newBuilder().build()); WebcastResponse.newBuilder().build());
} }
} }

View File

@@ -4,7 +4,7 @@ import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.live.GiftsManager; import io.github.jwdeveloper.tiktok.live.GiftsManager;
import java.util.*; import java.util.*;
import java.util.function.Predicate; import java.util.function.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class TikTokGiftsManager implements GiftsManager { public class TikTokGiftsManager implements GiftsManager {
@@ -12,7 +12,7 @@ public class TikTokGiftsManager implements GiftsManager {
public TikTokGiftsManager(List<Gift> giftList) public TikTokGiftsManager(List<Gift> giftList)
{ {
giftsByIdIndex = giftList.stream().collect(Collectors.toConcurrentMap(Gift::getId, e -> e)); giftsByIdIndex = giftList.stream().collect(Collectors.toConcurrentMap(Gift::getId, Function.identity()));
} }
public void attachGift(Gift gift) { public void attachGift(Gift gift) {

View File

@@ -22,15 +22,15 @@
*/ */
package io.github.jwdeveloper.tiktok.http.mappers; package io.github.jwdeveloper.tiktok.http.mappers;
import com.google.gson.JsonElement; import com.google.gson.*;
import com.google.gson.JsonParser;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift; import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.data.requests.GiftsData; import io.github.jwdeveloper.tiktok.data.requests.GiftsData;
import java.util.ArrayList; import java.util.List;
public class GiftsDataMapper { public class GiftsDataMapper {
public GiftsData.Response map(String json) { public GiftsData.Response map(String json) {
var parsedJson = JsonParser.parseString(json); var parsedJson = JsonParser.parseString(json);
var jsonObject = parsedJson.getAsJsonObject(); var jsonObject = parsedJson.getAsJsonObject();
@@ -42,7 +42,6 @@ public class GiftsDataMapper {
return new GiftsData.Response(json, gifts); return new GiftsData.Response(json, gifts);
} }
private Gift mapSingleGift(JsonElement jsonElement) { private Gift mapSingleGift(JsonElement jsonElement) {
var jsonObject = jsonElement.getAsJsonObject(); var jsonObject = jsonElement.getAsJsonObject();
@@ -52,4 +51,34 @@ public class GiftsDataMapper {
var image = jsonObject.get("image").getAsString(); var image = jsonObject.get("image").getAsString();
return new Gift(id, name, diamondCost, new Picture(image), jsonObject); return new Gift(id, name, diamondCost, new Picture(image), jsonObject);
} }
}
public GiftsData.Response mapRoom(String json) {
var parsedJson = JsonParser.parseString(json);
var jsonObject = parsedJson.getAsJsonObject();
if (jsonObject.get("data") instanceof JsonObject data && data.get("gifts") instanceof JsonArray giftArray) {
var gifts = giftArray.asList().parallelStream()
.map(this::mapSingleRoomGift)
.toList();
return new GiftsData.Response(json, gifts);
}
return new GiftsData.Response("", List.of());
}
private Gift mapSingleRoomGift(JsonElement jsonElement) {
var jsonObject = jsonElement.getAsJsonObject();
var id = jsonObject.get("id").getAsInt();
var name = jsonObject.get("name").getAsString();
var diamondCost = jsonObject.get("diamond_count").getAsInt();
Picture picture;
if (jsonObject.get("image") instanceof JsonObject image && image.get("url_list") instanceof JsonArray urls && !urls.isEmpty()) {
String url = urls.get(0).getAsString();
if (url.endsWith(".webp"))
url = url.substring(0, url.length()-4)+"png";
picture = new Picture(url);
} else
picture = Picture.empty();
return new Gift(id, name, diamondCost, picture, jsonObject);
}
}