Compare commits

...

47 Commits

Author SHA1 Message Date
David Kohler
4f74a0f1b7 MINOR 2024-06-02 16:09:45 -04:00
GitHub Action
d1eec34fca Update version in pom.xml 2024-06-02 20:07:58 +00:00
David Kohler
82196ef8e3 MINOR: Merge pull request #84 from jwdeveloper/develop-1.6.4
Develop 1.6.4
2024-06-02 16:06:24 -04:00
kohlerpop1
8685d96ccf Moved roomId declaration to RoomInfoEvent as it is always null during onConnecting event!
Made other improvements for readability and altered createdAt field.
2024-06-01 22:36:43 -04:00
kohlerpop1
69f1d5b5c2 Fixed proto file type names, created TikTokEventListenerBase with all events, created ListUser with additional information, and created all events for TikTokLink individual events 2024-06-01 22:18:43 -04:00
kohlerpop1
6f322b2a46 Fixed custom listener manager checks. Previous implementation allowed incorrect parameter types! 2024-05-29 15:38:06 -04:00
kohlerpop1
73c4c09ea1 Moved ActionResult message above content to make it easier to read in json print out!
Added status code 420 for IP cloudflare block
2024-05-29 14:11:27 -04:00
kohlerpop1
95e357af92 Updated HTTP response code messages
General optimization of classes and removal of no longer needed classes
Removed unused imports
2024-05-29 14:00:20 -04:00
Jacek W
6b31ec7d80 Merge pull request #80 from htliang128/master
Update of Socks Proxy adding headers
2024-05-26 22:46:43 +02:00
htliang128
919554bbc8 Update of Socks Proxy adding headers 2024-05-25 12:22:31 +08:00
htliang128
bd0a1f0d01 Update of Socks Proxy adding headers 2024-05-25 12:20:57 +08:00
htliang128
f48479a92c Update of Socks Proxy adding headers 2024-05-25 12:17:46 +08:00
GitHub Action
68a86f3dbd Update version in pom.xml 2024-05-24 01:34:38 +00:00
David Kohler
c3a7a27948 Merge pull request #78 from jwdeveloper/develop-1.6.3
Develop-1.6.3
2024-05-23 21:31:48 -04:00
kohlerpop1
af52e15a45 Removal of shared cookie parameter cookie in TikTokWebSocketClient!
Privatized objects in HttpClientSettings so getters are used!
2024-05-23 21:29:03 -04:00
GitHub Action
5577df7c9c Update version in pom.xml 2024-05-23 22:45:49 +00:00
David Kohler
2c68fe3421 Merge pull request #77 from jwdeveloper/develop-1.6.2
Develop 1.6.2
2024-05-23 18:42:15 -04:00
kohlerpop1
5abfd95c89 Update of Lombok
Fixed headers being passed to Websocket. Huge thanks to @isaackogan - https://github.com/isaackogan
2024-05-23 18:32:55 -04:00
kohlerpop1
5c715bfd52 Changed Picture#Empty to Picture#empty to follow Java standards
Updated descriptions in LiveClientSettings
Added new LiveHttpClient#fetchRoomGiftsData(String room_id) to fetch gifts for this specific room/livestream and altered GiftsDataMapper to reflect the new fetchRoomGiftsData and other TikTokLive client and http client classes
2024-05-13 21:14:03 -04:00
GitHub Action
b153afb332 Update version in pom.xml 2024-05-13 00:55:24 +00:00
David Kohler
d2ea00bcae Merge pull request #72 from jwdeveloper/develop-1.6.1
Develop 1.6.1
2024-05-12 20:52:28 -04:00
kohlerpop1
4297af1349 Simplify LiveDataMapper#map 2024-05-12 20:47:13 -04:00
kohlerpop1
d09c90ef54 Added append live username option to FileStorage and now support connection to 18+ age restricted! 2024-05-10 16:44:42 -04:00
kohlerpop1
9c96c8899a Added option to use File Locking as through testing, some events occur simultaneously causing the file to become overlapped or corrupted. 2024-05-04 15:21:34 -04:00
kohlerpop1
301df6392d More updated to TikTokLinkMicBattleEvent, updated Gift since its no longer enum we do not need to use Unsafe, and added default mappings for WebcastLinkMicBattle and WebcastLinkMicArmies 2024-04-19 13:41:07 -04:00
kohlerpop1
fb9fc04ee5 Revert "More updated to TikTokLinkMicBattleEvent, updated Gift since its no longer enum we do not need to use Unsafe, and added default mappings for WebcastLinkMicBattle and WebcastLinkMicArmies"
This reverts commit 43a8ba4225.
2024-04-19 13:33:49 -04:00
kohlerpop1
43a8ba4225 More updated to TikTokLinkMicBattleEvent, updated Gift since its no longer enum we do not need to use Unsafe, and added default mappings for WebcastLinkMicBattle and WebcastLinkMicArmies 2024-04-19 13:28:10 -04:00
David Kohler
dffccf1f0b Update README.md 2024-04-10 12:08:46 -04:00
GitHub Action
6dcccccb78 Update version in pom.xml 2024-04-10 16:07:17 +00:00
David Kohler
0d467d79c3 Update TikTokGiftEventHandlerTest.java
Fixed minor issue with Client compilation
2024-04-10 12:05:20 -04:00
David Kohler
33c98508c0 MINOR
Merge pull request #70 from jwdeveloper/develop-1.6.0
2024-04-10 12:01:00 -04:00
kohlerpop1
67948b14cc Changed isNotClosing to isOpen because if isOpen is false inside of any of the using methods, it throws an exception. 2024-04-10 11:54:35 -04:00
kohlerpop1
22e11a7822 Removed TikTokRoomInfo.getHostUser() in favor of TikTokRoomInfo.getHost().
Major rework of TikTokLinkMicBattleEvent and proto to support it.
Addition changes to other files to support!
2024-04-09 21:38:04 -04:00
GitHub Action
4545503441 Update version in pom.xml 2024-04-02 02:28:56 +00:00
David Kohler
498d34a90b Merge pull request #69 from jwdeveloper/develop-1.5.4
Changed isNotClosing to isOpen
2024-04-01 22:27:09 -04:00
kohlerpop1
103ed7e3ed Changed isNotClosing to isOpen because if isOpen is false inside of any of the using methods, it throws an exception. 2024-03-31 20:19:24 -04:00
GitHub Action
67e70c34bc Update version in pom.xml 2024-03-03 21:42:11 +00:00
JW
786c24d267 Merge remote-tracking branch 'origin/master' 2024-03-03 22:40:11 +01:00
JW
966d2f65d8 - improve recorder 2024-03-03 22:39:44 +01:00
GitHub Action
7ba7143f5a Update version in pom.xml 2024-03-02 09:57:33 +00:00
JW
92fde03f2b - improve collector 2024-03-02 10:55:44 +01:00
GitHub Action
e058290118 Update version in pom.xml 2024-03-01 23:17:33 +00:00
David Kohler
d25741b229 Merge pull request #67 from jwdeveloper/develop-1.5.1
Fix for mapping of HttpResponse & HttpRequest and more!
2024-03-01 18:15:41 -05:00
kohlerpop1
560a8d7c3b Added IllegalStateException to LiveUserDataMapper to catch getAsJsonObject exception.
Created HttpRequestJsonMapper and HttpResponseJsonMapper for ActionResult gson parser.
2024-03-01 16:08:05 -05:00
GitHub Action
6178bc25cf Update version in pom.xml 2024-03-01 01:54:49 +00:00
Jacek W
48d1138754 MINOR 2024-03-01 02:53:04 +01:00
Jacek W
a5320db820 Merge pull request #63 from jwdeveloper/develop-1.5.0
Develop 1.5.0
2024-03-01 02:51:35 +01:00
101 changed files with 1966 additions and 1944 deletions

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.4.0-Release</version> <version>1.6.4-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>API</artifactId> <artifactId>API</artifactId>

View File

@@ -38,8 +38,7 @@ public class TikTokBarrageEvent extends TikTokHeaderEvent {
private final Picture rightIcon; private final Picture rightIcon;
private final String eventName; private final String eventName;
private final int duration; private final int duration;
private final BarrageParam barrageParam;
private BarrageParam barrageParam;
public TikTokBarrageEvent(WebcastBarrageMessage msg) { public TikTokBarrageEvent(WebcastBarrageMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
@@ -49,6 +48,5 @@ public class TikTokBarrageEvent extends TikTokHeaderEvent {
rightIcon = Picture.map(msg.getRightIcon()); rightIcon = Picture.map(msg.getRightIcon());
duration = msg.getDuration(); duration = msg.getDuration();
barrageParam = BarrageParam.map(msg); barrageParam = BarrageParam.map(msg);
} }
} }

View File

@@ -38,9 +38,9 @@ public class TikTokCaptionEvent extends TikTokHeaderEvent {
String text; String text;
public TikTokCaptionEvent(WebcastCaptionMessage msg) { public TikTokCaptionEvent(WebcastCaptionMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
captionTimeStamp = msg.getTimeStamp(); captionTimeStamp = msg.getTimeStamp();
iSOLanguage = msg.getCaptionData().getLanguage(); iSOLanguage = msg.getCaptionData().getLanguage();
text = msg.getCaptionData().getText(); text = msg.getCaptionData().getText();
} }
} }

View File

@@ -40,7 +40,7 @@ import java.util.List;
public class TikTokCommentEvent extends TikTokHeaderEvent { public class TikTokCommentEvent extends TikTokHeaderEvent {
private final User user; private final User user;
private final String text; private final String text;
private final String getUserLanguage; private final String userLanguage;
private final User mentionedUser; private final User mentionedUser;
private final List<Picture> pictures; private final List<Picture> pictures;
private final boolean visibleToSender; private final boolean visibleToSender;
@@ -50,7 +50,7 @@ public class TikTokCommentEvent extends TikTokHeaderEvent {
user = User.map(msg.getUser(), msg.getUserIdentity()); user = User.map(msg.getUser(), msg.getUserIdentity());
text = msg.getContent(); text = msg.getContent();
visibleToSender = msg.getVisibleToSender(); visibleToSender = msg.getVisibleToSender();
getUserLanguage = msg.getContentLanguage(); userLanguage = msg.getContentLanguage();
mentionedUser = User.map(msg.getAtUser()); mentionedUser = User.map(msg.getAtUser());
pictures = msg.getEmotesListList().stream().map(e -> Picture.map(e.getEmote().getImage())).toList(); pictures = msg.getEmotesListList().stream().map(e -> Picture.map(e.getEmote().getImage())).toList();
} }
@@ -66,4 +66,4 @@ public class TikTokCommentEvent extends TikTokHeaderEvent {
builder.setContent(message); builder.setContent(message);
return new TikTokCommentEvent(builder.build()); return new TikTokCommentEvent(builder.build());
} }
} }

View File

@@ -30,14 +30,10 @@ import lombok.Getter;
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokDetectEvent extends TikTokHeaderEvent { public class TikTokDetectEvent extends TikTokHeaderEvent {
String language; private final String language;
public TikTokDetectEvent(WebcastMsgDetectMessage msg) {
public TikTokDetectEvent(WebcastMsgDetectMessage msg) { super(msg.getCommon());
super(msg.getCommon()); language = msg.getFromRegion();
language = msg.getFromRegion(); }
} }
}

View File

