Merge pull request #72 from jwdeveloper/develop-1.6.1

Develop 1.6.1
This commit is contained in:
David Kohler
2024-05-12 20:52:28 -04:00
committed by GitHub
11 changed files with 66 additions and 76 deletions

View File

@@ -27,7 +27,7 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.battles.*; import io.github.jwdeveloper.tiktok.data.models.battles.*;
import io.github.jwdeveloper.tiktok.messages.enums.LinkMicBattleStatus; import io.github.jwdeveloper.tiktok.messages.enums.LinkMicBattleStatus;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter; import lombok.*;
import java.util.*; import java.util.*;
@@ -43,6 +43,8 @@ public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent
true if battle is finished otherwise false true if battle is finished otherwise false
*/ */
private final boolean finished; private final boolean finished;
@Getter(AccessLevel.NONE)
private final boolean oneVsOne;
private final List<Team> teams; private final List<Team> teams;
public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) { public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) {
@@ -53,6 +55,7 @@ public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent
if (msg.getHostTeamCount() == 2) { // 1v1 battle if (msg.getHostTeamCount() == 2) { // 1v1 battle
teams.add(new Team1v1(msg.getHostTeam(0), msg)); teams.add(new Team1v1(msg.getHostTeam(0), msg));
teams.add(new Team1v1(msg.getHostTeam(1), msg)); teams.add(new Team1v1(msg.getHostTeam(1), msg));
oneVsOne = true;
} else { // 2v2 battle } else { // 2v2 battle
if (isFinished()) { if (isFinished()) {
teams.add(new Team2v2(msg.getHostData2V2List().stream().filter(data -> data.getTeamNumber() == 1).findFirst().orElse(null), msg)); teams.add(new Team2v2(msg.getHostData2V2List().stream().filter(data -> data.getTeamNumber() == 1).findFirst().orElse(null), msg));
@@ -61,6 +64,7 @@ public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent
teams.add(new Team2v2(msg.getHostTeam(0), msg.getHostTeam(1), msg)); teams.add(new Team2v2(msg.getHostTeam(0), msg.getHostTeam(1), msg));
teams.add(new Team2v2(msg.getHostTeam(2), msg.getHostTeam(3), msg)); teams.add(new Team2v2(msg.getHostTeam(2), msg.getHostTeam(3), msg));
} }
oneVsOne = false;
} }
// Info: // Info:
@@ -68,4 +72,12 @@ public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent
// - msg.getDetailsCount() & msg.getViewerTeamCount() always is 2 only when battle is finished // - msg.getDetailsCount() & msg.getViewerTeamCount() always is 2 only when battle is finished
// - msg.getHostTeamCount() always is 2 for 1v1 or 4 for 2v2 // - msg.getHostTeamCount() always is 2 for 1v1 or 4 for 2v2
} }
public boolean is1v1() {
return oneVsOne;
}
public boolean is2v2() {
return !oneVsOne;
}
} }

View File

