Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import io.github.jwdeveloper.tiktok.data.models.battles.*;
import io.github.jwdeveloper.tiktok.messages.enums.LinkMicBattleStatus;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter;
import lombok.*;

import java.util.*;

Expand All @@ -43,6 +43,8 @@ public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent
true if battle is finished otherwise false
*/
private final boolean finished;
@Getter(AccessLevel.NONE)
private final boolean oneVsOne;
private final List<Team> teams;

public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) {
Expand All @@ -53,6 +55,7 @@ public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) {
if (msg.getHostTeamCount() == 2) { // 1v1 battle
teams.add(new Team1v1(msg.getHostTeam(0), msg));
teams.add(new Team1v1(msg.getHostTeam(1), msg));
oneVsOne = true;
} else { // 2v2 battle
if (isFinished()) {
teams.add(new Team2v2(msg.getHostData2V2List().stream().filter(data -> data.getTeamNumber() == 1).findFirst().orElse(null), msg));
Expand All @@ -61,11 +64,20 @@ public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) {
teams.add(new Team2v2(msg.getHostTeam(0), msg.getHostTeam(1), msg));
teams.add(new Team2v2(msg.getHostTeam(2), msg.getHostTeam(3), msg));
}
oneVsOne = false;
}

// Info:
// - msg.getDetailsList() & msg.getViewerTeamList() both only have content 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
}

public boolean is1v1() {
return oneVsOne;
}

public boolean is2v2() {
return !oneVsOne;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import com.google.gson.JsonObject;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import lombok.*;

import java.util.*;
import lombok.Data;

@Data
public class Gift {
Expand All @@ -16,7 +14,7 @@ public class Gift {

private final int diamondCost;

private final Picture picture;
private Picture picture;

private final JsonObject properties;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ public class LiveClientSettings {
*/
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
* @see <a href="https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages">Documentation: How to obtain sessionId</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ public static LiveHttpClient requests() {
return new TikTokLiveHttpClient();
}


//I don't like it, but it is reasonable for now
private static GiftsManager giftsManager;

Expand All @@ -108,6 +107,4 @@ public static GiftsManager gifts() {
}
return giftsManager;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,19 @@
package io.github.jwdeveloper.tiktok;

import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.control.*;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
import io.github.jwdeveloper.tiktok.data.requests.*;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.exceptions.*;
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
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.listener.*;
import io.github.jwdeveloper.tiktok.live.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.models.ConnectionState;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.websocket.SocketClient;

import java.util.Base64;
Expand Down Expand Up @@ -144,7 +137,7 @@ public void tryConnect() {
var liveDataRequest = new LiveData.Request(userData.getRoomId());
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!");

if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,15 @@ public TikTokLiveMapper createMapper(GiftsManager giftsManager, TikTokRoomInfo r


//LinkMic events
// mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
mapper.forMessage(WebcastLinkMicBattle.class, (inputBytes, messageName, mapperHelper) -> {
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(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);

//Rank events
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package io.github.jwdeveloper.tiktok.gifts;

import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.live.GiftsManager;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

Expand All @@ -32,19 +28,15 @@ public Gift getByName(String name) {
}

public Gift getById(int giftId) {
if (!giftsByIdIndex.containsKey(giftId)) {
return Gift.UNDEFINED;
}

return giftsByIdIndex.get(giftId);
return giftsByIdIndex.getOrDefault(giftId, Gift.UNDEFINED);
}

public Gift getByFilter(Predicate<Gift> filter) {
return giftsByIdIndex.values()
.stream()
.filter(filter)
.findFirst()
.orElseGet(() -> Gift.UNDEFINED);
.orElse(Gift.UNDEFINED);
}

@Override
Expand All @@ -62,4 +54,4 @@ public List<Gift> toList() {
public Map<Integer, Gift> toMap() {
return Collections.unmodifiableMap(giftsByIdIndex);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ public LiveData.Response map(String json) {
default -> LiveData.LiveStatus.HostNotFound;
};
response.setLiveStatus(statusValue);
} else if (data.has("prompts") && jsonObject.has("status_code") &&
data.get("prompts").getAsString().isEmpty() && jsonObject.get("status_code").isJsonPrimitive()) {
} else if (data.has("prompts") && data.get("prompts").getAsString().isEmpty() && jsonObject.has("status_code")) {
response.setAgeRestricted(jsonObject.get("status_code").getAsInt() == TikTokLiveHttpClient.TIKTOK_AGE_RESTRICTED_CODE);
} else {
response.setLiveStatus(LiveData.LiveStatus.HostNotFound);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@
import io.github.jwdeveloper.tiktok.data.events.gift.*;
import io.github.jwdeveloper.tiktok.data.models.Picture;
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.mappers.TikTokMapperHelper;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import lombok.SneakyThrows;
import sun.misc.Unsafe;

import java.util.*;

Expand Down Expand Up @@ -124,36 +122,8 @@ private Gift getGiftObject(WebcastGiftMessage giftMessage) {
}

if (gift.getPicture().getLink().endsWith(".webp"))
{
updatePicture(gift, giftMessage);
}
gift.setPicture(Picture.map(giftMessage.getGift().getImage()));

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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@
import lombok.Data;

import java.io.File;
import java.util.function.*;

@Data
public class FileDataCollectorSettings {

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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@
import org.bson.Document;
import org.bson.json.JsonWriterSettings;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.*;

public class FileStorage implements Storage {

private final FileDataCollectorSettings settings;
private final Map<String, ReentrantLock> locks;

public FileStorage(FileDataCollectorSettings fileDataCollectorSettings) {
this.settings = fileDataCollectorSettings;
this.locks = settings.isUseFileLocks() ? new ConcurrentHashMap<>() : null;
}

@Override
Expand All @@ -30,13 +33,25 @@ public void disconnect() {

@Override
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 {
var file = new File(settings.getParentFile(), fileName);
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) {
e.printStackTrace();
}
}
}
}