@@ -30,9 +30,11 @@ import lombok.Getter;
* Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic. * 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. * Note that you should wait a little bit before attempting a reconnect to to avoid being rate-limited.
*/ */
@Getter
@EventMeta(eventType = EventType.Control) @EventMeta(eventType = EventType.Control)
public class TikTokDisconnectedEvent extends TikTokLiveClientEvent { public class TikTokDisconnectedEvent extends TikTokLiveClientEvent {
@Getter private final String reason; private final String reason;
public TikTokDisconnectedEvent(String reason) { public TikTokDisconnectedEvent(String reason) {
this.reason = reason.isBlank() ? "None" : reason; this.reason = reason.isBlank() ? "None" : reason;
} }

View File

@@ -36,9 +36,9 @@ import lombok.Value;
@Value @Value
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokEnvelopeEvent extends TikTokHeaderEvent { public class TikTokEnvelopeEvent extends TikTokHeaderEvent {
User user; User user;
public TikTokEnvelopeEvent(WebcastEnvelopeMessage msg) { public TikTokEnvelopeEvent(WebcastEnvelopeMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
user = User.map(msg.getEnvelopeInfo()); user = User.map(msg.getEnvelopeInfo());
} }
} }

View File

@@ -34,9 +34,10 @@ import java.util.List;
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokIMDeleteEvent extends TikTokHeaderEvent { public class TikTokIMDeleteEvent extends TikTokHeaderEvent {
List<Long> userIds; private final List<Long> msgIds, userIds;
public TikTokIMDeleteEvent(WebcastImDeleteMessage msg) { public TikTokIMDeleteEvent(WebcastImDeleteMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
this.msgIds = msg.getDeleteMsgIdsListList();
this.userIds = msg.getDeleteUserIdsListList(); this.userIds = msg.getDeleteUserIdsListList();
} }
} }

View File

@@ -31,10 +31,10 @@ import lombok.Getter;
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokInRoomBannerEvent extends TikTokHeaderEvent { public class TikTokInRoomBannerEvent extends TikTokHeaderEvent {
private final String json; private final String json;
public TikTokInRoomBannerEvent(WebcastInRoomBannerMessage msg) { public TikTokInRoomBannerEvent(WebcastInRoomBannerMessage msg) {
super(msg.getHeader()); super(msg.getHeader());
json = msg.getJson(); json = msg.getJson();
} }
} }

View File

@@ -33,11 +33,7 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokLinkLayerEvent extends TikTokHeaderEvent { public class TikTokLinkLayerEvent extends TikTokHeaderEvent {
public TikTokLinkLayerEvent(WebcastLinkLayerMessage msg) { public TikTokLinkLayerEvent(WebcastLinkLayerMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
} }
}
}

View File

@@ -27,12 +27,12 @@ import io.github.jwdeveloper.tiktok.annotations.EventType;
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.LinkMicArmy; import io.github.jwdeveloper.tiktok.data.models.LinkMicArmy;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.messages.enums.LinkMicBattleStatus;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicArmies; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicArmies;
import lombok.Getter; import lombok.Getter;
import java.util.List; import java.util.List;
/** /**
* Triggered every time a battle participant receives points. Contains the current status of the battle and the army that suported the group. * Triggered every time a battle participant receives points. Contains the current status of the battle and the army that suported the group.
*/ */
@@ -40,8 +40,10 @@ import java.util.List;
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokLinkMicArmiesEvent extends TikTokHeaderEvent { public class TikTokLinkMicArmiesEvent extends TikTokHeaderEvent {
private final Long battleId; private final Long battleId;
/**
private final Integer battleStatus; true if battle is finished otherwise false
*/
private final boolean finished;
private final Picture picture; private final Picture picture;
@@ -52,6 +54,6 @@ public class TikTokLinkMicArmiesEvent extends TikTokHeaderEvent {
battleId = msg.getId(); battleId = msg.getId();
armies = msg.getBattleItemsList().stream().map(LinkMicArmy::new).toList(); armies = msg.getBattleItemsList().stream().map(LinkMicArmy::new).toList();
picture = Picture.map(msg.getImage()); picture = Picture.map(msg.getImage());
battleStatus = msg.getBattleStatus(); finished = msg.getBattleStatus() == LinkMicBattleStatus.ARMY_FINISHED;
} }
} }

View File

@@ -22,29 +22,62 @@
*/ */
package io.github.jwdeveloper.tiktok.data.events; package io.github.jwdeveloper.tiktok.data.events;
import io.github.jwdeveloper.tiktok.annotations.EventMeta; import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.annotations.EventType;
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.LinkMicBattleTeam; import io.github.jwdeveloper.tiktok.data.models.battles.*;
import io.github.jwdeveloper.tiktok.messages.enums.LinkMicBattleStatus;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter; import lombok.*;
import java.util.List; import java.util.*;
/** /**
* Triggered every time a battle starts. * Triggered every time a battle starts & ends
*/ */
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent { public class TikTokLinkMicBattleEvent extends TikTokHeaderEvent
private final Long battleId; {
private final List<LinkMicBattleTeam> team1; private final Long battleId;
private final List<LinkMicBattleTeam> team2; /**
true if battle is finished otherwise false
*/
private final boolean finished;
@Getter(AccessLevel.NONE)
private final boolean oneVsOne;
private final List<Team> teams;
public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) { public TikTokLinkMicBattleEvent(WebcastLinkMicBattle msg) {
super(msg.getCommon()); super(msg.getCommon());
battleId = msg.getId(); battleId = msg.getId();
team1 = msg.getTeams1List().stream().map(LinkMicBattleTeam::new).toList(); finished = msg.getBattleStatus() == LinkMicBattleStatus.BATTLE_FINISHED;
team2 = msg.getTeams2List().stream().map(LinkMicBattleTeam::new).toList(); teams = new ArrayList<>();
} if (msg.getHostTeamCount() == 2) { // 1v1 battle
} teams.add(new Team1v1(msg.getHostTeam(0), msg));
teams.add(new Team1v1(msg.getHostTeam(1), msg));
oneVsOne = true;
} else { // 2v2 battle
if (isFinished()) {
teams.add(new Team2v2(msg.getHostData2V2List().stream().filter(data -> data.getTeamNumber() == 1).findFirst().orElse(null), msg));
teams.add(new Team2v2(msg.getHostData2V2List().stream().filter(data -> data.getTeamNumber() == 2).findFirst().orElse(null), msg));
} else {
teams.add(new Team2v2(msg.getHostTeam(0), msg.getHostTeam(1), msg));
teams.add(new Team2v2(msg.getHostTeam(2), msg.getHostTeam(3), msg));
}
oneVsOne = false;
}
// Info:
// - msg.getDetailsList() & msg.getViewerTeamList() both only have content when battle is finished
// - msg.getDetailsCount() & msg.getViewerTeamCount() always is 2 only when battle is finished
// - msg.getHostTeamCount() always is 2 for 1v1 or 4 for 2v2
}
public boolean is1v1() {
return oneVsOne;
}
public boolean is2v2() {
return !oneVsOne;
}
}

View File

@@ -32,10 +32,8 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokLinkMicMethodEvent extends TikTokHeaderEvent { public class TikTokLinkMicMethodEvent extends TikTokHeaderEvent {
public TikTokLinkMicMethodEvent(WebcastLinkMicMethod msg) { public TikTokLinkMicMethodEvent(WebcastLinkMicMethod msg) {
super(msg.getCommon()); super(msg.getCommon());
} }
}
}

View File

@@ -32,15 +32,14 @@ import lombok.Getter;
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokRankTextEvent extends TikTokHeaderEvent { public class TikTokRankTextEvent extends TikTokHeaderEvent {
private final String eventType; private final String eventType;
private final String label; private final String label;
public TikTokRankTextEvent(WebcastRankTextMessage msg) { public TikTokRankTextEvent(WebcastRankTextMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
var text = Text.map(msg.getSelfGetBadgeMsg()); var text = Text.map(msg.getSelfGetBadgeMsg());
label = text.getPattern(); label = text.getPattern();
eventType = text.getKey(); eventType = text.getKey();
} }
}
}

View File

@@ -33,13 +33,11 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokRankUpdateEvent extends TikTokHeaderEvent { public class TikTokRankUpdateEvent extends TikTokHeaderEvent {
public TikTokRankUpdateEvent(WebcastHourlyRankMessage msg) { public TikTokRankUpdateEvent(WebcastHourlyRankMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
}
} public TikTokRankUpdateEvent(WebcastRankUpdateMessage msg) {
super(msg.getCommon());
public TikTokRankUpdateEvent(WebcastRankUpdateMessage msg) { }
super(msg.getCommon()); }
}
}

View File

@@ -32,25 +32,24 @@ import lombok.Getter;
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokShopEvent extends TikTokHeaderEvent { public class TikTokShopEvent extends TikTokHeaderEvent {
private final String title; private final String title;
private final String price; private final String price;
private final Picture picture; private final Picture picture;
private final String shopUrl; private final String shopUrl;
private final String shopName; private final String shopName;
//Not working //Not working
public TikTokShopEvent(WebcastOecLiveShoppingMessage msg) { public TikTokShopEvent(WebcastOecLiveShoppingMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
var data = msg.getShopData(); var data = msg.getShopData();
title = data.getTitle(); title = data.getTitle();
price = data.getPriceString(); price = data.getPriceString();
picture = new Picture(data.getImageUrl()); picture = new Picture(data.getImageUrl());
shopUrl = data.getShopUrl(); shopUrl = data.getShopUrl();
shopName = data.getShopName(); shopName = data.getShopName();
} }
}
}

View File

@@ -30,12 +30,13 @@ import lombok.*;
/** /**
* Triggered before the connection is established. * Triggered before the connection is established.
*/ */
@Getter
@EventMeta(eventType = EventType.Control) @EventMeta(eventType = EventType.Control)
public class TikTokPreConnectionEvent extends TikTokLiveClientEvent public class TikTokPreConnectionEvent extends TikTokLiveClientEvent
{ {
@Getter private final LiveUserData.Response userData; private final LiveUserData.Response userData;
@Getter private final LiveData.Response roomData; private final LiveData.Response roomData;
@Getter @Setter boolean cancelConnection = false; @Setter boolean cancelConnection = false;
public TikTokPreConnectionEvent(LiveUserData.Response userData, LiveData.Response liveData) { public TikTokPreConnectionEvent(LiveUserData.Response userData, LiveData.Response liveData) {
this.userData = userData; this.userData = userData;

View File

@@ -0,0 +1,45 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkAcceptNoticeEvent extends TikTokLinkEvent {
private final long fromUserId, fromRoomId, toUserId;
public TikTokLinkAcceptNoticeEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasAcceptNoticeContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Accept Notice Content!");
var content = msg.getAcceptNoticeContent();
this.fromUserId = content.getFromUserId();
this.fromRoomId = content.getFromRoomId();
this.toUserId = content.getToUserId();
}
}

View File

@@ -20,18 +20,17 @@
* 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.data.models; package io.github.jwdeveloper.tiktok.data.events.link;
import lombok.Value; import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Value @Getter
public class EnumValue @EventMeta(eventType = EventType.Message)
{ public class TikTokLinkApplyEvent extends TikTokLinkEvent {
public int value;
public String name;
public static EnumValue Map(Enum<?> _enum) public TikTokLinkApplyEvent(WebcastLinkMessage msg) {
{ super(msg);
return new EnumValue(_enum.ordinal() ,_enum.name());
} }
} }

View File

@@ -0,0 +1,46 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkCancelEvent extends TikTokLinkEvent {
private final long fromUserId, toUserId, cancelType, actionId;
public TikTokLinkCancelEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasCancelContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Cancel Content!");
var content = msg.getCancelContent();
this.fromUserId = content.getFromUserId();
this.toUserId = content.getToUserId();
this.cancelType = content.getCancelType();
this.actionId = content.getActionId();
}
}

View File

@@ -20,22 +20,20 @@
* 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.data.models; package io.github.jwdeveloper.tiktok.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
import io.github.jwdeveloper.tiktok.data.models.users.User; @Getter
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle; @EventMeta(eventType = EventType.Message)
import lombok.Value; public class TikTokLinkCloseEvent extends TikTokLinkEvent {
import java.util.List; public TikTokLinkCloseEvent(WebcastLinkMessage msg) {
super(msg);
@Value // if (!msg.hasCloseContent())
public class LinkMicBattleTeam { // throw new IllegalArgumentException("Expected WebcastLinkMessage with Close Content!");
Long teamId; // Proto Empty
List<User> users;
public LinkMicBattleTeam(WebcastLinkMicBattle.LinkMicBattleTeam team) {
this.teamId = team.getId();
this.users = team.getUsersList().stream().map(User::new).toList();
} }
} }

View File

@@ -0,0 +1,39 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkCohostListChangeEvent extends TikTokLinkEvent {
public TikTokLinkCohostListChangeEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasCohostListChangeContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Cohost List Change Content!");
// Proto Empty
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkCreateEvent extends TikTokLinkEvent {
private final long hostId, roomId, linkType;
public TikTokLinkCreateEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasCreateContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Create Content!");
var content = msg.getCreateContent();
this.hostId = content.getOwnerId();
this.roomId = content.getOwnerRoomId();
this.linkType = content.getLinkType();
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.users.ListUser;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
import java.util.List;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkEnterEvent extends TikTokLinkEvent {
private final List<ListUser> listUsers;
private final int anchorMultiLiveEnum;
public TikTokLinkEnterEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasEnterContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Enter Content!");
var content = msg.getEnterContent();
this.listUsers = content.getLinkedUsersListList().stream().map(ListUser::map).toList();
this.anchorMultiLiveEnum = content.getAnchorMultiLiveEnum();
}
}

View File

@@ -20,24 +20,24 @@
* 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.data.events; package io.github.jwdeveloper.tiktok.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.EventMeta; import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.annotations.EventType;
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.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter; import lombok.Getter;
import java.util.List;
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokLinkEvent extends TikTokHeaderEvent { public class TikTokLinkEvent extends TikTokHeaderEvent {
private final String extra, transferExtra;
private final long expireTimestamp;
public TikTokLinkEvent(WebcastLinkMessage msg) { public TikTokLinkEvent(WebcastLinkMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
this.extra = msg.getExtra();
this.expireTimestamp = msg.getExpireTimestamp();
this.transferExtra = msg.getTransferExtra();
} }
} }

View File

@@ -0,0 +1,46 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkInviteEvent extends TikTokLinkEvent {
private final long roomId;
private final User inviter;
public TikTokLinkInviteEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasInviteContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Invite Content!");
var content = msg.getInviteContent();
this.roomId = content.getFromRoomId();
this.inviter = User.map(content.getFromUser());
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkKickOutEvent extends TikTokLinkEvent {
private final long fromUserId;
private final KickOutReason kickOutReason;
public TikTokLinkKickOutEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasKickOutContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Kick Out Content!");
var content = msg.getKickOutContent();
this.fromUserId = content.getFromUserId();
this.kickOutReason = KickOutReason.values()[content.getKickoutReasonValue()];
}
public enum KickOutReason {
KICKOUT_REASON_UNKNOWN,
KICKOUT_REASON_FIRST_FRAME_TIMEOUT,
KICKOUT_REASON_BY_HOST,
KICKOUT_REASON_RTC_LOST_CONNECTION,
KICKOUT_REASON_BY_PUNISH,
KICKOUT_REASON_BY_ADMIN,
KICKOUT_REASON_HOST_REMOVE_ALL_GUESTS
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkLeaveEvent extends TikTokLinkEvent {
private final long userId, sendLeaveUid, leaveReason;
private final String linkmicIdStr;
public TikTokLinkLeaveEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasLeaveContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Leave Content!");
var content = msg.getLeaveContent();
this.userId = content.getUserId();
this.linkmicIdStr = content.getLinkmicIdStr();
this.sendLeaveUid = content.getSendLeaveUid();
this.leaveReason = content.getLeaveReason();
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkLinkedListChangeEvent extends TikTokLinkEvent {
public TikTokLinkLinkedListChangeEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasLinkedListChangeContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Linked List Change Content!");
// Proto Empty
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.users.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
import java.util.List;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkListChangeEvent extends TikTokLinkEvent {
private final List<ListUser> linkedUsers, appliedUsers, connectingUsers;
public TikTokLinkListChangeEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasListChangeContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with List Change Content!");
var content = msg.getListChangeContent();
this.linkedUsers = content.getLinkedUsersList().stream().map(ListUser::map).toList();
this.appliedUsers = content.getAppliedUsersList().stream().map(ListUser::map).toList();
this.connectingUsers = content.getConnectingUsersList().stream().map(ListUser::map).toList();
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkMediaChangeEvent extends TikTokLinkEvent {
private final long op, toUserId, anchorId, roomId, changeScene;
public TikTokLinkMediaChangeEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasMediaChangeContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Media Change Content!");
var content = msg.getMediaChangeContent();
this.op = content.getOp();
this.toUserId = content.getToUserId();
this.anchorId = content.getAnchorId();
this.roomId = content.getRoomId();
this.changeScene = content.getChangeScene();
}
}

View File

@@ -20,24 +20,20 @@
* 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.data.events; package io.github.jwdeveloper.tiktok.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.EventMeta; import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.annotations.EventType; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent; import lombok.Getter;
import io.github.jwdeveloper.tiktok.data.models.users.User; @Getter
import lombok.Data;
@Data
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class CustomEvent extends TikTokHeaderEvent { public class TikTokLinkMicIdxUpdateEvent extends TikTokLinkEvent {
private final User user;
private final String title;
public CustomEvent(User user, String title) { public TikTokLinkMicIdxUpdateEvent(WebcastLinkMessage msg) {
this.user = user; super(msg);
this.title = title; // if (!msg.hasMicIdxUpdateContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Mic Idx Update Content!");
// Proto Empty
} }
} }

View File

@@ -0,0 +1,44 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkMuteEvent extends TikTokLinkEvent {
private final long userId, status;
public TikTokLinkMuteEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasMuteContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Mute Content!");
var content = msg.getMuteContent();
this.userId = content.getUserId();
this.status = content.getStatus();
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkRandomMatchEvent extends TikTokLinkEvent {
private final User user;
private final long roomId, inviteType, innerChannelId;
private final String matchId;
public TikTokLinkRandomMatchEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasRandomMatchContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Random Match Content!");
var content = msg.getRandomMatchContent();
this.user = User.map(content.getUser());
this.roomId = content.getRoomId();
this.inviteType = content.getInviteType();
this.matchId = content.getMatchId();
this.innerChannelId = content.getInnerChannelId();
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkReplyEvent extends TikTokLinkEvent {
private final long roomId;
private final User fromUser, toUser;
public TikTokLinkReplyEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasReplyContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Reply Content!");
var content = msg.getReplyContent();
this.roomId = content.getFromRoomId();
this.fromUser = User.map(content.getFromUser());
this.toUser = User.map(content.getToUser());
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkSysKickOutEvent extends TikTokLinkEvent {
private final long userId;
private final String linkmicIdStr;
public TikTokLinkSysKickOutEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasSysKickOutContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Sys Kick Out Content!");
var content = msg.getSysKickOutContent();
this.userId = content.getUserId();
this.linkmicIdStr = content.getLinkmicIdStr();
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkUpdateUserEvent extends TikTokLinkEvent {
private final long fromUserId, toUserId;
public TikTokLinkUpdateUserEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasUpdateUserContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with Update User Content!");
var content = msg.getUpdateUserContent();
this.fromUserId = content.getFromUserId();
this.toUserId = content.getToUserId();
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkUpdateUserSettingEvent extends TikTokLinkEvent {
public TikTokLinkUpdateUserSettingEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasUpdateUserSettingContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Update User Setting Content!");
// Proto Empty
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.data.models.Text;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkUserToastEvent extends TikTokLinkEvent {
private final long userId, roomId;
private final Text displayText;
public TikTokLinkUserToastEvent(WebcastLinkMessage msg) {
super(msg);
if (!msg.hasUserToastContent())
throw new IllegalArgumentException("Expected WebcastLinkMessage with User Toast Content!");
var content = msg.getUserToastContent();
this.userId = content.getUserId();
this.roomId = content.getRoomId();
this.displayText = Text.map(content.getDisplayText());
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.data.events.link;
import io.github.jwdeveloper.tiktok.annotations.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import lombok.Getter;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkWaitListChangeEvent extends TikTokLinkEvent {
public TikTokLinkWaitListChangeEvent(WebcastLinkMessage msg) {
super(msg);
// if (!msg.hasWaitingListChangeContent())
// throw new IllegalArgumentException("Expected WebcastLinkMessage with Waiting List Change Content!");
// Proto Empty
}
}

View File

@@ -30,7 +30,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/* /**
Triggered when LiveRoomInfo got updated such as likes, viewers, ranking .... Triggered when LiveRoomInfo got updated such as likes, viewers, ranking ....
*/ */
@Getter @Getter
@@ -39,4 +39,4 @@ Triggered when LiveRoomInfo got updated such as likes, viewers, ranking ....
public class TikTokRoomInfoEvent extends TikTokEvent public class TikTokRoomInfoEvent extends TikTokEvent
{ {
LiveRoomInfo roomInfo; LiveRoomInfo roomInfo;
} }

View File

@@ -33,15 +33,13 @@ import lombok.Getter;
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokRoomPinEvent extends TikTokHeaderEvent public class TikTokRoomPinEvent extends TikTokHeaderEvent
{ {
private final TikTokCommentEvent pinnedMessage;
private final long timestamp;
private TikTokCommentEvent pinnedMessage; public TikTokRoomPinEvent(WebcastRoomPinMessage msg, TikTokCommentEvent commentEvent)
private long timestamp; {
super(msg.getCommon());
public TikTokRoomPinEvent(WebcastRoomPinMessage msg, TikTokCommentEvent commentEvent) this.timestamp = msg.getTimestamp();
{ this.pinnedMessage = commentEvent;
super(msg.getCommon()); }
this.timestamp = msg.getTimestamp(); }
this.pinnedMessage = commentEvent;
}
}

View File

@@ -24,10 +24,8 @@ package io.github.jwdeveloper.tiktok.data.events.social;
import io.github.jwdeveloper.tiktok.annotations.EventMeta; 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.TikTokSubscribeEvent;
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.users.User; import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import lombok.Value; import lombok.Value;
@@ -38,21 +36,21 @@ import lombok.Value;
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokFollowEvent extends TikTokHeaderEvent public class TikTokFollowEvent extends TikTokHeaderEvent
{ {
User user; User user;
int totalFollowers; int totalFollowers;
public TikTokFollowEvent(WebcastSocialMessage msg) { public TikTokFollowEvent(WebcastSocialMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
user = User.map(msg.getUser()); user = User.map(msg.getUser());
totalFollowers = msg.getFollowCount(); totalFollowers = msg.getFollowCount();
} }
public static TikTokFollowEvent of(String userName) public static TikTokFollowEvent of(String userName)
{ {
return new TikTokFollowEvent(WebcastSocialMessage.newBuilder() return new TikTokFollowEvent(WebcastSocialMessage.newBuilder()
.setUser(io.github.jwdeveloper.tiktok.messages.data.User.newBuilder() .setUser(io.github.jwdeveloper.tiktok.messages.data.User.newBuilder()
.setNickname(userName) .setNickname(userName)
.build()) .build())
.build()); .build());
} }
} }

View File

@@ -35,19 +35,18 @@ import lombok.Getter;
@Getter @Getter
@EventMeta(eventType = EventType.Message) @EventMeta(eventType = EventType.Message)
public class TikTokShareEvent extends TikTokHeaderEvent { public class TikTokShareEvent extends TikTokHeaderEvent {
private final User user; private final User user;
private final int totalShares; private final int totalShares;
public TikTokShareEvent(WebcastSocialMessage msg, Integer amount) { public TikTokShareEvent(WebcastSocialMessage msg, Integer amount) {
super(msg.getCommon()); super(msg.getCommon());
user = User.map(msg.getUser()); user = User.map(msg.getUser());
this.totalShares = amount; this.totalShares = amount;
} }
public TikTokShareEvent(WebcastSocialMessage msg) { public TikTokShareEvent(WebcastSocialMessage msg) {
super(msg.getCommon()); super(msg.getCommon());
user = User.map(msg.getUser()); user = User.map(msg.getUser());
totalShares = 1; totalShares = 1;
} }
}
}

View File

@@ -46,4 +46,4 @@ public class LinkMicArmy {
List<User> Users; List<User> Users;
Integer Points; Integer Points;
} }
} }

View File

@@ -44,11 +44,11 @@ public class Picture {
} }
public static Picture map(io.github.jwdeveloper.tiktok.messages.data.Image profilePicture) { public static Picture map(io.github.jwdeveloper.tiktok.messages.data.Image profilePicture) {
var index = profilePicture.getUrlListCount() - 1; var index = profilePicture.getUrlCount() - 1;
if (index < 0) { if (index < 0) {
return new Picture(""); return new Picture("");
} }
var url = profilePicture.getUrlList(index); var url = profilePicture.getUrl(index);
return new Picture(url); return new Picture(url);
} }
@@ -93,7 +93,7 @@ public class Picture {
} }
} }
public static Picture Empty() { public static Picture empty() {
return new Picture(""); return new Picture("");
} }

View File

@@ -0,0 +1,47 @@
package io.github.jwdeveloper.tiktok.data.models.battles;
public abstract class Team {
/**
* Provides a check for verifying if this team represents a 1v1 Team.
* @return true if this team is of type {@link Team1v1}, false otherwise.
*/
public boolean is1v1Team() {
return this instanceof Team1v1;
}
/**
* Provides a check for verifying if this team represents a 1v1 Team.
* @return true if this team is of type {@link Team1v1}, false otherwise.
*/
public boolean is2v2Team() {
return this instanceof Team2v2;
}
/**
* Convenience method to get this team as a {@link Team1v1}. If this team is of some
* other type, an {@link IllegalStateException} will result. Hence it is best to use this method
* after ensuring that this element is of the desired type by calling {@link #is1v1Team()} first.
*
* @return this team as a {@link Team1v1}.
* @throws IllegalStateException if this team is of another type.
*/
public Team1v1 getAs1v1Team() {
if (is1v1Team())
return (Team1v1) this;
throw new IllegalStateException("Not a 1v1Team: " + this);
}
/**
* Convenience method to get this team as a {@link Team2v2}. If this team is of some
* other type, an {@link IllegalStateException} will result. Hence it is best to use this method
* after ensuring that this element is of the desired type by calling {@link #is2v2Team()} first.
*
* @return this team as a {@link Team2v2}.
* @throws IllegalStateException if this team is of another type.
*/
public Team2v2 getAs2v2Team() {
if (is2v2Team())
return (Team2v2) this;
throw new IllegalStateException("Not a 2v2Team: " + this);
}
}

View File

@@ -0,0 +1,26 @@
package io.github.jwdeveloper.tiktok.data.models.battles;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter;
import java.util.*;
@Getter
public class Team1v1 extends Team
{
/** Value >= 0 when finished otherwise -1 */
private final int totalPoints;
private final int winStreak;
private final User host;
private final List<Viewer> viewers;
public Team1v1(WebcastLinkMicBattle.LinkMicBattleHost hostTeam, WebcastLinkMicBattle msg) {
long hostId = hostTeam.getId();
this.winStreak = msg.getTeamDataList().stream().filter(data -> data.getTeamId() == hostId).map(data -> data.getData().getWinStreak()).findFirst().orElse(-1);
this.totalPoints = msg.getDetailsList().stream().filter(dets -> dets.getId() == hostId).map(dets -> dets.getSummary().getPoints()).findFirst().orElse(-1);
this.host = new User(hostTeam.getHostGroup(0).getHost(0));
this.viewers = msg.getViewerTeamList().stream().filter(team -> team.getId() == hostId).findFirst().map(topViewers ->
topViewers.getViewerGroup(0).getViewerList().stream().map(Viewer::new).toList()).orElseGet(ArrayList::new);
}
}

View File

@@ -0,0 +1,31 @@
package io.github.jwdeveloper.tiktok.data.models.battles;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter;
import java.util.*;
@Getter
public class Team2v2 extends Team {
/** Value >= 0 when finished otherwise -1 */
private final int totalPoints;
private final List<User> hosts;
private final List<Viewer> viewers;
public Team2v2(WebcastLinkMicBattle.LinkMicBattleHost hostTeam1, WebcastLinkMicBattle.LinkMicBattleHost hostTeam2, WebcastLinkMicBattle msg) {
this.totalPoints = -1;
this.hosts = List.of(new User(hostTeam1.getHostGroup(0).getHost(0)), new User(hostTeam2.getHostGroup(0).getHost(0)));
this.viewers = new ArrayList<>();
}
public Team2v2(WebcastLinkMicBattle.Host2v2Data hd, WebcastLinkMicBattle msg) {
this.totalPoints = hd.getTotalPoints();
var host = new User(msg.getHostTeamList().stream().filter(data -> data.getId() == hd.getHostdata(0).getHostId()).findFirst().orElseThrow().getHostGroup(0).getHost(0));
var cohost = new User(msg.getHostTeamList().stream().filter(data -> data.getId() == hd.getHostdata(1).getHostId()).findFirst().orElseThrow().getHostGroup(0).getHost(0));
this.hosts = List.of(host, cohost);
this.viewers = msg.getViewerTeamList().stream().filter(team -> team.getId() == host.getId() || team.getId() == cohost.getId()).findFirst().map(topViewers ->
topViewers.getViewerGroup(0).getViewerList().stream().map(Viewer::new).toList()).orElseGet(ArrayList::new);
}
}

View File

@@ -0,0 +1,17 @@
package io.github.jwdeveloper.tiktok.data.models.battles;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMicBattle;
import lombok.Getter;
@Getter
public class Viewer {
private final User user;
private final int points;
public Viewer(WebcastLinkMicBattle.LinkMicBattleTopViewers.TopViewerGroup.TopViewer topViewer) {
this.user = new User(topViewer.getId(), null, topViewer.getProfileId(), Picture.map(topViewer.getImages(0)));
this.points = topViewer.getPoints();
}
}

View File

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

View File

@@ -22,7 +22,6 @@
*/ */
package io.github.jwdeveloper.tiktok.data.models.gifts; package io.github.jwdeveloper.tiktok.data.models.gifts;
//TODO it should be called GiftComboStateType
public enum GiftComboStateType { public enum GiftComboStateType {
Finished, Finished,
Begin, Begin,

View File

@@ -0,0 +1,34 @@
package io.github.jwdeveloper.tiktok.data.models.users;
import lombok.Getter;
@Getter
public class ListUser
{
private final User user;
private final LinkType linkType;
private final long linkMicId, linkStatus, modifyTime, linkerId;
private final int userPosition, silenceStatus, roleType;
public ListUser(io.github.jwdeveloper.tiktok.messages.data.ListUser listUser) {
this.user = User.map(listUser.getUser());
this.linkMicId = listUser.getLinkmicId();
this.linkStatus = listUser.getLinkStatus();
this.linkType = LinkType.values()[listUser.getLinkTypeValue()];
this.userPosition = listUser.getUserPosition();
this.silenceStatus = listUser.getSilenceStatus();
this.modifyTime = listUser.getModifyTime();
this.linkerId = listUser.getLinkerId();
this.roleType = listUser.getRoleType();
}
public static ListUser map(io.github.jwdeveloper.tiktok.messages.data.ListUser listUser) {
return new ListUser(listUser);
}
public enum LinkType {
UNKNOWN,
AUDIO,
VIDEO
}
}

View File

@@ -24,7 +24,7 @@ package io.github.jwdeveloper.tiktok.data.models.users;
import io.github.jwdeveloper.tiktok.data.models.badges.Badge; 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.messages.webcast.WebcastEnvelopeMessage; import io.github.jwdeveloper.tiktok.messages.webcast.*;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
@@ -136,6 +136,14 @@ public class User {
this.picture = picture; this.picture = picture;
} }
public User(long id, String name, String profileId, Picture picture) {
this(id, name, profileId, picture, 0, 0, List.of(Badge.empty()));
}
public User(WebcastLinkMicBattle.LinkMicBattleHost.HostGroup.Host host) {
this(host.getId(), host.getName(), host.getProfileId(), Picture.map(host.getImages(0)));
}
public User(io.github.jwdeveloper.tiktok.messages.data.User user) { public User(io.github.jwdeveloper.tiktok.messages.data.User user) {
this(user.getId(), user.getDisplayId(), Picture.map(user.getAvatarThumb())); this(user.getId(), user.getDisplayId(), Picture.map(user.getAvatarThumb()));
profileName = user.getNickname(); profileName = user.getNickname();
@@ -159,10 +167,9 @@ public class User {
} }
} }
public static User EMPTY = new User(0L, public static User EMPTY = new User(0L,
"", "",
Picture.Empty(), Picture.empty(),
0, 0,
0, 0,
List.of(Badge.empty())); List.of(Badge.empty()));
@@ -209,4 +216,18 @@ public class User {
0, 0,
List.of(Badge.empty())); List.of(Badge.empty()));
} }
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + "'" +
", profileName='" + profileName + "'" +
", picture=" + picture +
", following=" + following +
", followers=" + followers +
", badges=" + badges +
", attributes=" + attributes +
"}";
}
} }

View File

@@ -23,20 +23,12 @@
package io.github.jwdeveloper.tiktok.data.requests; package io.github.jwdeveloper.tiktok.data.requests;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift; import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import lombok.AllArgsConstructor; import lombok.*;
import lombok.Data;
import lombok.Getter;
import java.util.List; import java.util.List;
public class GiftsData public class GiftsData
{ {
@Getter
public final class Request
{
}
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public static final class Response public static final class Response
@@ -44,5 +36,4 @@ public class GiftsData
private String json; private String json;
private List<Gift> gifts; private List<Gift> gifts;
} }
}
}