@@ -2,9 +2,7 @@ package io.github.jwdeveloper.tiktok.data.models.gifts;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;
import lombok.*; import lombok.Data;
import java.util.*;
@Data @Data
public class Gift { public class Gift {
@@ -16,7 +14,7 @@ public class Gift {
private final int diamondCost; private final int diamondCost;
private final Picture picture; private Picture picture;
private final JsonObject properties; private final JsonObject properties;

View File

@@ -91,6 +91,9 @@ public class LiveClientSettings {
*/ */
private long pingInterval = 5000; private long pingInterval = 5000;
/** Throw an exception on 18+ Age Restriction */
private boolean throwOnAgeRestriction;
/** /**
* Optional: Sometimes not every messages from chat are send to TikTokLiveJava to fix this issue you can set sessionId * Optional: Sometimes not every messages from chat are send to TikTokLiveJava to fix this issue you can set sessionId
* @see <a href="https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages">Documentation: How to obtain sessionId</a> * @see <a href="https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages">Documentation: How to obtain sessionId</a>

View File

@@ -91,7 +91,6 @@ public class TikTokLive {
return new TikTokLiveHttpClient(); return new TikTokLiveHttpClient();
} }
//I don't like it, but it is reasonable for now //I don't like it, but it is reasonable for now
private static GiftsManager giftsManager; private static GiftsManager giftsManager;
@@ -108,6 +107,4 @@ public class TikTokLive {
} }
return giftsManager; return giftsManager;
} }
} }

View File

@@ -23,26 +23,19 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent; import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
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.*; 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.*;
import io.github.jwdeveloper.tiktok.data.requests.LiveData; import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
import io.github.jwdeveloper.tiktok.exceptions.*; import io.github.jwdeveloper.tiktok.exceptions.*;
import io.github.jwdeveloper.tiktok.http.LiveHttpClient; import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.listener.ListenersManager; import io.github.jwdeveloper.tiktok.listener.*;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager; import io.github.jwdeveloper.tiktok.live.*;
import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.models.ConnectionState; import io.github.jwdeveloper.tiktok.models.ConnectionState;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.websocket.SocketClient; import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import java.util.Base64; import java.util.Base64;
@@ -144,7 +137,7 @@ public class TikTokLiveClient implements LiveClient {
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()) if (liveData.isAgeRestricted() && clientSettings.isThrowOnAgeRestriction())
throw new TikTokLiveException("Livestream for " + liveRoomInfo.getHostName() + " is 18+ or age restricted!"); throw new TikTokLiveException("Livestream for " + liveRoomInfo.getHostName() + " is 18+ or age restricted!");
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound) if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound)

View File

@@ -207,8 +207,14 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
//LinkMic events //LinkMic events
// mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class); mapper.forMessage(WebcastLinkMicBattle.class, (inputBytes, messageName, mapperHelper) -> {
// mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class); var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMicBattle.class);
return MappingResult.of(message, new TikTokLinkMicBattleEvent(message));
});
mapper.forMessage(WebcastLinkMicArmies.class, (inputBytes, messageName, mapperHelper) -> {
var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMicArmies.class);
return MappingResult.of(message, new TikTokLinkMicArmiesEvent(message));
});
// mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class); // mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class); // mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);

View File

@@ -1,13 +1,9 @@
package io.github.jwdeveloper.tiktok.gifts; package io.github.jwdeveloper.tiktok.gifts;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift; import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.live.GiftsManager; import io.github.jwdeveloper.tiktok.live.GiftsManager;
import java.util.Collections; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -32,11 +28,7 @@ public class TikTokGiftsManager implements GiftsManager {
} }
public Gift getById(int giftId) { public Gift getById(int giftId) {
if (!giftsByIdIndex.containsKey(giftId)) { return giftsByIdIndex.getOrDefault(giftId, Gift.UNDEFINED);
return Gift.UNDEFINED;
}
return giftsByIdIndex.get(giftId);
} }
public Gift getByFilter(Predicate<Gift> filter) { public Gift getByFilter(Predicate<Gift> filter) {
@@ -44,7 +36,7 @@ public class TikTokGiftsManager implements GiftsManager {
.stream() .stream()
.filter(filter) .filter(filter)
.findFirst() .findFirst()
.orElseGet(() -> Gift.UNDEFINED); .orElse(Gift.UNDEFINED);
} }
@Override @Override

View File

@@ -65,8 +65,7 @@ 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") && } else if (data.has("prompts") && data.get("prompts").getAsString().isEmpty() && 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); response.setAgeRestricted(jsonObject.get("status_code").getAsInt() == TikTokLiveHttpClient.TIKTOK_AGE_RESTRICTED_CODE);
} else { } else {
response.setLiveStatus(LiveData.LiveStatus.HostNotFound); response.setLiveStatus(LiveData.LiveStatus.HostNotFound);

View File

@@ -27,13 +27,11 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.*; import io.github.jwdeveloper.tiktok.data.events.gift.*;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.gifts.*; import io.github.jwdeveloper.tiktok.data.models.gifts.*;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.live.GiftsManager; import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapperHelper; import io.github.jwdeveloper.tiktok.mappers.TikTokMapperHelper;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult; import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import sun.misc.Unsafe;
import java.util.*; import java.util.*;
@@ -124,36 +122,8 @@ public class TikTokGiftEventHandler {
} }
if (gift.getPicture().getLink().endsWith(".webp")) if (gift.getPicture().getLink().endsWith(".webp"))
{ gift.setPicture(Picture.map(giftMessage.getGift().getImage()));
updatePicture(gift, giftMessage);
}
return gift; return gift;
} }
// TODO-kohlerpop1: I do not think this method is needed for any reason?
// TODO response:
/**
* Some generated gifts in JSON file contains .webp image format,
* that's bad since java by the defult is not supporing .webp and when URL is
* converted to Java.io.Image then image is null
*
* However, TikTok in GiftWebcast event always has image in .jpg format,
* so I take advantage of it and swap .webp url with .jpg url
*
*/
private void updatePicture(Gift gift, WebcastGiftMessage webcastGiftMessage) {
try {
var picture = Picture.map(webcastGiftMessage.getGift().getImage());
var constructor = Unsafe.class.getDeclaredConstructors()[0];
constructor.setAccessible(true);
var field = Gift.class.getDeclaredField("picture");
field.setAccessible(true);
field.set(gift, picture);
} catch (Exception e) {
throw new TikTokLiveException("Unable to update picture in gift: " + gift.toString());
}
}
} }

View File

@@ -25,9 +25,14 @@ package io.github.jwdeveloper.tiktok.extension.collector.api.settings;
import lombok.Data; import lombok.Data;
import java.io.File; import java.io.File;
import java.util.function.*;
@Data @Data
public class FileDataCollectorSettings { public class FileDataCollectorSettings {
private File parentFile; private File parentFile;
private BiPredicate<String, String> typeFilter = (dataType, dataTypeName) -> true;
private Predicate<String> userFilter = (tiktokUser) -> true;
private boolean useFileLocks = false;
private boolean appendUserName = false;
} }

View File

@@ -5,17 +5,20 @@ import io.github.jwdeveloper.tiktok.extension.collector.api.settings.FileDataCol
import org.bson.Document; import org.bson.Document;
import org.bson.json.JsonWriterSettings; import org.bson.json.JsonWriterSettings;
import java.io.File; import java.io.*;
import java.io.IOException; import java.nio.file.*;
import java.nio.file.Files; import java.util.*;
import java.nio.file.StandardOpenOption; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.*;
public class FileStorage implements Storage { public class FileStorage implements Storage {
private final FileDataCollectorSettings settings; private final FileDataCollectorSettings settings;
private final Map<String, ReentrantLock> locks;
public FileStorage(FileDataCollectorSettings fileDataCollectorSettings) { public FileStorage(FileDataCollectorSettings fileDataCollectorSettings) {
this.settings = fileDataCollectorSettings; this.settings = fileDataCollectorSettings;
this.locks = settings.isUseFileLocks() ? new ConcurrentHashMap<>() : null;
} }
@Override @Override
@@ -30,11 +33,23 @@ public class FileStorage implements Storage {
@Override @Override
public void insert(Document document) { public void insert(Document document) {
var fileName = document.get("dataType") + "_" + document.get("dataTypeName") + ".json"; if (settings.getTypeFilter().test(document.getString("dataType"), document.getString("dataTypeName")) && settings.getUserFilter().test(document.getString("tiktokUser"))) {
var fileName = document.get("dataType") + "_" + document.get("dataTypeName") + (settings.isAppendUserName() ? "_"+document.getString("tiktokUser") : "") + ".json";
if (settings.isUseFileLocks()) {
var lock = locks.computeIfAbsent(fileName, s -> new ReentrantLock());
lock.lock();
save(document, fileName);
lock.unlock();
} else
save(document, fileName);
}
}
private void save(Document document, String fileName) {
try { try {
var file = new File(settings.getParentFile(), fileName); var file = new File(settings.getParentFile(), fileName);
file.createNewFile(); file.createNewFile();
Files.writeString(file.toPath(), document.toJson(JsonWriterSettings.builder().indent(true).build()), StandardOpenOption.APPEND); Files.writeString(file.toPath(), document.toJson(JsonWriterSettings.builder().indent(true).build())+'\n', StandardOpenOption.APPEND);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }