Merge pull request #88 from jwdeveloper/develop-1.8.1

Develop 1.8.1
This commit is contained in:
Jacek W
2024-07-03 22:30:18 +02:00
committed by GitHub
64 changed files with 661 additions and 782 deletions

View File

@@ -32,9 +32,7 @@ import lombok.Getter;
import java.util.List; import java.util.List;
/**
* Triggered every time a new chat comment arrives.
*/
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokCommentEvent extends TikTokHeaderEvent { public class TikTokCommentEvent extends TikTokHeaderEvent {

View File

@@ -25,9 +25,6 @@ import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType; import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
/**
* Triggered when the connection is successfully established.
*/
@EventMeta(eventType = EventType.Control) @EventMeta(eventType = EventType.Control)
public class TikTokConnectedEvent extends TikTokLiveClientEvent public class TikTokConnectedEvent extends TikTokLiveClientEvent
{ {

View File

@@ -26,10 +26,7 @@ import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
import lombok.Getter; import lombok.Getter;
/**
* Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic.
* Note that you should wait a little bit before attempting a reconnect to to avoid being rate-limited.
*/
@Getter @Getter
@EventMeta(eventType = EventType.Control) @EventMeta(eventType = EventType.Control)
public class TikTokDisconnectedEvent extends TikTokLiveClientEvent { public class TikTokDisconnectedEvent extends TikTokLiveClientEvent {

View File

@@ -28,9 +28,6 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/**
* General error event. You should handle this.
*/
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
@EventMeta(eventType = EventType.Control) @EventMeta(eventType = EventType.Control)

View File

@@ -26,9 +26,7 @@ import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
/**
* Triggered when the live stream gets terminated by the host. Will also trigger the TikTokDisconnectedEvent event.
*/
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokLiveEndedEvent extends TikTokEvent { public class TikTokLiveEndedEvent extends TikTokEvent {
} }

View File

@@ -29,9 +29,7 @@ import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastQuestionNewMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastQuestionNewMessage;
import lombok.Getter; import lombok.Getter;
/*
Triggered every time someone asks a new question via the question feature.
*/
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokQuestionEvent extends TikTokHeaderEvent { public class TikTokQuestionEvent extends TikTokHeaderEvent {

View File

@@ -31,9 +31,7 @@ import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSubNotifyMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSubNotifyMessage;
import lombok.Getter; import lombok.Getter;
/**
* Triggers when a user creates a subscription.
*/
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokSubscribeEvent extends TikTokHeaderEvent { public class TikTokSubscribeEvent extends TikTokHeaderEvent {

View File

@@ -26,9 +26,6 @@ package io.github.jwdeveloper.tiktok.data.events.common;
import io.github.jwdeveloper.tiktok.utils.JsonUtil; import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import lombok.Getter; import lombok.Getter;
/**
* Base class for all events
*/
@Getter @Getter
public abstract class TikTokEvent { public abstract class TikTokEvent {

View File

@@ -27,9 +27,7 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
import io.github.jwdeveloper.tiktok.data.requests.*; import io.github.jwdeveloper.tiktok.data.requests.*;
import lombok.*; import lombok.*;
/**
* Triggered before the connection is established.
*/
@Getter @Getter
@EventMeta(eventType = EventType.Control) @EventMeta(eventType = EventType.Control)
public class TikTokPreConnectionEvent extends TikTokLiveClientEvent public class TikTokPreConnectionEvent extends TikTokLiveClientEvent

View File

@@ -29,20 +29,6 @@ import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import lombok.Getter; import lombok.Getter;
/**
* Triggered every time gift is sent
*
* @see GiftComboStateType it has 3 states
*
* <p>Example when user sends gift with combo</p>
* <p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
* <p>Combo: 4 -> comboState = GiftSendType.Active</p>
* <p>Combo: 8 -> comboState = GiftSendType.Active</p>
* <p>Combo: 12 -> comboState = GiftSendType.Finsihed</p>
* <p>
* Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
*/
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
@Getter @Getter
public class TikTokGiftComboEvent extends TikTokGiftEvent { public class TikTokGiftComboEvent extends TikTokGiftEvent {
@@ -57,10 +43,7 @@ public class TikTokGiftComboEvent extends TikTokGiftEvent {
return new TikTokGiftComboEvent( return new TikTokGiftComboEvent(
gift, gift,
new User(0L, "Test", new Picture("")), new User(0L, "Test", new Picture("")),
WebcastGiftMessage WebcastGiftMessage.newBuilder().setComboCount(combo).build(),
.newBuilder()
.setComboCount(combo)
.build(),
comboState); comboState);
} }
} }

View File

@@ -22,7 +22,6 @@
*/ */
package io.github.jwdeveloper.tiktok.data.events.gift; package io.github.jwdeveloper.tiktok.data.events.gift;
import io.github.jwdeveloper.tiktok.annotations.*; import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;
@@ -31,12 +30,6 @@ import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import lombok.Getter; import lombok.Getter;
/**
* Triggered when user sends gifts that has
* no combo (most of expensive gifts)
* or if combo has finished
*/
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
@Getter @Getter
public class TikTokGiftEvent extends TikTokHeaderEvent { public class TikTokGiftEvent extends TikTokHeaderEvent {

View File

@@ -30,9 +30,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/**
Triggered when LiveRoomInfo got updated such as likes, viewers, ranking ....
*/
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)

View File

@@ -29,9 +29,7 @@ import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Value; import lombok.Value;
/**
* Triggers when a user follows the streamer. Based on social event.
*/
@Value @Value
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokFollowEvent extends TikTokHeaderEvent public class TikTokFollowEvent extends TikTokHeaderEvent

View File

@@ -31,9 +31,7 @@ import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Getter; import lombok.Getter;
/**
* Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
*/
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokLikeEvent extends TikTokHeaderEvent public class TikTokLikeEvent extends TikTokHeaderEvent

View File

@@ -29,9 +29,7 @@ import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Getter; import lombok.Getter;
/**
* Triggers when a user shares the stream. Based on social event.
*/
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokShareEvent extends TikTokHeaderEvent { public class TikTokShareEvent extends TikTokHeaderEvent {

View File

@@ -35,10 +35,7 @@ import lombok.Value;
import java.time.Duration; import java.time.Duration;
/**
* Triggered every time TikTok sends data. Data incoming as protobuf message.
* You can deserialize the binary object depending on the use case.
*/
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
@EventMeta(eventType = EventType.Debug) @EventMeta(eventType = EventType.Debug)

View File

@@ -29,9 +29,7 @@ import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import lombok.Getter; import lombok.Getter;
/**
* Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
*/
@Getter @Getter
@EventMeta(eventType = EventType.Debug) @EventMeta(eventType = EventType.Debug)
public class TikTokWebsocketUnhandledMessageEvent extends TikTokUnhandledEvent<WebcastResponse.Message> public class TikTokWebsocketUnhandledMessageEvent extends TikTokUnhandledEvent<WebcastResponse.Message>

View File

@@ -23,9 +23,9 @@
package io.github.jwdeveloper.tiktok.data.models.gifts; package io.github.jwdeveloper.tiktok.data.models.gifts;
public enum GiftComboStateType { public enum GiftComboStateType {
Finished,
Begin, Begin,
Active; Active,
Finished;
public static GiftComboStateType fromNumber(long number) { public static GiftComboStateType fromNumber(long number) {
return switch ((int) number) { return switch ((int) number) {

View File

@@ -22,16 +22,12 @@
*/ */
package io.github.jwdeveloper.tiktok.data.models.users; package io.github.jwdeveloper.tiktok.data.models.users;
import io.github.jwdeveloper.tiktok.data.models.badges.Badge;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.badges.Badge;
import io.github.jwdeveloper.tiktok.messages.webcast.*; import io.github.jwdeveloper.tiktok.messages.webcast.*;
import lombok.AccessLevel; import lombok.*;
import lombok.Getter;
import java.util.Arrays; import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Getter @Getter
public class User { public class User {
@@ -49,12 +45,12 @@ public class User {
return attributes.stream().toList(); return attributes.stream().toList();
} }
public boolean hasAttribute(UserAttribute userFlag) { public boolean hasAttribute(UserAttribute attribute) {
return attributes.contains(userFlag); return attributes.contains(attribute);
} }
public void addAttribute(UserAttribute... flags) { public void addAttribute(UserAttribute... attributes) {
this.attributes.addAll(Arrays.stream(flags).toList()); this.attributes.addAll(List.of(attributes));
} }
public boolean isGiftGiver() { public boolean isGiftGiver() {

View File

@@ -20,19 +20,11 @@
* 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.gifts; package io.github.jwdeveloper.tiktok.exceptions;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class TikTokGiftManagerTest {
public class TikTokLiveUnknownHostException extends TikTokLiveException
{
public TikTokLiveUnknownHostException(String message) {
super(message);
}
} }

View File

@@ -0,0 +1,19 @@
package io.github.jwdeveloper.tiktok.live;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import java.util.HashSet;
import java.util.Optional;
public interface LiveEventsHandler {
void publish(LiveClient tikTokLiveClient, TikTokEvent tikTokEvent);
<T extends TikTokEvent> void subscribe(Class<?> clazz, EventConsumer<T> event);
<T extends TikTokEvent> void unsubscribeAll(Class<?> clazz);
<T extends TikTokEvent> void unsubscribe(EventConsumer<T> consumer);
<T extends TikTokEvent> void unsubscribe(Class<?> clazz, EventConsumer<T> consumer);
}

View File

@@ -0,0 +1,18 @@
package io.github.jwdeveloper.tiktok.live;
import io.github.jwdeveloper.tiktok.data.dto.MessageMetaData;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.Stopwatch;
import java.time.Duration;
public interface LiveMessagesHandler {
void handle(LiveClient client, WebcastResponse webcastResponse);
void handleSingleMessage(LiveClient client, WebcastResponse.Message message);
}

View File

@@ -22,8 +22,8 @@
*/ */
package io.github.jwdeveloper.tiktok.live.builder; package io.github.jwdeveloper.tiktok.live.builder;
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.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.control.TikTokPreConnectionEvent; 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;
@@ -36,6 +36,7 @@ import io.github.jwdeveloper.tiktok.data.events.social.TikTokShareEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent; import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent; import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent; import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent;
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftComboStateType;
public interface EventsBuilder<T> { public interface EventsBuilder<T> {
@@ -55,7 +56,9 @@ public interface EventsBuilder<T> {
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onEvent(EventConsumer<TikTokEvent> action); default T onEvent(EventConsumer<TikTokEvent> action) {
return onEvent(TikTokEvent.class, action);
}
/** /**
* Invoked when information about room (live) got updated such as viewer count, etc.. * Invoked when information about room (live) got updated such as viewer count, etc..
@@ -63,113 +66,244 @@ public interface EventsBuilder<T> {
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> action); default T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> action) {
return onEvent(TikTokRoomInfoEvent.class, action);
}
/** /**
* Invoked when someone send message to chat * Invoked when someone send message to chat
*
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onComment(EventConsumer<TikTokCommentEvent> action); default T onComment(EventConsumer<TikTokCommentEvent> action) {
return onEvent(TikTokCommentEvent.class, action);
}
/** /**
* Invoked when TikTokLiveJava makes http request and getting response * Invoked when TikTokLiveJava makes http request and getting response
*
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action); default T onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action) {
return onEvent(TikTokHttpResponseEvent.class, action);
}
/** /**
* Invoked when TikTok protocolBuffer data "message" was successfully mapped to event * Invoked when TikTok protocolBuffer data "message" was successfully mapped to event
* events contains protocol-buffer "Message" and TikTokLiveJava "Event" * events contains protocol-buffer "Message" and TikTokLiveJava "Event"
*
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> action); default T onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> action) {
return onEvent(TikTokWebsocketMessageEvent.class, action);
}
/** /**
* Invoked when there was not found event mapper for TikTok protocolBuffer data "message" * Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
*
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> action); default T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> action) {
return onEvent(TikTokWebsocketUnhandledMessageEvent.class, action);
}
/** /**
* Invoked every time TikTok sends protocolBuffer data to websocket * Invoked every time TikTok sends protocolBuffer data to websocket
* Response contains list of messages that are later mapped to events * Response contains list of messages that are later mapped to events
*
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> action); default T onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> action) {
return onEvent(TikTokWebsocketResponseEvent.class, action);
}
/** /**
* Invoked for gifts that has no combo, or when combo finishes * Triggers for these different reasons:
* <ol>
* <li>User sends gifts that have no combo (most of expensive gifts)</li>
* <li>{@link TikTokGiftComboEvent} has combaState = {@link GiftComboStateType#Finished}</li>
* </ol>
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onGift(EventConsumer<TikTokGiftEvent> action); default T onGift(EventConsumer<TikTokGiftEvent> action) {
return onEvent(TikTokGiftEvent.class, action);
}
/** /**
* Invoked for gifts that has combo options such as roses * Triggered every time a gift is sent
* <p>Example when user sends gift with combo</p>
* <ul>
* <li>Combo: 1 -> comboState = {@link GiftComboStateType#Begin}</li>
* <li>Combo: 4 -> comboState = {@link GiftComboStateType#Active}</li>
* <li>Combo: 8 -> comboState = {@link GiftComboStateType#Active}</li>
* <li>Combo: 12 -> comboState = {@link GiftComboStateType#Finished}</li>
* </ul>
* Both {@link TikTokGiftComboEvent} and {@link TikTokGiftEvent} events are triggered when comboState is Finished
*
* @apiNote {@link GiftComboStateType} has 3 states: {@link GiftComboStateType#Begin Begin}, {@link GiftComboStateType#Active Active}, & {@link GiftComboStateType#Finished Finished}
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> action); default T onGiftCombo(EventConsumer<TikTokGiftComboEvent> action) {
return onEvent(TikTokGiftComboEvent.class, action);
}
T onQuestion(EventConsumer<TikTokQuestionEvent> action); /**
* Triggered every time someone asks a new question via the question feature.
*
* @param action consumable action
* @return self instance
*/
default T onQuestion(EventConsumer<TikTokQuestionEvent> action) {
return onEvent(TikTokQuestionEvent.class, action);
}
T onSubscribe(EventConsumer<TikTokSubscribeEvent> action); /**
* Triggers when a user subscribe the streamer.
*
* @param action consumable action
* @return self instance
*/
default T onSubscribe(EventConsumer<TikTokSubscribeEvent> action) {
return onEvent(TikTokSubscribeEvent.class, action);
}
T onFollow(EventConsumer<TikTokFollowEvent> action); /**
* Triggers when a user follows the streamer. Based on social event.
*
* @param action consumable action
* @return self instance
*/
default T onFollow(EventConsumer<TikTokFollowEvent> action) {
return onEvent(TikTokFollowEvent.class, action);
}
T onLike(EventConsumer<TikTokLikeEvent> action); /**
* Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
*
* @param action consumable action
* @return self instance
*/
default T onLike(EventConsumer<TikTokLikeEvent> action) {
return onEvent(TikTokLikeEvent.class, action);
}
T onEmote(EventConsumer<TikTokEmoteEvent> action); /**
* Triggers when a user sends emote
*
* @param action consumable action
* @return self instance
*/
default T onEmote(EventConsumer<TikTokEmoteEvent> action) {
return onEvent(TikTokEmoteEvent.class, action);
}
T onJoin(EventConsumer<TikTokJoinEvent> action); /**
* Triggers when a user joins to the live
*
* @param action consumable action
* @return self instance
*/
default T onJoin(EventConsumer<TikTokJoinEvent> action) {
return onEvent(TikTokJoinEvent.class, action);
}
T onShare(EventConsumer<TikTokShareEvent> action); /**
* Triggers when a user shares the stream.
*
* @param action consumable action
* @return self instance
*/
default T onShare(EventConsumer<TikTokShareEvent> action) {
return onEvent(TikTokShareEvent.class, action);
}
T onLivePaused(EventConsumer<TikTokLivePausedEvent> action); /**
* Triggered when the live stream gets paused
*
* @param action consumable action
* @return self instance
*/
default T onLivePaused(EventConsumer<TikTokLivePausedEvent> action) {
return onEvent(TikTokLivePausedEvent.class, action);
}
T onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> action); /**
* Triggered when the live stream gets unpaused
*
* @param action consumable action
* @return self instance
*/
default T onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> action) {
return onEvent(TikTokLiveUnpausedEvent.class, action);
}
T onLiveEnded(EventConsumer<TikTokLiveEndedEvent> action); /**
* Triggered when the live stream gets terminated by the host. Will also trigger the TikTokDisconnectedEvent event.
*
* @param action consumable action
* @return self instance
*/
default T onLiveEnded(EventConsumer<TikTokLiveEndedEvent> action) {
return onEvent(TikTokLiveEndedEvent.class, action);
}
/** /**
* Invoked when client has been successfully connected to live * Invoked when client has been successfully connected to live
*
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onConnected(EventConsumer<TikTokConnectedEvent> action); default T onConnected(EventConsumer<TikTokConnectedEvent> action) {
return onEvent(TikTokConnectedEvent.class, action);
}
/** /**
* Invoked before client has been successfully connected to live * Invoked before client has been successfully connected to live
*
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onPreConnection(EventConsumer<TikTokPreConnectionEvent> action); default T onPreConnection(EventConsumer<TikTokPreConnectionEvent> action) {
return onEvent(TikTokPreConnectionEvent.class, action);
}
/** /**
* Invoked when client tries to reconnect * Invoked when client tries to reconnect
*
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onReconnecting(EventConsumer<TikTokReconnectingEvent> action); default T onReconnecting(EventConsumer<TikTokReconnectingEvent> action) {
return onEvent(TikTokReconnectingEvent.class, action);
}
/** /**
* Invoked when client disconnected * Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic.
* Note that you should wait a little bit before attempting a reconnect to avoid being rate-limited.
*
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> action); default T onDisconnected(EventConsumer<TikTokDisconnectedEvent> action) {
return onEvent(TikTokDisconnectedEvent.class, action);
}
/** /**
* Invoked when exception was throed inside client or event handler * Invoked when exception was throed inside client or event handler
*
* @param action consumable action * @param action consumable action
* @return self instance * @return self instance
*/ */
T onError(EventConsumer<TikTokErrorEvent> action); default T onError(EventConsumer<TikTokErrorEvent> action) {
return onEvent(TikTokErrorEvent.class, action);
}
// TODO Figure out how those events works // TODO Figure out how those events works
@@ -216,4 +350,10 @@ public interface EventsBuilder<T> {
//T onLinkMicBattle(TikTokEventConsumer<TikTokLinkMicBattleEvent> event); //T onLinkMicBattle(TikTokEventConsumer<TikTokLinkMicBattleEvent> event);
//T onUnhandledControl(TikTokEventConsumer<TikTokUnhandledControlEvent> event); //T onUnhandledControl(TikTokEventConsumer<TikTokUnhandledControlEvent> event);
/**
* To do figure out how to use Annotation processor.
* Goal is to generates methods for all possible events, everytime library is compiled
*/
} }

View File

@@ -22,10 +22,11 @@
*/ */
package io.github.jwdeveloper.tiktok.live.builder; package io.github.jwdeveloper.tiktok.live.builder;
import io.github.jwdeveloper.dependance.implementation.DependanceContainerBuilder;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings; import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener; import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper; import io.github.jwdeveloper.tiktok.mappers.LiveMapper;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -41,7 +42,7 @@ public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
* @param onCustomMappings lambda method * @param onCustomMappings lambda method
* @return * @return
*/ */
LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings); LiveClientBuilder onMapping(Consumer<LiveMapper> onCustomMappings);
/** /**
@@ -60,15 +61,26 @@ public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
*/ */
LiveClientBuilder addListener(TikTokEventListener listener); LiveClientBuilder addListener(TikTokEventListener listener);
/** /**
* Allows you to use own implementation of internal TikTokLive dependencies,
* when the default implementation does not meet your needs
* *
*
* @param onCustomizeDependencies access to dependency container
* @return
*/
LiveClientBuilder customize(Consumer<DependanceContainerBuilder> onCustomizeDependencies);
/**
* Builds new instance of the LiveClient
* @return LiveClient object * @return LiveClient object
*/ */
LiveClient build(); LiveClient build();
/** /**
* * Builds new instance of the LiveClient and connects to live
* @return LiveClient object and connects to TikTok live * @return LiveClient object
*/ */
LiveClient buildAndConnect(); LiveClient buildAndConnect();

View File

@@ -27,9 +27,10 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.mappers.data.MappingAction; import io.github.jwdeveloper.tiktok.mappers.data.MappingAction;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult; import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
import java.util.List;
import java.util.function.Function; import java.util.function.Function;
public interface TikTokMapper { public interface LiveMapper {
/** /**
* when mapper is not found for messageName, TikTokLiveException is thrown * when mapper is not found for messageName, TikTokLiveException is thrown
@@ -40,7 +41,6 @@ public interface TikTokMapper {
TikTokMapperModel forMessage(String messageName); TikTokMapperModel forMessage(String messageName);
/** /**
*
* @param mapperName protocol buffer class type * @param mapperName protocol buffer class type
* @return * @return
*/ */
@@ -54,10 +54,9 @@ public interface TikTokMapper {
TikTokMapperModel forAnyMessage(); TikTokMapperModel forAnyMessage();
List<TikTokEvent> handleMapping(String messageName, byte[] bytes);
boolean isRegistered(String mapperName); boolean isRegistered(String mapperName);
<T extends GeneratedMessageV3> boolean isRegistered(Class<T> mapperName); <T extends GeneratedMessageV3> boolean isRegistered(Class<T> mapperName);
} }

View File

@@ -26,7 +26,7 @@ import com.google.protobuf.GeneratedMessageV3;
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException; import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
import io.github.jwdeveloper.tiktok.utils.ProtoBufferObject; import io.github.jwdeveloper.tiktok.utils.ProtoBufferObject;
public interface TikTokMapperHelper { public interface LiveMapperHelper {
/** /**
* @param bytes protocol buffer data bytes * @param bytes protocol buffer data bytes

View File

@@ -22,7 +22,7 @@
*/ */
package io.github.jwdeveloper.tiktok.mappers.data; package io.github.jwdeveloper.tiktok.mappers.data;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapperHelper; import io.github.jwdeveloper.tiktok.mappers.LiveMapperHelper;
@FunctionalInterface @FunctionalInterface
public interface MappingAction<T> { public interface MappingAction<T> {
@@ -33,6 +33,6 @@ public interface MappingAction<T> {
* @param mapperHelper utils and helper methods that can be use to debbug/display/deserialize protocol buffer data * @param mapperHelper utils and helper methods that can be use to debbug/display/deserialize protocol buffer data
* @return * @return
*/ */
T onMapping(byte[] inputBytes, String messageName, TikTokMapperHelper mapperHelper); T onMapping(byte[] inputBytes, String messageName, LiveMapperHelper mapperHelper);
} }

View File

@@ -11,12 +11,7 @@
<artifactId>Client</artifactId> <artifactId>Client</artifactId>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency> <dependency>
@@ -30,12 +25,7 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.jwdeveloper.DepenDance</groupId>
<artifactId>DepenDance-Full</artifactId>
<version>0.0.18-Release</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>com.google.protobuf</groupId> <groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId> <artifactId>protobuf-java</artifactId>

View File

@@ -23,7 +23,6 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import io.github.jwdeveloper.dependance.injector.api.annotations.Inject;
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.*; import io.github.jwdeveloper.tiktok.data.events.control.*;
@@ -38,37 +37,39 @@ import io.github.jwdeveloper.tiktok.live.*;
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.websocket.SocketClient; import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import lombok.Getter;
import java.util.Base64; import java.util.Base64;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Logger; import java.util.logging.Logger;
@Getter
public class TikTokLiveClient implements LiveClient public class TikTokLiveClient implements LiveClient
{ {
private final TikTokRoomInfo liveRoomInfo; private final TikTokRoomInfo roomInfo;
private final LiveHttpClient httpClient; private final LiveHttpClient httpClient;
private final SocketClient webSocketClient; private final SocketClient webSocketClient;
private final TikTokLiveEventHandler tikTokEventHandler; private final LiveEventsHandler tikTokEventHandler;
private final LiveClientSettings clientSettings; private final LiveClientSettings clientSettings;
private final ListenersManager listenersManager; private final ListenersManager listenersManager;
private final Logger logger; private final Logger logger;
private final GiftsManager giftsManager; private final GiftsManager giftManager;
private final TikTokLiveMessageHandler messageHandler; private final LiveMessagesHandler messageHandler;
public TikTokLiveClient( public TikTokLiveClient(
TikTokLiveMessageHandler messageHandler, LiveMessagesHandler messageHandler,
GiftsManager giftsManager, GiftsManager giftsManager,
TikTokRoomInfo tikTokLiveMeta, TikTokRoomInfo tikTokLiveMeta,
LiveHttpClient tiktokHttpClient, LiveHttpClient tiktokHttpClient,
SocketClient webSocketClient, SocketClient webSocketClient,
TikTokLiveEventHandler tikTokEventHandler, LiveEventsHandler tikTokEventHandler,
LiveClientSettings clientSettings, LiveClientSettings clientSettings,
ListenersManager listenersManager, ListenersManager listenersManager,
Logger logger) { Logger logger) {
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
this.giftsManager = giftsManager; this.giftManager = giftsManager;
this.liveRoomInfo = tikTokLiveMeta; this.roomInfo = tikTokLiveMeta;
this.httpClient = tiktokHttpClient; this.httpClient = tiktokHttpClient;
this.webSocketClient = webSocketClient; this.webSocketClient = webSocketClient;
this.tikTokEventHandler = tikTokEventHandler; this.tikTokEventHandler = tikTokEventHandler;
@@ -77,15 +78,10 @@ public class TikTokLiveClient implements LiveClient
this.logger = logger; this.logger = logger;
} }
public void connectAsync(Consumer<LiveClient> onConnection) { public void connectAsync(Consumer<LiveClient> onConnection) {
CompletableFuture.runAsync(() -> { connectAsync().thenAccept(onConnection);
connect();
onConnection.accept(this);
});
} }
public CompletableFuture<LiveClient> connectAsync() { public CompletableFuture<LiveClient> connectAsync() {
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
connect(); connect();
@@ -119,61 +115,61 @@ public class TikTokLiveClient implements LiveClient
} }
public void tryConnect() { public void tryConnect() {
if (!liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) { if (!roomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
throw new TikTokLiveException("Already connected"); throw new TikTokLiveException("Already connected");
} }
setState(ConnectionState.CONNECTING); setState(ConnectionState.CONNECTING);
tikTokEventHandler.publish(this, new TikTokConnectingEvent()); tikTokEventHandler.publish(this, new TikTokConnectingEvent());
var userDataRequest = new LiveUserData.Request(liveRoomInfo.getHostName()); var userDataRequest = new LiveUserData.Request(roomInfo.getHostName());
var userData = httpClient.fetchLiveUserData(userDataRequest); var userData = httpClient.fetchLiveUserData(userDataRequest);
liveRoomInfo.setStartTime(userData.getStartTime()); roomInfo.setStartTime(userData.getStartTime());
liveRoomInfo.setRoomId(userData.getRoomId()); roomInfo.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: " + roomInfo.getHostName());
if (userData.getUserStatus() == LiveUserData.UserStatus.NotFound) if (userData.getUserStatus() == LiveUserData.UserStatus.NotFound)
throw new TikTokLiveOfflineHostException("User not found: " + liveRoomInfo.getHostName()); throw new TikTokLiveUnknownHostException("User not found: " + roomInfo.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() && clientSettings.isThrowOnAgeRestriction()) if (liveData.isAgeRestricted() && clientSettings.isThrowOnAgeRestriction())
throw new TikTokLiveException("Livestream for " + liveRoomInfo.getHostName() + " is 18+ or age restricted!"); throw new TikTokLiveException("Livestream for " + roomInfo.getHostName() + " is 18+ or age restricted!");
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound) if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound)
throw new TikTokLiveOfflineHostException("LiveStream for " + liveRoomInfo.getHostName() + " could not be found."); throw new TikTokLiveUnknownHostException("LiveStream for " + roomInfo.getHostName() + " could not be found.");
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostOffline) if (liveData.getLiveStatus() == LiveData.LiveStatus.HostOffline)
throw new TikTokLiveOfflineHostException("LiveStream for " + liveRoomInfo.getHostName() + " not found, is the Host offline?"); throw new TikTokLiveOfflineHostException("LiveStream for " + roomInfo.getHostName() + " not found, is the Host offline?");
tikTokEventHandler.publish(this, new TikTokRoomDataResponseEvent(liveData)); tikTokEventHandler.publish(this, new TikTokRoomDataResponseEvent(liveData));
liveRoomInfo.setTitle(liveData.getTitle()); roomInfo.setTitle(liveData.getTitle());
liveRoomInfo.setViewersCount(liveData.getViewers()); roomInfo.setViewersCount(liveData.getViewers());
liveRoomInfo.setTotalViewersCount(liveData.getTotalViewers()); roomInfo.setTotalViewersCount(liveData.getTotalViewers());
liveRoomInfo.setAgeRestricted(liveData.isAgeRestricted()); roomInfo.setAgeRestricted(liveData.isAgeRestricted());
liveRoomInfo.setHost(liveData.getHost()); roomInfo.setHost(liveData.getHost());
var preconnectEvent = new TikTokPreConnectionEvent(userData, liveData); var preconnectEvent = new TikTokPreConnectionEvent(userData, liveData);
tikTokEventHandler.publish(this, preconnectEvent); tikTokEventHandler.publish(this, preconnectEvent);
if (preconnectEvent.isCancelConnection()) if (preconnectEvent.isCancelConnection())
throw new TikTokLiveException("TikTokPreConnectionEvent cancelled connection!"); throw new TikTokLiveException("TikTokPreConnectionEvent cancelled connection!");
if (clientSettings.isFetchGifts())
giftManager.attachGiftsList(httpClient.fetchRoomGiftsData(userData.getRoomId()).getGifts());
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);
setState(ConnectionState.CONNECTED); setState(ConnectionState.CONNECTED);
tikTokEventHandler.publish(this, new TikTokRoomInfoEvent(liveRoomInfo)); tikTokEventHandler.publish(this, new TikTokRoomInfoEvent(roomInfo));
} }
public void disconnect() { public void disconnect() {
if (liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) { if (roomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
return; return;
} }
setState(ConnectionState.DISCONNECTED); setState(ConnectionState.DISCONNECTED);
@@ -182,7 +178,7 @@ public class TikTokLiveClient implements LiveClient
private void setState(ConnectionState connectionState) { private void setState(ConnectionState connectionState) {
logger.info("TikTokLive client state: " + connectionState.name()); logger.info("TikTokLive client state: " + connectionState.name());
liveRoomInfo.setConnectionState(connectionState); roomInfo.setConnectionState(connectionState);
} }
public void publishEvent(TikTokEvent event) { public void publishEvent(TikTokEvent event) {
@@ -203,22 +199,4 @@ public class TikTokLiveClient implements LiveClient
messageHandler.handleSingleMessage(this, message); messageHandler.handleSingleMessage(this, message);
} }
@Override
public GiftsManager getGiftManager() {
return giftsManager;
}
public LiveRoomInfo getRoomInfo() {
return liveRoomInfo;
}
@Override
public ListenersManager getListenersManager() {
return listenersManager;
}
@Override
public Logger getLogger() {
return logger;
}
} }

View File

@@ -24,19 +24,10 @@ package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.dependance.Dependance; import io.github.jwdeveloper.dependance.Dependance;
import io.github.jwdeveloper.dependance.api.DependanceContainer; import io.github.jwdeveloper.dependance.api.DependanceContainer;
import io.github.jwdeveloper.dependance.implementation.DependanceContainerBuilder;
import io.github.jwdeveloper.tiktok.mappers.MessagesMapperFactory; import io.github.jwdeveloper.tiktok.mappers.MessagesMapperFactory;
import io.github.jwdeveloper.tiktok.common.LoggerFactory; import io.github.jwdeveloper.tiktok.common.LoggerFactory;
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.gift.*;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.link.*;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.data.events.room.*;
import io.github.jwdeveloper.tiktok.data.events.social.*;
import io.github.jwdeveloper.tiktok.data.events.websocket.*;
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.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftsManager; import io.github.jwdeveloper.tiktok.gifts.TikTokGiftsManager;
@@ -60,9 +51,10 @@ import java.util.logging.Logger;
public class TikTokLiveClientBuilder implements LiveClientBuilder { public class TikTokLiveClientBuilder implements LiveClientBuilder {
protected final LiveClientSettings clientSettings; protected final LiveClientSettings clientSettings;
protected final TikTokLiveEventHandler eventHandler; protected final LiveEventsHandler eventHandler;
protected final List<TikTokEventListener> listeners; protected final List<TikTokEventListener> listeners;
protected final List<Consumer<TikTokMapper>> onCustomMappings; protected final List<Consumer<LiveMapper>> onCustomMappings;
protected final List<Consumer<DependanceContainerBuilder>> onCustomDependencies;
public TikTokLiveClientBuilder(String userName) { public TikTokLiveClientBuilder(String userName) {
this.clientSettings = LiveClientSettings.createDefault(); this.clientSettings = LiveClientSettings.createDefault();
@@ -70,9 +62,10 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
this.eventHandler = new TikTokLiveEventHandler(); this.eventHandler = new TikTokLiveEventHandler();
this.listeners = new ArrayList<>(); this.listeners = new ArrayList<>();
this.onCustomMappings = new ArrayList<>(); this.onCustomMappings = new ArrayList<>();
this.onCustomDependencies = new ArrayList<>();
} }
public LiveClientBuilder onMapping(Consumer<TikTokMapper> consumer) { public LiveClientBuilder onMapping(Consumer<LiveMapper> consumer) {
this.onCustomMappings.add(consumer); this.onCustomMappings.add(consumer);
return this; return this;
} }
@@ -88,6 +81,12 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return this; return this;
} }
@Override
public LiveClientBuilder customize(Consumer<DependanceContainerBuilder> onCustomizeDependencies) {
this.onCustomDependencies.add(onCustomizeDependencies);
return this;
}
protected void validate() { protected void validate() {
if (clientSettings.getClientLanguage() == null || clientSettings.getClientLanguage().isEmpty()) if (clientSettings.getClientLanguage() == null || clientSettings.getClientLanguage().isEmpty())
clientSettings.setClientLanguage("en"); clientSettings.setClientLanguage("en");
@@ -124,8 +123,8 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
}); });
//messages //messages
dependance.registerSingleton(TikTokLiveEventHandler.class, eventHandler); dependance.registerSingleton(LiveEventsHandler.class, eventHandler);
dependance.registerSingleton(TikTokLiveMessageHandler.class); dependance.registerSingleton(LiveMessagesHandler.class,TikTokLiveMessageHandler.class);
//listeners //listeners
dependance.registerSingletonList(TikTokEventListener.class, (e) -> listeners); dependance.registerSingletonList(TikTokEventListener.class, (e) -> listeners);
@@ -133,6 +132,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
//networking //networking
dependance.registerSingleton(HttpClientFactory.class); dependance.registerSingleton(HttpClientFactory.class);
dependance.registerSingleton(TikTokWebSocketPingingTask.class);
if (clientSettings.isOffline()) { if (clientSettings.isOffline()) {
dependance.registerSingleton(SocketClient.class, TikTokWebSocketOfflineClient.class); dependance.registerSingleton(SocketClient.class, TikTokWebSocketOfflineClient.class);
dependance.registerSingleton(LiveHttpClient.class, TikTokLiveHttpOfflineClient.class); dependance.registerSingleton(LiveHttpClient.class, TikTokLiveHttpOfflineClient.class);
@@ -157,8 +157,8 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
//mapper //mapper
dependance.registerSingleton(TikTokGenericEventMapper.class); dependance.registerSingleton(TikTokGenericEventMapper.class);
dependance.registerSingleton(TikTokMapperHelper.class, TikTokLiveMapperHelper.class); dependance.registerSingleton(LiveMapperHelper.class, TikTokLiveMapperHelper.class);
dependance.registerSingleton(TikTokMapper.class, (container) -> dependance.registerSingleton(LiveMapper.class, (container) ->
{ {
var dependace = (DependanceContainer) container.find(DependanceContainer.class); var dependace = (DependanceContainer) container.find(DependanceContainer.class);
var mapper = MessagesMapperFactory.create(dependace); var mapper = MessagesMapperFactory.create(dependace);
@@ -175,6 +175,8 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
//client //client
dependance.registerSingleton(LiveClient.class, TikTokLiveClient.class); dependance.registerSingleton(LiveClient.class, TikTokLiveClient.class);
onCustomDependencies.forEach(action -> action.accept(dependance));
var container = dependance.build(); var container = dependance.build();
return container.find(LiveClient.class); return container.find(LiveClient.class);
} }
@@ -189,365 +191,9 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return build().connectAsync(); return build().connectAsync();
} }
/**
* To do figure out how to use Annotation processor.
* Goal is to generates methods for all possible events, everytime library is compiled
*/
public TikTokLiveClientBuilder onUnhandledSocial(EventConsumer<TikTokUnhandledSocialEvent> event) {
eventHandler.subscribe(TikTokUnhandledSocialEvent.class, event);
return this;
}
public LiveClientBuilder onChest(EventConsumer<TikTokChestEvent> event) {
eventHandler.subscribe(TikTokChestEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicFanTicket(EventConsumer<TikTokLinkMicFanTicketEvent> event) {
eventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEnvelope(EventConsumer<TikTokEnvelopeEvent> event) {
eventHandler.subscribe(TikTokEnvelopeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onShop(EventConsumer<TikTokShopEvent> event) {
eventHandler.subscribe(TikTokShopEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onDetect(EventConsumer<TikTokDetectEvent> event) {
eventHandler.subscribe(TikTokDetectEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkLayer(EventConsumer<TikTokLinkLayerEvent> event) {
eventHandler.subscribe(TikTokLinkLayerEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onConnected(EventConsumer<TikTokConnectedEvent> event) {
eventHandler.subscribe(TikTokConnectedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onPreConnection(EventConsumer<TikTokPreConnectionEvent> event) {
eventHandler.subscribe(TikTokPreConnectionEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onCaption(EventConsumer<TikTokCaptionEvent> event) {
eventHandler.subscribe(TikTokCaptionEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onQuestion(EventConsumer<TikTokQuestionEvent> event) {
eventHandler.subscribe(TikTokQuestionEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRoomPin(EventConsumer<TikTokRoomPinEvent> event) {
eventHandler.subscribe(TikTokRoomPinEvent.class, event);
return this;
}
@Override @Override
public <E extends TikTokEvent> LiveClientBuilder onEvent(Class<E> eventClass, EventConsumer<E> event) { public <E extends TikTokEvent> LiveClientBuilder onEvent(Class<E> eventClass, EventConsumer<E> action) {
eventHandler.subscribe(eventClass, event); eventHandler.subscribe(eventClass, action);
return this;
}
@Override
public TikTokLiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) {
eventHandler.subscribe(TikTokRoomInfoEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLivePaused(EventConsumer<TikTokLivePausedEvent> event) {
eventHandler.subscribe(TikTokLivePausedEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event) {
eventHandler.subscribe(TikTokLiveUnpausedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLike(EventConsumer<TikTokLikeEvent> event) {
eventHandler.subscribe(TikTokLikeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLink(EventConsumer<TikTokLinkEvent> event) {
eventHandler.subscribe(TikTokLinkEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkInvite(EventConsumer<TikTokLinkInviteEvent> event) {
eventHandler.subscribe(TikTokLinkInviteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkReply(EventConsumer<TikTokLinkReplyEvent> event) {
eventHandler.subscribe(TikTokLinkReplyEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkCreate(EventConsumer<TikTokLinkCreateEvent> event) {
eventHandler.subscribe(TikTokLinkCreateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkClose(EventConsumer<TikTokLinkCloseEvent> event) {
eventHandler.subscribe(TikTokLinkCloseEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkEnter(EventConsumer<TikTokLinkEnterEvent> event) {
eventHandler.subscribe(TikTokLinkEnterEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkLeave(EventConsumer<TikTokLinkLeaveEvent> event) {
eventHandler.subscribe(TikTokLinkLeaveEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkCancel(EventConsumer<TikTokLinkCancelEvent> event) {
eventHandler.subscribe(TikTokLinkCancelEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkKickOut(EventConsumer<TikTokLinkKickOutEvent> event) {
eventHandler.subscribe(TikTokLinkKickOutEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkLinkedListChange(EventConsumer<TikTokLinkLinkedListChangeEvent> event) {
eventHandler.subscribe(TikTokLinkLinkedListChangeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkUpdateUser(EventConsumer<TikTokLinkUpdateUserEvent> event) {
eventHandler.subscribe(TikTokLinkUpdateUserEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkWaitListChange(EventConsumer<TikTokLinkWaitListChangeEvent> event) {
eventHandler.subscribe(TikTokLinkWaitListChangeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMute(EventConsumer<TikTokLinkMuteEvent> event) {
eventHandler.subscribe(TikTokLinkMuteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkRandomMatch(EventConsumer<TikTokLinkRandomMatchEvent> event) {
eventHandler.subscribe(TikTokLinkRandomMatchEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkUpdateUserSettings(EventConsumer<TikTokLinkUpdateUserSettingEvent> event) {
eventHandler.subscribe(TikTokLinkUpdateUserSettingEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicIdxUpdate(EventConsumer<TikTokLinkMicIdxUpdateEvent> event) {
eventHandler.subscribe(TikTokLinkMicIdxUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkListChange(EventConsumer<TikTokLinkListChangeEvent> event) {
eventHandler.subscribe(TikTokLinkListChangeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkCohostListChange(EventConsumer<TikTokLinkCohostListChangeEvent> event) {
eventHandler.subscribe(TikTokLinkCohostListChangeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMediaChange(EventConsumer<TikTokLinkMediaChangeEvent> event) {
eventHandler.subscribe(TikTokLinkMediaChangeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkAcceptNotice(EventConsumer<TikTokLinkAcceptNoticeEvent> event) {
eventHandler.subscribe(TikTokLinkAcceptNoticeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkSysKickOut(EventConsumer<TikTokLinkSysKickOutEvent> event) {
eventHandler.subscribe(TikTokLinkSysKickOutEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkUserToast(EventConsumer<TikTokLinkUserToastEvent> event) {
eventHandler.subscribe(TikTokLinkUserToastEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onBarrage(EventConsumer<TikTokBarrageEvent> event) {
eventHandler.subscribe(TikTokBarrageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onGift(EventConsumer<TikTokGiftEvent> event) {
eventHandler.subscribe(TikTokGiftEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onGiftCombo(EventConsumer<TikTokGiftComboEvent> event) {
eventHandler.subscribe(TikTokGiftComboEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicArmies(EventConsumer<TikTokLinkMicArmiesEvent> event) {
eventHandler.subscribe(TikTokLinkMicArmiesEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEmote(EventConsumer<TikTokEmoteEvent> event) {
eventHandler.subscribe(TikTokEmoteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnauthorizedMember(EventConsumer<TikTokUnauthorizedMemberEvent> event) {
eventHandler.subscribe(TikTokUnauthorizedMemberEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onInRoomBanner(EventConsumer<TikTokInRoomBannerEvent> event) {
eventHandler.subscribe(TikTokInRoomBannerEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicMethod(EventConsumer<TikTokLinkMicMethodEvent> event) {
eventHandler.subscribe(TikTokLinkMicMethodEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onSubscribe(EventConsumer<TikTokSubscribeEvent> event) {
eventHandler.subscribe(TikTokSubscribeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onPoll(EventConsumer<TikTokPollEvent> event) {
eventHandler.subscribe(TikTokPollEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onFollow(EventConsumer<TikTokFollowEvent> event) {
eventHandler.subscribe(TikTokFollowEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onComment(EventConsumer<TikTokCommentEvent> event) {
eventHandler.subscribe(TikTokCommentEvent.class, event);
return this;
}
@Override
public LiveClientBuilder onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action) {
eventHandler.subscribe(TikTokHttpResponseEvent.class, action);
return this;
}
public TikTokLiveClientBuilder onGoalUpdate(EventConsumer<TikTokGoalUpdateEvent> event) {
eventHandler.subscribe(TikTokGoalUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRankUpdate(EventConsumer<TikTokRankUpdateEvent> event) {
eventHandler.subscribe(TikTokRankUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onIMDelete(EventConsumer<TikTokIMDeleteEvent> event) {
eventHandler.subscribe(TikTokIMDeleteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLiveEnded(EventConsumer<TikTokLiveEndedEvent> event) {
eventHandler.subscribe(TikTokLiveEndedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onError(EventConsumer<TikTokErrorEvent> event) {
eventHandler.subscribe(TikTokErrorEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onJoin(EventConsumer<TikTokJoinEvent> event) {
eventHandler.subscribe(TikTokJoinEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRankText(EventConsumer<TikTokRankTextEvent> event) {
eventHandler.subscribe(TikTokRankTextEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onShare(EventConsumer<TikTokShareEvent> event) {
eventHandler.subscribe(TikTokShareEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnhandledMember(EventConsumer<TikTokUnhandledMemberEvent> event) {
eventHandler.subscribe(TikTokUnhandledMemberEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onSubNotify(EventConsumer<TikTokSubNotifyEvent> event) {
eventHandler.subscribe(TikTokSubNotifyEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicBattle(EventConsumer<TikTokLinkMicBattleEvent> event) {
eventHandler.subscribe(TikTokLinkMicBattleEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onDisconnected(EventConsumer<TikTokDisconnectedEvent> event) {
eventHandler.subscribe(TikTokDisconnectedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnhandledControl(EventConsumer<TikTokUnhandledControlEvent> event) {
eventHandler.subscribe(TikTokUnhandledControlEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEvent(EventConsumer<TikTokEvent> event) {
eventHandler.subscribe(TikTokEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> event) {
eventHandler.subscribe(TikTokWebsocketResponseEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> event) {
eventHandler.subscribe(TikTokWebsocketMessageEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> event) {
eventHandler.subscribe(TikTokWebsocketUnhandledMessageEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onReconnecting(EventConsumer<TikTokReconnectingEvent> event) {
eventHandler.subscribe(TikTokReconnectingEvent.class, event);
return this; return this;
} }
} }

View File

@@ -23,12 +23,13 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.LiveEventsHandler;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer; import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import java.util.*; import java.util.*;
public class TikTokLiveEventHandler { public class TikTokLiveEventHandler implements LiveEventsHandler {
private final Map<Class<?>, Set<EventConsumer>> events; private final Map<Class<?>, Set<EventConsumer>> events;
public TikTokLiveEventHandler() { public TikTokLiveEventHandler() {

View File

@@ -30,21 +30,22 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketRespons
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent; import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper; import io.github.jwdeveloper.tiktok.live.LiveEventsHandler;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper; import io.github.jwdeveloper.tiktok.live.LiveMessagesHandler;
import io.github.jwdeveloper.tiktok.mappers.LiveMapper;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.Stopwatch; import io.github.jwdeveloper.tiktok.utils.Stopwatch;
import java.time.Duration; import java.time.Duration;
public class TikTokLiveMessageHandler { public class TikTokLiveMessageHandler implements LiveMessagesHandler {
private final TikTokLiveEventHandler tikTokEventHandler; private final LiveEventsHandler tikTokEventHandler;
private final TikTokLiveMapper mapper; private final LiveMapper mapper;
public TikTokLiveMessageHandler(TikTokLiveEventHandler tikTokEventHandler, TikTokMapper mapper) { public TikTokLiveMessageHandler(LiveEventsHandler tikTokEventHandler, LiveMapper mapper) {
this.tikTokEventHandler = tikTokEventHandler; this.tikTokEventHandler = tikTokEventHandler;
this.mapper = (TikTokLiveMapper) mapper; this.mapper = mapper;
} }
public void handle(LiveClient client, WebcastResponse webcastResponse) { public void handle(LiveClient client, WebcastResponse webcastResponse) {
@@ -59,11 +60,9 @@ public class TikTokLiveMessageHandler {
} }
} }
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message) public void handleSingleMessage(LiveClient client, WebcastResponse.Message message) {
{
var messageClassName = message.getMethod(); var messageClassName = message.getMethod();
if (!mapper.isRegistered(messageClassName)) if (!mapper.isRegistered(messageClassName)) {
{
tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message)); tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message));
return; return;
} }

View File

@@ -36,13 +36,4 @@ public class HttpClientFactory {
public HttpClientBuilder client(String url) { public HttpClientBuilder client(String url) {
return new HttpClientBuilder(url, liveClientSettings.getHttpSettings().clone()); return new HttpClientBuilder(url, liveClientSettings.getHttpSettings().clone());
} }
//Does not contains default httpClientSettings, Params, headers, etd
//Edit: Do we even use it?
public HttpClientBuilder clientEmpty(String url) {
var settings = new HttpClientSettings();
settings.setProxyClientSettings(liveClientSettings.getHttpSettings().getProxyClientSettings());
return new HttpClientBuilder(url, settings);
}
} }

View File

@@ -29,6 +29,7 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokEventListenerMethodException; import io.github.jwdeveloper.tiktok.exceptions.TikTokEventListenerMethodException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveEventsHandler;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer; import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import java.util.ArrayList; import java.util.ArrayList;
@@ -37,10 +38,10 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
public class TikTokListenersManager implements ListenersManager { public class TikTokListenersManager implements ListenersManager {
private final TikTokLiveEventHandler eventObserver; private final LiveEventsHandler eventObserver;
private final List<ListenerBindingModel> bindingModels; private final List<ListenerBindingModel> bindingModels;
public TikTokListenersManager(List<TikTokEventListener> listeners, TikTokLiveEventHandler tikTokEventHandler) { public TikTokListenersManager(List<TikTokEventListener> listeners, LiveEventsHandler tikTokEventHandler) {
this.eventObserver = tikTokEventHandler; this.eventObserver = tikTokEventHandler;
this.bindingModels = new ArrayList<>(listeners.size()); this.bindingModels = new ArrayList<>(listeners.size());
for (var listener : listeners) { for (var listener : listeners) {

View File

@@ -23,11 +23,8 @@
package io.github.jwdeveloper.tiktok.mappers; package io.github.jwdeveloper.tiktok.mappers;
import io.github.jwdeveloper.dependance.api.DependanceContainer; import io.github.jwdeveloper.dependance.api.DependanceContainer;
import io.github.jwdeveloper.dependance.injector.api.containers.Container;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.data.events.*; import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.link.*; import io.github.jwdeveloper.tiktok.data.events.link.*;
import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult; import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokCommonEventHandler; import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokCommonEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokGiftEventHandler; import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokGiftEventHandler;
@@ -40,7 +37,7 @@ import static io.github.jwdeveloper.tiktok.messages.enums.LinkMessageType.*;
public class MessagesMapperFactory { public class MessagesMapperFactory {
public static TikTokLiveMapper create(DependanceContainer container) { public static TikTokLiveMapper create(DependanceContainer container) {
var helper = container.find(TikTokMapperHelper.class); var helper = container.find(LiveMapperHelper.class);
var mapper = new TikTokLiveMapper(helper); var mapper = new TikTokLiveMapper(helper);
//ConnectionEvents events //ConnectionEvents events

View File

@@ -27,25 +27,23 @@ import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.*;
import java.util.HashMap;
import java.util.Map;
/** /**
* Goal of this class is to map ProtocolBuffer objects to TikTok Event in generic way * Goal of this class is to map ProtocolBuffer objects to TikTok Event in generic way
* * <ul>
* First parameter is ProtocolBuffer class type * <li>First parameter is ProtocolBuffer class type</li>
* Second parameters is TikTokEvent class type * <li>Second parameters is TikTokEvent class type</li>
* Third parameters is bytes payload * <li>Third parameters is bytes payload</li>
* * </ul>
* mapToEvent(WebcastGiftMessage.class, TikTokGiftEvent.class, payload) * <p>mapToEvent(WebcastGiftMessage.class, TikTokGiftEvent.class, payload)</p>
* * <p>How does it work?</p>
* How does it work? * <ol>
* 1. Finds method `parseFrom(byte[] bytes)` inside ProtocolBuffer class * <li>Finds method `parseFrom(byte[] bytes)` inside ProtocolBuffer class</li>
* 2. put payload to the method methods and create new instance of ProtcolBuffer object * <li>Put payload to the method methods and create new instance of ProtcolBuffer object</li>
* 3. Finds in TikTokEvent constructor that takes ProtocolBuffer type as parameter * <li>Finds in TikTokEvent constructor that takes ProtocolBuffer type as parameter</li>
* 4. create new Instance in TikTokEvents using object from step 2 and constructor from step 3 * <li>Create new Instance in TikTokEvents using object from step 2 and constructor from step 3</li>
* * </ol>
* methodCache and constructorCache are used to boost performance * methodCache and constructorCache are used to boost performance
*/ */
public class TikTokGenericEventMapper { public class TikTokGenericEventMapper {
@@ -74,34 +72,27 @@ public class TikTokGenericEventMapper {
} }
} }
public Method getParsingMethod(Class<?> input) throws NoSuchMethodException { public Method getParsingMethod(Class<?> input) throws RuntimeException {
if (methodCache.containsKey(input)) { return methodCache.computeIfAbsent(input, aClass -> {
return methodCache.get(input); try {
return aClass.getDeclaredMethod("parseFrom", byte[].class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} }
var method = input.getDeclaredMethod("parseFrom", byte[].class); });
methodCache.put(input, method);
return method;
} }
private Constructor<?> getParsingConstructor(Class<?> input, Class<?> output) { private Constructor<?> getParsingConstructor(Class<?> input, Class<?> output) {
var pair = new TypePair(input, output); return constructorCache.computeIfAbsent(new TypePair(input, output), pair -> {
if (constructorCache.containsKey(pair)) {
return constructorCache.get(pair);
}
var optional = Arrays.stream(output.getConstructors()) var optional = Arrays.stream(output.getConstructors())
.filter(ea -> Arrays.stream(ea.getParameterTypes()) .filter(ea -> Arrays.stream(ea.getParameterTypes())
.toList() .toList()
.contains(input)) .contains(input))
.findFirst(); .findFirst();
if (optional.isEmpty()) { if (optional.isEmpty())
throw new TikTokMessageMappingException(input, output, "Unable to find constructor with input class type"); throw new TikTokMessageMappingException(input, output, "Unable to find constructor with input class type");
}
constructorCache.put(pair, optional.get());
return optional.get(); return optional.get();
});
} }
} }

View File

@@ -29,13 +29,13 @@ import io.github.jwdeveloper.tiktok.mappers.data.*;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
public class TikTokLiveMapper implements TikTokMapper { public class TikTokLiveMapper implements LiveMapper {
private final Map<String, TikTokLiveMapperModel> mappers; private final Map<String, TikTokLiveMapperModel> mappers;
private final TikTokMapperHelper mapperUtils; private final LiveMapperHelper mapperUtils;
private final TikTokLiveMapperModel globalMapperModel; private final TikTokLiveMapperModel globalMapperModel;
public TikTokLiveMapper(TikTokMapperHelper mapperUtils) { public TikTokLiveMapper(LiveMapperHelper mapperUtils) {
this.mappers = new HashMap<>(); this.mappers = new HashMap<>();
this.mapperUtils = mapperUtils; this.mapperUtils = mapperUtils;
this.globalMapperModel = new TikTokLiveMapperModel("any message"); this.globalMapperModel = new TikTokLiveMapperModel("any message");

View File

@@ -28,7 +28,7 @@ import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import io.github.jwdeveloper.tiktok.utils.ProtoBufferObject; import io.github.jwdeveloper.tiktok.utils.ProtoBufferObject;
import io.github.jwdeveloper.tiktok.utils.ProtocolUtils; import io.github.jwdeveloper.tiktok.utils.ProtocolUtils;
public class TikTokLiveMapperHelper implements TikTokMapperHelper { public class TikTokLiveMapperHelper implements LiveMapperHelper {
private final TikTokGenericEventMapper genericMapper; private final TikTokGenericEventMapper genericMapper;
public TikTokLiveMapperHelper(TikTokGenericEventMapper genericMapper) { public TikTokLiveMapperHelper(TikTokGenericEventMapper genericMapper) {

View File

@@ -28,7 +28,7 @@ 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.live.GiftsManager; import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapperHelper; import io.github.jwdeveloper.tiktok.mappers.LiveMapperHelper;
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;
@@ -48,18 +48,13 @@ public class TikTokGiftEventHandler {
} }
@SneakyThrows @SneakyThrows
public MappingResult handleGifts(byte[] msg, String name, TikTokMapperHelper helper) { public MappingResult handleGifts(byte[] msg, String name, LiveMapperHelper helper) {
var currentMessage = WebcastGiftMessage.parseFrom(msg); var currentMessage = WebcastGiftMessage.parseFrom(msg);
var gifts = handleGift(currentMessage); var gifts = handleGift(currentMessage);
return MappingResult.of(currentMessage, gifts); return MappingResult.of(currentMessage, gifts);
} }
public List<TikTokEvent> handleGift(WebcastGiftMessage currentMessage) { public List<TikTokEvent> handleGift(WebcastGiftMessage currentMessage) {
var userId = currentMessage.getUser().getId();
var currentType = GiftComboStateType.fromNumber(currentMessage.getSendType());
var containsPreviousMessage = giftsMessages.containsKey(userId);
//If gift is not streakable just return onGift event //If gift is not streakable just return onGift event
if (currentMessage.getGift().getType() != 1) { if (currentMessage.getGift().getType() != 1) {
var comboEvent = getGiftComboEvent(currentMessage, GiftComboStateType.Finished); var comboEvent = getGiftComboEvent(currentMessage, GiftComboStateType.Finished);
@@ -67,7 +62,11 @@ public class TikTokGiftEventHandler {
return List.of(comboEvent, giftEvent); return List.of(comboEvent, giftEvent);
} }
if (!containsPreviousMessage) { var userId = currentMessage.getUser().getId();
var currentType = GiftComboStateType.fromNumber(currentMessage.getSendType());
var previousMessage = giftsMessages.get(userId);
if (previousMessage == null) {
if (currentType == GiftComboStateType.Finished) { if (currentType == GiftComboStateType.Finished) {
return List.of(getGiftEvent(currentMessage)); return List.of(getGiftEvent(currentMessage));
} else { } else {
@@ -76,7 +75,6 @@ public class TikTokGiftEventHandler {
} }
} }
var previousMessage = giftsMessages.get(userId);
var previousType = GiftComboStateType.fromNumber(previousMessage.getSendType()); var previousType = GiftComboStateType.fromNumber(previousMessage.getSendType());
if (currentType == GiftComboStateType.Active && if (currentType == GiftComboStateType.Active &&
previousType == GiftComboStateType.Active) { previousType == GiftComboStateType.Active) {

View File

@@ -31,7 +31,7 @@ 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.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.data.models.RankingUser; import io.github.jwdeveloper.tiktok.data.models.RankingUser;
import io.github.jwdeveloper.tiktok.data.models.users.User; import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapperHelper; import io.github.jwdeveloper.tiktok.mappers.LiveMapperHelper;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult; import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLikeMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLikeMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage;
@@ -86,7 +86,7 @@ public class TikTokRoomInfoEventHandler {
} }
@SneakyThrows @SneakyThrows
public MappingResult handleMemberMessage(byte[] msg, String name, TikTokMapperHelper helper) { public MappingResult handleMemberMessage(byte[] msg, String name, LiveMapperHelper helper) {
var message = WebcastMemberMessage.parseFrom(msg); var message = WebcastMemberMessage.parseFrom(msg);
var event = switch (message.getAction()) { var event = switch (message.getAction()) {
@@ -103,7 +103,7 @@ public class TikTokRoomInfoEventHandler {
} }
@SneakyThrows @SneakyThrows
public MappingResult handleLike(byte[] msg, String name, TikTokMapperHelper helper) { public MappingResult handleLike(byte[] msg, String name, LiveMapperHelper helper) {
var message = WebcastLikeMessage.parseFrom(msg); var message = WebcastLikeMessage.parseFrom(msg);
var event = new TikTokLikeEvent(message); var event = new TikTokLikeEvent(message);
var roomInfoEvent = this.handleRoomInfo(tikTokRoomInfo -> var roomInfoEvent = this.handleRoomInfo(tikTokRoomInfo ->

View File

@@ -29,6 +29,8 @@ import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.data.settings.*; import io.github.jwdeveloper.tiktok.data.settings.*;
import io.github.jwdeveloper.tiktok.exceptions.*; import io.github.jwdeveloper.tiktok.exceptions.*;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveEventsHandler;
import io.github.jwdeveloper.tiktok.live.LiveMessagesHandler;
import org.java_websocket.client.WebSocketClient; import org.java_websocket.client.WebSocketClient;
import javax.net.ssl.*; import javax.net.ssl.*;
@@ -38,22 +40,23 @@ import java.util.HashMap;
public class TikTokWebSocketClient implements SocketClient { public class TikTokWebSocketClient implements SocketClient {
private final LiveClientSettings clientSettings; private final LiveClientSettings clientSettings;
private final TikTokLiveMessageHandler messageHandler; private final LiveMessagesHandler messageHandler;
private final TikTokLiveEventHandler tikTokEventHandler; private final LiveEventsHandler tikTokEventHandler;
private WebSocketClient webSocketClient;
private final TikTokWebSocketPingingTask pingingTask; private final TikTokWebSocketPingingTask pingingTask;
private WebSocketClient webSocketClient;
private boolean isConnected; private boolean isConnected;
public TikTokWebSocketClient( public TikTokWebSocketClient(
LiveClientSettings clientSettings, LiveClientSettings clientSettings,
TikTokLiveMessageHandler messageHandler, LiveMessagesHandler messageHandler,
TikTokLiveEventHandler tikTokEventHandler) { LiveEventsHandler tikTokEventHandler,
TikTokWebSocketPingingTask pingingTask)
{
this.clientSettings = clientSettings; this.clientSettings = clientSettings;
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
this.tikTokEventHandler = tikTokEventHandler; this.tikTokEventHandler = tikTokEventHandler;
this.pingingTask = pingingTask;
isConnected = false; isConnected = false;
pingingTask = new TikTokWebSocketPingingTask();
} }
@Override @Override
@@ -96,9 +99,15 @@ public class TikTokWebSocketClient implements SocketClient {
if (proxySettings.getType() == Proxy.Type.SOCKS) { if (proxySettings.getType() == Proxy.Type.SOCKS) {
SSLContext sc = SSLContext.getInstance("SSL"); SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new X509TrustManager() { sc.init(null, new TrustManager[]{new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {} public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {} }
public X509Certificate[] getAcceptedIssuers() { return null; }
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}}, null); }}, null);
webSocketClient.setSocketFactory(sc.getSocketFactory()); webSocketClient.setSocketFactory(sc.getSocketFactory());
} }

View File

@@ -27,6 +27,8 @@ import io.github.jwdeveloper.tiktok.*;
import io.github.jwdeveloper.tiktok.data.events.*; import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException; import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveEventsHandler;
import io.github.jwdeveloper.tiktok.live.LiveMessagesHandler;
import io.github.jwdeveloper.tiktok.messages.webcast.*; import io.github.jwdeveloper.tiktok.messages.webcast.*;
import org.java_websocket.client.WebSocketClient; import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455; import org.java_websocket.drafts.Draft_6455;
@@ -38,15 +40,15 @@ import java.util.*;
public class TikTokWebSocketListener extends WebSocketClient { public class TikTokWebSocketListener extends WebSocketClient {
private final TikTokLiveMessageHandler messageHandler; private final LiveMessagesHandler messageHandler;
private final TikTokLiveEventHandler tikTokEventHandler; private final LiveEventsHandler tikTokEventHandler;
private final LiveClient tikTokLiveClient; private final LiveClient tikTokLiveClient;
public TikTokWebSocketListener(URI serverUri, public TikTokWebSocketListener(URI serverUri,
Map<String, String> httpHeaders, Map<String, String> httpHeaders,
int connectTimeout, int connectTimeout,
TikTokLiveMessageHandler messageHandler, LiveMessagesHandler messageHandler,
TikTokLiveEventHandler tikTokEventHandler, LiveEventsHandler tikTokEventHandler,
LiveClient tikTokLiveClient) { LiveClient tikTokLiveClient) {
super(serverUri, new Draft_6455(), httpHeaders, connectTimeout); super(serverUri, new Draft_6455(), httpHeaders, connectTimeout);
this.messageHandler = messageHandler; this.messageHandler = messageHandler;

View File

@@ -27,13 +27,14 @@ import io.github.jwdeveloper.tiktok.data.events.TikTokConnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData; import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveEventsHandler;
public class TikTokWebSocketOfflineClient implements SocketClient { public class TikTokWebSocketOfflineClient implements SocketClient {
private final TikTokLiveEventHandler handler; private final LiveEventsHandler handler;
private LiveClient liveClient; private LiveClient liveClient;
public TikTokWebSocketOfflineClient(TikTokLiveEventHandler handler) { public TikTokWebSocketOfflineClient(LiveEventsHandler handler) {
this.handler = handler; this.handler = handler;
} }

View File

@@ -22,32 +22,29 @@
*/ */
package io.github.jwdeveloper.tiktok.websocket; package io.github.jwdeveloper.tiktok.websocket;
import io.github.jwdeveloper.tiktok.live.LiveEventsHandler;
import org.java_websocket.WebSocket; import org.java_websocket.WebSocket;
public class TikTokWebSocketPingingTask public class TikTokWebSocketPingingTask {
{
private Thread thread; private Thread thread;
private boolean isRunning = false; private boolean isRunning = false;
private final int MAX_TIMEOUT = 250; private final int MAX_TIMEOUT = 250;
private final int SLEEP_TIME = 500; private final int SLEEP_TIME = 500;
public void run(WebSocket webSocket, long pingTaskTime) public void run(WebSocket webSocket, long pingTaskTime) {
{
stop(); stop();
thread = new Thread(() -> pingTask(webSocket, pingTaskTime), "pinging-task"); thread = new Thread(() -> pingTask(webSocket, pingTaskTime), "pinging-task");
isRunning = true; isRunning = true;
thread.start(); thread.start();
} }
public void stop() public void stop() {
{
if (thread != null) if (thread != null)
thread.interrupt(); thread.interrupt();
isRunning = false; isRunning = false;
} }
private void pingTask(WebSocket webSocket, long pingTaskTime) private void pingTask(WebSocket webSocket, long pingTaskTime) {
{
while (isRunning) { while (isRunning) {
try { try {
if (webSocket.isOpen()) { if (webSocket.isOpen()) {
@@ -55,8 +52,7 @@ public class TikTokWebSocketPingingTask
Thread.sleep(pingTaskTime + (int) (Math.random() * MAX_TIMEOUT)); Thread.sleep(pingTaskTime + (int) (Math.random() * MAX_TIMEOUT));
} else } else
Thread.sleep(SLEEP_TIME); Thread.sleep(SLEEP_TIME);
} } catch (Exception e) {
catch (Exception e) {
//TODO we should display some kind of error message //TODO we should display some kind of error message
isRunning = false; isRunning = false;
} }

View File

@@ -1,55 +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.common;
import java.io.IOException;
import java.util.Base64;
public class TikTokBaseTest
{
public byte[] getFileBytes(String path)
{
try {
var stream = getClass().getClassLoader().getResourceAsStream(path);
var bytes= stream.readAllBytes();
stream.close();
return bytes;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public byte[] getFileBytesUtf(String path)
{
try {
var stream = getClass().getClassLoader().getResourceAsStream(path);
var bytes= stream.readAllBytes();
stream.close();
return Base64.getDecoder().decode(bytes);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,44 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.live.*;
/**
* When the default implementation does not meet your needs,
* you can override it using `customize` method
*/
public class CustomizationExample {
public static void main(String[] args) {
var customEventHandler = new CustomEventsHandler();
var client = TikTokLive.newClient("john")
.configure(liveClientSettings ->
{
liveClientSettings.setFetchGifts(false);
liveClientSettings.setOffline(true);
})
.onError((liveClient, event) ->
{
event.getException().printStackTrace();
})
.customize(container ->
{
//overriding default implementation of LiveEventsHandler, with own one
container.registerSingleton(LiveEventsHandler.class, customEventHandler);
}).build();
client.connect();
client.publishEvent(TikTokGiftEvent.of("rose", 1, 12));
client.publishEvent(TikTokGiftEvent.of("stone", 2, 12));
}
public static class CustomEventsHandler extends TikTokLiveEventHandler {
@Override
public void publish(LiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
System.out.println("Hello from custom events handler: " + tikTokEvent.getClass().getSimpleName());
}
}
}

View File

@@ -426,9 +426,9 @@ Triggered every time gift is sent
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p> <p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
<p>Combo: 4 -> comboState = GiftSendType.Active</p> <p>Combo: 4 -> comboState = GiftSendType.Active</p>
<p>Combo: 8 -> comboState = GiftSendType.Active</p> <p>Combo: 8 -> comboState = GiftSendType.Active</p>
<p>Combo: 12 -> comboState = GiftSendType.Finsihed</p> <p>Combo: 12 -> comboState = GiftSendType.Finished</p>
<p> <p>
Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered Remember if comboState is Finished both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
```java ```java

15
pom.xml
View File

@@ -12,7 +12,7 @@
<module>API</module> <module>API</module>
<module>Client</module> <module>Client</module>
<module>Examples</module> <module>Examples</module>
<module>Tools-ReadmeGenerator</module> <module>tools-readme</module>
<module>extension-recorder</module> <module>extension-recorder</module>
<module>extension-collector</module> <module>extension-collector</module>
@@ -23,7 +23,12 @@
<maven.compiler.target>16</maven.compiler.target> <maven.compiler.target>16</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
@@ -74,6 +79,12 @@
</build> </build>
<dependencies> <dependencies>
<dependency>
<groupId>com.github.jwdeveloper.DepenDance</groupId>
<artifactId>DepenDance-Full</artifactId>
<version>0.0.18-Release</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>

View File

@@ -9,7 +9,7 @@
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>Tools-ReadmeGenerator</artifactId> <artifactId>tools-readme</artifactId>
<repositories> <repositories>
<repository> <repository>
<id>jitpack.io</id> <id>jitpack.io</id>
@@ -23,10 +23,21 @@
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>com.hubspot.jinjava</groupId>
<artifactId>jinjava</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.13.0</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>com.github.jwdeveloper.Descrabble</groupId> <groupId>com.github.jwdeveloper.Descrabble</groupId>
<artifactId>Descrabble-Full</artifactId> <artifactId>Descrabble-Full</artifactId>
<version>0.0.7-Release</version> <version>0.0.11-Release</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>

3
tools-readme/readme.md Normal file
View File

@@ -0,0 +1,3 @@
Generates documentation from template
that can be found under
- `src/main/resources/readme-template.html`

View File

@@ -0,0 +1,17 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.descrabble.api.DescriptionDecorator;
import io.github.jwdeveloper.descrabble.api.elements.Element;
import io.github.jwdeveloper.descrabble.api.elements.ElementFactory;
public class EventsDecorator implements DescriptionDecorator {
@Override
public void decorate(Element root, ElementFactory factory)
{
}
}

View File

@@ -0,0 +1,38 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.descrabble.api.DescriptionGenerator;
import io.github.jwdeveloper.descrabble.framework.Descrabble;
import io.github.jwdeveloper.descrabble.plugin.github.DescrabbleGithub;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
public class Main
{
public static void main(String[] args) throws IOException {
var version = System.getenv("VERSION");
if (version == null || version.equals("")) {
version = "[Replace with current version]";
}
var inputStream = Main.class.getResourceAsStream("/readme-template.html");
var targetFile = new File("temp.file");
FileUtils.copyInputStreamToFile(inputStream, targetFile);
var output = System.getProperty("user.dir");
DescriptionGenerator generator = Descrabble.create()
.withTemplate(targetFile)
.withVariable("version", version)
.withDecorator(new EventsDecorator())
.withPlugin(DescrabbleGithub.plugin("README.md"))
.build();
generator.generate(output);
targetFile.delete();
inputStream.close();
}
}

View File

@@ -0,0 +1,27 @@
package io.github.jwdeveloper.tiktok;
import com.google.common.base.Charsets;
import com.google.common.collect.Maps;
import com.google.common.io.Resources;
import com.hubspot.jinjava.Jinjava;
import java.io.IOException;
import java.util.HashMap;
public class Main2 {
public static void main(String[] args) throws IOException {
var version = System.getenv("VERSION");
if (version == null || version.equals("")) {
version = "[Replace with current version]";
}
var template = Resources.toString(Resources.getResource("my-template.html"), Charsets.UTF_8);
var jinjava = new Jinjava();
var context = new HashMap<String, Object>();
context.put("version", version);
var renderedTemplate = jinjava.render(template, context);
}
}

View File

@@ -51,10 +51,6 @@ public class ReadmeGenerator {
return version == null ? "NOT_FOUND" : version; return version == null ? "NOT_FOUND" : version;
} }
public String getCodeExample(String path) {
var content = FilesUtility.loadFileContent(path);
content = content.substring(content.indexOf("*/") + 2);
return content;
}
} }

View File

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 241 KiB

View File

@@ -405,9 +405,9 @@ TikTokLive.newClient("host-name")
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p> <p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
<p>Combo: 4 -> comboState = GiftSendType.Active</p> <p>Combo: 4 -> comboState = GiftSendType.Active</p>
<p>Combo: 8 -> comboState = GiftSendType.Active</p> <p>Combo: 8 -> comboState = GiftSendType.Active</p>
<p>Combo: 12 -> comboState = GiftSendType.Finsihed</p> <p>Combo: 12 -> comboState = GiftSendType.Finished</p>
<p> <p>
Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered Remember if comboState is Finished both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
```java ```java

View File

@@ -0,0 +1,70 @@
<container>
<image width="15%"
image="https://raw.githubusercontent.com/jwdeveloper/DepenDance/master/Tools-Readme/src/main/resources/logo.svg">
</image>
</container>
<container>
<title>TikTok Live Java</title>
<br>
<i align="center">*❤️❤️🎁 *Connect to TikTok live in 3 lines* 🎁❤️❤️*</i>
<br>
<container>
<image width="20%" image="https://jitpack.io/v/jwdeveloper/DepenDance.svg"
open="https://jitpack.io/#jwdeveloper/DepenDance"></image>
<image image="https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white"
open="https://discord.gg/2hu6fPPeF7"></image>
<image image="https://img.shields.io/badge/java-%23ED8B00.svg?style=for-the-badge&logo=openjdk&logoColor=white"></image>
</container>
</container>
<text>
A Java library inspired by [TikTokLive](https://github.com/isaackogan/TikTokLive) and [TikTokLiveSharp](https://github.com/frankvHoof93/TikTokLiveSharp). Use it to receive live stream events such as comments and gifts in realtime from [TikTok LIVE](https://www.tiktok.com/live) by connecting to TikTok's internal WebCast push service.
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
</text>
<br>
<code language="xml">
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
<artifactId>Client</artifactId>
<version>{{version}}</version>
<scope>compile</scope>
</dependency>
</code>
<br>
<text>Lightweight dependency injection container that is both small and performance efficient</text>
<title>Features</title>
<br>
<text>- [x] Injecting object via constructor</text>
<br>
<text>- [x] Method object providers</text>
<br>
<text>- [x] Class Scanner to avoid manual registration [Scanner](#autoscan)</text>
<br>
<text>- [x] You need to get [List of objects](#lists) in the constructor, no problem</text>
<br>
<text>- [x] Create [object instance](#object-instances) by yourself and register it to container!</text>
<br>
<text>- [x] Object lifetimes [SINGLETON, TRANSIENT] [see](#basic)</text>
<br>
<text>- [x] [Generic types](#generic-types)</text>
<br>
<text>- [x] [Many constructors](#manyconstructors)</text>
<br>
<text>- [x] Highly customizable, adjust container with build in [events](#events) system</text>
<br>
<title>Tutorial</title>

View File

@@ -81,7 +81,8 @@ Do you prefer other programming languages?
## Events ## Events
{{events-content}}
@{events-content}
{{for item of data}} {{for item of data}}
@@ -102,6 +103,5 @@ my name is {{item.name}}
{{listener-content}} {{listener-content}}
``` ```
## Contributing ## Contributing
Your improvements are welcome! Feel free to open an <a href="https://github.com/jwdeveloper/TikTok-Live-Java/issues">issue</a> or <a href="https://github.com/jwdeveloper/TikTok-Live-Java/pulls">pull request</a>. Your improvements are welcome! Feel free to open an <a href="https://github.com/jwdeveloper/TikTok-Live-Java/issues">issue</a> or <a href="https://github.com/jwdeveloper/TikTok-Live-Java/pulls">pull request</a>.