View File

@@ -34,30 +34,24 @@ import java.util.TreeMap;
import java.util.function.Consumer; import java.util.function.Consumer;
@Getter
public class HttpClientSettings { public class HttpClientSettings {
@Getter private final Map<String, Object> params;
final Map<String, Object> params;
@Getter private final Map<String, String> headers;
final Map<String, String> headers;
@Getter private final Map<String, String> cookies;
final Map<String, String> cookies;
@Getter
@Setter
ProxyClientSettings proxyClientSettings;
@Getter
Consumer<HttpClient.Builder> onClientCreating;
@Getter
Consumer<HttpRequest.Builder> onRequestCreating;
@Setter @Setter
@Getter private ProxyClientSettings proxyClientSettings;
Duration timeout;
private Consumer<HttpClient.Builder> onClientCreating;
private Consumer<HttpRequest.Builder> onRequestCreating;
@Setter
private Duration timeout;
public HttpClientSettings() { public HttpClientSettings() {
this.params = new TreeMap<>(); this.params = new TreeMap<>();
@@ -65,10 +59,8 @@ public class HttpClientSettings {
this.cookies = new HashMap<>(); this.cookies = new HashMap<>();
this.timeout = Duration.ofSeconds(2); this.timeout = Duration.ofSeconds(2);
this.proxyClientSettings = new ProxyClientSettings(); this.proxyClientSettings = new ProxyClientSettings();
this.onClientCreating = (x) -> { this.onClientCreating = (x) -> {};
}; this.onRequestCreating = (x) -> {};
this.onRequestCreating = (x) -> {
};
} }
/** /**

View File

@@ -33,20 +33,15 @@ import java.util.logging.Level;
@Data @Data
public class LiveClientSettings { public class LiveClientSettings {
/** /**
* TODO: give better description * Sets client to offline mode, prohibits connection to TikTok servers
* <p> * @apiNote Useful when testing client with custom events
* sets client in the offline mode, so it do not connects to TikTok servers
* it makes sense to use it when you are testing client with your custom events
*/ */
private boolean offline; private boolean offline;
/** /**
* TODO: give better description * Fetch and download gifts data before TikTokLive starts
* <p> * @apiNote If `false`, client.giftManager() does not contain initial gifts
* Determines if gifts data is downloaded before TikTokLive starts,
* when `false` then client.giftManager() does not contain initial gifts
*/ */
private boolean fetchGifts = true; private boolean fetchGifts = true;
@@ -91,6 +86,9 @@ public class LiveClientSettings {
*/ */
private long pingInterval = 5000; private long pingInterval = 5000;
/** Throw an exception on 18+ Age Restriction */
private boolean throwOnAgeRestriction;
/** /**
* Optional: Sometimes not every messages from chat are send to TikTokLiveJava to fix this issue you can set sessionId * Optional: Sometimes not every messages from chat are send to TikTokLiveJava to fix this issue you can set sessionId
* @see <a href="https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages">Documentation: How to obtain sessionId</a> * @see <a href="https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages">Documentation: How to obtain sessionId</a>
@@ -180,6 +178,4 @@ public class LiveClientSettings {
headers.put("Accept-Language", "en-US,en; q=0.9"); headers.put("Accept-Language", "en-US,en; q=0.9");
return headers; return headers;
} }
} }

View File

@@ -30,10 +30,14 @@ import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
public interface LiveHttpClient public interface LiveHttpClient
{ {
/** /**
* @return list of gifts that are available in your country * @return {@link GiftsData.Response} list of gifts that are compiled and available on github
*/ */
GiftsData.Response fetchGiftsData(); GiftsData.Response fetchGiftsData();
/**
* @return {@link GiftsData.Response} list of gifts that are available in your region / livestream
*/
GiftsData.Response fetchRoomGiftsData(String room_id);
/** /**
* Returns information about user that is having a livestream * Returns information about user that is having a livestream

View File

@@ -22,53 +22,52 @@
*/ */
package io.github.jwdeveloper.tiktok.listener; package io.github.jwdeveloper.tiktok.listener;
import io.github.jwdeveloper.tiktok.live.LiveClient;
/** /**
* * ListenersManager
* @see ListenersManager * <p>
*
* TikTokEventListener is an alternative way of handing TikTok events. * TikTokEventListener is an alternative way of handing TikTok events.
* <p>
* {@code TikTokLive.newClient("someuser").addListener(listener);}
* <p>
* After registertion, all listeners are kept in Listener manager - {@link LiveClient#getListenersManager()}
* <p>
* Method in TikTokEventListener should meet requirements below to be detected
* <p>- @TikTokEventObserver annotation
* <p>- 2 parameters of (LiveClient, Class extending TikTokEvent)
* <pre>
* {@code
* public static class CustomListener implements TikTokEventListener
* {
* @TikTokEventObserver
* public void onError(LiveClient liveClient, TikTokErrorEvent event)
* {
* System.out.println(event.getException().getMessage());
* }
* *
* TikTokLive.newClient("someuser").addListener(listener) * @TikTokEventObserver
* public void onCommentMessage(LiveClient liveClient, TikTokCommentEvent event)
* {
* System.out.println(event.getText());
* }
* *
* After registertion all listeners are kept in Listener manager * @TikTokEventObserver
* that could be obtained by client.getListenerManager(); * public void onGiftMessage(LiveClient liveClient, TikTokGiftMessageEvent event)
* * {
* Method in TikTokEventListener should meet 4 requirements to be detected * System.out.println(event.getGift().getDescription());
* - must have @TikTokEventHandler annotation * }
* - must have 2 parameters
* - first parameter must be LiveClient
* - second must be class that extending TikTokEvent
*
* public static class CustomListener implements TikTokEventListener
* {
* @TikTokEventHandler
* public void onError(LiveClient liveClient, TikTokErrorEvent event)
* {
* System.out.println(event.getException().getMessage());
* }
*
* @TikTokEventHandler
* public void onCommentMessage(LiveClient liveClient, TikTokCommentEvent event)
* {
* System.out.println(event.getText());
* }
*
* @TikTokEventHandler
* public void onGiftMessage(LiveClient liveClient, TikTokGiftMessageEvent event)
* {
* System.out.println(event.getGift().getDescription());
* }
*
* @TikTokEventHandler
* public void onAnyEvent(LiveClient liveClient, TikTokEvent event)
* {
* System.out.println(event.getClass().getSimpleName());
* }
* }
* *
* @TikTokEventObserver
* public void onAnyEvent(LiveClient liveClient, TikTokEvent event)
* {
* System.out.println(event.getClass().getSimpleName());
* }
* }
* }
* </pre>
*/ */
public interface TikTokEventListener public interface TikTokEventListener
{ {
} }

View File

@@ -0,0 +1,134 @@
package io.github.jwdeveloper.tiktok.listener;
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.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.live.LiveClient;
public abstract class TikTokEventListenerBase implements TikTokEventListener
{
public void onUnhandledSocial(LiveClient client, TikTokUnhandledSocialEvent event) {}
public void onChest(LiveClient client, TikTokChestEvent event) {}
public void onLinkMicFanTicket(LiveClient client, TikTokLinkMicFanTicketEvent event) {}
public void onEnvelope(LiveClient client, TikTokEnvelopeEvent event) {}
public void onShop(LiveClient client, TikTokShopEvent event) {}
public void onDetect(LiveClient client, TikTokDetectEvent event) {}
public void onLinkLayer(LiveClient client, TikTokLinkLayerEvent event) {}
public void onConnected(LiveClient client, TikTokConnectedEvent event) {}
public void onPreConnection(LiveClient client, TikTokPreConnectionEvent event) {}
public void onCaption(LiveClient client, TikTokCaptionEvent event) {}
public void onQuestion(LiveClient client, TikTokQuestionEvent event) {}
public void onRoomPin(LiveClient client, TikTokRoomPinEvent event) {}
public void onRoomInfo(LiveClient client, TikTokRoomInfoEvent event) {}
public void onLivePaused(LiveClient client, TikTokLivePausedEvent event) {}
public void onLiveUnpaused(LiveClient client, TikTokLiveUnpausedEvent event) {}
public void onLike(LiveClient client, TikTokLikeEvent event) {}
public void onLink(LiveClient client, TikTokLinkEvent event) {}
public void onLinkInvite(LiveClient client, TikTokLinkInviteEvent event) {}
public void onLinkReply(LiveClient client, TikTokLinkReplyEvent event) {}
public void onLinkCreate(LiveClient client, TikTokLinkCreateEvent event) {}
public void onLinkClose(LiveClient client, TikTokLinkCloseEvent event) {}
public void onLinkEnter(LiveClient client, TikTokLinkEnterEvent event) {}
public void onLinkLeave(LiveClient client, TikTokLinkLeaveEvent event) {}
public void onLinkCancel(LiveClient client, TikTokLinkCancelEvent event) {}
public void onLinkKickOut(LiveClient client, TikTokLinkKickOutEvent event) {}
public void onLinkLinkedListChange(LiveClient client, TikTokLinkLinkedListChangeEvent event) {}
public void onLinkUpdateUser(LiveClient client, TikTokLinkUpdateUserEvent event) {}
public void onLinkWaitListChange(LiveClient client, TikTokLinkWaitListChangeEvent event) {}
public void onLinkMute(LiveClient client, TikTokLinkMuteEvent event) {}
public void onLinkRandomMatch(LiveClient client, TikTokLinkRandomMatchEvent event) {}
public void onLinkUpdateUserSettings(LiveClient client, TikTokLinkUpdateUserSettingEvent event) {}
public void onLinkMicIdxUpdate(LiveClient client, TikTokLinkMicIdxUpdateEvent event) {}
public void onLinkListChange(LiveClient client, TikTokLinkListChangeEvent event) {}
public void onLinkCohostListChange(LiveClient client, TikTokLinkCohostListChangeEvent event) {}
public void onLinkMediaChange(LiveClient client, TikTokLinkMediaChangeEvent event) {}
public void onLinkAcceptNotice(LiveClient client, TikTokLinkAcceptNoticeEvent event) {}
public void onLinkSysKickOut(LiveClient client, TikTokLinkSysKickOutEvent event) {}
public void onLinkUserToast(LiveClient client, TikTokLinkUserToastEvent event) {}
public void onBarrage(LiveClient client, TikTokBarrageEvent event) {}
public void onGift(LiveClient client, TikTokGiftEvent event) {}
public void onGiftCombo(LiveClient client, TikTokGiftComboEvent event) {}
public void onLinkMicArmies(LiveClient client, TikTokLinkMicArmiesEvent event) {}
public void onEmote(LiveClient client, TikTokEmoteEvent event) {}
public void onUnauthorizedMember(LiveClient client, TikTokUnauthorizedMemberEvent event) {}
public void onInRoomBanner(LiveClient client, TikTokInRoomBannerEvent event) {}
public void onLinkMicMethod(LiveClient client, TikTokLinkMicMethodEvent event) {}
public void onSubscribe(LiveClient client, TikTokSubscribeEvent event) {}
public void onPoll(LiveClient client, TikTokPollEvent event) {}
public void onFollow(LiveClient client, TikTokFollowEvent event) {}
public void onComment(LiveClient client, TikTokCommentEvent event) {}
public void onHttpResponse(LiveClient client, TikTokHttpResponseEvent action) {}
public void onGoalUpdate(LiveClient client, TikTokGoalUpdateEvent event) {}
public void onRankUpdate(LiveClient client, TikTokRankUpdateEvent event) {}
public void onIMDelete(LiveClient client, TikTokIMDeleteEvent event) {}
public void onLiveEnded(LiveClient client, TikTokLiveEndedEvent event) {}
public void onError(LiveClient client, TikTokErrorEvent event) {}
public void onJoin(LiveClient client, TikTokJoinEvent event) {}
public void onRankText(LiveClient client, TikTokRankTextEvent event) {}
public void onShare(LiveClient client, TikTokShareEvent event) {}
public void onUnhandledMember(LiveClient client, TikTokUnhandledMemberEvent event) {}
public void onSubNotify(LiveClient client, TikTokSubNotifyEvent event) {}
public void onLinkMicBattle(LiveClient client, TikTokLinkMicBattleEvent event) {}
public void onDisconnected(LiveClient client, TikTokDisconnectedEvent event) {}
public void onUnhandledControl(LiveClient client, TikTokUnhandledControlEvent event) {}
public void onEvent(LiveClient client, TikTokEvent event) {}
public void onWebsocketResponse(LiveClient client, TikTokWebsocketResponseEvent event) {}
public void onWebsocketMessage(LiveClient client, TikTokWebsocketMessageEvent event) {}
public void onWebsocketUnhandledMessage(LiveClient client, TikTokWebsocketUnhandledMessageEvent event) {}
public void onReconnecting(LiveClient client, TikTokReconnectingEvent event) {}
}

View File

@@ -47,7 +47,7 @@ public interface LiveRoomInfo
String getRoomId(); String getRoomId();
String getHostName(); String getHostName();
String getTitle(); String getTitle();
User getHostUser(); User getHost();
List<RankingUser> getUsersRanking(); List<RankingUser> getUsersRanking();
ConnectionState getConnectionState(); ConnectionState getConnectionState();
} }

View File

@@ -102,7 +102,8 @@ message Text {
// @Image // @Image
message Image { message Image {
repeated string urlList = 1; repeated string url = 1;
string extras = 2;
bool isAnimated = 9; bool isAnimated = 9;
} }
@@ -1061,9 +1062,9 @@ message CohostListChangeContent {
message LinkerListChangeContent { message LinkerListChangeContent {
repeated ListUser linkedUsersList = 1; repeated ListUser linkedUsers = 1;
repeated ListUser appliedUsersList = 2; repeated ListUser appliedUsers = 2;
repeated ListUser connectingUsersList = 3; repeated ListUser connectingUsers = 3;
} }
message LinkerMediaChangeContent { message LinkerMediaChangeContent {

View File

@@ -35,6 +35,14 @@ enum LinkmicApplierSortSetting {
LINKMIC_APPLIER_SORT_SETTING_BY_GIFT_SCORE = 1; LINKMIC_APPLIER_SORT_SETTING_BY_GIFT_SCORE = 1;
} }
enum LinkMicBattleStatus {
BATTLE_ARMY_UNKNOWN = 0;
ARMY_ONGOING = 1;
ARMY_FINISHED = 2;
BATTLE_ONGOING = 4;
BATTLE_FINISHED = 5;
}
enum HashtagNamespace { enum HashtagNamespace {
GLOBAL = 0; GLOBAL = 0;
GAMING = 1; GAMING = 1;
@@ -242,21 +250,21 @@ enum CommonContentCase {
enum LinkMessageType { enum LinkMessageType {
TPYE_LINKER_UNKNOWN = 0; TYPE_LINKER_UNKNOWN = 0;
TYPE_LINKER_CREATE = 1; TYPE_LINKER_CREATE = 1;
TYPE_LINKER_CLOSE = 2; TYPE_LINKER_CLOSE = 2;
TYPE_LINKER_INVITE = 3; TYPE_LINKER_INVITE = 3;
TYPE_LINKER_APPLY = 4; TYPE_LINKER_APPLY = 4;
TYPE_LINKER_REPLY = 5; TYPE_LINKER_REPLY = 5;
TPYE_LINKER_ENTER = 6; TYPE_LINKER_ENTER = 6;
TPYE_LINKER_LEAVE = 7; TYPE_LINKER_LEAVE = 7;
TYPE_LINKER_PERMIT = 8; TYPE_LINKER_PERMIT = 8;
TPYE_LINKER_CANCEL_INVITE = 9; TYPE_LINKER_CANCEL_INVITE = 9;
TYPE_LINKER_WAITING_LIST_CHANGE = 10; TYPE_LINKER_WAITING_LIST_CHANGE = 10;
TYPE_LINKER_LINKED_LIST_CHANGE = 11; TYPE_LINKER_LINKED_LIST_CHANGE = 11;
TYPE_LINKER_UPDATE_USER = 12; TYPE_LINKER_UPDATE_USER = 12;
TPYE_LINKER_KICK_OUT = 13; TYPE_LINKER_KICK_OUT = 13;
TPYE_LINKER_CANCEL_APPLY = 14; TYPE_LINKER_CANCEL_APPLY = 14;
TYPE_LINKER_MUTE = 15; TYPE_LINKER_MUTE = 15;
TYPE_LINKER_MATCH = 16; TYPE_LINKER_MATCH = 16;
TYPE_LINKER_UPDATE_USER_SETTING = 17; TYPE_LINKER_UPDATE_USER_SETTING = 17;
@@ -267,8 +275,8 @@ enum LinkMessageType {
TYPE_LINKER_COHOST_LIST_CHANGE = 22; TYPE_LINKER_COHOST_LIST_CHANGE = 22;
TYPE_LINKER_MEDIA_CHANGE = 23; TYPE_LINKER_MEDIA_CHANGE = 23;
TYPE_LINKER_ACCEPT_NOTICE = 24; TYPE_LINKER_ACCEPT_NOTICE = 24;
TPYE_LINKER_SYS_KICK_OUT = 101; TYPE_LINKER_SYS_KICK_OUT = 101;
TPYE_LINKMIC_USER_TOAST = 102; TYPE_LINKMIC_USER_TOAST = 102;
} }
enum MessageType { enum MessageType {

View File

@@ -521,7 +521,7 @@ message WebcastLinkMicArmies {
uint64 id2 = 4; uint64 id2 = 4;
uint64 timeStamp1 = 5; uint64 timeStamp1 = 5;
uint64 timeStamp2 = 6; uint64 timeStamp2 = 6;
int32 battleStatus = 7; // SHOULD BE AN ENUM LinkMicBattleStatus battleStatus = 7;
uint64 data1 = 8; uint64 data1 = 8;
uint64 data2 = 9; uint64 data2 = 9;
uint32 data3 = 10; uint32 data3 = 10;
@@ -574,11 +574,26 @@ message WebcastLinkMicBattle {
Common common = 1; Common common = 1;
uint64 id = 2; uint64 id = 2;
LinkMicBattleConfig battleConfig = 3; LinkMicBattleConfig battleConfig = 3;
uint32 data2 = 4; LinkMicBattleStatus battleStatus = 4;
repeated LinkMicBattleDetails details = 5; repeated LinkMicBattleDetails details = 5;
repeated LinkMicBattleTeam teams1 = 9; repeated LinkMicBattleTopViewers viewerTeam = 9;
repeated LinkMicBattleTeam teams2 = 10; repeated LinkMicBattleHost hostTeam = 10;
repeated LinkMicBattleTeamData teamData = 13; repeated LinkMicBattleTeamData teamData = 13;
uint64 unknownData16 = 16;
repeated Host2v2Data hostData2v2 = 17;
message Host2v2Data {
uint32 teamNumber = 1;
repeated HostData hostdata = 2;
uint32 unknownData3 = 3;
uint32 totalPoints = 4;
message HostData {
uint64 hostId = 1;
uint32 points = 2;
string hostIdStr = 3;
}
}
message LinkMicBattleConfig { message LinkMicBattleConfig {
uint64 id1 = 1; uint64 id1 = 1;
@@ -586,29 +601,69 @@ message WebcastLinkMicBattle {
uint32 data1 = 3; uint32 data1 = 3;
uint64 id2 = 4; uint64 id2 = 4;
uint32 data2 = 5; uint32 data2 = 5;
uint32 data3 = 6;
uint32 data4 = 8;
}
message LinkMicBattleTeamData {
uint64 teamId = 1;
LinkMicBattleData data = 2;
} }
message LinkMicBattleData { message LinkMicBattleData {
uint64 id = 1; uint64 id = 1;
uint32 data1 = 2; uint32 data1 = 2;
uint32 data2 = 3; uint32 winStreak = 3;
uint32 data3 = 5; uint32 data3 = 5;
string url = 6; string url = 6;
} }
message LinkMicBattleDetails { message LinkMicBattleDetails {
uint64 id = 1; uint64 id = 1;
LinkMicBattleData details = 2; LinkMicBattleDetailsSummary summary = 2;
message LinkMicBattleDetailsSummary {
uint64 id = 1;
uint32 unknownData2 = 2;
uint32 points = 3;
}
} }
message LinkMicBattleTeam { message LinkMicBattleTopViewers {
uint64 id = 1; uint64 id = 1;
repeated User users = 2; repeated TopViewerGroup viewerGroup = 2;
message TopViewerGroup {
repeated TopViewer viewer = 1;
uint32 points = 2;
string hostIdOrTeamNum = 3; // 1v1 Battle = HostId | 2v2 Battle = Team # - 1 & 2
message TopViewer {
uint64 id = 1;
uint32 points = 2;
string profileId = 3;
repeated Image images = 4;
string stringId = 6;
}
}
} }
message LinkMicBattleTeamData { message LinkMicBattleHost {
uint64 teamId = 1; uint64 id = 1;
LinkMicBattleData data = 2; repeated HostGroup hostGroup = 2;
message HostGroup {
repeated Host host = 1;
uint32 points = 2;
string hostId = 3;
message Host {
uint64 id = 1;
string profileId = 2;
repeated Image images = 3;
string name = 4;
}
}
} }
} }
@@ -750,7 +805,7 @@ message WebcastLinkMessage {
LinkerListChangeContent ListChangeContent = 20; LinkerListChangeContent ListChangeContent = 20;
CohostListChangeContent CohostListChangeContent = 21; CohostListChangeContent CohostListChangeContent = 21;
LinkerMediaChangeContent MediaChangeContent = 22; LinkerMediaChangeContent MediaChangeContent = 22;
LinkerAcceptNoticeContent ReplyAcceptNoticeContent = 23; LinkerAcceptNoticeContent AcceptNoticeContent = 23;
LinkerSysKickOutContent SysKickOutContent = 101; LinkerSysKickOutContent SysKickOutContent = 101;
LinkmicUserToastContent UserToastContent = 102; LinkmicUserToastContent UserToastContent = 102;
string extra = 200; string extra = 200;
@@ -792,6 +847,4 @@ message RoomVerifyMessage {
string content = 3; string content = 3;
int64 noticeType = 4; int64 noticeType = 4;
bool closeRoom = 5; bool closeRoom = 5;
} }

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.4.0-Release</version> <version>1.6.4-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

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

View File

@@ -23,26 +23,19 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent; import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.control.*; import io.github.jwdeveloper.tiktok.data.events.control.*;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent; import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent; import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData; import io.github.jwdeveloper.tiktok.data.requests.*;
import io.github.jwdeveloper.tiktok.data.requests.LiveData; import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
import io.github.jwdeveloper.tiktok.exceptions.*; import io.github.jwdeveloper.tiktok.exceptions.*;
import io.github.jwdeveloper.tiktok.http.LiveHttpClient; import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.listener.ListenersManager; import io.github.jwdeveloper.tiktok.listener.*;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager; import io.github.jwdeveloper.tiktok.live.*;
import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.models.ConnectionState; import io.github.jwdeveloper.tiktok.models.ConnectionState;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.websocket.SocketClient; import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import java.util.Base64; import java.util.Base64;
@@ -135,6 +128,9 @@ public class TikTokLiveClient implements LiveClient {
liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp()); liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp());
liveRoomInfo.setRoomId(userData.getRoomId()); liveRoomInfo.setRoomId(userData.getRoomId());
if (clientSettings.isFetchGifts())
giftsManager.attachGiftsList(httpClient.fetchRoomGiftsData(userData.getRoomId()).getGifts());
if (userData.getUserStatus() == LiveUserData.UserStatus.Offline) if (userData.getUserStatus() == LiveUserData.UserStatus.Offline)
throw new TikTokLiveOfflineHostException("User is offline: " + liveRoomInfo.getHostName()); throw new TikTokLiveOfflineHostException("User is offline: " + liveRoomInfo.getHostName());
@@ -144,7 +140,7 @@ public class TikTokLiveClient implements LiveClient {
var liveDataRequest = new LiveData.Request(userData.getRoomId()); var liveDataRequest = new LiveData.Request(userData.getRoomId());
var liveData = httpClient.fetchLiveData(liveDataRequest); var liveData = httpClient.fetchLiveData(liveDataRequest);
if (liveData.isAgeRestricted()) if (liveData.isAgeRestricted() && clientSettings.isThrowOnAgeRestriction())
throw new TikTokLiveException("Livestream for " + liveRoomInfo.getHostName() + " is 18+ or age restricted!"); throw new TikTokLiveException("Livestream for " + liveRoomInfo.getHostName() + " is 18+ or age restricted!");
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound) if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound)

View File

@@ -29,6 +29,7 @@ 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.envelop.TikTokChestEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.*; import io.github.jwdeveloper.tiktok.data.events.gift.*;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent; 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.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.data.events.room.*; import io.github.jwdeveloper.tiktok.data.events.room.*;
import io.github.jwdeveloper.tiktok.data.events.social.*; import io.github.jwdeveloper.tiktok.data.events.social.*;
@@ -44,14 +45,15 @@ import io.github.jwdeveloper.tiktok.mappers.*;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult; import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
import io.github.jwdeveloper.tiktok.mappers.handlers.*; import io.github.jwdeveloper.tiktok.mappers.handlers.*;
import io.github.jwdeveloper.tiktok.messages.webcast.*; import io.github.jwdeveloper.tiktok.messages.webcast.*;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient; import io.github.jwdeveloper.tiktok.websocket.*;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketOfflineClient;
import java.util.*; import java.util.*;
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;
import static io.github.jwdeveloper.tiktok.messages.enums.LinkMessageType.*;
public class TikTokLiveClientBuilder implements LiveClientBuilder { public class TikTokLiveClientBuilder implements LiveClientBuilder {
protected final LiveClientSettings clientSettings; protected final LiveClientSettings clientSettings;
@@ -207,9 +209,42 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
//LinkMic events //LinkMic events
// mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class); mapper.forMessage(WebcastLinkMicBattle.class, (inputBytes, messageName, mapperHelper) -> {
// mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class); var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMicBattle.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class); return MappingResult.of(message, new TikTokLinkMicBattleEvent(message));
});
mapper.forMessage(WebcastLinkMicArmies.class, (inputBytes, messageName, mapperHelper) -> {
var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMicArmies.class);
return MappingResult.of(message, new TikTokLinkMicArmiesEvent(message));
});
mapper.forMessage(WebcastLinkMessage.class, ((inputBytes, messageName, mapperHelper) -> {
var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMessage.class);
return MappingResult.of(message, switch (message.getMessageType()) {
case TYPE_LINKER_INVITE -> new TikTokLinkInviteEvent(message);
case TYPE_LINKER_REPLY -> new TikTokLinkReplyEvent(message);
case TYPE_LINKER_CREATE -> new TikTokLinkCreateEvent(message);
case TYPE_LINKER_CLOSE -> new TikTokLinkCloseEvent(message);
case TYPE_LINKER_ENTER -> new TikTokLinkEnterEvent(message);
case TYPE_LINKER_LEAVE -> new TikTokLinkLeaveEvent(message);
case TYPE_LINKER_CANCEL_INVITE, TYPE_LINKER_CANCEL_APPLY -> new TikTokLinkCancelEvent(message);
case TYPE_LINKER_KICK_OUT -> new TikTokLinkKickOutEvent(message);
case TYPE_LINKER_LINKED_LIST_CHANGE -> new TikTokLinkLinkedListChangeEvent(message);
case TYPE_LINKER_UPDATE_USER -> new TikTokLinkUpdateUserEvent(message);
case TYPE_LINKER_WAITING_LIST_CHANGE, TYPE_LINKER_WAITING_LIST_CHANGE_V2 -> new TikTokLinkWaitListChangeEvent(message);
case TYPE_LINKER_MUTE -> new TikTokLinkMuteEvent(message);
case TYPE_LINKER_MATCH -> new TikTokLinkRandomMatchEvent(message);
case TYPE_LINKER_UPDATE_USER_SETTING -> new TikTokLinkUpdateUserSettingEvent(message);
case TYPE_LINKER_MIC_IDX_UPDATE -> new TikTokLinkMicIdxUpdateEvent(message);
case TYPE_LINKER_LINKED_LIST_CHANGE_V2 -> new TikTokLinkListChangeEvent(message);
case TYPE_LINKER_COHOST_LIST_CHANGE -> new TikTokLinkCohostListChangeEvent(message);
case TYPE_LINKER_MEDIA_CHANGE -> new TikTokLinkMediaChangeEvent(message);
case TYPE_LINKER_ACCEPT_NOTICE -> new TikTokLinkAcceptNoticeEvent(message);
case TYPE_LINKER_SYS_KICK_OUT -> new TikTokLinkSysKickOutEvent(message);
case TYPE_LINKMIC_USER_TOAST -> new TikTokLinkUserToastEvent(message);
default -> new TikTokLinkEvent(message);
});
}));
// mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class); // mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
//Rank events //Rank events
@@ -335,6 +370,111 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return this; 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) { public TikTokLiveClientBuilder onBarrage(EventConsumer<TikTokBarrageEvent> event) {
eventHandler.subscribe(TikTokBarrageEvent.class, event); eventHandler.subscribe(TikTokBarrageEvent.class, event);
return this; return this;

View File

@@ -43,6 +43,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
private static final String TIKTOK_URL_WEB = "https://www.tiktok.com/"; private static final String TIKTOK_URL_WEB = "https://www.tiktok.com/";
private static final String TIKTOK_URL_WEBCAST = "https://webcast.tiktok.com/webcast/"; private static final String TIKTOK_URL_WEBCAST = "https://webcast.tiktok.com/webcast/";
public static final String TIKTOK_GIFTS_URL = "https://raw.githubusercontent.com/TikTok-LIVE-Private/GiftsGenerator/master/page/public/gifts.json"; public static final String TIKTOK_GIFTS_URL = "https://raw.githubusercontent.com/TikTok-LIVE-Private/GiftsGenerator/master/page/public/gifts.json";
public static final String TIKTOK_ROOM_GIFTS_URL = TIKTOK_URL_WEBCAST+"gift/list/";
public static final int TIKTOK_AGE_RESTRICTED_CODE = 4003110; public static final int TIKTOK_AGE_RESTRICTED_CODE = 4003110;
private final HttpClientFactory httpFactory; private final HttpClientFactory httpFactory;
@@ -55,7 +56,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
public TikTokLiveHttpClient(HttpClientFactory factory, LiveClientSettings settings) { public TikTokLiveHttpClient(HttpClientFactory factory, LiveClientSettings settings) {
this.httpFactory = factory; this.httpFactory = factory;
this.clientSettings = settings; this.clientSettings = settings;
this.logger = LoggerFactory.create("HttpClient", clientSettings); this.logger = LoggerFactory.create("HttpClient-"+hashCode(), clientSettings);
liveUserDataMapper = new LiveUserDataMapper(); liveUserDataMapper = new LiveUserDataMapper();
liveDataMapper = new LiveDataMapper(); liveDataMapper = new LiveDataMapper();
giftsDataMapper = new GiftsDataMapper(); giftsDataMapper = new GiftsDataMapper();
@@ -65,6 +66,31 @@ public class TikTokLiveHttpClient implements LiveHttpClient
this(new HttpClientFactory(LiveClientSettings.createDefault()), LiveClientSettings.createDefault()); this(new HttpClientFactory(LiveClientSettings.createDefault()), LiveClientSettings.createDefault());
} }
public GiftsData.Response fetchRoomGiftsData(String room_id) {
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
if (proxyClientSettings.isEnabled()) {
while (proxyClientSettings.hasNext()) {
try {
return getRoomGiftsData(room_id);
} catch (TikTokProxyRequestException ignored) {}
}
}
return getRoomGiftsData(room_id);
}
public GiftsData.Response getRoomGiftsData(String room_id) {
var result = httpFactory.client(TIKTOK_ROOM_GIFTS_URL)
.withParam("room_id", room_id)
.build()
.toJsonResponse();
if (result.isFailure())
throw new TikTokLiveRequestException("Unable to fetch gifts information's - "+result);
var json = result.getContent();
return giftsDataMapper.mapRoom(json);
}
public GiftsData.Response fetchGiftsData() { public GiftsData.Response fetchGiftsData() {
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings(); var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
if (proxyClientSettings.isEnabled()) { if (proxyClientSettings.isEnabled()) {
@@ -152,7 +178,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
try { try {
var resultHeader = ActionResult.of(credentialsResponse.headers().firstValue("x-set-tt-cookie")); var resultHeader = ActionResult.of(credentialsResponse.headers().firstValue("x-set-tt-cookie"));
if (resultHeader.isFailure()) { if (resultHeader.isFailure()) {
logger.warning("SignServer Headers: "+request.getRoomId()+" - "+credentialsResponse.headers().map()); logger.warning("Sign Server Headers: "+request.getRoomId()+" - "+credentialsResponse.headers().map());
throw new TikTokSignServerException("Sign server did not return the x-set-tt-cookie header - "+result); throw new TikTokSignServerException("Sign server did not return the x-set-tt-cookie header - "+result);
} }
var websocketCookie = resultHeader.getContent(); var websocketCookie = resultHeader.getContent();

View File

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

View File

@@ -61,11 +61,6 @@ public class TikTokRoomInfo implements LiveRoomInfo {
return connectionState == state; return connectionState == state;
} }
@Override
public User getHostUser() {
return host;
}
public void updateRanking(List<RankingUser> rankingUsers) { public void updateRanking(List<RankingUser> rankingUsers) {
usersRanking.clear(); usersRanking.clear();
usersRanking.addAll(rankingUsers); usersRanking.addAll(rankingUsers);

View File

@@ -1,18 +1,25 @@
package io.github.jwdeveloper.tiktok.common; package io.github.jwdeveloper.tiktok.common;
import com.google.gson.*; import com.google.gson.*;
import io.github.jwdeveloper.tiktok.http.mappers.*;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.net.http.*;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
@Data @Data
public class ActionResult<T> { public class ActionResult<T> {
private static final Gson gson = new Gson().newBuilder().disableHtmlEscaping()
.registerTypeHierarchyAdapter(HttpResponse.class, new HttpResponseJsonMapper())
.registerTypeHierarchyAdapter(HttpRequest.class, new HttpRequestJsonMapper())
.setPrettyPrinting().create();
private boolean success = true; private boolean success = true;
private T content;
private String message; private String message;
private T content;
@Accessors(chain = true, fluent = true) @Accessors(chain = true, fluent = true)
private ActionResult<?> previous; private ActionResult<?> previous;
@@ -93,7 +100,7 @@ public class ActionResult<T> {
public JsonObject toJson() { public JsonObject toJson() {
JsonObject map = new JsonObject(); JsonObject map = new JsonObject();
map.addProperty("success", success); map.addProperty("success", success);
map.add("content", new Gson().toJsonTree(content)); map.add("content", gson.toJsonTree(content));
map.addProperty("message", message); map.addProperty("message", message);
map.add("previous", hasPrevious() ? previous.toJson() : null); map.add("previous", hasPrevious() ? previous.toJson() : null);
return map; return map;
@@ -101,6 +108,6 @@ public class ActionResult<T> {
@Override @Override
public String toString() { public String toString() {
return "ActionResult: "+new Gson().newBuilder().setPrettyPrinting().create().toJson(toJson()); return "ActionResult: "+gson.toJson(toJson());
} }
} }

View File

@@ -1,14 +1,10 @@
package io.github.jwdeveloper.tiktok.gifts; package io.github.jwdeveloper.tiktok.gifts;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift; import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.live.GiftsManager; import io.github.jwdeveloper.tiktok.live.GiftsManager;
import java.util.Collections; import java.util.*;
import java.util.List; import java.util.function.*;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class TikTokGiftsManager implements GiftsManager { public class TikTokGiftsManager implements GiftsManager {
@@ -16,7 +12,7 @@ public class TikTokGiftsManager implements GiftsManager {
public TikTokGiftsManager(List<Gift> giftList) public TikTokGiftsManager(List<Gift> giftList)
{ {
giftsByIdIndex = giftList.stream().collect(Collectors.toConcurrentMap(Gift::getId, e -> e)); giftsByIdIndex = giftList.stream().collect(Collectors.toConcurrentMap(Gift::getId, Function.identity()));
} }
public void attachGift(Gift gift) { public void attachGift(Gift gift) {
@@ -32,11 +28,7 @@ public class TikTokGiftsManager implements GiftsManager {
} }
public Gift getById(int giftId) { public Gift getById(int giftId) {
if (!giftsByIdIndex.containsKey(giftId)) { return giftsByIdIndex.getOrDefault(giftId, Gift.UNDEFINED);
return Gift.UNDEFINED;
}
return giftsByIdIndex.get(giftId);
} }
public Gift getByFilter(Predicate<Gift> filter) { public Gift getByFilter(Predicate<Gift> filter) {
@@ -44,7 +36,7 @@ public class TikTokGiftsManager implements GiftsManager {
.stream() .stream()
.filter(filter) .filter(filter)
.findFirst() .findFirst()
.orElseGet(() -> Gift.UNDEFINED); .orElse(Gift.UNDEFINED);
} }
@Override @Override
@@ -62,4 +54,4 @@ public class TikTokGiftsManager implements GiftsManager {
public Map<Integer, Gift> toMap() { public Map<Integer, Gift> toMap() {
return Collections.unmodifiableMap(giftsByIdIndex); return Collections.unmodifiableMap(giftsByIdIndex);
} }
} }

View File

@@ -30,6 +30,7 @@ import lombok.AllArgsConstructor;
import java.net.*; import java.net.*;
import java.net.http.*; import java.net.http.*;
import java.nio.charset.*; import java.nio.charset.*;
import java.time.*;
import java.util.*; import java.util.*;
import java.util.regex.*; import java.util.regex.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -47,7 +48,21 @@ public class HttpClient {
try { try {
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray()); var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
var result = ActionResult.of(response); var result = ActionResult.of(response);
return response.statusCode() != 200 ? result.message("HttpResponse Code: ", response.statusCode()).failure() : result.success(); return switch (response.statusCode()) {
case 420 -> result.message("HttpResponse Code:", response.statusCode(), "| IP Cloudflare Blocked.").failure();
case 429 -> {
var wait = response.headers().firstValue("ratelimit-reset");
if (wait.isEmpty())
yield result.message("HttpResponse Code:", response.statusCode(), "| Sign server rate limit reached. Try again later.").failure();
Duration duration = Duration.ofSeconds(Long.parseLong(wait.get()));
yield result.message("HttpResponse Code:", response.statusCode(),
String.format("| Sign server rate limit reached. Try again in %02d:%02d.", duration.toMinutesPart(), duration.toSecondsPart())).failure();
}
case 500, 501, 502, 503 -> result.message("HttpResponse Code:", response.statusCode(), "| Sign server Error. Try again later.").failure();
case 504 -> result.message("HttpResponse Code:", response.statusCode(), "| Sign server Timeout. Try again later.").failure();
case 200 -> result.success();
default -> result.message("HttpResponse Code:", response.statusCode()).failure();
};
} catch (Exception e) { } catch (Exception e) {
throw new TikTokLiveRequestException(e); throw new TikTokLiveRequestException(e);
} }

View File

@@ -105,6 +105,7 @@ public class HttpProxyClient extends HttpClient {
socksConnection.setSSLSocketFactory(sc.getSocketFactory()); socksConnection.setSSLSocketFactory(sc.getSocketFactory());
socksConnection.setConnectTimeout(httpClientSettings.getTimeout().toMillisPart()); socksConnection.setConnectTimeout(httpClientSettings.getTimeout().toMillisPart());
socksConnection.setReadTimeout(httpClientSettings.getTimeout().toMillisPart()); socksConnection.setReadTimeout(httpClientSettings.getTimeout().toMillisPart());
httpClientSettings.getHeaders().forEach(socksConnection::setRequestProperty);
byte[] body = socksConnection.getInputStream().readAllBytes(); byte[] body = socksConnection.getInputStream().readAllBytes();

View File

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

View File

@@ -0,0 +1,21 @@
package io.github.jwdeveloper.tiktok.http.mappers;
import com.google.gson.*;
import java.lang.reflect.Type;
import java.net.http.HttpRequest;
public class HttpRequestJsonMapper implements JsonSerializer<HttpRequest>
{
@Override
public JsonElement serialize(HttpRequest src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.addProperty("method", src.method());
object.add("timeout", context.serialize(src.timeout().toString()));
object.addProperty("expectContinue", src.expectContinue());
object.add("uri", context.serialize(src.uri()));
object.add("version", context.serialize(src.version().toString()));
object.add("headers", context.serialize(src.headers().map()));
return object;
}
}

View File

@@ -0,0 +1,21 @@
package io.github.jwdeveloper.tiktok.http.mappers;
import com.google.gson.*;
import java.lang.reflect.Type;
import java.net.http.HttpResponse;
public class HttpResponseJsonMapper implements JsonSerializer<HttpResponse>
{
@Override
public JsonElement serialize(HttpResponse src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.addProperty("statusCode", src.statusCode());
object.add("request", context.serialize(src.request()));
object.add("headers", context.serialize(src.headers().map()));
object.add("body", context.serialize(src.body()));
object.add("uri", context.serialize(src.uri().toString()));
object.add("version", context.serialize(src.version().toString()));
return object;
}
}

View File

@@ -65,8 +65,7 @@ public class LiveDataMapper {
default -> LiveData.LiveStatus.HostNotFound; default -> LiveData.LiveStatus.HostNotFound;
}; };
response.setLiveStatus(statusValue); response.setLiveStatus(statusValue);
} else if (data.has("prompts") && jsonObject.has("status_code") && } else if (data.has("prompts") && data.get("prompts").getAsString().isEmpty() && jsonObject.has("status_code")) {
data.get("prompts").getAsString().isEmpty() && jsonObject.get("status_code").isJsonPrimitive()) {
response.setAgeRestricted(jsonObject.get("status_code").getAsInt() == TikTokLiveHttpClient.TIKTOK_AGE_RESTRICTED_CODE); response.setAgeRestricted(jsonObject.get("status_code").getAsInt() == TikTokLiveHttpClient.TIKTOK_AGE_RESTRICTED_CODE);
} else { } else {
response.setLiveStatus(LiveData.LiveStatus.HostNotFound); response.setLiveStatus(LiveData.LiveStatus.HostNotFound);

View File

@@ -65,7 +65,7 @@ public class LiveUserDataMapper
}; };
return new LiveUserData.Response(json, statusEnum, roomId, startTime); return new LiveUserData.Response(json, statusEnum, roomId, startTime);
} catch (JsonSyntaxException e) { } catch (JsonSyntaxException | IllegalStateException e) {
logger.warning("Malformed Json: '"+json+"' - Error Message: "+e.getMessage()); logger.warning("Malformed Json: '"+json+"' - Error Message: "+e.getMessage());
return new LiveUserData.Response(json, LiveUserData.UserStatus.NotFound, "", -1); return new LiveUserData.Response(json, LiveUserData.UserStatus.NotFound, "", -1);
} }

View File

@@ -96,16 +96,17 @@ public class TikTokListenersManager implements ListenersManager {
m.isAnnotationPresent(TikTokEventObserver.class)).toList(); m.isAnnotationPresent(TikTokEventObserver.class)).toList();
var eventsMap = new HashMap<Class<?>, List<EventConsumer<?>>>(); var eventsMap = new HashMap<Class<?>, List<EventConsumer<?>>>();
for (var method : methods) { for (var method : methods) {
var eventClazz = method.getParameterTypes()[1]; var liveclientClass = method.getParameterTypes()[0];
var eventClass = method.getParameterTypes()[1];
if (eventClazz.isAssignableFrom(LiveClient.class) && if (!LiveClient.class.isAssignableFrom(liveclientClass) && !liveclientClass.equals(LiveClient.class)) {
!eventClazz.equals(LiveClient.class)) { throw new TikTokEventListenerMethodException("Method " + method.getName() + "() 1st parameter must be instance of " + LiveClient.class.getName()
throw new TikTokEventListenerMethodException("Method " + method.getName() + "() 1nd parameter must instance of " + LiveClient.class.getName()); + " | Invalid parameter class: "+liveclientClass.getName());
} }
if (eventClazz.isAssignableFrom(TikTokEvent.class) && if (!TikTokEvent.class.isAssignableFrom(eventClass) && !eventClass.equals(TikTokEvent.class)) {
!eventClazz.equals(TikTokEvent.class)) { throw new TikTokEventListenerMethodException("Method " + method.getName() + "() 2nd parameter must be instance of " + TikTokEvent.class.getName()
throw new TikTokEventListenerMethodException("Method " + method.getName() + "() 2nd parameter must instance of " + TikTokEvent.class.getName()); + " | Invalid parameter class: "+eventClass.getName());
} }
EventConsumer eventMethodRef = (liveClient, event) -> EventConsumer eventMethodRef = (liveClient, event) ->
@@ -117,7 +118,7 @@ public class TikTokListenersManager implements ListenersManager {
throw new TikTokEventListenerMethodException(e); throw new TikTokEventListenerMethodException(e);
} }
}; };
eventsMap.computeIfAbsent(eventClazz, (a) -> new ArrayList<>()).add(eventMethodRef); eventsMap.computeIfAbsent(eventClass, (a) -> new ArrayList<>()).add(eventMethodRef);
} }
return new ListenerBindingModel(listener, eventsMap); return new ListenerBindingModel(listener, eventsMap);
} }

View File

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

View File

@@ -63,7 +63,7 @@ public class TikTokWebSocketClient implements SocketClient {
messageHandler.handle(liveClient, connectionData.getWebcastResponse()); messageHandler.handle(liveClient, connectionData.getWebcastResponse());
var headers = new HashMap<String, String>(); var headers = new HashMap<>(clientSettings.getHttpSettings().getHeaders());
headers.put("Cookie", connectionData.getWebsocketCookies()); headers.put("Cookie", connectionData.getWebsocketCookies());
webSocketClient = new TikTokWebSocketListener(connectionData.getWebsocketUrl(), webSocketClient = new TikTokWebSocketListener(connectionData.getWebsocketUrl(),
headers, headers,

View File

@@ -61,7 +61,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
} catch (Exception e) { } catch (Exception e) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e)); tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e));
} }
if (isNotClosing()) { if (isOpen()) {
sendPing(); sendPing();
} }
} }
@@ -79,8 +79,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
pushFrameBuilder.setPayloadType("ack"); pushFrameBuilder.setPayloadType("ack");
pushFrameBuilder.setLogId(websocketPushFrame.getLogId()); pushFrameBuilder.setLogId(websocketPushFrame.getLogId());
pushFrameBuilder.setPayload(webcastResponse.getInternalExtBytes()); pushFrameBuilder.setPayload(webcastResponse.getInternalExtBytes());
if (isNotClosing()) if (isOpen()) {
{
this.send(pushFrameBuilder.build().toByteArray()); this.send(pushFrameBuilder.build().toByteArray());
} }
} }
@@ -90,7 +89,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
@Override @Override
public void onOpen(ServerHandshake serverHandshake) { public void onOpen(ServerHandshake serverHandshake) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokConnectedEvent()); tikTokEventHandler.publish(tikTokLiveClient, new TikTokConnectedEvent());
if (isNotClosing()) { if (isOpen()) {
sendPing(); sendPing();
} }
} }
@@ -104,7 +103,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
@Override @Override
public void onError(Exception error) { public void onError(Exception error) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(error)); tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(error));
if (isNotClosing()) { if (isOpen()) {
sendPing(); sendPing();
} }
} }
@@ -129,10 +128,6 @@ public class TikTokWebSocketListener extends WebSocketClient {
} }
} }
private boolean isNotClosing() {
return !isClosed() && !isClosing();
}
@Override @Override
public void onMessage(String s) { public void onMessage(String s) {
// System.err.println(s); // System.err.println(s);

View File

@@ -22,12 +22,7 @@
*/ */
package io.github.jwdeveloper.tiktok.gifts; package io.github.jwdeveloper.tiktok.gifts;
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftOld;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;

View File

@@ -117,7 +117,7 @@ class TikTokGiftEventHandlerTest {
giftBuilder.setId(giftId); giftBuilder.setId(giftId);
giftBuilder.setName(giftName); giftBuilder.setName(giftName);
giftBuilder.setImage(Image.newBuilder().addUrlList(giftImage).build()); giftBuilder.setImage(Image.newBuilder().addUrl(giftImage).build());
giftBuilder.setType(streakable ? 1 : 0); giftBuilder.setType(streakable ? 1 : 0);
userBuilder.setId(userId); userBuilder.setId(userId);
@@ -129,4 +129,4 @@ class TikTokGiftEventHandlerTest {
} }
} }

View File

@@ -41,7 +41,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.4.0-Release</version> <version>1.6.4-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -75,7 +75,7 @@
<dependency> <dependency>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>extension-collector</artifactId> <artifactId>extension-collector</artifactId>
<version>1.4.0-Release</version> <version>1.6.4-Release</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -70,7 +70,7 @@ Maven
<dependency> <dependency>
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId> <groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
<artifactId>Client</artifactId> <artifactId>Client</artifactId>
<version>1.4.0-Release</version> <version>1.7.0-Release</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -87,7 +87,7 @@ dependencyResolutionManagement {
} }
dependencies { dependencies {
implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.1.0-Release' implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.5.0-Release'
} }
``` ```

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.4.0-Release</version> <version>1.6.4-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<version>1.4.0-Release</version> <version>1.6.4-Release</version>
</parent> </parent>
@@ -33,7 +33,7 @@
<dependency> <dependency>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>API</artifactId> <artifactId>API</artifactId>
<version>1.4.0-Release</version> <version>1.6.4-Release</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -0,0 +1,8 @@
package io.github.jwdeveloper.tiktok.extension.collector.api;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import org.bson.Document;
public interface CollectorEvent {
boolean execute(LiveClient client, Document document);
}

View File

@@ -1,5 +1,6 @@
package io.github.jwdeveloper.tiktok.extension.collector.api.settings; package io.github.jwdeveloper.tiktok.extension.collector.api.settings;
import io.github.jwdeveloper.tiktok.extension.collector.api.CollectorEvent;
import lombok.Data; import lombok.Data;
import org.bson.Document; import org.bson.Document;
@@ -9,5 +10,5 @@ import java.util.function.Function;
@Data @Data
public class CollectorListenerSettings { public class CollectorListenerSettings {
private Map<String, Object> extraFields; private Map<String, Object> extraFields;
private Function<Document, Boolean> filter; private CollectorEvent filter;
} }

View File

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

View File

@@ -22,6 +22,7 @@
*/ */
package io.github.jwdeveloper.tiktok.extension.collector.impl; package io.github.jwdeveloper.tiktok.extension.collector.impl;
import io.github.jwdeveloper.tiktok.extension.collector.api.CollectorEvent;
import io.github.jwdeveloper.tiktok.extension.collector.api.Storage; import io.github.jwdeveloper.tiktok.extension.collector.api.Storage;
import io.github.jwdeveloper.tiktok.extension.collector.api.settings.CollectorListenerSettings; import io.github.jwdeveloper.tiktok.extension.collector.api.settings.CollectorListenerSettings;
import org.bson.Document; import org.bson.Document;
@@ -40,6 +41,7 @@ public class DataCollector {
public void connect() { public void connect() {
storage.connect(); storage.connect();
} }
public void disconnect() { public void disconnect() {
storage.disconnect(); storage.disconnect();
} }
@@ -49,11 +51,11 @@ public class DataCollector {
} }
public DataCollectorListener newListener(Map<String, Object> additionalFields) { public DataCollectorListener newListener(Map<String, Object> additionalFields) {
return newListener(additionalFields, (e) -> true); return newListener(additionalFields, (live, document) -> true);
} }
public DataCollectorListener newListener(Map<String, Object> additionalFields, public DataCollectorListener newListener(Map<String, Object> additionalFields,
Function<Document, Boolean> filter) { CollectorEvent filter) {
var settings = new CollectorListenerSettings(); var settings = new CollectorListenerSettings();
settings.setExtraFields(additionalFields); settings.setExtraFields(additionalFields);
settings.setFilter(filter); settings.setFilter(filter);

View File

@@ -4,6 +4,7 @@ import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
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.TikTokConnectingEvent; import io.github.jwdeveloper.tiktok.data.events.control.TikTokConnectingEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent; import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.extension.collector.api.LiveDataCollector; import io.github.jwdeveloper.tiktok.extension.collector.api.LiveDataCollector;
@@ -16,22 +17,20 @@ import org.bson.Document;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.time.LocalDateTime;
import java.util.Base64; import java.util.Base64;
import java.util.UUID;
public class DataCollectorListener implements LiveDataCollector { public class DataCollectorListener implements LiveDataCollector {
private final Storage storage; private final Storage storage;
private final CollectorListenerSettings settings; private final CollectorListenerSettings settings;
private String sessionId; private String roomId, userName;
private String userName;
public DataCollectorListener(Storage collection, CollectorListenerSettings settings) { public DataCollectorListener(Storage collection, CollectorListenerSettings settings) {
this.storage = collection; this.storage = collection;
this.settings = settings; this.settings = settings;
} }
@TikTokEventObserver @TikTokEventObserver
private void onResponse(LiveClient liveClient, TikTokWebsocketResponseEvent event) { private void onResponse(LiveClient liveClient, TikTokWebsocketResponseEvent event) {
includeResponse(liveClient, event.getResponse()); includeResponse(liveClient, event.getResponse());
@@ -40,45 +39,41 @@ public class DataCollectorListener implements LiveDataCollector {
@TikTokEventObserver @TikTokEventObserver
private void onEvent(LiveClient liveClient, TikTokEvent event) { private void onEvent(LiveClient liveClient, TikTokEvent event) {
if (event instanceof TikTokConnectingEvent) { if (event instanceof TikTokConnectingEvent)
sessionId = UUID.randomUUID().toString();
userName = liveClient.getRoomInfo().getHostName(); userName = liveClient.getRoomInfo().getHostName();
} else if (event instanceof TikTokRoomInfoEvent && roomId == null)
roomId = liveClient.getRoomInfo().getRoomId();
if (event instanceof TikTokErrorEvent) { else if (event instanceof TikTokErrorEvent)
return; return;
}
includeEvent(event); includeEvent(liveClient, event);
} }
@TikTokEventObserver @TikTokEventObserver
private void onError(LiveClient liveClient, TikTokErrorEvent event) { private void onError(LiveClient liveClient, TikTokErrorEvent event) {
event.getException().printStackTrace(); event.getException().printStackTrace();
includeError(event); includeError(liveClient, event);
} }
private void includeResponse(LiveClient liveClient, WebcastResponse message) { private void includeResponse(LiveClient liveClient, WebcastResponse message) {
var messageContent = Base64.getEncoder().encodeToString(message.toByteArray()); var messageContent = Base64.getEncoder().encodeToString(message.toByteArray());
insertDocument(createDocument("response", "webcast", messageContent)); insertDocument(liveClient, createDocument("response", "webcast", messageContent));
} }
private void includeMessage(LiveClient liveClient, WebcastResponse.Message message) { private void includeMessage(LiveClient liveClient, WebcastResponse.Message message) {
var method = message.getMethod(); var method = message.getMethod();
var messageContent = Base64.getEncoder().encodeToString(message.getPayload().toByteArray()); var messageContent = Base64.getEncoder().encodeToString(message.getPayload().toByteArray());
insertDocument(liveClient, createDocument("message", method, messageContent));
insertDocument(createDocument("message", method, messageContent));
} }
private void includeEvent(TikTokEvent event) { private void includeEvent(LiveClient client, TikTokEvent event) {
var json = JsonUtil.toJson(event); var json = JsonUtil.toJson(event);
var content = Base64.getEncoder().encodeToString(json.getBytes()); var content = Base64.getEncoder().encodeToString(json.getBytes());
var name = event.getClass().getSimpleName(); var name = event.getClass().getSimpleName();
insertDocument(createDocument("event", name, content)); insertDocument(client, createDocument("event", name, content));
} }
private void includeError(TikTokErrorEvent event) { private void includeError(LiveClient client, TikTokErrorEvent event) {
var exception = event.getException(); var exception = event.getException();
var exceptionName = event.getException().getClass().getSimpleName(); var exceptionName = event.getException().getClass().getSimpleName();
@@ -86,34 +81,28 @@ public class DataCollectorListener implements LiveDataCollector {
var pw = new PrintWriter(sw); var pw = new PrintWriter(sw);
event.getException().printStackTrace(pw); event.getException().printStackTrace(pw);
var content = sw.toString(); var content = sw.toString();
var contentBase64 = Base64.getEncoder().encodeToString(content.getBytes());
var doc = createDocument("error", exceptionName, content); var doc = createDocument("error", exceptionName, contentBase64);
if (exception instanceof TikTokLiveMessageException ex) { if (exception instanceof TikTokLiveMessageException ex)
doc.append("message", ex.messageToBase64()) doc.append("message", ex.messageToBase64()).append("response", ex.webcastResponseToBase64());
.append("response", ex.webcastResponseToBase64()); insertDocument(client, doc);
}
insertDocument(doc);
}
private void insertDocument(Document document) {
if (!settings.getFilter().apply(document)) {
return;
}
storage.insert(document);
} }
private void insertDocument(LiveClient client, Document document) {
if (settings.getFilter().execute(client, document))
storage.insert(document);
}
private Document createDocument(String dataType, String dataTypeName, String content) { private Document createDocument(String dataType, String dataTypeName, String content) {
var doc = new Document(); var doc = new Document();
doc.append("session", sessionId); doc.append("roomId", roomId);
for (var entry : settings.getExtraFields().entrySet()) { for (var entry : settings.getExtraFields().entrySet())
doc.append(entry.getKey(), entry.getValue()); doc.append(entry.getKey(), entry.getValue());
}
doc.append("tiktokUser", userName); doc.append("tiktokUser", userName);
doc.append("dataType", dataType); doc.append("dataType", dataType);
doc.append("dataTypeName", dataTypeName); doc.append("dataTypeName", dataTypeName);
doc.append("content", content); doc.append("content", content);
doc.append("createdAt", LocalDateTime.now().toString());
return doc; return doc;
} }
} }

View File

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

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.4.0-Release</version> <version>1.6.4-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>extension-recorder</artifactId> <artifactId>extension-recorder</artifactId>

View File

@@ -30,6 +30,7 @@ import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder; import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.*; import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.*;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.enums.LiveQuality; import io.github.jwdeveloper.tiktok.extension.recorder.impl.enums.LiveQuality;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.event.TikTokLiveRecorderStartedEvent;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.models.ConnectionState; import io.github.jwdeveloper.tiktok.models.ConnectionState;
@@ -60,7 +61,9 @@ public class RecorderListener implements LiveRecorder {
var json = event.getLiveData().getJson(); var json = event.getLiveData().getJson();
liveClient.getLogger().info("Searching for live download url"); liveClient.getLogger().info("Searching for live download url");
downloadData = settings.getPrepareDownloadData() != null ? settings.getPrepareDownloadData().apply(json) : mapToDownloadData(json); downloadData = settings.getPrepareDownloadData() != null ?
settings.getPrepareDownloadData().apply(json) :
mapToDownloadData(json);
if (downloadData.getDownloadLiveUrl().isEmpty()) if (downloadData.getDownloadLiveUrl().isEmpty())
liveClient.getLogger().warning("Unable to find download live url!"); liveClient.getLogger().warning("Unable to find download live url!");
@@ -72,8 +75,11 @@ public class RecorderListener implements LiveRecorder {
private void onConnected(LiveClient liveClient, TikTokConnectedEvent event) { private void onConnected(LiveClient liveClient, TikTokConnectedEvent event) {
if (isConnected()) if (isConnected())
return; return;
liveDownloadThread = new Thread(() -> { liveDownloadThread = new Thread(() -> {
try { try {
liveClient.getLogger().info("Recording started");
var url = new URL(downloadData.getFullUrl()); var url = new URL(downloadData.getFullUrl());
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
var headers = LiveClientSettings.DefaultRequestHeaders(); var headers = LiveClientSettings.DefaultRequestHeaders();
@@ -87,8 +93,8 @@ public class RecorderListener implements LiveRecorder {
file.createNewFile(); file.createNewFile();
try ( try (
var in = connection.getInputStream(); var in = connection.getInputStream();
var fos = new FileOutputStream(file) var fos = new FileOutputStream(file)
) { ) {
byte[] dataBuffer = new byte[1024]; byte[] dataBuffer = new byte[1024];
int bytesRead; int bytesRead;
@@ -98,13 +104,19 @@ public class RecorderListener implements LiveRecorder {
} }
} catch (IOException ignored) { } catch (IOException ignored) {
} finally { } finally {
liveClient.getLogger().severe("Stopped recording "+liveClient.getRoomInfo().getHostName()); liveClient.getLogger().severe("Stopped recording " + liveClient.getRoomInfo().getHostName());
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
}); });
var recordingStartedEvent = new TikTokLiveRecorderStartedEvent(downloadData);
liveClient.publishEvent(recordingStartedEvent);
if (recordingStartedEvent.isCanceled()) {
liveClient.getLogger().info("Recording cancelled");
return;
}
liveDownloadThread.start(); liveDownloadThread.start();
} }
@@ -120,32 +132,6 @@ public class RecorderListener implements LiveRecorder {
liveDownloadThread.interrupt(); liveDownloadThread.interrupt();
} }
private int terminateFfmpeg(final Process process) {
if (!process.isAlive()) {
// ffmpeg -version, do nothing
return process.exitValue();
}
// ffmpeg -f x11grab
System.out.println("About to destroy the child process...");
try (final OutputStreamWriter out = new OutputStreamWriter(process.getOutputStream(), UTF_8)) {
out.write('q');
} catch (final IOException ioe) {
ioe.printStackTrace();
}
try {
if (!process.waitFor(5L, TimeUnit.SECONDS)) {
process.destroy();
process.waitFor();
}
return process.exitValue();
} catch (InterruptedException ie) {
System.out.println("Interrupted");
ie.printStackTrace();
Thread.currentThread().interrupt();
return -1;
}
}
private DownloadData mapToDownloadData(String json) { private DownloadData mapToDownloadData(String json) {

View File

@@ -26,10 +26,18 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.DownloadData; import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.DownloadData;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@AllArgsConstructor @AllArgsConstructor
@Data @Getter
public class TikTokLiveRecorderStartedEvent extends TikTokEvent public class TikTokLiveRecorderStartedEvent extends TikTokEvent {
{
DownloadData downloadData; DownloadData downloadData;
@Setter
boolean canceled;
public TikTokLiveRecorderStartedEvent(DownloadData downloadData) {
this.downloadData = downloadData;
}
} }

Some files were not shown because too many files have changed in this diff Show More