Compare commits

...

13 Commits

Author SHA1 Message Date
JW
3832db111e Changes:
onCustomEvent() <- registering custom events
  onMapping() <-  custom mappings
  check out 'CustomMappingExample'

  more gifs has been added
  exceptions are more explicit
2023-12-11 23:18:40 +01:00
JW
46d5f15d3f . 2023-12-11 03:56:17 +01:00
JW
e3e0d8a88e Merge remote-tracking branch 'origin/master' 2023-12-05 01:43:34 +01:00
JW
e0136d0f3b Collaboration Guide 2023-12-05 01:43:26 +01:00
Jacek W
dd5ccbfb7f Update README.md 2023-11-14 18:48:58 +01:00
GitHub Action
110a4fab4c Update version in pom.xml 2023-11-14 17:48:13 +00:00
Jacek W
69a2a6a338 Merge pull request #18 from jwdeveloper/develop-1-0-6
Changes:
  fixed TikTokLive.isHostNameValid()
  fixed TikTokLive.isLiveOnline()
  
  those methods was not working in some regions
2023-11-14 18:46:28 +01:00
JW
530551763c Changes:
fixed TikTokLive.isHostNameValid()
  fixed TikTokLive.isLiveOnline()

  those methods was not working in some regions
2023-11-14 18:44:09 +01:00
GitHub Action
ca1827853a Update version in pom.xml 2023-11-13 23:09:58 +00:00
Jacek W
ea8c740faa Merge pull request #17 from jwdeveloper/develop-1-0-5
New Events
- onLiveUnpaused()
- onRoomInfo() triggered when LiveRoomInfo got updated

Removed:
- clientSettings.setHandleExistingEvents - onRoom Replaced with onRoomInfo event - onRoomUserInfo Replaced with onRoomInfo event

Gifts:
- onGift event was not triggered for the more expensive gifts
- onGiftCombo with more expensive gifts was stuck in the GiftSendType.Begin state

Fixed:
- setPrintToConsole(false) was not disabling logs
2023-11-14 00:08:34 +01:00
JW
1977cbe8dc Changes:
New Events
     -  onLiveUnpaused()
     -  onRoomInfo() triggered when LiveRoomInfo got updated

  Removed:
      - clientSettings.setHandleExistingEvents
      - onRoom  Replaced with onRoomInfo event
      - onRoomUserInfo  Replaced with onRoomInfo event

  Gifts:
    - onGift event was not triggered for the more expensive gifts
    - onGiftCombo with more expensive gifts was stuck in the GiftSendType.Begin state

  Fixed:
     - setPrintToConsole(false) was not disabling logs
2023-11-14 00:07:14 +01:00
Jacek W
c3a48c4d70 Update README.md 2023-11-10 22:29:53 +01:00
GitHub Action
2c51844fd9 Update version in pom.xml 2023-11-10 21:29:22 +00:00
94 changed files with 48083 additions and 8424 deletions

View File

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

View File

@@ -52,11 +52,6 @@ public class ClientSettings {
*/
private Duration retryConnectionTimeout;
/**
* Whether to handle Events received from Room when Connecting
*/
private boolean handleExistingEvents;
/**
* Whether to print Logs to Console
*/

View File

@@ -57,7 +57,6 @@ public class Constants {
var clientSettings = new ClientSettings();
clientSettings.setTimeout(Duration.ofSeconds(DEFAULT_TIMEOUT));
clientSettings.setClientLanguage("en-US");
clientSettings.setHandleExistingEvents(true);
clientSettings.setRetryOnConnectionFailure(false);
clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1));
clientSettings.setPrintToConsole(false);

View File

@@ -0,0 +1,36 @@
/*
* 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.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Value;
import java.time.Duration;
@Data
@AllArgsConstructor
public class MessageMetaData
{
private Duration handlingTime;
}

View File

@@ -20,41 +20,24 @@
* 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.utils;
package io.github.jwdeveloper.tiktok.data.dto;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import lombok.AllArgsConstructor;
import lombok.Data;
public class CancelationToken
@Data
@AllArgsConstructor
public class TikTokUserInfo
{
private boolean isCanceled =false;
UserStatus userStatus;
public void cancel()
String roomId;
public enum UserStatus
{
isCanceled =true;
}
public boolean isCancel()
{
return isCanceled;
}
public void throwIfCancel()
{
if(!isCanceled)
{
return;
}
throw new TikTokLiveException("Token requested cancelation");
}
public boolean isNotCancel()
{
return !isCancel();
}
public static CancelationToken create()
{
return new CancelationToken();
NotFound,
Offline,
LivePaused,
Live
}
}

View File

@@ -20,48 +20,24 @@
* 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.room;
package io.github.jwdeveloper.tiktok.data.events;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
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.UserAttribute;
import io.github.jwdeveloper.tiktok.messages.webcast.RoomMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSystemMessage;
import lombok.Getter;
import lombok.Data;
@Getter
@Data
@EventMeta(eventType = EventType.Message)
public class TikTokRoomEvent extends TikTokHeaderEvent
{
private User hostUser;
private String hostLanguage;
private final String welcomeMessage;
public class CustomEvent extends TikTokHeaderEvent {
private final User user;
private final String title;
public TikTokRoomEvent(WebcastRoomMessage msg) {
super(msg.getCommon());
welcomeMessage = msg.getContent();
public CustomEvent(User user, String title) {
this.user = user;
this.title = title;
}
public TikTokRoomEvent(RoomMessage msg) {
super(msg.getCommon());
welcomeMessage = msg.getContent();
}
public TikTokRoomEvent(WebcastSystemMessage msg) {
super(msg.getCommon());
welcomeMessage = msg.getMessage();
}
public TikTokRoomEvent(WebcastLiveIntroMessage msg) {
super(msg.getCommon());
hostUser = User.map(msg.getHost());
hostUser.addAttribute(UserAttribute.LiveHost);
welcomeMessage = msg.getContent();
hostLanguage = msg.getLanguage();
}
}

View File

@@ -34,18 +34,10 @@ import java.util.List;
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokLinkEvent extends TikTokHeaderEvent {
private final String token;
private User user;
private final List<User> otherUsers;
public TikTokLinkEvent(WebcastLinkMessage msg) {
super(msg.getCommon());
token = msg.getToken();
if (msg.getUser().getUser().hasUser()) {
user = new User(msg.getUser().getUser().getUser());
}
otherUsers = msg.getUser().getOtherUsersList().stream().map(e -> new User(e.getUser())).toList();
}
}

View File

@@ -0,0 +1,32 @@
/*
* 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;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
@EventMeta(eventType = EventType.Message)
public class TikTokLiveUnpausedEvent extends TikTokEvent {
}

View File

@@ -26,7 +26,9 @@ import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
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.UserAttribute;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSubNotifyMessage;
import lombok.Getter;
/**
@@ -34,16 +36,20 @@ import lombok.Getter;
*/
@Getter
@EventMeta(eventType = EventType.Message)
public class TikTokSubscribeEvent extends TikTokHeaderEvent {
private User user;
public class TikTokSubscribeEvent extends TikTokHeaderEvent
{
private final User user;
public TikTokSubscribeEvent(WebcastMemberMessage msg) {
super(msg.getCommon());
if(msg.hasUser())
{
user = new User(msg.getUser());
public TikTokSubscribeEvent(WebcastMemberMessage msg) {
super(msg.getCommon());
user = User.map(msg.getUser());
user.addAttribute(UserAttribute.Subscriber);
}
public TikTokSubscribeEvent(WebcastSubNotifyMessage msg) {
super(msg.getCommon());
user = User.map(msg.getUser());
user.addAttribute(UserAttribute.Subscriber);
}
}
}

View File

@@ -24,32 +24,19 @@ package io.github.jwdeveloper.tiktok.data.events.room;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
import io.github.jwdeveloper.tiktok.data.models.RankingUser;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomUserSeqMessage;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
import java.util.stream.Collectors;
/*
Triggered when LiveRoomInfo got updated such as likes, viewers, ranking ....
*/
@Getter
@AllArgsConstructor
@EventMeta(eventType = EventType.Message)
public class TikTokRoomUserInfoEvent extends TikTokHeaderEvent {
private final int totalUsers;
/**
* Only top 5 users in ranking has detailed data
* rest has only ID
*/
private final List<RankingUser> usersRanking;
public TikTokRoomUserInfoEvent(WebcastRoomUserSeqMessage msg) {
super(msg.getCommon());
totalUsers = msg.getTotalUser();
usersRanking = msg.getRanksListList().stream().map(RankingUser::new)
.sorted((ru1, ru2) -> Integer.compare(ru2.getScore(), ru1.getScore()))
.collect(Collectors.toList());
}
public class TikTokRoomInfoEvent extends TikTokEvent
{
LiveRoomInfo roomInfo;
}

View File

@@ -24,7 +24,9 @@ package io.github.jwdeveloper.tiktok.data.events.websocket;
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.dto.MessageMetaData;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -34,22 +36,32 @@ import java.time.Duration;
/**
* Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
* Triggered every time TikTok sends data. Data incoming as protobuf message.
* You can deserialize the binary object depending on the use case.
*/
@Getter
@AllArgsConstructor
@EventMeta(eventType = EventType.Debug)
public class TikTokWebsocketMessageEvent extends TikTokEvent
{
private TikTokEvent event;
public class TikTokWebsocketMessageEvent extends TikTokEvent {
/*
* Original message that is coming from TikTok
* message.method - Name of message type, for example "WebcastGiftMessage"
* message.payload - Bytes array that contains actual data of message.
* Example of parsing, WebcastGiftMessage giftMessage = WebcastGiftMessage.parseFrom(message.getPayload());
*/
private WebcastResponse.Message message;
private MetaData metaData;
/*
* TikTokLiveJava event that was created from TikTok message data
* Example: TikTokGiftEvent
*/
private TikTokEvent event;
/*
* Metadata information about mapping message to event, such as time and stuff
*/
private MessageMetaData metaData;
@Value
public static class MetaData
{
Duration handlingTime;
}
}

View File

@@ -39,4 +39,9 @@ public class TikTokWebsocketUnhandledMessageEvent extends TikTokUnhandledEvent<W
public TikTokWebsocketUnhandledMessageEvent(WebcastResponse.Message data) {
super(data);
}
public WebcastResponse.Message getMessage()
{
return this.getData();
}
}

View File

@@ -1,3 +1,25 @@
/*
* 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.models.chest;

View File

@@ -1,3 +1,25 @@
/*
* 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.
*/
// This enum is generated
package io.github.jwdeveloper.tiktok.data.models.gifts;
@@ -33,6 +55,8 @@ public enum Gift {
PANTHER_PAWS_8358(8358, "Panther Paws", 199, "https://storage.streamdps.com/iblock/a25/a25d2409e1d851566987913c9fb9860f/6aeb9164cf39e2602933d28dbd106119.webp"),
GOLDEN_PARTY(9499, "Golden Party", 3000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/a00450f3e3aa1f01b62774950e5729c3.png~tplv-obj.jpg"),
SHOOTING_STARS(5753, "Shooting Stars", 1580, "https://storage.streamdps.com/iblock/b36/b36bb8c332ade25b2e591cd3ed164a99/a06c10f4dc562c24f4f5b6812b9fa01f.png"),
LION(6369, "Lion", 29999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/4fb89af2082a290b37d704e20f4fe729~tplv-obj.jpg"),
@@ -47,6 +71,8 @@ public enum Gift {
MAKE_UP_BOX(6033, "Make-up Box", 1999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/a29aa87203ec09c699e3dafa1944b23e~tplv-obj.jpg"),
PLAY_SAMBA(5793, "Play Samba", 99, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/fd3d6cc127464bacded6ed009074ae2f~tplv-obj.png"),
LITTLE_CROWN(6097, "Little Crown", 99, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/cf3db11b94a975417043b53401d0afe1~tplv-obj.jpg"),
RUBY_RED(8434, "Ruby red", 88, "https://storage.streamdps.com/iblock/405/405fcf52a1de3d14ab9834c1f30cc330/0deed9ee2c79ba6bf2005b0ce667bf60.webp"),
@@ -155,6 +181,8 @@ public enum Gift {
COWBOY_HAT(8842, "Cowboy Hat", 199, "https://storage.streamdps.com/iblock/5f3/5f3df5eccbc82f458fdacd0f82d13e40/40980853c80e3da0e902a1db49ea9798.webp"),
FESTA_JUNINA_S_HAT(8638, "Festa Junina's Hat", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/61b32ccce11b289b3c1db7438dfb4450~tplv-obj.png"),
SPORTS_CAR(6089, "Sports Car", 7000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/e7ce188da898772f18aaffe49a7bd7db~tplv-obj.jpg"),
ICE_TEA(5464, "Ice Tea", 1, "https://storage.streamdps.com/iblock/531/5313a4ca89a7c7588a88898c8f1e9053/dab85392562772099474a050c251d340.png"),
@@ -199,6 +227,8 @@ public enum Gift {
GIFT_BOX_6835(6835, "Gift Box", 3999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/3646c259f8ce6f79c762ad00ce51dda0~tplv-obj.jpg"),
FISHING_GEAR(5956, "Fishing Gear", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/1b2353958374f585e25b2f2344c6d0ad~tplv-obj.png"),
ARCADE_GAME(5876, "Arcade Game", 1200, "https://storage.streamdps.com/iblock/d5a/d5aaa3c8ef3d271c2f93709c3ff51e67/721d870d5a5d9d82d726ff5a9ba3aa5e.png"),
ARCADE_GAME_7041(7041, "Arcade Game", 1200, "https://storage.streamdps.com/iblock/fd0/fd0785612b024900444a0a69083400ff/3181d6af50b05dd65a7ba75902bb5b94.webp"),
@@ -217,6 +247,10 @@ public enum Gift {
GAMEPAD(6052, "Gamepad", 10, "https://storage.streamdps.com/iblock/711/711b578c104edcf1639ff4e2e7779660/6cbb6613fbbd40dac6dfd8857b05545a.png"),
LIVE_FEST_CLAPPERS(9333, "LIVE Fest Clappers", 100, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/63e85e00169ec5be3bfa90bb004cda5e.png~tplv-obj.png"),
RAINBOW(8616, "Rainbow", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5fb7267489192fc77c4c8b647c124680~tplv-obj.png"),
ORANGE_JUICE(5778, "Orange Juice", 1, "https://storage.streamdps.com/iblock/3d6/3d635024d8744f8648306d56a5c4f62f/be0f5f006bd2350e904b23b607e4f06b.png"),
GERRY_THE_GIRAFFE(6842, "Gerry the Giraffe", 1000, "https://storage.streamdps.com/iblock/792/792ef3f53d86b5cb066d5c0bb5b00a87/91aa5cf7f51a533841bea8617419c54d.webp"),
@@ -289,7 +323,9 @@ public enum Gift {
SAKURA_TRAIN(6244, "Sakura Train", 3999, "https://storage.streamdps.com/iblock/a8e/a8e50d5c5d0eaa42bd71dbeca3b1b95a/204910c857958e7e9efd0178d30a2fbe.png"),
AUTUMN_LEAVES(6967, "Autumn Leaves", 500, "https://storage.streamdps.com/iblock/f04/f042339687e8abaa2fc0e1976d9b11f4/251a0624bc3a23ba39d75467868dcbf8.webp"),
AUTUMN_LEAVES(5890, "Autumn leaves", 500, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/30adcaf443df63e3bfd2751ad251f87d~tplv-obj.png"),
FRANGIPANI(5992, "Frangipani", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7464fad59650123fe0989e426618847d~tplv-obj.png"),
SKI_GOGGLES(7781, "Ski Goggles", 199, "https://storage.streamdps.com/iblock/f42/f42cbce436db4e60adbf85641a768a12/fa9a4cea3c23829cf6f0725fea8d3c1a.webp"),
@@ -329,6 +365,8 @@ public enum Gift {
RABBIT(6348, "Rabbit", 1999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/61b42d630091b661e82fc8ed400b1de2~tplv-obj.jpg"),
ASMR(6240, "ASMR", 10, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/748e74c8309e08dbc5b03e03f28a0ea0~tplv-obj.png"),
ROSE(5655, "Rose", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/eba3a9bb85c33e017f3648eaf88d7189~tplv-obj.jpg"),
TRENDING_FIGURE(9138, "Trending Figure", 999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/df7b556ccf369bf9a42fe83ec8a77acf.png~tplv-obj.jpg"),
@@ -349,6 +387,8 @@ public enum Gift {
FLAME_HEART(9087, "Flame heart", 1, "https://storage.streamdps.com/iblock/10d/10df10624cdeebe8ff5e0e89e8c8e960/28b8da2878a420f8465cbbc1ec1e6b58.webp"),
FAIRY_BREAD(5823, "Fairy Bread", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a42f9ac9cd6b26da03818ff65ac919f1~tplv-obj.png"),
TIKTOK_SHUTTLE(6751, "TikTok Shuttle", 20000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/8ef48feba8dd293a75ae9d4376fb17c9~tplv-obj.jpg"),
MAGGIE(7911, "Maggie", 15000, "https://storage.streamdps.com/iblock/a12/a12a1b23f1f6a19d728de84e1f43e21d/ff288346e9855a9bb6deb4450491028f.webp"),
@@ -361,10 +401,14 @@ public enum Gift {
GAMER_CYBER_MASK(7895, "Gamer Cyber Mask", 399, "https://storage.streamdps.com/iblock/383/383652cc1fd3cae9402eeae3a8f5ee1e/df8a16397bb0ed28c0e522b4cfb26500.webp"),
HAPPY_FATHER_S_DAY(8712, "Happy Father's Day", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/193eba78ded4d388a0b5a7ae95943796~tplv-obj.png"),
KO(7542, "KO", 20, "https://storage.streamdps.com/iblock/e5e/e5efb63a21695a08d9647508aca3c95e/cffda8af4cc1a9f4a66eb01b11f4db85.webp"),
KO_7655(7655, "KO", 20, "https://storage.streamdps.com/iblock/aa6/aa613e765fe5c42519bd83d2d4705118/7db90e1f83b8c87c74dfdc8ee88440cb.webp"),
MAGIC_FOREST(9135, "Magic Forest", 6000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/63a758dbef9788f690e97cd65dbbb8d2~tplv-obj.png"),
LEON_AND_LILI(8916, "Leon and Lili", 9699, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6958244f3eeb69ce754f735b5833a4aa.png~tplv-obj.jpg"),
MAGIC_STAGE(6263, "Magic Stage", 2599, "https://storage.streamdps.com/iblock/399/399df717aefef9de9259e8256221076f/dfa2835c35b2177701ee65139bdfc59a.png"),
@@ -383,6 +427,8 @@ public enum Gift {
PAIMON_SURPRISE(8299, "Paimon Surprise", 1299, "https://storage.streamdps.com/iblock/ffc/ffc784ca54363f5d1d0c195419a3c19b/27096967caade6f066ce748bf5327244.webp"),
GOOD_EVENING(8267, "Good Evening", 399, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0015a756ff783f37a2cf3b5d634b3cd6~tplv-obj.png"),
HI_MAY(6471, "Hi May", 88, "https://storage.streamdps.com/iblock/970/970b0a868ce24c4b7b7059a904fa7b00/622d597d3cec282d6d2c8129fedd5075.png"),
WEDDING(6286, "Wedding", 1400, "https://storage.streamdps.com/iblock/7be/7beeb7f1098cf5f784739a0be38a06f8/0678483823c912e4dea96fa19a2f0d86.png"),
@@ -405,6 +451,8 @@ public enum Gift {
MUSIC_NOTE(5915, "Music Note", 169, "https://storage.streamdps.com/iblock/cc1/cc17f136f458a86943d7fd503c0a34b4/c56797b8b830d159f31fe5ca5527f586.png"),
FLOWER_SHOW(5831, "Flower Show", 500, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b6266323ef3ea0d313cbab6911ff8c46~tplv-obj.png"),
MAXWELL(8189, "Maxwell", 10, "https://storage.streamdps.com/iblock/82b/82b7041dcdd8fcc1842c0dd7b5a63099/73736d5ec979ad00f4b771397d9b998b.webp"),
LOVE_DROP(8277, "Love Drop", 1800, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/1ea684b3104abb725491a509022f7c02~tplv-obj.jpg"),
@@ -413,6 +461,8 @@ public enum Gift {
YACHT(6103, "Yacht", 9888, "https://storage.streamdps.com/iblock/b6c/b6c9d3c6df6733cc85149897764d2c6b/023d358a3d7a7a330ed006eb07117582.png"),
YACHT_9501(9501, "Yacht", 20000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/e69e2626f6ff43d1c1f2b8ae5ea42514.png~tplv-obj.jpg"),
WINDOW_BASKET(8648, "Window basket", 500, "https://storage.streamdps.com/iblock/a8d/a8d0c44c86385d4cd02ad2d840dcb148/8bbdca8666946a2e7172b3eaeed02303.webp"),
SWAN(5897, "Swan", 699, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/97a26919dbf6afe262c97e22a83f4bf1~tplv-obj.jpg"),
@@ -427,6 +477,8 @@ public enum Gift {
SCORPIO_STAR_SIGN(7159, "Scorpio Star Sign", 9999, "https://storage.streamdps.com/iblock/c91/c91f3a3685b5c54d9e96d5f9443c4fda/50c48574ff60f328b7a50b80cd9aa4b8.webp"),
SOCCER_BALL(5852, "Soccer Ball", 39, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e1932db6aea81bbddc4e7dc0229ac155~tplv-obj.png"),
GAME_CONTROLLER(6467, "Game Controller", 100, "https://storage.streamdps.com/iblock/603/6032c1b0d5c2c07abe04956b3cdd45cd/d75d75a7e81f96f39d2ffd574063924f.png"),
GAME_CONTROLLER_6960(6960, "Game Controller", 100, "https://storage.streamdps.com/iblock/030/030f63329d68d21c5faacab88006a17f/fbb8dd78b47184321d93e3ae5a1f2cca.webp"),
@@ -435,6 +487,8 @@ public enum Gift {
HANGING_LIGHTS(5937, "Hanging Lights", 199, "https://storage.streamdps.com/iblock/e03/e03da22fa8c302dbf1d9439c65380549/6d9f912b5a9253f91c01ed58e3ccbe47.png"),
FOOTY(5893, "Footy", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/94f8ac5c7b6f90aba713b44ddac40bf1~tplv-obj.png"),
BATIK_CLOTHES(5461, "Batik Clothes", 1000, "https://storage.streamdps.com/iblock/46d/46d0f497391a934d27d9b993f444d8b2/121af719b172eed61d8a75c1b1341c9d.png"),
DANCING_QUEENS(9240, "Dancing queens", 20000, "https://storage.streamdps.com/iblock/c79/c793af446369ecef5238e73312c84ccd/464a76f3e6eaee9afc771f45a4bba9df.webp"),
@@ -481,20 +535,30 @@ public enum Gift {
FOUNTAIN(8887, "Fountain", 1200, "https://storage.streamdps.com/iblock/07d/07d678346c7eb588bc3cbddf343ab791/8f8f50f5350e4b1c0b151aff333e43a4.webp"),
KOALA(5822, "Koala", 10, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/22c8fa54da366c111f7bb915d4429e2d~tplv-obj.png"),
GARLAND_HEADPIECE(6437, "Garland Headpiece", 199, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/bdbdd8aeb2b69c173a3ef666e63310f3~tplv-obj.jpg"),
AEROBIC_HEADBAND(9255, "Aerobic headband", 99, "https://storage.streamdps.com/iblock/3d9/3d98c2fbc96922da37a9d22881bb06b9/0a99af132ab8e3fe9806d2412abc6bf0.webp"),
MOUNTAINS(9516, "Mountains", 12000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/51a7d74bcb4a6417be59f0ffc0b77e96.png~tplv-obj.png"),
FULL_MOON(7222, "Full moon", 299, "https://storage.streamdps.com/iblock/e64/e64dd135280596ce7f1aebbdc3e33a80/494b818b6a4217f1807255ca148c7b2d.webp"),
CHEEMS_DOG(6486, "Cheems Dog", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/d2c9e50efa3b9ff1ed31c96440a9d3a1~tplv-obj.png"),
CAT_PAWS(6046, "Cat Paws", 1, "https://storage.streamdps.com/iblock/c04/c04061e18b637df6759417bfe5418c9c/89bc2c5278f4a3c28acebdd10f6bc089.webp"),
WAVING_HAND(5959, "Waving Hand", 7, "https://storage.streamdps.com/iblock/6da/6da44060164719c3bcb171fb06d6d0d4/a80d1fa6879b0970246f41c444dca47c.webp"),
FRUITS_HAT_(6744, "Fruits Hat ", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2316b31fc5259cc29f281d88fbca0568~tplv-obj.png"),
BUBBLES(5850, "Bubbles", 500, "https://storage.streamdps.com/iblock/4b1/4b1a012395fd18f6ed835539089dd3c3/98688050698f0180bdd46018a4e98ec1.png"),
SILVER_SPORTS_CAR(8433, "Silver sports car", 5000, "https://storage.streamdps.com/iblock/132/132eb0981780e3e268f844106037b277/a1afff85fc6c53482fccbea21709d36b.webp"),
LIGHTNING_STORM(9515, "Lightning Storm", 6000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6f673fbb0ae6860e2b1e254538c958ba.png~tplv-obj.png"),
RACCOON(8448, "Raccoon", 15, "https://storage.streamdps.com/iblock/539/5396582d174489f32525f871cb3087f8/041896a3554f3d4b8c86f486bc81b125.webp"),
HEART_ME(7934, "Heart Me", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/d56945782445b0b8c8658ed44f894c7b~tplv-obj.jpg"),
@@ -503,6 +567,8 @@ public enum Gift {
TIKTOK_TROPHY(7357, "TikTok Trophy", 699, "https://storage.streamdps.com/iblock/7f6/7f6d5df92bf4b5b559567b9a870d485f/1811197db0860ff395435d51d35598ef.webp"),
LOVE_BOMB(6050, "Love Bomb", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2a1c1b14f5e9f7be5d76fa4928f574f1~tplv-obj.png"),
TENNIS(6169, "Tennis", 1, "https://storage.streamdps.com/iblock/f20/f20121609887f7ff35952c1bc52529e2/9ff66229b1f81d21b15444ba2b53db98.png"),
NECKLACE(5662, "Necklace", 400, "https://storage.streamdps.com/iblock/a40/a40013bbd1e38e11c0772f8b605c6c25/567d58bd02385de4af1523980cb03a85.png"),
@@ -515,6 +581,8 @@ public enum Gift {
BIRTHDAY_CAKE_9097(9097, "Birthday Cake", 1, "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"),
BANANA_LEAF_VESSEL(5991, "Banana leaf vessel", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8e635863e20cfa3651bd8a5b762ae72d~tplv-obj.png"),
ICE_LOLLY(6545, "Ice Lolly", 10, "https://storage.streamdps.com/iblock/93d/93dda2498d64aa0a29d444103a7804dd/92fd7397fffbaa8755cb233815964bbf.png"),
CONFETTI(5585, "Confetti", 100, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/cb4e11b3834e149f08e1cdcc93870b26~tplv-obj.jpg"),
@@ -547,6 +615,8 @@ public enum Gift {
CELEBRATION_TIME(6790, "Celebration Time", 6999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/e73e786041d8218d8e9dbbc150855f1b~tplv-obj.jpg"),
EXCLUSIVE_YACHT(9524, "Exclusive Yacht", 20000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/da8c85d5ae09ebf320216202e8fa015d.png~tplv-obj.jpg"),
MONTY(7742, "Monty", 1, "https://storage.streamdps.com/iblock/c70/c70e3a9404b18068056d04d5394d739a/4e0e55d9d10a7747b7caf462cd87b4b3.webp"),
PYRAMIDS(8416, "Pyramids", 15000, "https://storage.streamdps.com/iblock/988/988ffe82e8f3b235bd91dac1e31e708d/ad0365d14ba0480e5d6d60f6eb798608.webp"),
@@ -585,16 +655,22 @@ public enum Gift {
SWING(5899, "Swing", 399, "https://storage.streamdps.com/iblock/8a1/8a16a7c5d463793c8c3ab5aa407a87d8/dee86ec9c8e98ebcc58e2e3c09b93d10.png"),
STORMS_AT_SEA(9514, "Storms at sea", 2200, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4918fbbdf220873dd8cae4c94d1ae037.png~tplv-obj.png"),
SUPERHERO_FIGHT(8814, "Superhero fight", 30000, "https://storage.streamdps.com/iblock/d6b/d6b1c955153c8f8c5048d6c8f0d1b418/97d04b889e64328e9ab07224f6072b5f.webp"),
COOKIE(6883, "Cookie", 5, "https://storage.streamdps.com/iblock/fd2/fd20c8c619b1d43efb9f2fe1923c48a7/45c056f74c9f214dc55d464eab43b224.webp"),
DOG_BONE(8108, "Dog Bone", 10, "https://storage.streamdps.com/iblock/8ba/8badf8e0a5bcbf8d98ed6c4fc0e16c69/b0a8a8020986eb564713c042d23f83b2.webp"),
RUSSIAN_CREPES(5547, "Russian Crepes", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8525a07c6bf16a74eee66e9ad119b3b8.png~tplv-obj.png"),
FLYING_JETS(7482, "Flying Jets", 5000, "https://storage.streamdps.com/iblock/5a4/5a4f3c7adc31f60326e3adf1a3a20bf9/bc96de02ceba4b91c1f9c996293974b4.webp"),
FLYING_JETS_7720(7720, "Flying Jets", 5000, "https://storage.streamdps.com/iblock/738/73887ee5dc4a63709a10a2e3eff67b7c/1588215b603e2495582288471573cd57.webp"),
FLYING_JETS_9500(9500, "Flying Jets", 5000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1d067d13988e8754ed6adbebd89b9ee8.png~tplv-obj.jpg"),
INDOOR_FAN(6565, "Indoor Fan", 199, "https://storage.streamdps.com/iblock/499/499dc6bf36be95e90398a56d18bfeebe/231f634c0c86d034f193477f208f66ca.webp"),
MIC(5650, "Mic", 5, "https://storage.streamdps.com/iblock/1db/1dbec91a90cdeca9f7fb1ea7280ad5cd/cae0a287f4d2e8d0e1558dcbb4aa3b2f.png"),
@@ -621,12 +697,16 @@ public enum Gift {
ROMANTIC_CARRIAGE(5627, "Romantic Carriage", 6000, "https://storage.streamdps.com/iblock/681/68132980826d9ddb208928c54a798f7f/e4f143cb38a0687729539972b2132ac1.png"),
AMAZING(5983, "Amazing", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/18256fd3f4402601dd07c83adae3e9a2~tplv-obj.png"),
BRIDAL_VEIL(5902, "Bridal Veil", 299, "https://storage.streamdps.com/iblock/ac0/ac0cbd1870dd92251f6ef620acb652e5/fe8eca664be736231b8e8e2cc2237a15.png"),
TULIP_BOX(5325, "Tulip Box", 200, "https://storage.streamdps.com/iblock/d44/d4471e5deb9cb5831f846ca4c9df9c5d/7d1236ecd67b3e655c3dfd72673a423d.png"),
SQUIRREL(7213, "Squirrel", 1, "https://storage.streamdps.com/iblock/5c3/5c37dce1eab0d67386329f3a2920a874/38104bd52d316ea76464433b3b07dea7.webp"),
CHOC_CHIP_COOKIE(6416, "Choc Chip Cookie", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7dd2731de2e644301a329d3eb437b427~tplv-obj.png"),
METEOR_SHOWER(6563, "Meteor Shower", 3000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/71883933511237f7eaa1bf8cd12ed575~tplv-obj.jpg"),
CAKE(5720, "Cake", 20, "https://storage.streamdps.com/iblock/edb/edbe349c5a4be01ec1fbf2225d0f48dc/4169ef7f0263177384205df6663451c8.png"),
@@ -669,6 +749,10 @@ public enum Gift {
CHOCOLATE(5860, "Chocolate", 1, "https://storage.streamdps.com/iblock/522/52287f41673e2fd836c83ec78e95f08a/77307666e41e09e54052fd321c2906c4.png"),
RIO_DE_JANEIRO(7218, "Rio de Janeiro", 9999, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/34c0eb43c3d50e8ab64408171ebbe733~tplv-obj.png"),
BLOOMING_RIBBONS(9498, "Blooming Ribbons", 1000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f76750ab58ee30fc022c9e4e11d25c9d.png~tplv-obj.jpg"),
CORNFLOWER(8186, "Cornflower", 5, "https://storage.streamdps.com/iblock/025/025c50c390f6a12148a69728284c7298/36b50fe529db9d7db028b0774842e103.webp"),
ASMR_TIME_(6990, "ASMR Time ", 10, "https://storage.streamdps.com/iblock/49d/49dccba4525df92ed17678cc6ea47e95/b2c8c52d5294bb531d7d87a4c3ff97fe.webp"),
@@ -747,8 +831,12 @@ public enum Gift {
HI_MARCH(7977, "Hi March", 88, "https://storage.streamdps.com/iblock/e22/e2266686271c7a90ff04517f248c6f73/0459d679c01a5bfa5a4be1d61ec81ec8.webp"),
FANTASTIC(6813, "Fantastic", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a1b2204b06aa19d45a0338e9f0099ea7~tplv-obj.png"),
HEDGEHOG(6868, "Hedgehog", 299, "https://storage.streamdps.com/iblock/841/841e924150793d6961df0a1c89cc67ca/5886839b7de0b1289303081f9af380f8.webp"),
LIVE_FEST(9334, "LIVE Fest", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1e98afffef90ed4b2cc9c9ebb88e3608.png~tplv-obj.png"),
I_LOVE_TR(7139, "I LOVE TR", 1, "https://storage.streamdps.com/iblock/84d/84d68e92c471e7da792aa98d856c824c/7728ac60043efb9c96e2ce0f77dbef31.webp"),
SHIBA_INU(5482, "Shiba Inu", 222, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/ddbcee02f5b86b803b0ec34357cd82ec.png~tplv-obj.jpg"),
@@ -779,6 +867,8 @@ public enum Gift {
RHYTHMIC_BEAR(9468, "Rhythmic Bear", 2999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/16eacf541e4bd6816e88139d079519f5.png~tplv-obj.jpg"),
CRYSTAL_BALL(6428, "Crystal Ball", 1700, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7e4f9a99b7003ae05186f5324aae9fbf~tplv-obj.png"),
PHOENIX(7319, "Phoenix", 25999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/ef248375c4167d70c1642731c732c982~tplv-obj.jpg"),
BOUQUET_FLOWER(5780, "Bouquet Flower", 30, "https://storage.streamdps.com/iblock/ceb/cebb5d5f7004d6ccf9336ae20281be88/5061b1767c2325fe6704eb08d97c5cb8.png"),
@@ -799,6 +889,8 @@ public enum Gift {
FRUITS_HAT(7091, "Fruits Hat", 199, "https://storage.streamdps.com/iblock/404/404cc4794702cc6feb93bf4517bc0762/05846cb2d9548cf2f0573159110ecb64.webp"),
SPINNING_TOP(6483, "Spinning Top", 10, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/6cde70e04a6b40a9879f7b99ff191808~tplv-obj.png"),
MISHKA_BEAR(5486, "Mishka Bear", 100, "https://storage.streamdps.com/iblock/880/8809f52dbf40e0d670067f8c223d7c04/c603798bc6cd2bdc5a032ddbeb55e258.png"),
MISHKA_BEAR_5566(5566, "Mishka Bear", 100, "https://storage.streamdps.com/iblock/010/010ccc7a5d5e21231b46cea3223d5b1f/aa9c15ca87e4df8dad9be22164978fc2.png"),
@@ -827,8 +919,12 @@ public enum Gift {
BIG_LOVE(7224, "Big Love", 5, "https://storage.streamdps.com/iblock/9d7/9d791fea266e119ffd938095526a1b55/1923108683e8c0aba3b78e1d0e8137cf.webp"),
TGIF(6592, "TGIF", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2734231d880b5cd20149f4cc8c760279~tplv-obj.png"),
GOLDEN_GAMEPAD(6582, "Golden Gamepad", 30, "https://storage.streamdps.com/iblock/e85/e85940610dd45adc8733b51106c60712/ca839e1139ca0b94070c1e38093e95ec.png"),
COCONUT_TREE(5794, "Coconut Tree", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/eb0923dbab5251f4c2e0496b11b55c4f~tplv-obj.png"),
SUMMER_BAND(6555, "Summer Band", 3999, "https://storage.streamdps.com/iblock/43b/43b88814d979720d80a6e17258ab3bd8/b1abf3d90ae212317d6ae339ed5f5be7.png"),
GORILLA(8602, "Gorilla", 30000, "https://storage.streamdps.com/iblock/1e2/1e29b9d1a0263f1487498dc556cdcbc1/bec227242f8c9b258855071aa050ac17.webp"),
@@ -845,12 +941,16 @@ public enum Gift {
COOPER_SKATES_HOME(6865, "Cooper Skates Home", 599, "https://storage.streamdps.com/iblock/041/04184b09ec8e7bf137d33cf57ce4eec9/3c2e360b023b9980e54e9d9a394883b9.webp"),
EXCLUSIVE_JET(9523, "Exclusive Jet", 5000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1cc167a00aa4d5dfe48018afb38c3daa.png~tplv-obj.jpg"),
BIRTHDAY_PARTY(6787, "Birthday Party", 6999, "https://storage.streamdps.com/iblock/135/135b2ac0877de059f56e510b0ac70d08/07285ba7471fb98743bfe308d0b58ce2.webp"),
BIRTHDAY_PARTY_9095(9095, "Birthday Party", 6999, "https://storage.streamdps.com/iblock/d0d/d0d1164a9ed81239b70cb25b93927023/d0dba293643c67dc33c1f4dda04e5b50.webp"),
TEASING(6390, "Teasing", 401, "https://storage.streamdps.com/iblock/e14/e14c9b35975f1da5b8a5e3f116dae2bb/9f8cea9b65620e8376e44802c25ddf27.png"),
CRICKET(6006, "Cricket", 99, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/408d55c0526ada808be7db3e22c02a56~tplv-obj.png"),
FOAMY_DRINK(6740, "Foamy Drink", 100, "https://storage.streamdps.com/iblock/cc8/cc8133c73d5ca2cb5fde306f5b4e2a11/fb273956755fe6fbf7263023a9c36ebe.webp"),
CAPYBARA(8217, "Capybara", 30, "https://storage.streamdps.com/iblock/e94/e944534be54186446d7c38563c772029/553d899c4bd4be31e7b051bb36e842f8.webp"),
@@ -897,6 +997,8 @@ public enum Gift {
GRAPES(7234, "Grapes", 1, "https://storage.streamdps.com/iblock/442/442580106ac8748b79ef450eb25b5981/df624c619c48b583adee184bca134c80.webp"),
LLAMA_GREETINGS(6531, "Llama Greetings", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a6b95ce6350f5f4bdff6880ac6993789~tplv-obj.png"),
SAM_THE_WHALE(8391, "Sam the Whale", 30000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/f48a1887eb88238738996bb997b31c0f.png~tplv-obj.jpg"),
DIAMOND_TREE(7963, "Diamond Tree", 1088, "https://storage.streamdps.com/iblock/47a/47afc3c8563cacbff2ce13f2310a2fc4/84761a2a3e0431bda3bf3d2cc9d02b3f.webp"),
@@ -913,10 +1015,14 @@ public enum Gift {
BIRD_WHISPERER(8344, "Bird Whisperer", 5000, "https://storage.streamdps.com/iblock/079/079bf5895816fb04293d01375eaf23a5/672128ca0f65deb0e75e2a9a690a79f0.webp"),
GOOD_NIGHT(8268, "Good Night", 399, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b7b55087141bd5f965eb31a99a5f157b~tplv-obj.png"),
ALIEN_PEACE_SIGN(7831, "Alien Peace Sign", 1, "https://storage.streamdps.com/iblock/5f7/5f7b29f5c7a4ca3a4dbbe8dc0e195459/cd83433a0f1697a0b66a891cbd7cf1af.webp"),
THE_MAGIC_LAMP(7161, "The Magic Lamp", 1000, "https://storage.streamdps.com/iblock/e0d/e0d45fccd69220f321531383d97f51fc/4296cc4b886f31bb5b2cf106ebf640ab.webp"),
TACO_(6113, "Taco ", 9, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/43d06db8c962623dbed6ecf70fb89ca8~tplv-obj.png"),
TIARA(8496, "Tiara", 299, "https://storage.streamdps.com/iblock/1b1/1b1ee7b697bae41ee2cbf834d1f1099e/303eec791a710c2417bb5075529681d9.webp"),
COFFEE(5333, "Coffee", 1, "https://storage.streamdps.com/iblock/920/920b64634d946a2238950c353c16df81/0fe22d9bdee1bd6d9d77f66bcd8cf45a.png"),
@@ -953,8 +1059,12 @@ public enum Gift {
OWL(5885, "Owl", 500, "https://storage.streamdps.com/iblock/e87/e87fc92de64aa711c6ce23ed3b2214c2/338e115665b1c9f75108b50a43adb95b.png"),
TOP_HOST(6194, "Top Host", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5947dc37282c417b411c61f20ee7d6d4~tplv-obj.png"),
TIKTOK_CROWN(8873, "TikTok Crown", 299, "https://storage.streamdps.com/iblock/a79/a790613bdf2e83725d0519bbf289529d/83bb670c15ab91b9192c50300f4c8054.webp"),
LOVED(6705, "Loved", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2a41781b0a29ba3c409c5dd83eed07f8~tplv-obj.png"),
ON_FIRE(6840, "On Fire", 200, "https://storage.streamdps.com/iblock/cba/cba95075d6b63b84fbc52abb9d1d8208/d93ecc0b966bf972f01e77339a68e124.webp"),
ON_FIRE_6958(6958, "On Fire", 200, "https://storage.streamdps.com/iblock/4ec/4ec314b4ee7dff4e92a8e1e75100dddf/19c9b5d8b5f24b1465632a31e55edca1.webp"),
@@ -1037,6 +1147,8 @@ public enum Gift {
NACHOS(7088, "Nachos", 9, "https://storage.streamdps.com/iblock/ff1/ff16cd1c796189ed8fcfdb019eb224ef/1ae8b0b05294c56b99197256fcaa3fd4.webp"),
SNAG(6411, "Snag", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/aa2d9b162c766a7fdf71fcead6d7bbcd~tplv-obj.png"),
APPETIZERS(6106, "Appetizers", 19, "https://storage.streamdps.com/iblock/76b/76b94aaced493a2448cf655b5468feaf/8c1bea41ec9fb547f0a0eb46d658a1c8.png"),
LOVE_LETTER(7932, "Love Letter", 1, "https://storage.streamdps.com/iblock/a40/a40cb58d5e8c07fa3e46a9acb4e34f6f/477507a1b14df0a22ef895c6214f3789.webp"),
@@ -1047,8 +1159,12 @@ public enum Gift {
BUMPER_CARS(5996, "Bumper Cars", 1288, "https://storage.streamdps.com/iblock/53b/53b569311552b729d1b347268370e576/8f236deca90a65e7046f7576d69976af.png"),
CAMPFIRE(5843, "Campfire", 388, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e280eb1b7fe92b4efe612d98064d5a2d~tplv-obj.png"),
CAKE_SLICE(6784, "Cake Slice", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/f681afb4be36d8a321eac741d387f1e2~tplv-obj.jpg"),
EXCLUSIVE_SPARK(9522, "Exclusive Spark", 1000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f0bda1eb6856e2feea9cfcb6c575c8a0.png~tplv-obj.jpg"),
CROCODILE(8740, "Crocodile", 10, "https://storage.streamdps.com/iblock/4e2/4e2d9df24c472158b8ed93546fc73b16/75722a173b75d601e0a80a679902529f.webp"),
LOVE_YOU_6671(6671, "Love You", 199, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/134e51c00f46e01976399883ca4e4798~tplv-obj.jpg"),
@@ -1063,8 +1179,12 @@ public enum Gift {
DIAMOND_CROWN_5604(5604, "Diamond Crown", 1499, "https://storage.streamdps.com/iblock/3b5/3b56c2352a02829ac4445094a3f76b51/738ad17c91919a940ee2001f9f262a95.png"),
COCONUT_DRINK(8225, "Coconut Drink", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ce27ad017f987240dc447e65ae866f4f~tplv-obj.png"),
M4_TROPHY(7544, "M4 Trophy", 450, "https://storage.streamdps.com/iblock/f40/f40a34a8e59806907deaa4f74df3462d/8deac28cb21517228bcd354645a987ea.webp"),
FLOWER(6034, "Flower", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9c20971eeb28b6b4ba37e57df3983da0~tplv-obj.png"),
PERFUME(5658, "Perfume", 20, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/20b8f61246c7b6032777bb81bf4ee055~tplv-obj.jpg"),
KISS_YOUR_HEART(6661, "Kiss your Heart", 99, "https://storage.streamdps.com/iblock/13d/13d940df83e04a30523ca88c080ee8d8/213f06af314da4637a9ae8fc25bfaea3.webp"),

View File

@@ -45,6 +45,8 @@ public class User {
@Getter(AccessLevel.NONE)
private Set<UserAttribute> attributes;
public List<UserAttribute> getAttributes() {
return attributes.stream().toList();
}
@@ -107,6 +109,23 @@ public class User {
this.attributes = new HashSet<>();
}
public User(Long id,
String name,
String profileName,
Picture picture,
long following,
long followers,
List<Badge> badges) {
this.id = id;
this.name = name;
this.profileName = profileName;
this.picture = picture;
this.following = following;
this.followers = followers;
this.badges = badges;
this.attributes = new HashSet<>();
}
public User(Long userId,
String nickName) {
this.id = userId;

View File

@@ -26,15 +26,20 @@ package io.github.jwdeveloper.tiktok.exceptions;
/**
* Happens when incoming data from TikTok can not be mapped to TikTokEvent's
*/
public class TikTokMessageMappingException extends TikTokLiveException
{
public TikTokMessageMappingException(Class<?> inputClazz, Class<?> outputClass, Throwable throwable)
{
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + " to class " + outputClass.getSimpleName(),throwable);
public class TikTokMessageMappingException extends TikTokLiveException {
public TikTokMessageMappingException(Class<?> inputClazz, Class<?> outputClass, Throwable throwable) {
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + " to class " + outputClass.getSimpleName(), throwable);
}
public TikTokMessageMappingException(Class<?> inputClazz, Class<?> outputClass, String message)
{
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + " to class " + outputClass.getSimpleName()+": "+message);
public TikTokMessageMappingException(Class<?> inputClazz, Class<?> outputClass, String message) {
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + " to class " + outputClass.getSimpleName() + ": " + message);
}
public TikTokMessageMappingException(Class<?> inputClazz, String message, Throwable throwable) {
super("Unable to handle mapping from class: " + inputClazz.getSimpleName() + ": " + message, throwable);
}
public TikTokMessageMappingException(String message, Throwable throwable) {
super( message, throwable);
}
}

View File

@@ -22,14 +22,31 @@
*/
package io.github.jwdeveloper.tiktok.live;
import io.github.jwdeveloper.tiktok.data.models.RankingUser;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.models.ConnectionState;
import java.util.List;
public interface LiveRoomInfo
{
/**
*
* @return get current count of viewers of live
*/
int getViewersCount();
/**
*
* @return get total current count of viewers since beginning of live
*/
int getTotalViewersCount();
int getLikesCount();
boolean isAgeRestricted();
String getRoomId();
String getHostName();
String getTitle();
User getHostUser();
List<RankingUser> getUsersRanking();
ConnectionState getConnectionState();
}

View File

@@ -22,6 +22,7 @@
*/
package io.github.jwdeveloper.tiktok.live;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import lombok.Data;
@Data
@@ -29,6 +30,11 @@ public class LiveRoomMeta {
private LiveRoomStatus status;
private boolean ageRestricted;
private String titie;
private int likeCount;
private int totalViewers;
private int viewers;
private User host;
public enum LiveRoomStatus
{

View File

@@ -24,11 +24,9 @@ package io.github.jwdeveloper.tiktok.live.builder;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomUserInfoEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
@@ -40,9 +38,14 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandl
public interface EventsBuilder<T> {
T onRoom(EventConsumer<TikTokRoomEvent> event);
/**
* Method used to register own custom events
* @param eventClazz event class
* @param event action
*/
<E extends TikTokEvent> T onCustomEvent(Class<E> eventClazz, EventConsumer<E> event);
T onRoomUserInfo(EventConsumer<TikTokRoomUserInfoEvent> event);
T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event);
T onComment(EventConsumer<TikTokCommentEvent> event);
@@ -53,9 +56,8 @@ public interface EventsBuilder<T> {
T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> event);
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> event);
T onGift(EventConsumer<TikTokGiftEvent> event);
T onQuestion(EventConsumer<TikTokQuestionEvent> event);
@@ -71,12 +73,13 @@ public interface EventsBuilder<T> {
T onJoin(EventConsumer<TikTokJoinEvent> event);
T onShare(EventConsumer<TikTokShareEvent> event);
T onUnhandledSocial(EventConsumer<TikTokUnhandledSocialEvent> event);
// T onChest(EventConsumer<TikTokChestEvent> event);
// T onChest(EventConsumer<TikTokChestEvent> event);
T onLivePaused(EventConsumer<TikTokLivePausedEvent> event);
T onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event);
T onLiveEnded(EventConsumer<TikTokLiveEndedEvent> event);
T onConnected(EventConsumer<TikTokConnectedEvent> event);
@@ -86,11 +89,10 @@ public interface EventsBuilder<T> {
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> event);
T onError(EventConsumer<TikTokErrorEvent> event);
T onEvent(EventConsumer<TikTokEvent> event);
// TODO Figure out how those events works
//T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);

View File

@@ -23,20 +23,60 @@
package io.github.jwdeveloper.tiktok.live.builder;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
LiveClientBuilder configure(Consumer<ClientSettings> consumer);
/**
* This method is triggered after default mappings are registered
* It could be used to OVERRIDE behaviour of mappings and implement custom behaviour
*
* Be aware if for example you override WebcastGiftEvent, onGiftEvent() will not be working
*
* @param onCustomMappings lambda method
* @return
*/
LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings);
/**
* Configuration of client settings
* @see ClientSettings
* @param onConfigure
* @return
*/
LiveClientBuilder configure(Consumer<ClientSettings> onConfigure);
/**
* @see TikTokEventListener
* Adding events listener class, its fancy way to register events without using lamda method
* but actual method in class that implements TikTokEventListener
* @return
*/
LiveClientBuilder addListener(TikTokEventListener listener);
/**
*
* @return LiveClient object
*/
LiveClient build();
/**
*
* @return LiveClient object and connects to TikTok live
*/
LiveClient buildAndConnect();
/**
*
* @return LiveClient object and connects to TikTok live asynchronously
*/
CompletableFuture<LiveClient> buildAndConnectAsync();
}

View File

@@ -0,0 +1,73 @@
package io.github.jwdeveloper.tiktok.mappers;
import com.google.protobuf.GeneratedMessageV3;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import java.util.List;
import java.util.function.Function;
public interface TikTokMapper {
/**
* Triggered when `sourceClass` is mapped,
* input is bytes that are coming from TikTok in `sourceClass` packet
* output is TikTok event we want to create
* <p>
* bytesToEvent(WebcastGiftMessage.class, bytes ->
* {
* var giftMessage = WebcastGiftMessage.parseFrom(bytes);
* var giftName = giftMessage.getGift().getName();
* return new TikTokEvent(Gift.ROSE, giftMessage);
* })
*
* @param sourceClass protocol buffer webcast class
* @param onMapping lambda function that is triggered on mapping. takes as input ProtocolBuffer object and as output TikTokEvent
*/
void bytesToEvent(Class<? extends GeneratedMessageV3> sourceClass, Function<byte[], TikTokEvent> onMapping);
void bytesToEvents(Class<? extends GeneratedMessageV3> sourceClass, Function<byte[], List<TikTokEvent>> onMapping);
/**
* In case you found some TikTok message that has not Webcast class use this method
*
* @param messageName Name of TikTok data event
* @param onMapping lambda function that is triggered on mapping. takes as input ProtocolBuffer object and as output TikTokEvent
*/
void bytesToEvent(String messageName, Function<byte[], TikTokEvent> onMapping);
void bytesToEvents(String messageName, Function<byte[], List<TikTokEvent>> onMapping);
/**
* This method can be used to override default mapping for
* certain TikTok incoming data message. For this example
* we are overriding WebcastGiftMessage and retuning CustomGiftEvent
* instead of TikTokGiftEvent
* <p>
* webcastObjectToEvent(WebcastGiftMessage.class, webcastGiftMessage ->
* {
* var giftName = webcastGiftMessage.getGift().getName();
* var user = webcastGiftMessage.getUser().getNickname();
* return new CustomGiftEvent(giftName, user);
* })
*
* @param sourceClass ProtocolBuffer class that represent incoming custom data, hint class should starts with Webcast prefix
* @param onMapping lambda function that is triggered on mapping. takes as input ProtocolBuffer object and as output TikTokEvent
*/
<T extends GeneratedMessageV3> void webcastObjectToEvent(Class<T> sourceClass, Function<T, TikTokEvent> onMapping);
<T extends GeneratedMessageV3> void webcastObjectToEvents(Class<T> sourceClass, Function<T, List<TikTokEvent>> onMapping);
/**
* Triggered when `sourceClass` is mapped,
* looking for constructor in `outputClass` with one parameter that is of type `sourceClass`
* and created instance of object from this constructor
*
* @param sourceClass protocol buffer webcast class
* @param outputClass TikTok event class
*/
void webcastObjectToConstructor(Class<? extends GeneratedMessageV3> sourceClass, Class<? extends TikTokEvent> outputClass);
}

View File

@@ -25,8 +25,10 @@ package io.github.jwdeveloper.tiktok.utils;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.GsonBuilder;
import io.github.jwdeveloper.tiktok.data.dto.MessageMetaData;
import java.awt.*;
import java.time.Duration;
import java.util.ArrayList;
public class JsonUtil {
@@ -34,13 +36,25 @@ public class JsonUtil {
return new GsonBuilder()
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
public boolean shouldSkipField(FieldAttributes fieldAttributes)
{
return false;
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
return aClass.equals(Image.class);
public boolean shouldSkipClass(Class<?> aClass)
{
if(aClass.equals(Image.class))
{
return true;
}
if(aClass.equals(MessageMetaData.class))
{
return true;
}
return false;
}
})
.disableHtmlEscaping()

View File

@@ -0,0 +1,56 @@
package io.github.jwdeveloper.tiktok.utils;
import java.nio.file.Path;
import java.util.Map;
import java.util.TreeMap;
public class ProtoBufferFileGenerator {
public static String generate(ProtoBufferObject protoBuffObj, String name) {
var sb = new StringBuilder();
var offset = 2;
sb.append("message ").append(name).append(" { \n");
var objects = new TreeMap<String, ProtoBufferObject>();
var objectCounter = 0;
for (var entry : protoBuffObj.getFields().entrySet()) {
var index = entry.getKey();
var field = entry.getValue();
var fieldName = field.type.toLowerCase() + "Value";
var value = field.value;
if (field.value instanceof ProtoBufferObject object) {
fieldName += objectCounter;
value = "";
objects.put(fieldName,object);
objectCounter++;
}
for (var i = 0; i < offset; i++) {
sb.append(" ");
}
sb.append(field.type).append(" ").append(fieldName)
.append(" ")
.append("=")
.append(" ")
.append(index)
.append(";")
.append(" //")
.append(value)
.append("\n");
}
sb.append(" \n");
for(var object : objects.entrySet())
{
var structure = generate(object.getValue(),object.getKey());
sb.append(structure);
}
sb.append(" \n");
sb.append("} \n");
return sb.toString();
}
}

View File

@@ -0,0 +1,31 @@
package io.github.jwdeveloper.tiktok.utils;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
public class ProtoBufferJsonGenerator {
public static JsonObject genratejson(ProtoBufferObject protoBuffObj) {
JsonObject jsonObject = new JsonObject();
for (var entry : protoBuffObj.getFields().entrySet()) {
var fieldName = entry.getKey() + "_" + entry.getValue().type;
if (entry.getValue().value instanceof ProtoBufferObject protoObj)
{
JsonObject childJson = genratejson(protoObj);
jsonObject.add(fieldName, childJson);
continue;
}
var value = entry.getValue().value.toString();
jsonObject.addProperty(fieldName, value);
}
return jsonObject;
}
public static String generate(ProtoBufferObject protoBufferObject) {
var json = genratejson(protoBufferObject);
var gson = new GsonBuilder().setPrettyPrinting().create();
return gson.toJson(json);
}
}

View File

@@ -0,0 +1,76 @@
package io.github.jwdeveloper.tiktok.utils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Map;
import java.util.TreeMap;
public class ProtoBufferObject {
@Getter
private final Map<Integer, ProtoBufferField> fields;
public ProtoBufferObject() {
this.fields = new TreeMap<>();
}
public void addField(int index, String type, Object value) {
fields.put(index, new ProtoBufferField(type, value));
}
public void addField(int index, ProtoBufferField value) {
fields.put(index, value);
}
public String toProtoFile()
{
return ProtoBufferFileGenerator.generate(this,"UnknownMessage");
}
public String toJson()
{
return ProtoBufferJsonGenerator.generate(this);
}
@Override
public String toString() {
return toString(0, true);
}
public String toString(int offset ,boolean nested) {
var sb = new StringBuilder();
sb.append("\n");
for (var entry : fields.entrySet()) {
var index = entry.getKey();
var field = entry.getValue();
for(var i =0;i<offset;i++)
{
sb.append(" ");
}
sb.append(index).append(" ")
.append(field.type).append(" ");
var value = field.value;
if (value instanceof ProtoBufferObject child) {
sb.append(child.toString(offset+2,nested));
} else {
sb.append(entry.getValue().value);
}
sb.append("\n");
}
return sb.toString();
}
@AllArgsConstructor
public class ProtoBufferField {
public String type;
public Object value;
}
}

View File

@@ -0,0 +1,94 @@
package io.github.jwdeveloper.tiktok.utils;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.UnknownFieldSet;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.util.Base64;
public class ProtocolUtils {
public static String toBase64(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
public static String toBase64(WebcastResponse.Message bytes) {
return Base64.getEncoder().encodeToString(bytes.toByteArray());
}
public static byte[] fromBase64(String base64) {
return Base64.getDecoder().decode(base64);
}
public static ProtoBufferObject getProtocolBufferStructure(byte[] bytes) {
try {
var files = UnknownFieldSet.parseFrom(bytes);
var protoBufferObject = new ProtoBufferObject();
createStructure(files, protoBufferObject);
return protoBufferObject;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void createStructure(UnknownFieldSet unknownFieldSet, ProtoBufferObject root) throws InvalidProtocolBufferException {
for (var entry : unknownFieldSet.asMap().entrySet()) {
var objectValue = entry.getValue();
var type = "undefind";
Object value = null;
var index = entry.getKey();
if (!objectValue.getLengthDelimitedList().isEmpty()) {
var nestedObject = new ProtoBufferObject();
for (var str : objectValue.getLengthDelimitedList()) {
try {
var nestedFieldsSet = UnknownFieldSet.parseFrom(str);
createStructure(nestedFieldsSet, nestedObject);
} catch (Exception e)
{
type = "string";
value = str.toStringUtf8();
}
}
if (value != null) {
root.addField(index, "string", value);
} else {
root.addField(index, "object", nestedObject);
}
continue;
}
if (!objectValue.getFixed32List().isEmpty()) {
type = "Fixed32List";
value = objectValue.getFixed32List();
}
if (!objectValue.getFixed64List().isEmpty()) {
type = "Fixed64List";
value = objectValue.getFixed64List();
}
if (!objectValue.getGroupList().isEmpty()) {
type = "getGroupList";
value = objectValue.getGroupList();
}
if (!objectValue.getVarintList().isEmpty()) {
type = "int";
value = objectValue.getVarintList().get(0);
}
root.addField(index, type, value);
}
}
public static WebcastResponse.Message fromBase64ToMessage(String base64) throws InvalidProtocolBufferException {
var bytes = fromBase64(base64);
return WebcastResponse.Message.parseFrom(bytes);
}
}

View File

@@ -974,3 +974,159 @@ message FanTicketRoomNoticeContent {
int64 EventTime = 4;
string FanTicketIconUrl = 5;
}
message LinkerAcceptNoticeContent {
int64 FromUserId = 1;
int64 FromRoomId = 2;
int64 ToUserId = 3;
}
message LinkerCancelContent {
int64 FromUserId = 1;
int64 ToUserId = 2;
int64 CancelType = 3;
int64 ActionId = 4;
}
message LinkerCloseContent {
}
message LinkerCreateContent {
int64 OwnerId = 1;
int64 OwnerRoomId = 2;
int64 LinkType = 3;
}
message LinkerEnterContent {
repeated User LinkedUsersList = 1;
//LinkmicMultiLiveEnum AnchorMultiLiveEnum = 2;
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 3;
}
message LinkerInviteContent {
int64 FromUserId = 1;
int64 FromRoomId = 2;
string ToRtcExtInfo = 3;
bool RtcJoinChannel = 4;
int64 Vendor = 5;
string SecFromUserId = 6;
string ToLinkmicIdStr = 7;
User FromUser = 8;
int64 RequiredMicIdx = 9;
map<int64, string> RtcExtInfoMap = 10;
//Data.LinkmicMultiLiveEnum AnchorMultiLiveEnum = 11;
//Data.LinkmicUserSettingInfo AnchorSettingInfo = 12;
string InviterLinkmicIdStr = 13;
// InviteTopHostInfo FromTopHostInfo = 16;
int64 ActionId = 17;
// repeated LinkmicUserInfo LinkedUsersList = 18;
// Data.PerceptionDialogInfo Dialog = 19;
// Data.PunishEventInfo PunishInfo = 20;
int32 FromRoomAgeRestricted = 21;
// Data.Tag FromTag = 22;
// repeated Data.CohostABTestSetting AbTestSettingList = 23;
// Data.LinkerInviteMessageExtra LinkerInviteMsgExtra = 101;
}
message LinkerKickOutContent {
int64 FromUserId = 1;
//LinkMic.KickoutReason KickoutReason = 2;
}
message LinkerLeaveContent {
int64 UserId = 1;
string LinkmicIdStr = 2;
int64 SendLeaveUid = 3;
int64 LeaveReason = 4;
}
message LinkerLinkedListChangeContent {
repeated User LinkedUsersList = 1;
}
message LinkerListChangeContent {
repeated User LinkedUsersList = 1;
repeated User AppliedUsersList = 2;
repeated User ConnectingUsersList = 3;
}
message LinkerMediaChangeContent {
// MicIdxOperation Op = 1;
int64 ToUserId = 2;
int64 AnchorId = 3;
int64 RoomId = 4;
// LinkerSceneType ChangeScene = 5;
}
message LinkerMicIdxUpdateContent {
LinkerMicIdxUpdateInfo MicIdxUpdateInfo = 1;
}
message LinkerMicIdxUpdateInfo {
// MicIdxOperation Op = 1;
int64 UserId = 2;
int64 MicIdx = 3;
}
message LinkerMuteContent {
int64 UserId = 1;
// Data.MuteStatus Status = 2;
}
message LinkerRandomMatchContent {
User User = 1;
int64 RoomId = 2;
int64 InviteType = 3;
string MatchId = 4;
int64 InnerChannelId = 5;
}
message LinkerReplyContent {
int64 FromUserId = 1;
int64 FromRoomId = 2;
// LinkmicInfo FromUserLinkmicInfo = 3;
int64 ToUserId = 4;
// LinkmicInfo ToUserLinkmicInfo = 5;
int64 LinkType = 6;
int64 ReplyStatus = 7;
LinkerSetting LinkerSetting = 8;
User FromUser = 9;
User ToUser = 10;
map<int64, string> RtcExtInfoMap = 11;
LinkerMicIdxUpdateInfo InviteeMicIdxUpdateInfo = 12;
map<int64, int64> ApplierMicIdxInfoMap = 13;
// Data.LinkmicMultiLiveEnum AnchorMultiLiveEnum = 14;
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 15;
int64 ActionId = 16;
// repeated LinkmicUserInfo LinkedUsersList = 17;
int64 SourceType = 18;
}
message LinkerSetting {
int64 MaxMemberLimit = 1;
int64 LinkType = 2;
int64 Scene = 3;
int64 OwnerUserId = 4;
int64 OwnerRoomId = 5;
int64 Vendor = 6;
}
message LinkerSysKickOutContent {
int64 UserId = 1;
string LinkmicIdStr = 2;
}
message LinkerUpdateUserContent {
int64 FromUserId = 1;
int64 ToUserId = 2;
map<string, string> UpdateInfoMap = 3;
}
message LinkerUpdateUserSettingContent {
// Data.LinkmicUserSettingInfo UpdateUserSettingInfo = 1;
}
message LinkerWaitingListChangeContent {
}

View File

@@ -68,6 +68,7 @@ enum MemberMessageAction {
enum ControlAction {
ControlActionUNKNOWN = 0;
STREAM_PAUSED = 1; // Stream Paused by Host
STREAM_UNPAUSED = 2;
STREAM_ENDED = 3; // Stream Ended by Host
}

View File

@@ -177,6 +177,8 @@ message WebcastCaptionMessage {
}
}
// Comment sent by User
//@WebcastChatMessage
message WebcastChatMessage {
@@ -608,7 +610,7 @@ message WebcastUnauthorizedMemberMessage {
string nickName = 4;
Text enterText = 5;
}
S
//@WebcastMsgDetectMessage
message WebcastMsgDetectMessage {
Common common = 1;
@@ -681,29 +683,33 @@ message WebcastSystemMessage {
//@WebcastLinkMessage
message WebcastLinkMessage {
Common common = 1;
uint32 data1 = 2;
uint64 data2 = 3;
uint32 data3 = 4;
LinkMessageData data = 18;
LinkMessageUserContainer user = 20;
string token = 200;
message LinkMessageData {
DataContainer data = 1; // index 1 is an Id
}
message LinkMessageUserContainer {
LinkMessageUser user = 1;
repeated LinkMessageUser otherUsers = 2;
message LinkMessageUser {
User user = 1;
uint64 timeStamp = 2;
uint32 data1 = 4;
string idString = 5;
uint32 data2 = 7;
}
}
int64 MessageType = 2;
int64 LinkerId = 3;
int64 Scene = 4;
LinkerInviteContent InviteContent = 5;
LinkerReplyContent ReplyContent = 6;
LinkerCreateContent CreateContent = 7;
LinkerCloseContent CloseContent = 8;
LinkerEnterContent EnterContent = 9;
LinkerLeaveContent LeaveContent = 10;
LinkerCancelContent CancelContent = 11;
LinkerKickOutContent KickOutContent = 12;
LinkerLinkedListChangeContent LinkedListChangeContent = 13;
LinkerUpdateUserContent UpdateUserContent = 14;
LinkerWaitingListChangeContent WaitingListChangeContent = 15;
LinkerMuteContent MuteContent = 16;
LinkerRandomMatchContent RandomMatchContent = 17;
LinkerUpdateUserSettingContent UpdateUserSettingContent = 18;
LinkerMicIdxUpdateContent MicIdxUpdateContent = 19;
LinkerListChangeContent ListChangeContent = 20;
// CohostListChangeContent CohostListChangeContent = 21;
LinkerMediaChangeContent MediaChangeContent = 22;
LinkerAcceptNoticeContent ReplyAcceptNoticeContent = 23;
LinkerSysKickOutContent SysKickOutContent = 101;
// LinkmicUserToastContent UserToastContent = 102;
string Extra = 200;
int64 ExpireTimestamp = 201;
string TransferExtra = 202;
}
//@WebcastLinkLayerMessage

View File

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

View File

@@ -25,6 +25,7 @@ package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
@@ -92,8 +93,7 @@ public class TikTokLiveClient implements LiveClient {
public void connect() {
try {
tryConnect();
} catch (TikTokLiveException e)
{
} catch (TikTokLiveException e) {
setState(ConnectionState.DISCONNECTED);
tikTokEventHandler.publish(this, new TikTokErrorEvent(e));
tikTokEventHandler.publish(this, new TikTokDisconnectedEvent());
@@ -108,6 +108,10 @@ public class TikTokLiveClient implements LiveClient {
this.connect();
}
throw e;
} catch (Exception e) {
logger.info("Unhandled exception report this bug to github https://github.com/jwdeveloper/TikTokLiveJava/issues");
this.disconnect();
e.printStackTrace();
}
}
@@ -127,6 +131,7 @@ public class TikTokLiveClient implements LiveClient {
setState(ConnectionState.CONNECTING);
apiService.updateSessionId();
if (clientSettings.getRoomId() != null) {
@@ -138,14 +143,24 @@ public class TikTokLiveClient implements LiveClient {
}
var roomData = apiService.fetchRoomInfo();
if (roomData.getStatus() != LiveRoomMeta.LiveRoomStatus.HostOnline) {
throw new TikTokLiveOfflineHostException("LiveStream for Host name could not be found. Is the Host online?");
var liveRoomMeta = apiService.fetchRoomInfo();
if (liveRoomMeta.getStatus() == LiveRoomMeta.LiveRoomStatus.HostNotFound) {
throw new TikTokLiveOfflineHostException("LiveStream for Host name could not be found.");
}
if (liveRoomMeta.getStatus() == LiveRoomMeta.LiveRoomStatus.HostOffline) {
throw new TikTokLiveOfflineHostException("LiveStream for not be found, is the Host offline?");
}
liveRoomInfo.setTitle(liveRoomMeta.getTitie());
liveRoomInfo.setViewersCount(liveRoomMeta.getViewers());
liveRoomInfo.setTotalViewersCount(liveRoomMeta.getTotalViewers());
liveRoomInfo.setAgeRestricted(liveRoomMeta.isAgeRestricted());
liveRoomInfo.setHost(liveRoomMeta.getHost());
var clientData = apiService.fetchClientData();
webSocketClient.start(clientData, this);
setState(ConnectionState.CONNECTED);
tikTokEventHandler.publish(this, new TikTokRoomInfoEvent(liveRoomInfo));
}

View File

@@ -28,9 +28,8 @@ import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomUserInfoEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
@@ -41,8 +40,14 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandl
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
import io.github.jwdeveloper.tiktok.live.GiftManager;
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
import io.github.jwdeveloper.tiktok.mappers.events.TikTokCommonEventHandler;
import io.github.jwdeveloper.tiktok.mappers.events.TikTokGiftEventHandler;
import io.github.jwdeveloper.tiktok.mappers.events.TikTokRoomInfoEventHandler;
import io.github.jwdeveloper.tiktok.mappers.events.TikTokSocialMediaEventHandler;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
@@ -53,6 +58,7 @@ import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
import io.github.jwdeveloper.tiktok.messages.webcast.*;
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
@@ -66,9 +72,11 @@ import java.util.logging.*;
public class TikTokLiveClientBuilder implements LiveClientBuilder {
protected final ClientSettings clientSettings;
protected final Logger logger;
protected final TikTokEventObserver tikTokEventHandler;
protected final List<TikTokEventListener> listeners;
protected Consumer<TikTokMapper> onCustomMappings;
public TikTokLiveClientBuilder(String userName) {
this.tikTokEventHandler = new TikTokEventObserver();
@@ -76,10 +84,18 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
this.clientSettings.setHostName(userName);
this.logger = Logger.getLogger(TikTokLive.class.getSimpleName() + " " + userName);
this.listeners = new ArrayList<>();
this.onCustomMappings = (e) -> {
};
}
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> consumer) {
consumer.accept(clientSettings);
public LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings) {
this.onCustomMappings = onCustomMappings;
return this;
}
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> onConfigure) {
onConfigure.accept(clientSettings);
return this;
}
@@ -103,8 +119,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
throw new TikTokLiveException("HostName can not be null");
}
if (clientSettings.getHostName().startsWith("@"))
{
if (clientSettings.getHostName().startsWith("@")) {
clientSettings.setHostName(clientSettings.getHostName().substring(1));
}
@@ -131,12 +146,9 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
logger.setLevel(clientSettings.getLogLevel());
if (clientSettings.isPrintToConsole() && clientSettings.getLogLevel() == Level.OFF) {
logger.setLevel(Level.ALL);
if (!clientSettings.isPrintToConsole()) {
logger.setLevel(Level.OFF);
}
}
public LiveClient build() {
@@ -151,19 +163,14 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
var giftManager = new TikTokGiftManager(logger);
var eventMapper = new TikTokGenericEventMapper();
var giftHandler = new TikTokGiftEventHandler(giftManager);
var eventsMapper = createMapper(giftManager, tiktokRoomInfo);
var messageHandler = new TikTokMessageHandler(tikTokEventHandler, eventsMapper);
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler,
tiktokRoomInfo,
eventMapper,
giftHandler
);
var webSocketClient = new TikTokWebSocketClient(logger,
cookieJar,
clientSettings,
webResponseHandler,
messageHandler,
tikTokEventHandler);
return new TikTokLiveClient(tiktokRoomInfo,
@@ -176,6 +183,64 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
logger);
}
public TikTokLiveMapper createMapper(GiftManager giftManager, TikTokRoomInfo roomInfo) {
var eventMapper = new TikTokGenericEventMapper();
var mapper = new TikTokLiveMapper(eventMapper);
//ConnectionEvents events
var commonHandler = new TikTokCommonEventHandler();
var giftHandler = new TikTokGiftEventHandler(giftManager);
var roomInfoHandler = new TikTokRoomInfoEventHandler(roomInfo);
var socialHandler = new TikTokSocialMediaEventHandler(roomInfo);
mapper.bytesToEvent(WebcastControlMessage.class, commonHandler::handleWebcastControlMessage);
//Room status events
mapper.bytesToEvent(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
mapper.bytesToEvent(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
mapper.webcastObjectToConstructor(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
//User Interactions events
mapper.webcastObjectToConstructor(WebcastChatMessage.class, TikTokCommentEvent.class);
mapper.bytesToEvents(WebcastLikeMessage.class, roomInfoHandler::handleLike);
mapper.bytesToEvents(WebcastGiftMessage.class, giftHandler::handleGift);
mapper.bytesToEvent(WebcastSocialMessage.class, socialHandler::handle);
mapper.bytesToEvents(WebcastMemberMessage.class, roomInfoHandler::handleMemberMessage);
//Host Interaction events
mapper.bytesToEvent(WebcastPollMessage.class, commonHandler::handlePollEvent);
mapper.bytesToEvent(WebcastRoomPinMessage.class, commonHandler::handlePinMessage);
mapper.webcastObjectToConstructor(WebcastGoalUpdateMessage.class, TikTokGoalUpdateEvent.class);
//LinkMic events
mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
//Rank events
mapper.webcastObjectToConstructor(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
mapper.webcastObjectToConstructor(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
mapper.webcastObjectToConstructor(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
//Others events
mapper.webcastObjectToConstructor(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
mapper.webcastObjectToConstructor(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
mapper.webcastObjectToConstructor(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
mapper.webcastObjectToConstructor(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
mapper.webcastObjectToConstructor(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
mapper.webcastObjectToConstructor(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
mapper.webcastObjectToConstructor(WebcastQuestionNewMessage.class, TikTokQuestionEvent.class);
mapper.bytesToEvents(WebcastEnvelopeMessage.class, commonHandler::handleEnvelop);
mapper.webcastObjectToConstructor(WebcastSubNotifyMessage.class, TikTokSubscribeEvent.class);
mapper.webcastObjectToConstructor(WebcastEmoteChatMessage.class, TikTokEmoteEvent.class);
onCustomMappings.accept(mapper);
return mapper;
}
public LiveClient buildAndConnect() {
var client = build();
client.connect();
@@ -186,18 +251,20 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return build().connectAsync();
}
public TikTokLiveClientBuilder onUnhandledSocial(
EventConsumer<TikTokUnhandledSocialEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledSocialEvent.class, event);
return this;
}
// @Override
// @Override
public LiveClientBuilder onChest(EventConsumer<TikTokChestEvent> event) {
tikTokEventHandler.subscribe(TikTokChestEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicFanTicket(
EventConsumer<TikTokLinkMicFanTicketEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
@@ -247,16 +314,31 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return this;
}
public TikTokLiveClientBuilder onRoom(EventConsumer<TikTokRoomEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomEvent.class, event);
@Override
public <E extends TikTokEvent> LiveClientBuilder onCustomEvent(Class<E> eventClazz, EventConsumer<E> event) {
tikTokEventHandler.subscribe(eventClazz, event);
return this;
}
@Override
public LiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomInfoEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLivePaused(EventConsumer<TikTokLivePausedEvent> event) {
tikTokEventHandler.subscribe(TikTokLivePausedEvent.class, event);
return this;
}
@Override
public LiveClientBuilder onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event) {
tikTokEventHandler.subscribe(TikTokLiveUnpausedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLike(EventConsumer<TikTokLikeEvent> event) {
tikTokEventHandler.subscribe(TikTokLikeEvent.class, event);
return this;
@@ -329,13 +411,6 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return this;
}
public TikTokLiveClientBuilder onRoomUserInfo(
EventConsumer<TikTokRoomUserInfoEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomUserInfoEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onComment(EventConsumer<TikTokCommentEvent> event) {
tikTokEventHandler.subscribe(TikTokCommentEvent.class, event);
return this;

View File

@@ -23,34 +23,51 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.messages.data.User;
import io.github.jwdeveloper.tiktok.data.models.RankingUser;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.models.ConnectionState;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
import lombok.Data;
import java.util.LinkedList;
import java.util.List;
@Data
public class TikTokRoomInfo implements LiveRoomInfo
{
public class TikTokRoomInfo implements LiveRoomInfo {
private String roomId;
private int likesCount;
private int viewersCount;
private int totalViewersCount;
private boolean ageRestricted;
private User host;
private Picture picture;
private String description;
private List<RankingUser> usersRanking = new LinkedList<>();
private String hostName;
private String title;
private String language = "en";
private ConnectionState connectionState = ConnectionState.DISCONNECTED;
public boolean hasConnectionState(ConnectionState state)
{
public boolean hasConnectionState(ConnectionState state) {
return connectionState == state;
}
@Override
public User getHostUser() {
return null;
}
public void updateRanking(List<RankingUser> rankingUsers) {
usersRanking.clear();
usersRanking.addAll(rankingUsers);
}
}

View File

@@ -23,47 +23,30 @@
package io.github.jwdeveloper.tiktok.handlers;
import io.github.jwdeveloper.tiktok.data.dto.MessageMetaData;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.Stopwatch;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public abstract class TikTokMessageHandler {
public class TikTokMessageHandler {
private final Map<String, io.github.jwdeveloper.tiktok.handler.TikTokMessageHandler> handlers;
private final TikTokEventObserver tikTokEventHandler;
protected final TikTokGenericEventMapper mapper;
private final TikTokLiveMapper mapper;
public TikTokMessageHandler(TikTokEventObserver tikTokEventHandler, TikTokGenericEventMapper mapper) {
handlers = new HashMap<>();
public TikTokMessageHandler(TikTokEventObserver tikTokEventHandler, TikTokLiveMapper mapper) {
this.tikTokEventHandler = tikTokEventHandler;
this.mapper = mapper;
}
public void registerMapping(Class<?> clazz, Function<byte[], TikTokEvent> func) {
handlers.put(clazz.getSimpleName(), messagePayload -> List.of(func.apply(messagePayload)));
}
public void registerMappings(Class<?> clazz, Function<byte[], List<TikTokEvent>> func) {
handlers.put(clazz.getSimpleName(), func::apply);
}
public void registerMapping(Class<?> input, Class<?> output) {
registerMapping(input, (e) -> mapper.mapToEvent(input, output, e));
}
public void handle(LiveClient client, WebcastResponse webcastResponse) {
tikTokEventHandler.publish(client, new TikTokWebsocketResponseEvent(webcastResponse));
@@ -79,19 +62,18 @@ public abstract class TikTokMessageHandler {
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message) throws Exception {
var messageClassName = message.getMethod();
if (!handlers.containsKey(messageClassName)) {
if (!mapper.isRegistered(messageClassName)) {
tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message));
return;
}
var handler = handlers.get(messageClassName);
var stopwatch = new Stopwatch();
stopwatch.start();
var events = handler.handle(message.getPayload().toByteArray());
var events = mapper.handleMapping(messageClassName, message.getPayload().toByteArray());
var handlingTimeInMs = stopwatch.stop();
var metadata = new TikTokWebsocketMessageEvent.MetaData(Duration.ofNanos(handlingTimeInMs));
var metadata = new MessageMetaData(Duration.ofNanos(handlingTimeInMs));
for (var event : events) {
tikTokEventHandler.publish(client, new TikTokWebsocketMessageEvent(event, message, metadata));
tikTokEventHandler.publish(client, new TikTokWebsocketMessageEvent(message, event, metadata));
tikTokEventHandler.publish(client, event);
}
}

View File

@@ -1,210 +0,0 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.handlers;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEndEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollStartEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollUpdateEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomUserInfoEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokShareEvent;
import io.github.jwdeveloper.tiktok.data.models.Text;
import io.github.jwdeveloper.tiktok.data.models.chest.Chest;
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
import io.github.jwdeveloper.tiktok.messages.enums.EnvelopeDisplay;
import io.github.jwdeveloper.tiktok.messages.webcast.*;
import io.github.jwdeveloper.tiktok.models.SocialTypes;
import lombok.SneakyThrows;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
private final TikTokRoomInfo roomInfo;
private final TikTokGiftEventHandler giftHandler;
private final Pattern socialMediaPattern = Pattern.compile("pm_mt_guidance_viewer_([0-9]+)_share");
public TikTokMessageHandlerRegistration(TikTokEventObserver tikTokEventHandler,
TikTokRoomInfo roomInfo,
TikTokGenericEventMapper genericTikTokEventMapper,
TikTokGiftEventHandler tikTokGiftEventHandler) {
super(tikTokEventHandler, genericTikTokEventMapper);
this.giftHandler = tikTokGiftEventHandler;
this.roomInfo = roomInfo;
init();
}
public void init() {
//ConnectionEvents events
registerMapping(WebcastControlMessage.class, this::handleWebcastControlMessage);
registerMapping(WebcastSystemMessage.class, TikTokRoomEvent.class);
//Room status events
registerMapping(WebcastLiveIntroMessage.class, TikTokRoomEvent.class);
registerMapping(WebcastRoomUserSeqMessage.class, this::handleRoomUserSeqMessage);
registerMapping(RoomMessage.class, TikTokRoomEvent.class);
registerMapping(WebcastRoomMessage.class, TikTokRoomEvent.class);
registerMapping(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
//User Interactions events
registerMapping(WebcastChatMessage.class, TikTokCommentEvent.class);
registerMapping(WebcastLikeMessage.class, this::handleLike);
registerMappings(WebcastGiftMessage.class, giftHandler::handleGift);
registerMapping(WebcastSocialMessage.class, this::handleSocialMedia);
registerMapping(WebcastMemberMessage.class, this::handleMemberMessage);
//Host Interaction events
registerMapping(WebcastPollMessage.class, this::handlePollEvent);
registerMapping(WebcastRoomPinMessage.class, this::handlePinMessage);
registerMapping(WebcastGoalUpdateMessage.class, TikTokGoalUpdateEvent.class);
//LinkMic events
registerMapping(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
registerMapping(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
registerMapping(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
registerMapping(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
//Rank events
registerMapping(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
registerMapping(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
registerMapping(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
//Others events
registerMapping(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
registerMapping(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
registerMapping(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
registerMapping(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
registerMapping(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
registerMapping(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
registerMapping(WebcastQuestionNewMessage.class, TikTokQuestionEvent.class);
registerMappings(WebcastEnvelopeMessage.class, this::handleEnvelop);
registerMapping(WebcastSubNotifyMessage.class, TikTokSubNotifyEvent.class);
registerMapping(WebcastEmoteChatMessage.class, TikTokEmoteEvent.class);
}
@SneakyThrows
private TikTokEvent handleWebcastControlMessage(byte[] msg) {
var message = WebcastControlMessage.parseFrom(msg);
return switch (message.getAction()) {
case STREAM_PAUSED -> new TikTokLivePausedEvent();
case STREAM_ENDED -> new TikTokLiveEndedEvent();
default -> new TikTokUnhandledControlEvent(message);
};
}
@SneakyThrows
private TikTokEvent handleSocialMedia(byte[] msg) {
var message = WebcastSocialMessage.parseFrom(msg);
var socialType = Text.map(message.getCommon().getDisplayText()).getKey();
var matcher = socialMediaPattern.matcher(socialType);
if (matcher.find()) {
var value = matcher.group(1);
var number = Integer.parseInt(value);
return new TikTokShareEvent(message, number);
}
return switch (socialType) {
case SocialTypes.LikeType -> new TikTokLikeEvent(message, roomInfo.getLikesCount());
case SocialTypes.FollowType -> new TikTokFollowEvent(message);
case SocialTypes.ShareType -> new TikTokShareEvent(message);
case SocialTypes.JoinType -> new TikTokJoinEvent(message, roomInfo.getViewersCount());
default -> new TikTokUnhandledSocialEvent(message);
};
}
@SneakyThrows
private TikTokEvent handleMemberMessage(byte[] msg) {
var message = WebcastMemberMessage.parseFrom(msg);
roomInfo.setViewersCount(message.getMemberCount());
return switch (message.getAction()) {
case JOINED -> new TikTokJoinEvent(message);
case SUBSCRIBED -> new TikTokSubscribeEvent(message);
default -> new TikTokUnhandledMemberEvent(message);
};
}
private TikTokEvent handleRoomUserSeqMessage(byte[] msg) {
var event = (TikTokRoomUserInfoEvent) mapper.mapToEvent(WebcastRoomUserSeqMessage.class, TikTokRoomUserInfoEvent.class, msg);
roomInfo.setViewersCount(event.getTotalUsers());
return event;
}
private TikTokEvent handleLike(byte[] msg) {
var event = (TikTokLikeEvent) mapper.mapToEvent(WebcastLikeMessage.class, TikTokLikeEvent.class, msg);
roomInfo.setLikesCount(event.getTotalLikes());
return event;
}
@SneakyThrows
private TikTokEvent handlePinMessage(byte[] msg) {
var pinMessage = WebcastRoomPinMessage.parseFrom(msg);
var chatMessage = WebcastChatMessage.parseFrom(pinMessage.getPinnedMessage());
var chatEvent = new TikTokCommentEvent(chatMessage);
return new TikTokRoomPinEvent(pinMessage, chatEvent);
}
//TODO Probably not working
@SneakyThrows
private TikTokEvent handlePollEvent(byte[] msg) {
var poolMessage = WebcastPollMessage.parseFrom(msg);
return switch (poolMessage.getMessageType()) {
case 0 -> new TikTokPollStartEvent(poolMessage);
case 1 -> new TikTokPollEndEvent(poolMessage);
case 2 -> new TikTokPollUpdateEvent(poolMessage);
default -> new TikTokPollEvent(poolMessage);
};
}
@SneakyThrows
private List<TikTokEvent> handleEnvelop(byte[] data) {
var msg = WebcastEnvelopeMessage.parseFrom(data);
if (msg.getDisplay() != EnvelopeDisplay.EnvelopeDisplayNew) {
return Collections.emptyList();
}
var totalDiamonds = msg.getEnvelopeInfo().getDiamondCount();
var totalUsers = msg.getEnvelopeInfo().getPeopleCount();
var chest = new Chest(totalDiamonds, totalUsers);
return List.of(new TikTokChestEvent(chest, msg));
}
}

View File

@@ -1,4 +0,0 @@
package io.github.jwdeveloper.tiktok.handlers.events;
public class TikTokChestEventHandler {
}

View File

@@ -22,8 +22,11 @@
*/
package io.github.jwdeveloper.tiktok.http;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.data.dto.TikTokUserInfo;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
@@ -57,62 +60,50 @@ public class TikTokApiService {
}
public String fetchRoomId(String userName) {
var roomId = fetchRoomIdFromTiktokApi(userName);
clientSettings.getClientParameters().put("room_id", roomId);
logger.info("RoomID -> " + roomId);
return roomId;
var userInfo = fetchUserInfoFromTikTokApi(userName);
clientSettings.getClientParameters().put("room_id", userInfo.getRoomId());
logger.info("RoomID -> " + userInfo.getRoomId());
return userInfo.getRoomId();
}
private String fetchRoomIdFromTikTokPage(String userName)
{
/* var roomId = RequestChain.<String>create()
.then(() -> fetchRoomIdFromTikTokPage(userName))
.then(() -> fetchRoomIdFromTiktokApi(userName))
.run();*/
logger.info("Fetching room ID");
String html;
try {
html = tiktokHttpClient.getLivestreamPage(userName);
} catch (Exception e) {
throw new TikTokLiveRequestException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
}
var firstPattern = Pattern.compile("room_id=([0-9]*)");
var firstMatcher = firstPattern.matcher(html);
var id = "";
if (firstMatcher.find()) {
id = firstMatcher.group(1);
} else {
var secondPattern = Pattern.compile("\"roomId\":\"([0-9]*)\"");
var secondMatcher = secondPattern.matcher(html);
if (secondMatcher.find()) {
id = secondMatcher.group(1);
}
}
if (id.isEmpty()) {
throw new TikTokLiveOfflineHostException("Unable to fetch room ID, live host could be offline or name is misspelled");
}
return id;
}
private String fetchRoomIdFromTiktokApi(String userName) {
public TikTokUserInfo fetchUserInfoFromTikTokApi(String userName) {
var params = new HashMap<>(clientSettings.getClientParameters());
params.put("uniqueId", userName);
params.put("sourceType", 54);
var roomData = tiktokHttpClient.getJsonFromTikTokApi("api-live/user/room/", params);
JsonObject roomData = null;
try {
roomData = tiktokHttpClient.getJsonFromTikTokApi("api-live/user/room/", params);
} catch (Exception e) {
throw new TikTokLiveRequestException("Failed to fetch pre connection room information, it happens when TikTok temporary blocks you. Try to connect again in few minutes");
}
var message = roomData.get("message").getAsString();
if (message.equals("params_error")) {
throw new TikTokLiveRequestException("fetchRoomIdFromTiktokApi -> Unable to fetch roomID, contact with developer");
}
if (message.equals("user_not_found")) {
return new TikTokUserInfo(TikTokUserInfo.UserStatus.NotFound, "");
}
//live -> status 2
//live paused -> 3
//not live -> status 4
var data = roomData.getAsJsonObject("data");
var user =data.getAsJsonObject("user");
var user = data.getAsJsonObject("user");
var roomId = user.get("roomId").getAsString();
var status = user.get("status").getAsInt();
var statusEnum = switch (status) {
case 2 -> TikTokUserInfo.UserStatus.Live;
case 3 -> TikTokUserInfo.UserStatus.LivePaused;
case 4 -> TikTokUserInfo.UserStatus.Offline;
default -> TikTokUserInfo.UserStatus.NotFound;
};
return roomId;
return new TikTokUserInfo(statusEnum, roomId);
}
@@ -120,12 +111,18 @@ public class TikTokApiService {
logger.info("Fetching RoomInfo");
try {
var response = tiktokHttpClient.getJsonFromWebcastApi("room/info/", clientSettings.getClientParameters());
if (!response.has("data")) {
var gson = new GsonBuilder().setPrettyPrinting().create();
var json = gson.toJson(response);
throw new TikTokLiveRequestException("room info response does not contains data field: \n"+ json);
}
var mapper = new LiveRoomMetaMapper();
var liveRoomMeta = mapper.map(response);
logger.info("RoomInfo status -> " + liveRoomMeta.getStatus());
return liveRoomMeta;
} catch (Exception e) {
throw new TikTokLiveRequestException("Failed to fetch room info from WebCast, see stacktrace for more info.", e);
throw new TikTokLiveRequestException("Failed to fetch room info from WebCast server, see stacktrace for more info.", e);
}
}
@@ -138,7 +135,7 @@ public class TikTokApiService {
clientSettings.getClientParameters().put("internal_ext", response.getInternalExt());
return response;
} catch (Exception e) {
throw new TikTokLiveRequestException("Failed to fetch client data", e);
throw new TikTokLiveRequestException("Failed to fetch live websocket connection data", e);
}
}
}

View File

@@ -1,12 +1,37 @@
/*
* 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.http;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.Constants;
import io.github.jwdeveloper.tiktok.data.dto.TikTokUserInfo;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Logger;
import java.util.regex.Pattern;
public class TikTokDataChecker
{
public class TikTokDataChecker {
public CompletableFuture<Boolean> isOnlineAsync(String hostName) {
return CompletableFuture.supplyAsync(() -> isOnline(hostName));
@@ -17,63 +42,24 @@ public class TikTokDataChecker
}
public boolean isOnline(String hostName) {
var factory = new TikTokHttpRequestFactory(new TikTokCookieJar());
var url = getLiveUrl(hostName);
try {
var response = factory.get(url);
var titleContent = extractTitleContent(response);
return isTitleLiveOnline(titleContent);
} catch (Exception e)
{
throw new TikTokLiveRequestException("Unable to make check live online request",e);
}
var data = getApiService().fetchUserInfoFromTikTokApi(hostName);
return data.getUserStatus() == TikTokUserInfo.UserStatus.Live ||
data.getUserStatus() == TikTokUserInfo.UserStatus.LivePaused;
}
public boolean isHostNameValid(String hostName) {
var factory = new TikTokHttpRequestFactory(new TikTokCookieJar());
var url = getProfileUrl(hostName);
try {
var response = factory.get(url);
var titleContent = extractTitleContent(response);
return isTitleHostNameValid(titleContent, hostName);
} catch (Exception e)
{
throw new TikTokLiveRequestException("Unable to make check host name valid request",e);
}
var data = getApiService().fetchUserInfoFromTikTokApi(hostName);
return data.getUserStatus() != TikTokUserInfo.UserStatus.NotFound;
}
private boolean isTitleLiveOnline(String title) {
return title.contains("is LIVE");
public TikTokApiService getApiService() {
var jar = new TikTokCookieJar();
var factory = new TikTokHttpRequestFactory(jar);
var client = new TikTokHttpClient(jar, factory);
var settings = new ClientSettings();
settings.setClientParameters(Constants.DefaultClientParams());
var apiService = new TikTokApiService(client, Logger.getGlobal(), settings);
return apiService;
}
private boolean isTitleHostNameValid(String title, String hostName)
{
return title.contains(hostName);
}
private String extractTitleContent(String html) {
var regex = "<title\\b[^>]*>(.*?)<\\/title>";
var pattern = Pattern.compile(regex);
var matcher = pattern.matcher(html);
if (matcher.find()) {
return matcher.group(1);
} else {
return "";
}
}
private String getLiveUrl(String hostName) {
var sb = new StringBuilder();
sb.append("https://www.tiktok.com/@");
sb.append(hostName);
sb.append("/live");
return sb.toString();
}
private String getProfileUrl(String hostName) {
var sb = new StringBuilder();
sb.append("https://www.tiktok.com/@");
sb.append(hostName);
return sb.toString();
}
}

View File

@@ -70,6 +70,7 @@ public class TikTokHttpClient {
public JsonObject getJsonFromWebcastApi(String path, Map<String, Object> parameters) {
var get = getRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
var json = JsonParser.parseString(get);
var jsonObject = json.getAsJsonObject();
return jsonObject;

View File

@@ -22,9 +22,15 @@
*/
package io.github.jwdeveloper.tiktok.mappers;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.data.models.users.UserAttribute;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
import java.util.ArrayList;
public class LiveRoomMetaMapper {
/**
* 0 - Unknown
@@ -46,15 +52,12 @@ public class LiveRoomMetaMapper {
var status = data.get("status");
var statusId = status.getAsInt();
var statusValue = switch (statusId) {
case 0 -> LiveRoomMeta.LiveRoomStatus.HostNotFound;
case 2 -> LiveRoomMeta.LiveRoomStatus.HostOnline;
case 4 -> LiveRoomMeta.LiveRoomStatus.HostOffline;
default-> LiveRoomMeta.LiveRoomStatus.HostNotFound;
default -> LiveRoomMeta.LiveRoomStatus.HostNotFound;
};
liveRoomMeta.setStatus(statusValue);
}
else
{
} else {
liveRoomMeta.setStatus(LiveRoomMeta.LiveRoomStatus.HostNotFound);
}
@@ -63,6 +66,61 @@ public class LiveRoomMetaMapper {
var restricted = element.get("restricted").getAsBoolean();
liveRoomMeta.setAgeRestricted(restricted);
}
if (data.has("title")) {
var element = data.get("title");
var title = element.getAsString();
liveRoomMeta.setTitie(title);
}
if (data.has("stats")) {
var statsElement = data.getAsJsonObject("stats");
var likeElement = statsElement.get("like_count");
var likes = likeElement.getAsInt();
var titalUsersElement = statsElement.get("total_user");
var totalUsers = titalUsersElement.getAsInt();
liveRoomMeta.setLikeCount(likes);
liveRoomMeta.setTotalViewers(totalUsers);
}
if(data.has("user_count"))
{
var element = data.get("user_count");
var viewers = element.getAsInt();
liveRoomMeta.setViewers(viewers);
}
if(data.has("owner"))
{
var element = data.getAsJsonObject("owner");
var user = getUser(element);
liveRoomMeta.setHost(user);
}
return liveRoomMeta;
}
public User getUser(JsonObject jsonElement)
{
var id = jsonElement.get("id").getAsLong();
var name = jsonElement.get("display_id").getAsString();
var profileName = jsonElement.get("nickname").getAsString();
var followElement =jsonElement.getAsJsonObject("follow_info");
var followers = followElement.get("follower_count").getAsInt();
var followingCount = followElement.get("following_count").getAsInt();
var pictureElement =jsonElement.getAsJsonObject("avatar_large");
var link = pictureElement.getAsJsonArray("url_list").get(1).getAsString();
var picture = new Picture(link);
var user = new User(id,name,profileName,picture,followers,followingCount,new ArrayList<>());
user.addAttribute(UserAttribute.LiveHost);
return user;
}
}

View File

@@ -74,7 +74,7 @@ public class TikTokGenericEventMapper {
}
}
private Method getParsingMethod(Class<?> input) throws NoSuchMethodException {
public Method getParsingMethod(Class<?> input) throws NoSuchMethodException {
if (methodCache.containsKey(input)) {
return methodCache.get(input);
}

View File

@@ -0,0 +1,88 @@
package io.github.jwdeveloper.tiktok.mappers;
import com.google.protobuf.GeneratedMessageV3;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public class TikTokLiveMapper implements TikTokMapper {
private final Map<String, Function<byte[], List<TikTokEvent>>> mappers;
private final TikTokGenericEventMapper genericMapper;
public TikTokLiveMapper(TikTokGenericEventMapper genericMapper) {
this.mappers = new HashMap<>();
this.genericMapper = genericMapper;
}
@Override
public void bytesToEvent(String messageName, Function<byte[], TikTokEvent> onMapping) {
mappers.put(messageName, messagePayload -> List.of(onMapping.apply(messagePayload)));
}
@Override
public void bytesToEvents(String messageName, Function<byte[], List<TikTokEvent>> onMapping) {
mappers.put(messageName, onMapping::apply);
}
public void bytesToEvent(Class<? extends GeneratedMessageV3> clazz, Function<byte[], TikTokEvent> onMapping) {
mappers.put(clazz.getSimpleName(), messagePayload -> List.of(onMapping.apply(messagePayload)));
}
public void bytesToEvents(Class<? extends GeneratedMessageV3> clazz, Function<byte[], List<TikTokEvent>> onMapping) {
mappers.put(clazz.getSimpleName(), onMapping::apply);
}
@Override
public void webcastObjectToConstructor(Class<? extends GeneratedMessageV3> sourceClass, Class<? extends TikTokEvent> outputClass) {
bytesToEvent(sourceClass, (e) -> genericMapper.mapToEvent(sourceClass, outputClass, e));
}
@Override
public <T extends GeneratedMessageV3> void webcastObjectToEvent(Class<T> source, Function<T, TikTokEvent> onMapping) {
bytesToEvent(source, (bytes) ->
{
try {
var parsingMethod = genericMapper.getParsingMethod(source);
var sourceObject = parsingMethod.invoke(null, bytes);
var event = onMapping.apply((T) sourceObject);
return event;
} catch (Exception e) {
throw new TikTokMessageMappingException(source, "can't find parsing method", e);
}
});
}
@Override
public <T extends GeneratedMessageV3> void webcastObjectToEvents(Class<T> source, Function<T, List<TikTokEvent>> onMapping) {
bytesToEvents(source, (bytes) ->
{
try {
var parsingMethod = genericMapper.getParsingMethod(source);
var sourceObject = parsingMethod.invoke(null, bytes);
var event = onMapping.apply((T) sourceObject);
return event;
} catch (Exception e) {
throw new TikTokMessageMappingException(source, "can't find parsing method", e);
}
});
}
public boolean isRegistered(String input) {
return mappers.containsKey(input);
}
public List<TikTokEvent> handleMapping(String input, byte[] bytes) {
if (!isRegistered(input)) {
return List.of();
}
var mapper = mappers.get(input);
var events = mapper.apply(bytes);
return events;
}
}

View File

@@ -0,0 +1,26 @@
/*
* 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.mappers.events;
public class TikTokChestEventHandler {
}

View File

@@ -0,0 +1,66 @@
package io.github.jwdeveloper.tiktok.mappers.events;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEndEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollStartEvent;
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollUpdateEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
import io.github.jwdeveloper.tiktok.data.models.chest.Chest;
import io.github.jwdeveloper.tiktok.messages.enums.EnvelopeDisplay;
import io.github.jwdeveloper.tiktok.messages.webcast.*;
import lombok.SneakyThrows;
import java.util.Collections;
import java.util.List;
public class TikTokCommonEventHandler
{
@SneakyThrows
public TikTokEvent handleWebcastControlMessage(byte[] msg) {
var message = WebcastControlMessage.parseFrom(msg);
return switch (message.getAction()) {
case STREAM_PAUSED -> new TikTokLivePausedEvent();
case STREAM_ENDED -> new TikTokLiveEndedEvent();
case STREAM_UNPAUSED -> new TikTokLiveUnpausedEvent();
default -> new TikTokUnhandledControlEvent(message);
};
}
@SneakyThrows
public TikTokEvent handlePinMessage(byte[] msg) {
var pinMessage = WebcastRoomPinMessage.parseFrom(msg);
var chatMessage = WebcastChatMessage.parseFrom(pinMessage.getPinnedMessage());
var chatEvent = new TikTokCommentEvent(chatMessage);
return new TikTokRoomPinEvent(pinMessage, chatEvent);
}
//TODO Probably not working
@SneakyThrows
public TikTokEvent handlePollEvent(byte[] msg) {
var poolMessage = WebcastPollMessage.parseFrom(msg);
return switch (poolMessage.getMessageType()) {
case 0 -> new TikTokPollStartEvent(poolMessage);
case 1 -> new TikTokPollEndEvent(poolMessage);
case 2 -> new TikTokPollUpdateEvent(poolMessage);
default -> new TikTokPollEvent(poolMessage);
};
}
@SneakyThrows
public List<TikTokEvent> handleEnvelop(byte[] data) {
var msg = WebcastEnvelopeMessage.parseFrom(data);
if (msg.getDisplay() != EnvelopeDisplay.EnvelopeDisplayNew) {
return Collections.emptyList();
}
var totalDiamonds = msg.getEnvelopeInfo().getDiamondCount();
var totalUsers = msg.getEnvelopeInfo().getPeopleCount();
var chest = new Chest(totalDiamonds, totalUsers);
return List.of(new TikTokChestEvent(chest, msg));
}
}

View File

@@ -20,7 +20,7 @@
* 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.handlers.events;
package io.github.jwdeveloper.tiktok.mappers.events;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
@@ -53,12 +53,19 @@ public class TikTokGiftEventHandler {
return handleGift(currentMessage);
}
public List<TikTokEvent> handleGift(WebcastGiftMessage currentMessage)
{
public List<TikTokEvent> handleGift(WebcastGiftMessage currentMessage) {
var userId = currentMessage.getUser().getId();
var currentType = GiftSendType.fromNumber(currentMessage.getSendType());
var containsPreviousMessage = giftsMessages.containsKey(userId);
//If gift is not streakable just return onGift event
if (currentMessage.getGift().getType() != 1) {
var comboEvent = getGiftComboEvent(currentMessage, GiftSendType.Finished);
var giftEvent = getGiftEvent(currentMessage);
return List.of(comboEvent, giftEvent);
}
if (!containsPreviousMessage) {
if (currentType == GiftSendType.Finished) {
return List.of(getGiftEvent(currentMessage));
@@ -89,7 +96,6 @@ public class TikTokGiftEventHandler {
}
private TikTokGiftEvent getGiftEvent(WebcastGiftMessage message) {
var gift = getGiftObject(message);
return new TikTokGiftEvent(gift, message);
@@ -100,15 +106,13 @@ public class TikTokGiftEventHandler {
return new TikTokGiftComboEvent(gift, message, state);
}
private Gift getGiftObject(WebcastGiftMessage giftMessage)
{
private Gift getGiftObject(WebcastGiftMessage giftMessage) {
var giftId = (int) giftMessage.getGiftId();
var gift = giftManager.findById(giftId);
if (gift == Gift.UNDEFINED) {
gift = giftManager.findByName(giftMessage.getGift().getName());
}
if (gift == Gift.UNDEFINED)
{
if (gift == Gift.UNDEFINED) {
gift = giftManager.registerGift(
giftId,
giftMessage.getGift().getName(),

View File

@@ -0,0 +1,115 @@
/*
* 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.mappers.events;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokUnhandledMemberEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.data.models.RankingUser;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLikeMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastMemberMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomUserSeqMessage;
import lombok.SneakyThrows;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class TikTokRoomInfoEventHandler {
private final TikTokRoomInfo roomInfo;
public TikTokRoomInfoEventHandler(TikTokRoomInfo roomInfo) {
this.roomInfo = roomInfo;
}
public TikTokEvent handleRoomInfo(Consumer<TikTokRoomInfo> consumer) {
consumer.accept(roomInfo);
return new TikTokRoomInfoEvent(roomInfo);
}
@SneakyThrows
public TikTokEvent handleUserRanking(byte[] msg) {
var message = WebcastRoomUserSeqMessage.parseFrom(msg);
var totalUsers = message.getTotalUser();
var userRanking = message.getRanksListList().stream().map(RankingUser::new)
.sorted((ru1, ru2) -> Integer.compare(ru2.getScore(), ru1.getScore()))
.collect(Collectors.toList());
return handleRoomInfo(tikTokRoomInfo ->
{
tikTokRoomInfo.setTotalViewersCount(totalUsers);
tikTokRoomInfo.updateRanking(userRanking);
});
}
@SneakyThrows
public TikTokEvent handleIntro(byte[] msg) {
var message = WebcastLiveIntroMessage.parseFrom(msg);
var hostUser = User.map(message.getHost());
var language = message.getLanguage();
return handleRoomInfo(tikTokRoomInfo ->
{
if(tikTokRoomInfo.getHost() == null)
{
tikTokRoomInfo.setHost(hostUser);
}
tikTokRoomInfo.setLanguage(language);
});
}
@SneakyThrows
public List<TikTokEvent> handleMemberMessage(byte[] msg) {
var message = WebcastMemberMessage.parseFrom(msg);
var event = switch (message.getAction()) {
case JOINED -> new TikTokJoinEvent(message);
case SUBSCRIBED -> new TikTokSubscribeEvent(message);
default -> new TikTokUnhandledMemberEvent(message);
};
var roomInfoEvent = this.handleRoomInfo(tikTokRoomInfo ->
{
tikTokRoomInfo.setViewersCount(message.getMemberCount());
});
return List.of(event, roomInfoEvent);
}
@SneakyThrows
public List<TikTokEvent> handleLike(byte[] msg)
{
var message = WebcastLikeMessage.parseFrom(msg);
var event = new TikTokLikeEvent(message);
var roomInfoEvent = this.handleRoomInfo(tikTokRoomInfo ->
{
tikTokRoomInfo.setLikesCount(event.getTotalLikes());
});
return List.of(event, roomInfoEvent);
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.mappers.events;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.data.events.TikTokUnhandledSocialEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.data.events.social.TikTokShareEvent;
import io.github.jwdeveloper.tiktok.data.models.Text;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
import io.github.jwdeveloper.tiktok.models.SocialTypes;
import lombok.SneakyThrows;
import java.util.regex.Pattern;
public class TikTokSocialMediaEventHandler
{
private final TikTokRoomInfo roomInfo;
private final Pattern socialMediaPattern = Pattern.compile("pm_mt_guidance_viewer_([0-9]+)_share");
public TikTokSocialMediaEventHandler(TikTokRoomInfo roomInfo) {
this.roomInfo = roomInfo;
}
@SneakyThrows
public TikTokEvent handle(byte[] msg)
{
var message = WebcastSocialMessage.parseFrom(msg);
var socialType = Text.map(message.getCommon().getDisplayText()).getKey();
var matcher = socialMediaPattern.matcher(socialType);
if (matcher.find()) {
var value = matcher.group(1);
var number = Integer.parseInt(value);
return new TikTokShareEvent(message, number);
}
return switch (socialType) {
case SocialTypes.LikeType -> new TikTokLikeEvent(message, roomInfo.getLikesCount());
case SocialTypes.FollowType -> new TikTokFollowEvent(message);
case SocialTypes.ShareType -> new TikTokShareEvent(message);
case SocialTypes.JoinType -> new TikTokJoinEvent(message, roomInfo.getViewersCount());
default -> new TikTokUnhandledSocialEvent(message);
};
}
}

View File

@@ -24,11 +24,9 @@ package io.github.jwdeveloper.tiktok.websocket;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.Constants;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
import io.github.jwdeveloper.tiktok.http.HttpUtils;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.live.LiveClient;
@@ -44,7 +42,7 @@ public class TikTokWebSocketClient implements SocketClient {
private final Logger logger;
private final ClientSettings clientSettings;
private final TikTokCookieJar tikTokCookieJar;
private final TikTokMessageHandlerRegistration webResponseHandler;
private final TikTokMessageHandler messageHandler;
private final TikTokEventObserver tikTokEventHandler;
private WebSocketClient webSocketClient;
private TikTokWebSocketPingingTask pingingTask;
@@ -53,12 +51,12 @@ public class TikTokWebSocketClient implements SocketClient {
public TikTokWebSocketClient(Logger logger,
TikTokCookieJar tikTokCookieJar,
ClientSettings clientSettings,
TikTokMessageHandlerRegistration webResponseHandler,
TikTokMessageHandler messageHandler,
TikTokEventObserver tikTokEventHandler) {
this.logger = logger;
this.tikTokCookieJar = tikTokCookieJar;
this.clientSettings = clientSettings;
this.webResponseHandler = webResponseHandler;
this.messageHandler = messageHandler;
this.tikTokEventHandler = tikTokEventHandler;
isConnected = false;
}
@@ -74,10 +72,7 @@ public class TikTokWebSocketClient implements SocketClient {
}
try {
if (clientSettings.isHandleExistingEvents()) {
logger.info("Handling existing events");
webResponseHandler.handle(tikTokLiveClient, webcastResponse);
}
messageHandler.handle(tikTokLiveClient, webcastResponse);
var url = getWebSocketUrl(webcastResponse);
webSocketClient = startWebSocket(url, tikTokLiveClient);
webSocketClient.connect();
@@ -85,7 +80,8 @@ public class TikTokWebSocketClient implements SocketClient {
pingingTask = new TikTokWebSocketPingingTask();
pingingTask.run(webSocketClient);
isConnected = true;
} catch (Exception e) {
} catch (Exception e)
{
isConnected = false;
throw new TikTokLiveException("Failed to connect to the websocket", e);
}
@@ -109,7 +105,7 @@ public class TikTokWebSocketClient implements SocketClient {
return new TikTokWebSocketListener(url,
headers,
3000,
webResponseHandler,
messageHandler,
tikTokEventHandler,
liveClient);
}

View File

@@ -28,7 +28,7 @@ import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastPushFrame;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
@@ -44,33 +44,22 @@ import java.util.Optional;
public class TikTokWebSocketListener extends WebSocketClient {
private final TikTokMessageHandlerRegistration webResponseHandler;
private final TikTokMessageHandler messageHandler;
private final TikTokEventObserver tikTokEventHandler;
private final LiveClient tikTokLiveClient;
public TikTokWebSocketListener(URI serverUri,
Map<String, String> httpHeaders,
int connectTimeout,
TikTokMessageHandlerRegistration webResponseHandler,
TikTokMessageHandler messageHandler,
TikTokEventObserver tikTokEventHandler,
LiveClient tikTokLiveClient) {
super(serverUri, new Draft_6455(), httpHeaders,connectTimeout);
this.webResponseHandler = webResponseHandler;
this.messageHandler = messageHandler;
this.tikTokEventHandler = tikTokEventHandler;
this.tikTokLiveClient = tikTokLiveClient;
}
@Override
public void onOpen(ServerHandshake serverHandshake) {
tikTokEventHandler.publish(tikTokLiveClient,new TikTokConnectedEvent());
if(isNotClosing())
{
sendPing();
}
}
@Override
public void onMessage(ByteBuffer bytes)
{
@@ -85,6 +74,19 @@ public class TikTokWebSocketListener extends WebSocketClient {
}
}
@Override
public void onOpen(ServerHandshake serverHandshake) {
tikTokEventHandler.publish(tikTokLiveClient,new TikTokConnectedEvent());
if(isNotClosing())
{
sendPing();
}
}
@Override
public void onClose(int i, String s, boolean b) {
tikTokEventHandler.publish(tikTokLiveClient,new TikTokDisconnectedEvent());
@@ -114,7 +116,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
// sendAckId(webResponse.getFetchInterval());
}
webResponseHandler.handle(tikTokLiveClient, webResponse);
messageHandler.handle(tikTokLiveClient, webResponse);
}
private Optional<WebcastPushFrame> getWebcastWebsocketMessage(byte[] buffer) {

View File

@@ -69,4 +69,7 @@ public class TikTokGiftManagerTest {
}
}

View File

@@ -22,9 +22,12 @@
*/
package io.github.jwdeveloper.tiktok.handlers.events;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.mappers.events.TikTokGiftEventHandler;
import io.github.jwdeveloper.tiktok.messages.data.GiftStruct;
import io.github.jwdeveloper.tiktok.messages.data.Image;
import io.github.jwdeveloper.tiktok.messages.data.User;
@@ -52,7 +55,20 @@ class TikTokGiftEventHandlerTest {
@Test
void shouldHandleGifts() {
var message = getGiftMessage("example-new-name", 123, "image-new.png", 0, 1);
var message = getGiftMessage("example-new-name", 123, "image-new.png", 0, 1,false);
var result = handler.handleGift(message);
Assertions.assertEquals(2, result.size());
var event = (TikTokGiftEvent) result.get(0);
var gift = event.getGift();
Assertions.assertEquals("image-new.png",gift.getPicture().getLink());
Assertions.assertEquals(123,gift.getId());
}
@Test
void shouldHandleStrakableGift() {
var message = getGiftMessage("example-new-name", 123, "image-new.png", 0, 1,true);
var result = handler.handleGift(message);
Assertions.assertEquals(1, result.size());
@@ -63,12 +79,35 @@ class TikTokGiftEventHandlerTest {
Assertions.assertEquals(123,gift.getId());
}
@Test
void shouldHandleStrike()
{
var message1 = getGiftMessage("example-new-name", 123, "image-new.png", 1, 1,true);
var message2 = getGiftMessage("example-new-name", 123, "image-new.png", 2, 1,true);
var message3 = getGiftMessage("example-new-name", 123, "image-new.png", 0, 1,true);
var result1 = handler.handleGift(message1);
var result2 = handler.handleGift(message2);
var result3 = handler.handleGift(message3);
var event1 = (TikTokGiftComboEvent) result1.get(0);
var event2 = (TikTokGiftComboEvent) result2.get(0);
Assertions.assertEquals(2, result3.size());
var event3 = (TikTokGiftComboEvent) result3.get(0);
Assertions.assertEquals(GiftSendType.Begin,event1.getComboState());
Assertions.assertEquals(GiftSendType.Active,event2.getComboState());
Assertions.assertEquals(GiftSendType.Finished,event3.getComboState());
}
public WebcastGiftMessage getGiftMessage(String giftName,
int giftId,
String giftImage,
int sendType,
int userId) {
int userId,
boolean streakable) {
var builder = WebcastGiftMessage.newBuilder();
var giftBuilder = GiftStruct.newBuilder();
var userBuilder = User.newBuilder();
@@ -77,6 +116,7 @@ class TikTokGiftEventHandlerTest {
giftBuilder.setId(giftId);
giftBuilder.setName(giftName);
giftBuilder.setImage(Image.newBuilder().addUrlList(giftImage).build());
giftBuilder.setType(streakable?1:0);
userBuilder.setId(userId);
builder.setGiftId(giftId);
@@ -86,4 +126,6 @@ class TikTokGiftEventHandlerTest {
return builder.build();
}
}

View File

@@ -1,18 +1,103 @@
/*
* 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.http;
import io.github.jwdeveloper.tiktok.TikTokLive;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Random;
public class TikTokLiveOnlineCheckerTest {
private final String TARGET_USER = "bangbetmenygy";
public boolean enableTests = false;
@Test
public void shouldTestOnline() {
if(!enableTests)
{
return;
}
var TARGET_USER = "bangbetmenygy";
var sut = new TikTokDataChecker();
var result = sut.isOnline(TARGET_USER);
Assertions.assertTrue(result);
}
@Test
public void shouldBeOffline() {
var TARGET_USER = "karacomparetto";
var sut = new TikTokDataChecker();
var result = sut.isOnline(TARGET_USER);
Assertions.assertFalse(result);
}
@Test
public void shouldBeValid() throws InterruptedException {
var TARGET_USER = "dostawcavideo";
var sut = new TikTokDataChecker();
var result = sut.isHostNameValid(TARGET_USER);
TikTokLive.newClient("asdasd")
.onWebsocketResponse((liveClient, event) ->
{
for(var message : event.getResponse().getMessagesList())
{
if(message.getMethod().equals("WebcastGiftMessage"))
{
try
{
var bytes = message.getMethodBytes();
var rawMessage = WebcastGiftMessage.parseFrom(bytes);
var giftName =rawMessage.getGift().getName();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
});
Assertions.assertTrue(result);
}
@Test
public void shouldNotBeValid() {
var TARGET_USER = "dqagdagda , asdaaasd";
var sut = new TikTokDataChecker();
var result = sut.isHostNameValid(TARGET_USER);
Assertions.assertFalse(result);
}
}

View File

@@ -41,7 +41,7 @@
<parent>
<artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.0.3-Release</version>
<version>1.0.6-Release</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -25,6 +25,7 @@ package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.live.GiftManager;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
public class CustomGiftExample {
/**
@@ -38,7 +39,20 @@ public class CustomGiftExample {
{
liveClient.disconnect();
})
.onWebsocketResponse((liveClient, event) ->
{
var packets =event.getResponse().getMessagesList();
for(var packet : packets)
{
var name = packet.getMethod();
var data = packet.getPayload();
if(name.equals("WebcastGiftMessage"))
{
// var message = WebcastGiftMessage.parseFrom(data);
}
}
})
.onGift((liveClient, event) ->
{
liveClient.getLogger().info(event.getGift().getName());

View File

@@ -0,0 +1,88 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastChatMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import io.github.jwdeveloper.tiktok.utils.ProtocolUtils;
public class CustomMappingExample {
public static void main(String[] args) {
TikTokLive.newClient("vadimpyrography")
.onCustomEvent(CustomChatEvent.class, (liveClient, event) ->
{
System.out.println("hello world!");
})
.onError((liveClient, event) ->
{
event.getException().printStackTrace();
})
.onMapping(mapper ->
{
mapper.webcastObjectToEvent(WebcastChatMessage.class, chatMessage ->
{
var language = chatMessage.getContentLanguage();
var userName = chatMessage.getUser().getNickname();
var message = chatMessage.getContent();
return new CustomChatEvent(language, userName, message);
});
mapper.bytesToEvent("WebcastGiftMessage", bytes ->
{
try
{
var event = WebcastGiftMessage.parseFrom(bytes);
return new TikTokGiftEvent(Gift.ROSA, event);
} catch (Exception e) {
throw new TikTokMessageMappingException("unable to map gift message!", e);
}
});
mapper.bytesToEvent("WebcastMemberMessage",bytes ->
{
//displaying unknown messages from tiktok
var structure = ProtocolUtils.getProtocolBufferStructure(bytes);
System.out.println(structure.toJson());
return new TikTokErrorEvent(new RuntimeException("Message not implemented"));
});
}).buildAndConnect();
}
public static class CustomChatEvent extends TikTokEvent {
private final String langauge;
private final String userName;
private final String message;
public CustomChatEvent(String language, String userName, String message) {
this.langauge = language;
this.userName = userName;
this.message = message;
}
public String getLangauge() {
return langauge;
}
public String getUserName() {
return userName;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return "CustomChatEvent{" +
"language='" + langauge + '\'' +
", userName='" + userName + '\'' +
", message='" + message + '\'' +
'}';
}
}
}

View File

@@ -22,34 +22,66 @@
*/
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.TikTokSubNotifyEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import java.io.IOException;
import java.time.Duration;
import java.util.HashMap;
import java.util.logging.Level;
public class SimpleExample
{
public static String TIKTOK_HOSTNAME = "seanfitzness";
public class SimpleExample {
public static String TIKTOK_HOSTNAME = "bangbetmenygy";
public static void main(String[] args) throws IOException {
showLogo();
// set tiktok username
/*
Optional checking if host name is correct
//Optional checking if host name is correct
if(TikTokLive.isHostNameValid(TIKTOK_HOSTNAME))
{
System.out.println("user name exists!");
}
*/
// Optional checking if live is online
if (TikTokLive.isLiveOnline(TIKTOK_HOSTNAME)) {
System.out.println("Live is online!");
}
Optional checking if live is online
if(TikTokLive.isLiveOnline(TIKTOK_HOSTNAME))
{
System.out.println("Live is online!");
}
*/
TikTokLive.newClient("test")
.onWebsocketResponse((liveClient, event) ->
{
var response = event.getResponse();
for (var message : response.getMessagesList()) {
var name = message.getMethod();
var binaryData = message.getPayload();
System.out.println("Event name: " + name);
if (name.equals("WebcastGiftEvent")) {
try {
WebcastGiftMessage giftMessage = WebcastGiftMessage.parseFrom(binaryData);
var giftName = giftMessage.getGift().getName();
var giftId = giftMessage.getGiftId();
var userName = giftMessage.getUser().getNickname();
System.out.println("Gift: "+giftName+" id: "+giftId+" from user: "+userName);
} catch (Exception e) {
throw new RuntimeException("Mapping error", e);
}
}
}
}).buildAndConnect();
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
.configure(clientSettings ->
@@ -59,7 +91,6 @@ public class SimpleExample
clientSettings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
clientSettings.setLogLevel(Level.ALL); // Log level
clientSettings.setPrintToConsole(true); // Printing all logs to console even if log level is Level.OFF
clientSettings.setHandleExistingEvents(true); // Invokes all TikTok events that had occurred before connection
clientSettings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
@@ -74,18 +105,42 @@ public class SimpleExample
//clientSettings.setRoomId("XXXXXXXXXXXXXXXXX");
})
.onConnected((liveClient, event) ->
{
for (var gift : liveClient.getGiftManager().getGifts()) {
gift.getPicture().downloadImageAsync().thenAccept(image ->
{
});
}
})
.onWebsocketMessage((liveClient, event) ->
{
var tiktokLiveEvent = event.getEvent();
if (tiktokLiveEvent instanceof TikTokSubNotifyEvent e) {
System.out.println("it was subscrible event");
}
})
.onWebsocketResponse((liveClient, event) ->
{
event.getResponse();
})
.onGift((liveClient, event) ->
{
switch (event.getGift()) {
case ROSE -> print(ConsoleColors.RED, "Rose!");
case GG -> print(ConsoleColors.YELLOW, " GOOD GAME!");
case TIKTOK -> print(ConsoleColors.CYAN,"Thanks for TikTok");
default -> print(ConsoleColors.GREEN, "[Thanks for gift] ", ConsoleColors.YELLOW, event.getGift().getName(), "x", event.getCombo());
case TIKTOK -> print(ConsoleColors.CYAN, "Thanks for TikTok");
default ->
print(ConsoleColors.GREEN, "[Thanks for gift] ", ConsoleColors.YELLOW, event.getGift().getName(), "x", event.getCombo());
}
})
.onGiftCombo((liveClient, event) ->
{
print(ConsoleColors.RED,"GIFT COMBO",event.getGift().getName(),event.getCombo());
print(ConsoleColors.RED, "GIFT COMBO", event.getGift().getName(), event.getCombo());
})
.onConnected((client, event) ->
{
@@ -93,11 +148,11 @@ public class SimpleExample
})
.onDisconnected((liveClient, event) ->
{
print(ConsoleColors.RED,"[Disconnected]");
print(ConsoleColors.RED, "[Disconnected]");
})
.onRoom((liveClient, event) ->
.onRoomInfo((liveClient, event) ->
{
var info = event.getRoomInfo();
})
.onFollow((liveClient, event) ->
{
@@ -131,9 +186,8 @@ public class SimpleExample
System.out.println(sb);
}
private static void showLogo()
{
System.out.println(ConsoleColors.GREEN+"""
private static void showLogo() {
System.out.println(ConsoleColors.GREEN + """
_____ _ _ _____ _ _ _ \s
|_ _(_) | _|_ _|__ | | _| | (_)_ _____\s

695
README.md
View File

@@ -1,9 +1,8 @@
<div align="center" >
<a target="blank" >
<img src="https://github.com/jwdeveloper/TikTokLiveJava/assets/79764581/1f9951b4-a270-4535-bf38-a6f41cdf8f43" width="15%" >
<img src="https://raw.githubusercontent.com/jwdeveloper/TikTokLiveJava/develop-1_0_0/Tools-ReadmeGenerator/src/main/resources/logo.svg" width="15%" >
</img>
</a>
</div>
<div align="center" >
<h1>TikTok Live Java</h1>
@@ -17,7 +16,6 @@
</a>
<a href="https://discord.gg/e2XwPNTBBr" target="blank" >
<img src="https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white" >
</img>
@@ -30,11 +28,8 @@
</div>
</div>
# Introduction
A Java library inspired by [TikTokLive](https://github.com/isaackogan/TikTokLive) and [TikTokLiveSharp](https://github.com/sebheron/TikTokLiveSharp). Use it to receive live stream events such as comments and gifts in realtime from [TikTok LIVE](https://www.tiktok.com/live) by connecting to TikTok's internal WebCast push service.
A Java library inspired by [TikTokLive](https://github.com/isaackogan/TikTokLive) and [TikTokLiveSharp](https://github.com/frankvHoof93/TikTokLiveSharp). Use it to receive live stream events such as comments and gifts in realtime from [TikTok LIVE](https://www.tiktok.com/live) by connecting to TikTok's internal WebCast push service.
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
@@ -52,19 +47,12 @@ Do you prefer other programming languages?
**NOTE:** This is not an official API. It's a reverse engineering project.
#### Overview
- [Getting started](#getting-started)
- [Events](#events)
- [Listeners](#listeners)
- [Contributing](#contributing)
## Getting started
1. Install the package via Maven
@@ -81,7 +69,7 @@ Do you prefer other programming languages?
<dependency>
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
<artifactId>Client</artifactId>
<version>1.0.3-Release</version>
<version>1.0.6-Release</version>
<scope>compile</scope>
</dependency>
</dependencies>
@@ -107,6 +95,13 @@ TikTokLive.newClient("bangbetmenygy")
{
System.out.println(event.getComboState()+ " " + event.getCombo() + " " + event.getGift().getName());
})
.onRoomInfo((liveClient, event) ->
{
var roomInfo = event.getRoomInfo();
System.out.println("Room Id: "+roomInfo.getRoomId());
System.out.println("Likes: "+roomInfo.getLikesCount());
System.out.println("Viewers: "+roomInfo.getViewersCount());
})
.onJoin((liveClient, event) ->
{
System.out.println(event.getUser().getProfileName() + "Hello on my stream! ");
@@ -134,7 +129,6 @@ TikTokLive.newClient("bangbetmenygy")
settings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
settings.setLogLevel(Level.ALL); // Log level
settings.setPrintToConsole(true); // Printing all logs to console even if log level is Level.OFF
settings.setHandleExistingEvents(true); // Invokes all TikTok events that had occurred before connection
settings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
settings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
@@ -156,36 +150,35 @@ TikTokLive.newClient("bangbetmenygy")
**Control**:
**Control**:
- [onConnected](#onconnected-tiktokconnectedevent)
- [onReconnecting](#onreconnecting-tiktokreconnectingevent)
- [onDisconnected](#ondisconnected-tiktokdisconnectedevent)
- [onReconnecting](#onreconnecting-tiktokreconnectingevent)
- [onError](#onerror-tiktokerrorevent)
**Message**:
**Message**:
- [onEvent](#onevent-tiktokevent)
- [onShare](#onshare-tiktokshareevent)
- [onLivePaused](#onlivepaused-tiktoklivepausedevent)
- [onRoom](#onroom-tiktokroomevent)
- [onGiftCombo](#ongiftcombo-tiktokgiftcomboevent)
- [onJoin](#onjoin-tiktokjoinevent)
- [onRoomUserInfo](#onroomuserinfo-tiktokroomuserinfoevent)
- [onComment](#oncomment-tiktokcommentevent)
- [onGift](#ongift-tiktokgiftevent)
- [onLike](#onlike-tiktoklikeevent)
- [onSubscribe](#onsubscribe-tiktoksubscribeevent)
- [onQuestion](#onquestion-tiktokquestionevent)
- [onEmote](#onemote-tiktokemoteevent)
- [onLiveEnded](#onliveended-tiktokliveendedevent)
- [onFollow](#onfollow-tiktokfollowevent)
- [onUnhandledSocial](#onunhandledsocial-tiktokunhandledsocialevent)
- [onLike](#onlike-tiktoklikeevent)
- [onLiveEnded](#onliveended-tiktokliveendedevent)
- [onRoomInfo](#onroominfo-tiktokroominfoevent)
- [onShare](#onshare-tiktokshareevent)
- [onGiftCombo](#ongiftcombo-tiktokgiftcomboevent)
- [onEmote](#onemote-tiktokemoteevent)
- [onGift](#ongift-tiktokgiftevent)
- [onComment](#oncomment-tiktokcommentevent)
- [onLivePaused](#onlivepaused-tiktoklivepausedevent)
- [onLiveUnpaused](#onliveunpaused-tiktokliveunpausedevent)
- [onJoin](#onjoin-tiktokjoinevent)
**Debug**:
**Debug**:
- [onWebsocketResponse](#onwebsocketresponse-tiktokwebsocketresponseevent)
- [onWebsocketUnhandledMessage](#onwebsocketunhandledmessage-tiktokwebsocketunhandledmessageevent)
- [onWebsocketResponse](#onwebsocketresponse-tiktokwebsocketresponseevent)
- [onWebsocketMessage](#onwebsocketmessage-tiktokwebsocketmessageevent)
# Examples
<br>
@@ -193,7 +186,7 @@ TikTokLive.newClient("bangbetmenygy")
## onConnected [TikTokConnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokConnectedEvent.java)
Triggered when the connection is successfully established.
Triggered when the connection is successfully established.
```java
@@ -207,6 +200,26 @@ TikTokLive.newClient("host-name")
<br>
## onDisconnected [TikTokDisconnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokDisconnectedEvent.java)
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.
```java
TikTokLive.newClient("host-name")
.onDisconnected((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onReconnecting [TikTokReconnectingEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokReconnectingEvent.java)
@@ -224,32 +237,12 @@ TikTokLive.newClient("host-name")
<br>
## onDisconnected [TikTokDisconnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokDisconnectedEvent.java)
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.
```java
TikTokLive.newClient("host-name")
.onDisconnected((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onError [TikTokErrorEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokErrorEvent.java)
General error event. You should handle this.
General error event. You should handle this.
```java
@@ -268,7 +261,7 @@ TikTokLive.newClient("host-name")
## onEvent [TikTokEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/common/TikTokEvent.java)
Base class for all events
Base class for all events
```java
@@ -282,190 +275,12 @@ TikTokLive.newClient("host-name")
<br>
## onShare [TikTokShareEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokShareEvent.java)
Triggers when a user shares the stream. Based on social event.
```java
TikTokLive.newClient("host-name")
.onShare((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onLivePaused [TikTokLivePausedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLivePausedEvent.java)
```java
TikTokLive.newClient("host-name")
.onLivePaused((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onRoom [TikTokRoomEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/room/TikTokRoomEvent.java)
```java
TikTokLive.newClient("host-name")
.onRoom((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onGiftCombo [TikTokGiftComboEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftComboEvent.java)
Triggered every time gift is sent
@see GiftSendType it has 3 states
<p>Example when user sends gift with combo</p>
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
<p>Combo: 4 -> comboState = GiftSendType.Active</p>
<p>Combo: 8 -> comboState = GiftSendType.Active</p>
<p>Combo: 12 -> comboState = GiftSendType.Finsihed</p>
Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
```java
TikTokLive.newClient("host-name")
.onGiftCombo((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onJoin [TikTokJoinEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokJoinEvent.java)
```java
TikTokLive.newClient("host-name")
.onJoin((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onRoomUserInfo [TikTokRoomUserInfoEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/room/TikTokRoomUserInfoEvent.java)
Only top 5 users in ranking has detailed data
rest has only ID
```java
TikTokLive.newClient("host-name")
.onRoomUserInfo((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onComment [TikTokCommentEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokCommentEvent.java)
Triggered every time a new chat comment arrives.
```java
TikTokLive.newClient("host-name")
.onComment((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onGift [TikTokGiftEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftEvent.java)
Triggered when user sends gifts that has
no combo (most of expensive gifts)
or if combo has finished
```java
TikTokLive.newClient("host-name")
.onGift((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onLike [TikTokLikeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokLikeEvent.java)
Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
```java
TikTokLive.newClient("host-name")
.onLike((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onSubscribe [TikTokSubscribeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokSubscribeEvent.java)
Triggers when a user creates a subscription.
Triggers when a user creates a subscription.
```java
@@ -498,50 +313,12 @@ TikTokLive.newClient("host-name")
<br>
## onEmote [TikTokEmoteEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokEmoteEvent.java)
Triggered every time a subscriber sends an emote (sticker).
```java
TikTokLive.newClient("host-name")
.onEmote((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onLiveEnded [TikTokLiveEndedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLiveEndedEvent.java)
Triggered when the live stream gets terminated by the host. Will also trigger the TikTokDisconnectedEvent event.
```java
TikTokLive.newClient("host-name")
.onLiveEnded((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onFollow [TikTokFollowEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokFollowEvent.java)
Triggers when a user follows the streamer. Based on social event.
Triggers when a user follows the streamer. Based on social event.
```java
@@ -557,13 +334,228 @@ TikTokLive.newClient("host-name")
<br>
## onUnhandledSocial [TikTokUnhandledSocialEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokUnhandledSocialEvent.java)
## onLike [TikTokLikeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokLikeEvent.java)
Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
```java
TikTokLive.newClient("host-name")
.onLike((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onLiveEnded [TikTokLiveEndedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLiveEndedEvent.java)
Triggered when the live stream gets terminated by the host. Will also trigger the TikTokDisconnectedEvent event.
```java
TikTokLive.newClient("host-name")
.onLiveEnded((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onRoomInfo [TikTokRoomInfoEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/room/TikTokRoomInfoEvent.java)
```java
TikTokLive.newClient("host-name")
.onUnhandledSocial((liveClient, event) ->
.onRoomInfo((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onShare [TikTokShareEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokShareEvent.java)
Triggers when a user shares the stream. Based on social event.
```java
TikTokLive.newClient("host-name")
.onShare((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onGiftCombo [TikTokGiftComboEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftComboEvent.java)
Triggered every time gift is sent
@see GiftSendType it has 3 states
<p>Example when user sends gift with combo</p>
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
<p>Combo: 4 -> comboState = GiftSendType.Active</p>
<p>Combo: 8 -> comboState = GiftSendType.Active</p>
<p>Combo: 12 -> comboState = GiftSendType.Finsihed</p>
Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
```java
TikTokLive.newClient("host-name")
.onGiftCombo((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onEmote [TikTokEmoteEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokEmoteEvent.java)
Triggered every time a subscriber sends an emote (sticker).
```java
TikTokLive.newClient("host-name")
.onEmote((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onGift [TikTokGiftEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftEvent.java)
Triggered when user sends gifts that has
no combo (most of expensive gifts)
or if combo has finished
```java
TikTokLive.newClient("host-name")
.onGift((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onComment [TikTokCommentEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokCommentEvent.java)
Triggered every time a new chat comment arrives.
```java
TikTokLive.newClient("host-name")
.onComment((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onLivePaused [TikTokLivePausedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLivePausedEvent.java)
```java
TikTokLive.newClient("host-name")
.onLivePaused((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onLiveUnpaused [TikTokLiveUnpausedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLiveUnpausedEvent.java)
```java
TikTokLive.newClient("host-name")
.onLiveUnpaused((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onJoin [TikTokJoinEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokJoinEvent.java)
```java
TikTokLive.newClient("host-name")
.onJoin((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onWebsocketUnhandledMessage [TikTokWebsocketUnhandledMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketUnhandledMessageEvent.java)
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
```java
TikTokLive.newClient("host-name")
.onWebsocketUnhandledMessage((liveClient, event) ->
{
})
@@ -580,30 +572,11 @@ TikTokLive.newClient("host-name")
```java
TikTokLive.newClient("host-name")
.onWebsocketResponse((liveClient, event) ->
{
.onWebsocketResponse((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onWebsocketUnhandledMessage [TikTokWebsocketUnhandledMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketUnhandledMessageEvent.java)
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
```java
TikTokLive.newClient("host-name")
.onWebsocketUnhandledMessage((liveClient, event) ->
{
})
.buildAndConnect();
})
.buildAndConnect();
```
@@ -613,16 +586,16 @@ TikTokLive.newClient("host-name")
## onWebsocketMessage [TikTokWebsocketMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketMessageEvent.java)
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
```java
TikTokLive.newClient("host-name")
.onWebsocketMessage((liveClient, event) ->
{
.onWebsocketMessage((liveClient, event) ->
{
})
.buildAndConnect();
})
.buildAndConnect();
```
@@ -635,72 +608,72 @@ TikTokLive.newClient("host-name")
```java
/**
*
* Listeners are an alternative way of handling events.
* I would to suggest to use then when logic of handing event
* is more complex
*
*/
public static void main(String[] args) throws IOException {
/**
*
* Listeners are an alternative way of handling events.
* I would to suggest to use then when logic of handing event
* is more complex
*
*/
public static void main(String[] args) throws IOException {
showLogo();
CustomListener customListener = new CustomListener();
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
.addListener(customListener)
.buildAndConnect();
.addListener(customListener)
.buildAndConnect();
System.in.read();
}
/**
*
* Method in TikTokEventListener should meet 4 requirements to be detected
* - 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 onLike(LiveClient liveClient, TikTokLikeEvent event) {
System.out.println(event.toString());
}
/**
*
* Method in TikTokEventListener should meet 4 requirements to be detected
* - 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 onLike(LiveClient liveClient, TikTokLikeEvent event) {
System.out.println(event.toString());
}
@TikTokEventHandler
public void onError(LiveClient liveClient, TikTokErrorEvent event) {
// event.getException().printStackTrace();
}
@TikTokEventHandler
public void onComment(LiveClient liveClient, TikTokCommentEvent event) {
var userName = event.getUser().getName();
var text = event.getText();
liveClient.getLogger().info(userName + ": " + text);
}
@TikTokEventHandler
public void onGift(LiveClient liveClient, TikTokGiftEvent event) {
var message = switch (event.getGift()) {
case ROSE -> "Thanks :)";
case APPETIZERS -> ":OO";
case APRIL -> ":D";
case TIKTOK -> ":P";
case CAP -> ":F";
default -> ":I";
};
liveClient.getLogger().info(message);
}
@TikTokEventHandler
public void onAnyEvent(LiveClient liveClient, TikTokEvent event) {
liveClient.getLogger().info(event.getClass().getSimpleName());
}
@TikTokEventHandler
public void onError(LiveClient liveClient, TikTokErrorEvent event) {
// event.getException().printStackTrace();
}
//
@TikTokEventHandler
public void onComment(LiveClient liveClient, TikTokCommentEvent event) {
var userName = event.getUser().getName();
var text = event.getText();
liveClient.getLogger().info(userName + ": " + text);
}
@TikTokEventHandler
public void onGift(LiveClient liveClient, TikTokGiftEvent event) {
var message = switch (event.getGift()) {
case ROSE -> "Thanks :)";
case APPETIZERS -> ":OO";
case APRIL -> ":D";
case TIKTOK -> ":P";
case CAP -> ":F";
default -> ":I";
};
liveClient.getLogger().info(message);
}
@TikTokEventHandler
public void onAnyEvent(LiveClient liveClient, TikTokEvent event) {
liveClient.getLogger().info(event.getClass().getSimpleName());
}
}
//
```

View File

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

View File

@@ -22,11 +22,20 @@
*/
package io.github.jwdeveloper.tiktok.tools.collector;
import io.github.jwdeveloper.tiktok.TikTokLive;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import io.github.jwdeveloper.tiktok.tools.collector.client.TikTokMessageCollectorClient;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;
public class RunCollector {
@@ -38,22 +47,38 @@ public class RunCollector {
public static void main(String[] args) throws SQLException, IOException {
TikTokMessageCollectorClient.create("giftsCollector")
.addUser("crece.sara")
.addUser("moniczkka")
//.addUser("crece.sara")
//.addUser("moniczkka")
.addUser("valeria.viral")
// .addUser("cbcgod")
// .addUser("psychotropnazywo")
// .addUser("accordionistka")
.addEventFilter(WebcastGiftMessage.class)
//.addEventFilter(WebcastGiftMessage.class)
.addOnBuilder(liveClientBuilder ->
{
liveClientBuilder.onGiftCombo((liveClient, event) ->
{
liveClient.getLogger().setLevel(Level.OFF);
var gifts = liveClient.getGiftManager().getGifts();
var sb = new StringBuilder();
sb.append("GIFT COMBO User: " + event.getUser().getProfileName()+" ");
sb.append("Name: " + event.getGift().getName() + " ");
sb.append("Combo: " + event.getCombo() + " ");
sb.append("COST: " + event.getGift().getDiamondCost() + " ");
sb.append("STATE: " + event.getComboState() + " ");
System.out.println(sb.toString());
});
liveClientBuilder.onGift((liveClient, event) ->
{
liveClient.getLogger().setLevel(Level.OFF);
var gifts = liveClient.getGiftManager().getGifts();
var sb = new StringBuilder();
sb.append("GIFT User: " + event.getUser().getProfileName()+" ");
sb.append("Name: " + event.getGift().getName() + " ");
sb.append("COST: " + event.getGift().getDiamondCost() + " ");
sb.append("Combo: " + event.getCombo() + " ");
System.out.println(sb.toString());
});

View File

@@ -31,6 +31,6 @@ public class TikTokMessageCollectorClient
public static TikTokMessagessCollectorBuilder create(MessageCollector messageCollector, String outputName)
{
return new TikTokMessagessCollectorBuilder(outputName);
return new TikTokMessagessCollectorBuilder(messageCollector,outputName);
}
}

View File

@@ -26,9 +26,9 @@ import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import io.github.jwdeveloper.tiktok.utils.ProtocolUtils;
public class MessageUtil
{
public class MessageUtil {
public static String getContent(WebcastResponse.Message message) {
try {
var methodName = message.getMethod();
@@ -38,7 +38,7 @@ public class MessageUtil
return JsonUtil.messageToJson(deserialized);
} catch (Exception ex) {
return ConsoleColors.RED+ "Can not find mapper for "+message.getMethod();
return ConsoleColors.RED + "Can not find mapper for " + message.getMethod();
}
}
@@ -49,11 +49,13 @@ public class MessageUtil
var parseMethod = inputClazz.getDeclaredMethod("parseFrom", byte[].class);
var deserialized = parseMethod.invoke(null, bytes);
return JsonUtil.messageToJson(deserialized);
} catch (Exception ex)
{
} catch (Exception ex) {
var sb = new StringBuilder();
sb.append("Can not find mapper for "+methodName);
sb.append("Can not find protocolbuffer file message representation for " + methodName);
sb.append("\n");
var structure = ProtocolUtils.getProtocolBufferStructure(bytes);
var json =structure.toJson();
sb.append(json);
//String jsonString = JsonFormat.printToString(protobufData);
return sb.toString();
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,264 @@
{
"RoomMessage": [
{
"eventData": "CioKDVN5c3RlbU1lc3NhZ2UQmofs1NO1z8sXGKGW59iz55WpZSDxhpnNvDESuQFXZWxjb21lIHRvIFRpa1RvayBMSVZFISBIYXZlIGZ1biBpbnRlcmFjdGluZyB3aXRoIHRoZSBMSVZFIGNyZWF0b3IgYW5kIG90aGVyIHZpZXdlcnMgaW4gcmVhbCB0aW1lIGFuZCByZW1lbWJlciB0byBjcmVhdGUgYSBzYWZlIHZpZXdpbmcgZXhwZXJpZW5jZSBieSBmb2xsb3dpbmcgb3VyIENvbW11bml0eSBHdWlkZWxpbmVzLjgB",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:06:35.153694400"
},
{
"eventData": "CioKDVN5c3RlbU1lc3NhZ2UQjPTq1re3z8sXGKGW59iz55WpZSCI5ZzNvDESuQFXZWxjb21lIHRvIFRpa1RvayBMSVZFISBIYXZlIGZ1biBpbnRlcmFjdGluZyB3aXRoIHRoZSBMSVZFIGNyZWF0b3IgYW5kIG90aGVyIHZpZXdlcnMgaW4gcmVhbCB0aW1lIGFuZCByZW1lbWJlciB0byBjcmVhdGUgYSBzYWZlIHZpZXdpbmcgZXhwZXJpZW5jZSBieSBmb2xsb3dpbmcgb3VyIENvbW11bml0eSBHdWlkZWxpbmVzLjgB",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:07:36.360859900"
},
{
"eventData": "CioKDVN5c3RlbU1lc3NhZ2UQocTpm8nCz8sXGKGW59iz55WpZSDSkrTNvDESuQFXZWxjb21lIHRvIFRpa1RvayBMSVZFISBIYXZlIGZ1biBpbnRlcmFjdGluZyB3aXRoIHRoZSBMSVZFIGNyZWF0b3IgYW5kIG90aGVyIHZpZXdlcnMgaW4gcmVhbCB0aW1lIGFuZCByZW1lbWJlciB0byBjcmVhdGUgYSBzYWZlIHZpZXdpbmcgZXhwZXJpZW5jZSBieSBmb2xsb3dpbmcgb3VyIENvbW11bml0eSBHdWlkZWxpbmVzLjgB",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:13:58.969658600"
},
{
"eventData": "CioKDVN5c3RlbU1lc3NhZ2UQ8a6h9abiz8sXGKGW59iz55WpZSDS2PbNvDESuQFXZWxjb21lIHRvIFRpa1RvayBMSVZFISBIYXZlIGZ1biBpbnRlcmFjdGluZyB3aXRoIHRoZSBMSVZFIGNyZWF0b3IgYW5kIG90aGVyIHZpZXdlcnMgaW4gcmVhbCB0aW1lIGFuZCByZW1lbWJlciB0byBjcmVhdGUgYSBzYWZlIHZpZXdpbmcgZXhwZXJpZW5jZSBieSBmb2xsb3dpbmcgb3VyIENvbW11bml0eSBHdWlkZWxpbmVzLjgB",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:32:09.427463"
}
],
"WebcastChatMessage": [
{
"eventData": "ClAKEldlYmNhc3RDaGF0TWVzc2FnZRCglqWQ1+2VqWUYoZbn2LPnlallIMjgmc28MTABSAJQAnoIdXNlYXN0MmGwAQG4AQLAAQLIAerYmc28MRKdCgiFiKX0gI2FlmAaF/CfkoAgUG9yYSB1bWllcmHEhyDwn5KASvgFCrYBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9dklLVGljWFYwZEdmZmdNa0QzYzJvU1BEJTJGbjAlM0QKpgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9Nk1YbjZlellUMzRxVWNzdU1xUTFHMTBRMWVZJTNECqYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTgxNEpPdU9DOGR5b1RkOVNWOU5CN1I2UmI2NCUzRAqsAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YRTNLaDI1QnlzMERVJTJGJTJGVWtyZWQlMkJMWnVCeFUlM0QSPDEwMHgxMDAvdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMVKOAwrCAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfnRwbHYtdGlrdG9reC1jb21wcmVzc19xdWFsaXR5XzMwOjcyOjcyLndlYnA/eC1leHBpcmVzPTE2OTk5MTY0MDAmeC1zaWduYXR1cmU9Q1RLNlJMNnVlTkpSelI5dHBLSjVGM0FvdHBJJTNECsYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2t4LWNvbXByZXNzX3F1YWxpdHlfMzA6NzI6NzIuanBlZz94LWV4cGlyZXM9MTY5OTkxNjQwMCZ4LXNpZ25hdHVyZT1IVG0lMkY3WEFMQTJzSlklMkJIMWp0MTN6QUdGc00wJTNEsgEGCIQFEKgVugEAggIAsgINZG9zdGF3Y2F2aWRlb/ICTE1TNHdMakFCQUFBQXFrRnQtRUpmRzRESFV1WXltUUJzU19qNmRyVWl5dFozM3RFTXlidWFHRi1pWHo3X1dZSXBfakQ0cElDVk1qd2QaA2FzZHICemiSAQIwAZoBFAoOdXNlcl90eXBlX3J1bGUQoMIemgEYChFjb21tdW5pdHktZmxhZ2dlZBDZt9oBmgEaCg5jb21tZW50YXRvcl9pZBCFiKX0gI2FlmCaARIKB2RlZmF1bHQQ8LqSkbvBggOaARAKC2RlZmF1bHRfYXBwEJBOmgERCgZyYW5rVjMQ4/2WkbvBggOaARoKD3R0cF9ydWxlX3JlcmFuaxDw5/SVu8GCA5oBGgoOdGltZXN0YW1wX2Rlc2MQkMWV28rtzq4BmgE1Cip0aWtjYXN0X2NvbW11bml0eV9jb21tZW50XzE4ODY2X3Y3X3I2NTUwNjkQkdSYkbvBggOaAToKL3Rpa2Nhc3RfY29tbXVuaXR5X2NvbW1lbnRfMTg4NjZfdjdfcjY1NTA2OV9kZXNjEO7S95W7wYIDmgEaCg9pZGNfcnVsZV9yZXJhbmsQ8Jv+qLvBggOaARYKC3YxM19yNzEyMDg4EPCb/qi7wYIDmgEWCgt2MTJfcjcwMjA3NRDwm/6ou8GCA5oBFgoLdjEzX3I3NjUxNjYQ8Jv+qLvBggOaARYKC3YxM19yNzY1MTY3EPCb/qi7wYIDmgEWCgt2MTNfcjc2NTE2ORDwm/6ou8GCA5oBFgoLdjEzX3I3NjcxMjIQ8Jv+qLvBggOaARYKC3YxM19yNzcwODA0EPCb/qi7wYIDmgEWCgt2MTNfcjc3MDgwNRDwm/6ou8GCA5oBFgoLdjEzX3I3NzA4MDYQ8Jv+qLvBggOaARYKC3YxM19yNzcwODA3EPCb/qi7wYIDmgEWCgt2MTNfcjc3MDgwOBDwm/6ou8GCA5oBFgoLdjEzX3I3NzA4MTAQ8Jv+qLvBggOaARoKD2lkY19ydWxlX3JlcmFuaxDwm/6ou8GCA6IBAQA=",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:06:47.126429700"
},
{
"eventData": "ClAKEldlYmNhc3RDaGF0TWVzc2FnZRCglqWQ1+2VqWUYoZbn2LPnlallIMjgmc28MTABSAJQAnoIdXNlYXN0MmGwAQG4AQLAAQLIAerYmc28MRKdCgiFiKX0gI2FlmAaF/CfkoAgUG9yYSB1bWllcmHEhyDwn5KASvgFCrYBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9dklLVGljWFYwZEdmZmdNa0QzYzJvU1BEJTJGbjAlM0QKpgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9Nk1YbjZlellUMzRxVWNzdU1xUTFHMTBRMWVZJTNECqYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTgxNEpPdU9DOGR5b1RkOVNWOU5CN1I2UmI2NCUzRAqsAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YRTNLaDI1QnlzMERVJTJGJTJGVWtyZWQlMkJMWnVCeFUlM0QSPDEwMHgxMDAvdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMVKOAwrCAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfnRwbHYtdGlrdG9reC1jb21wcmVzc19xdWFsaXR5XzMwOjcyOjcyLndlYnA/eC1leHBpcmVzPTE2OTk5MTY0MDAmeC1zaWduYXR1cmU9Q1RLNlJMNnVlTkpSelI5dHBLSjVGM0FvdHBJJTNECsYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2t4LWNvbXByZXNzX3F1YWxpdHlfMzA6NzI6NzIuanBlZz94LWV4cGlyZXM9MTY5OTkxNjQwMCZ4LXNpZ25hdHVyZT1IVG0lMkY3WEFMQTJzSlklMkJIMWp0MTN6QUdGc00wJTNEsgEGCIQFEKgVugEAggIAsgINZG9zdGF3Y2F2aWRlb/ICTE1TNHdMakFCQUFBQXFrRnQtRUpmRzRESFV1WXltUUJzU19qNmRyVWl5dFozM3RFTXlidWFHRi1pWHo3X1dZSXBfakQ0cElDVk1qd2QaA2FzZHICemiSAQIwAZoBFAoOdXNlcl90eXBlX3J1bGUQoMIemgEYChFjb21tdW5pdHktZmxhZ2dlZBDZt9oBmgEaCg5jb21tZW50YXRvcl9pZBCFiKX0gI2FlmCaARIKB2RlZmF1bHQQ8LqSkbvBggOaARAKC2RlZmF1bHRfYXBwEJBOmgERCgZyYW5rVjMQ4/2WkbvBggOaARoKD3R0cF9ydWxlX3JlcmFuaxDw5/SVu8GCA5oBGgoOdGltZXN0YW1wX2Rlc2MQkMWV28rtzq4BmgE1Cip0aWtjYXN0X2NvbW11bml0eV9jb21tZW50XzE4ODY2X3Y3X3I2NTUwNjkQkdSYkbvBggOaAToKL3Rpa2Nhc3RfY29tbXVuaXR5X2NvbW1lbnRfMTg4NjZfdjdfcjY1NTA2OV9kZXNjEO7S95W7wYIDmgEaCg9pZGNfcnVsZV9yZXJhbmsQ8Jv+qLvBggOaARYKC3YxM19yNzEyMDg4EPCb/qi7wYIDmgEWCgt2MTJfcjcwMjA3NRDwm/6ou8GCA5oBFgoLdjEzX3I3NjUxNjYQ8Jv+qLvBggOaARYKC3YxM19yNzY1MTY3EPCb/qi7wYIDmgEWCgt2MTNfcjc2NTE2ORDwm/6ou8GCA5oBFgoLdjEzX3I3NjcxMjIQ8Jv+qLvBggOaARYKC3YxM19yNzcwODA0EPCb/qi7wYIDmgEWCgt2MTNfcjc3MDgwNRDwm/6ou8GCA5oBFgoLdjEzX3I3NzA4MDYQ8Jv+qLvBggOaARYKC3YxM19yNzcwODA3EPCb/qi7wYIDmgEWCgt2MTNfcjc3MDgwOBDwm/6ou8GCA5oBFgoLdjEzX3I3NzA4MTAQ8Jv+qLvBggOaARoKD2lkY19ydWxlX3JlcmFuaxDwm/6ou8GCA6IBAQA=",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:07:36.364450900"
},
{
"eventData": "ClAKEldlYmNhc3RDaGF0TWVzc2FnZRCglp7Ix/SVqWUYoZbn2LPnlallIOvxm828MTABSAJQAnoIdXNlYXN0MmGwAQK4AQLAAQLIAfPqm828MRKVCgiFiMi2nP/V4l0aDG5vdGlmaWNhdGlvbkr+BQq6AWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzgzOTE5MWFlZDIzMzRjMTgyMTI1Y2M0YTAzMzA0Y2NhfnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPSUyQmRnaCUyRmxmVDNmUm4zZWZtQjMlMkZCSXU0NHJXUSUzRAqoAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzgzOTE5MWFlZDIzMzRjMTgyMTI1Y2M0YTAzMzA0Y2NhfmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1XRkNLeXMyTVAyMlclMkZGR0lRdzFCMHpIQ1l6RSUzRAqqAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzgzOTE5MWFlZDIzMzRjMTgyMTI1Y2M0YTAzMzA0Y2NhfmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT0lMkZITVJNaEFYQ3lFbXZkbyUyRnB6aVRDNjQ0c2hNJTNECqgBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvODM5MTkxYWVkMjMzNGMxODIxMjVjYzRhMDMzMDRjY2F+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPWt2V3FUWmFOclBsTSUyRkVlV2hKakJ5TzkxUG5nJTNEEjwxMDB4MTAwL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvODM5MTkxYWVkMjMzNGMxODIxMjVjYzRhMDMzMDRjY2FSjAMKwgFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC84MzkxOTFhZWQyMzM0YzE4MjEyNWNjNGEwMzMwNGNjYX50cGx2LXRpa3Rva3gtY29tcHJlc3NfcXVhbGl0eV8zMDo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNjk5OTE2NDAwJngtc2lnbmF0dXJlPU5vMWN2RXB2Yno1QXFtTnZmQzh1ZDl0d3hKTSUzRArEAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzgzOTE5MWFlZDIzMzRjMTgyMTI1Y2M0YTAzMzA0Y2NhfnRwbHYtdGlrdG9reC1jb21wcmVzc19xdWFsaXR5XzMwOjcyOjcyLmpwZWc/eC1leHBpcmVzPTE2OTk5MTY0MDAmeC1zaWduYXR1cmU9eEduYkFuVUFFckZKUzFTcW1OME5vJTJGOUVRM1UlM0SyAQgI3QwQ1BEYAboBAIICALICCm5pZXRvcGVyejDyAkxNUzR3TGpBQkFBQUF6emlzM0d0blI4bUJsVEIwQjZCY3RDVHBEd0NrMV9lc1hLckJTZkZOVTRCM0hkYXVESEkxUzl6QTM4TGR0cklWGgVzaWVtYXICcGySAQIgAZoBFAoOdXNlcl90eXBlX3J1bGUQwJoMmgEXChFjb21tdW5pdHktZmxhZ2dlZBCorRqaARoKDmNvbW1lbnRhdG9yX2lkEIWIyLac/9XiXZoBEgoHZGVmYXVsdBDg2uShu8GCA5oBEAoLZGVmYXVsdF9hcHAQkE6aAREKBnJhbmtWMxDjsaCku8GCA5oBGgoPdHRwX3J1bGVfcmVyYW5rEMiPx6a7wYIDmgEaCg50aW1lc3RhbXBfZGVzYxC4ncPKyu3OrgGaATUKKnRpa2Nhc3RfY29tbXVuaXR5X2NvbW1lbnRfMTg4NjZfdjdfcjY1NTA2ORDhz6Wku8GCA5oBOgovdGlrY2FzdF9jb21tdW5pdHlfY29tbWVudF8xODg2Nl92N19yNjU1MDY5X2Rlc2MQn7/9qLvBggOaARoKD2lkY19ydWxlX3JlcmFuaxDIw9C5u8GCA5oBFgoLdjEzX3I3MTIwODgQyMPQubvBggOaARYKC3YxMl9yNzAyMDc1EMjD0Lm7wYIDmgEWCgt2MTNfcjc2NTE2NhDIw9C5u8GCA5oBFgoLdjEzX3I3NjUxNjcQyMPQubvBggOaARYKC3YxM19yNzY1MTY5EMjD0Lm7wYIDmgEWCgt2MTNfcjc2NzEyMhDIw9C5u8GCA5oBFgoLdjEzX3I3NzA4MDQQyMPQubvBggOaARYKC3YxM19yNzcwODA1EMjD0Lm7wYIDmgEWCgt2MTNfcjc3MDgwNhDIw9C5u8GCA5oBFgoLdjEzX3I3NzA4MDcQyMPQubvBggOaARYKC3YxM19yNzcwODA4EMjD0Lm7wYIDmgEWCgt2MTNfcjc3MDgxMBDIw9C5u8GCA5oBGgoPaWRjX3J1bGVfcmVyYW5rEMjD0Lm7wYIDogEBAA==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:07:36.364951"
},
{
"eventData": "ClAKEldlYmNhc3RDaGF0TWVzc2FnZRChlqfexJ+WqWUYoZbn2LPnlallINPCsc28MTABSAJQAnoIdXNlYXN0MmGwAQG4AQLAAQLIAcy+sc28MRKfCgiFiKX0gI2FlmAaF/CfkoAgUG9yYSB1bWllcmHEhyDwn5KASvoFCrgBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9eWRWc0c3JTJCYTRUbU9XRXFPSGd6JTJCQmVRU1k2YyUzRAqmAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT02TVhuNmV6WVQzNHFVY3N1TXFRMUcxMFExZVklM0QKpgFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9ODE0Sk91T0M4ZHlvVGQ5U1Y5TkI3UjZSYjY0JTNECqwBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPVhFM0toMjVCeXMwRFUlMkYlMkZVa3JlZCUyQkxadUJ4VSUzRBI8MTAweDEwMC90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxUo4DCsIBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2t4LWNvbXByZXNzX3F1YWxpdHlfMzA6NzI6NzIud2VicD94LWV4cGlyZXM9MTY5OTkxNjQwMCZ4LXNpZ25hdHVyZT1DVEs2Ukw2dWVOSlJ6Ujl0cEtKNUYzQW90cEklM0QKxgFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX50cGx2LXRpa3Rva3gtY29tcHJlc3NfcXVhbGl0eV8zMDo3Mjo3Mi5qcGVnP3gtZXhwaXJlcz0xNjk5OTE2NDAwJngtc2lnbmF0dXJlPUhUbSUyRjdYQUxBMnNKWSUyQkgxanQxM3pBR0ZzTTAlM0SyAQYIhAUQqBW6AQCCAgCyAg1kb3N0YXdjYXZpZGVv8gJMTVM0d0xqQUJBQUFBcWtGdC1FSmZHNERIVXVZeW1RQnNTX2o2ZHJVaXl0WjMzdEVNeWJ1YUdGLWlYejdfV1lJcF9qRDRwSUNWTWp3ZBoDYXNkcgJ6aJIBAjABmgEUCg51c2VyX3R5cGVfcnVsZRCgwh6aARgKEWNvbW11bml0eS1mbGFnZ2VkENm32gGaARoKDmNvbW1lbnRhdG9yX2lkEIWIpfSAjYWWYJoBEgoHZGVmYXVsdBCwxunKvMGCA5oBEAoLZGVmYXVsdF9hcHAQkE6aAREKBnJhbmtWMxDj2JLLvMGCA5oBGgoPdHRwX3J1bGVfcmVyYW5rEJj7y8+8wYIDmgEaCg50aW1lc3RhbXBfZGVzYxDosb6hye3OrgGaATUKKnRpa2Nhc3RfY29tbXVuaXR5X2NvbW1lbnRfMTg4NjZfdjdfcjY1NTA2ORCRr5TLvMGCA5oBOgovdGlrY2FzdF9jb21tdW5pdHlfY29tbWVudF8xODg2Nl92N19yNjU1MDY5X2Rlc2MQ7q3zz7zBggOaARoKD2lkY19ydWxlX3JlcmFuaxCYr9XivMGCA5oBFgoLdjEzX3I3MTIwODgQmK/V4rzBggOaARYKC3YxMl9yNzAyMDc1EJiv1eK8wYIDmgEWCgt2MTNfcjc2NTE2NhCYr9XivMGCA5oBFgoLdjEzX3I3NjUxNjcQmK/V4rzBggOaARYKC3YxM19yNzY1MTY5EJiv1eK8wYIDmgEWCgt2MTNfcjc2NzEyMhCYr9XivMGCA5oBFgoLdjEzX3I3NzA4MDQQmK/V4rzBggOaARYKC3YxM19yNzcwODA1EJiv1eK8wYIDmgEWCgt2MTNfcjc3MDgwNhCYr9XivMGCA5oBFgoLdjEzX3I3NzA4MDcQmK/V4rzBggOaARYKC3YxM19yNzcwODA4EJiv1eK8wYIDmgEWCgt2MTNfcjc3MDgxMBCYr9XivMGCA5oBGgoPaWRjX3J1bGVfcmVyYW5rEJiv1eK8wYIDogEBAA==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:13:58.973166900"
},
{
"eventData": "ClAKEldlYmNhc3RDaGF0TWVzc2FnZRChlt6SlaOWqWUYoZbn2LPnlallIMLsss28MTABSAJQAnoIdXNlYXN0MmGwAQG4AQLAAQLIAY7pss28MRKZCgiFiKX0gI2FlmAaF/CfkoAgUG9yYSB1bWllcmHEhyDwn5KASvQFCrYBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9dklLVGljWFYwZEdmZmdNa0QzYzJvU1BEJTJGbjAlM0QKpgFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9ODE0Sk91T0M4ZHlvVGQ5U1Y5TkI3UjZSYjY0JTNECqYBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTZNWG42ZXpZVDM0cVVjc3VNcVExRzEwUTFlWSUzRAqoAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YTll0ZU5yaXVjcjJSeGZDVEdZR1JHJTJGNXZTYyUzRBI8MTAweDEwMC90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxUo4DCsIBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2t4LWNvbXByZXNzX3F1YWxpdHlfMzA6NzI6NzIud2VicD94LWV4cGlyZXM9MTY5OTkxNjQwMCZ4LXNpZ25hdHVyZT1DVEs2Ukw2dWVOSlJ6Ujl0cEtKNUYzQW90cEklM0QKxgFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX50cGx2LXRpa3Rva3gtY29tcHJlc3NfcXVhbGl0eV8zMDo3Mjo3Mi5qcGVnP3gtZXhwaXJlcz0xNjk5OTE2NDAwJngtc2lnbmF0dXJlPUhUbSUyRjdYQUxBMnNKWSUyQkgxanQxM3pBR0ZzTTAlM0SyAQYIhAUQqBW6AQCCAgCyAg1kb3N0YXdjYXZpZGVv8gJMTVM0d0xqQUJBQUFBcWtGdC1FSmZHNERIVXVZeW1RQnNTX2o2ZHJVaXl0WjMzdEVNeWJ1YUdGLWlYejdfV1lJcF9qRDRwSUNWTWp3ZBoDYXNkcgJ6aJIBAjABmgEUCg51c2VyX3R5cGVfcnVsZRCgwh6aARgKEWNvbW11bml0eS1mbGFnZ2VkENm32gGaARoKDmNvbW1lbnRhdG9yX2lkEIWIpfSAjYWWYJoBEgoHZGVmYXVsdBCY3pnVvMGCA5oBEAoLZGVmYXVsdF9hcHAQkE6aAREKBnJhbmtWMxDj37nZvMGCA5oBGgoPdHRwX3J1bGVfcmVyYW5rEICT/Nm8wYIDmgEaCg50aW1lc3RhbXBfZGVzYxCAmo6Xye3OrgGaATUKKnRpa2Nhc3RfY29tbXVuaXR5X2NvbW1lbnRfMTg4NjZfdjdfcjY1NTA2ORCRtrvZvMGCA5oBOgovdGlrY2FzdF9jb21tdW5pdHlfY29tbWVudF8xODg2Nl92N19yNjU1MDY5X2Rlc2MQ7rSa3rzBggOaARoKD2lkY19ydWxlX3JlcmFuaxCAx4XtvMGCA5oBFgoLdjEzX3I3MTIwODgQgMeF7bzBggOaARYKC3YxMl9yNzAyMDc1EIDHhe28wYIDmgEWCgt2MTNfcjc2NTE2NhCAx4XtvMGCA5oBFgoLdjEzX3I3NjUxNjcQgMeF7bzBggOaARYKC3YxM19yNzY1MTY5EIDHhe28wYIDmgEWCgt2MTNfcjc2NzEyMhCAx4XtvMGCA5oBFgoLdjEzX3I3NzA4MDQQgMeF7bzBggOaARYKC3YxM19yNzcwODA1EIDHhe28wYIDmgEWCgt2MTNfcjc3MDgwNhCAx4XtvMGCA5oBFgoLdjEzX3I3NzA4MDcQgMeF7bzBggOaARYKC3YxM19yNzcwODA4EIDHhe28wYIDmgEWCgt2MTNfcjc3MDgxMBCAx4XtvMGCA5oBGgoPaWRjX3J1bGVfcmVyYW5rEIDHhe28wYIDogEBAA==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:13:58.974165"
},
{
"eventData": "ClAKEldlYmNhc3RDaGF0TWVzc2FnZRCglq+yx6aWqWUYoZbn2LPnlallIIPXtM28MTABSAJQAnoIdXNlYXN0MmGwAQK4AQLAAQLIAa7StM28MRKdCgiFiKX0gI2FlmAaF/CfkoAgUG9yYSB1bWllcmHEhyDwn5KASvgFCrYBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9dklLVGljWFYwZEdmZmdNa0QzYzJvU1BEJTJGbjAlM0QKpgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9Nk1YbjZlellUMzRxVWNzdU1xUTFHMTBRMWVZJTNECqYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTgxNEpPdU9DOGR5b1RkOVNWOU5CN1I2UmI2NCUzRAqsAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YRTNLaDI1QnlzMERVJTJGJTJGVWtyZWQlMkJMWnVCeFUlM0QSPDEwMHgxMDAvdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMVKOAwrCAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfnRwbHYtdGlrdG9reC1jb21wcmVzc19xdWFsaXR5XzMwOjcyOjcyLndlYnA/eC1leHBpcmVzPTE2OTk5MTY0MDAmeC1zaWduYXR1cmU9Q1RLNlJMNnVlTkpSelI5dHBLSjVGM0FvdHBJJTNECsYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2t4LWNvbXByZXNzX3F1YWxpdHlfMzA6NzI6NzIuanBlZz94LWV4cGlyZXM9MTY5OTkxNjQwMCZ4LXNpZ25hdHVyZT1IVG0lMkY3WEFMQTJzSlklMkJIMWp0MTN6QUdGc00wJTNEsgEGCIQFEKgVugEAggIAsgINZG9zdGF3Y2F2aWRlb/ICTE1TNHdMakFCQUFBQXFrRnQtRUpmRzRESFV1WXltUUJzU19qNmRyVWl5dFozM3RFTXlidWFHRi1pWHo3X1dZSXBfakQ0cElDVk1qd2QaCGFkYXNkYXNkcgJ0cpIBAjABmgEUCg51c2VyX3R5cGVfcnVsZRCgwh6aARgKEWNvbW11bml0eS1mbGFnZ2VkEPzApwOaARoKDmNvbW1lbnRhdG9yX2lkEIWIpfSAjYWWYJoBEgoHZGVmYXVsdBCIjsPjvMGCA5oBEAoLZGVmYXVsdF9hcHAQkE6aAREKBnJhbmtWMxDj5uDnvMGCA5oBGgoPdHRwX3J1bGVfcmVyYW5rEIi7pei8wYIDmgEaCg50aW1lc3RhbXBfZGVzYxD48eSIye3OrgGaATUKKnRpa2Nhc3RfY29tbXVuaXR5X2NvbW1lbnRfMTg4NjZfdjdfcjY1NTA2ORCam+PnvMGCA5oBOgovdGlrY2FzdF9jb21tdW5pdHlfY29tbWVudF8xODg2Nl92N19yNjU1MDY5X2Rlc2MQ5d3A7LzBggOaARoKD2lkY19ydWxlX3JlcmFuaxCI7677vMGCA5oBFgoLdjEzX3I3MTIwODgQiO+u+7zBggOaARYKC3YxMl9yNzAyMDc1EIjvrvu8wYIDmgEWCgt2MTNfcjc2NTE2NhCI7677vMGCA5oBFgoLdjEzX3I3NjUxNjcQiO+u+7zBggOaARYKC3YxM19yNzY1MTY5EIjvrvu8wYIDmgEWCgt2MTNfcjc2NzEyMhCI7677vMGCA5oBFgoLdjEzX3I3NzA4MDQQiO+u+7zBggOaARYKC3YxM19yNzcwODA1EIjvrvu8wYIDmgEWCgt2MTNfcjc3MDgwNhCI7677vMGCA5oBFgoLdjEzX3I3NzA4MDcQiO+u+7zBggOaARYKC3YxM19yNzcwODA4EIjvrvu8wYIDmgEWCgt2MTNfcjc3MDgxMBCI7677vMGCA5oBGgoPaWRjX3J1bGVfcmVyYW5rEPD2rvu8wYIDogEBAA==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:14:07.736142"
},
{
"eventData": "ClAKEldlYmNhc3RDaGF0TWVzc2FnZRChlqWizKeWqWUYoZbn2LPnlallIN7Htc28MTABSAJQAnoIdXNlYXN0MmGwAQK4AQLAAQLIAafEtc28MRKdCgiFiKX0gI2FlmAaF/CfkoAgUG9yYSB1bWllcmHEhyDwn5KASvgFCrYBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9dklLVGljWFYwZEdmZmdNa0QzYzJvU1BEJTJGbjAlM0QKpgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9Nk1YbjZlellUMzRxVWNzdU1xUTFHMTBRMWVZJTNECqYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTgxNEpPdU9DOGR5b1RkOVNWOU5CN1I2UmI2NCUzRAqsAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YRTNLaDI1QnlzMERVJTJGJTJGVWtyZWQlMkJMWnVCeFUlM0QSPDEwMHgxMDAvdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMVKOAwrCAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfnRwbHYtdGlrdG9reC1jb21wcmVzc19xdWFsaXR5XzMwOjcyOjcyLndlYnA/eC1leHBpcmVzPTE2OTk5MTY0MDAmeC1zaWduYXR1cmU9Q1RLNlJMNnVlTkpSelI5dHBLSjVGM0FvdHBJJTNECsYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+dHBsdi10aWt0b2t4LWNvbXByZXNzX3F1YWxpdHlfMzA6NzI6NzIuanBlZz94LWV4cGlyZXM9MTY5OTkxNjQwMCZ4LXNpZ25hdHVyZT1IVG0lMkY3WEFMQTJzSlklMkJIMWp0MTN6QUdGc00wJTNEsgEGCIQFEKgVugEAggIAsgINZG9zdGF3Y2F2aWRlb/ICTE1TNHdMakFCQUFBQXFrRnQtRUpmRzRESFV1WXltUUJzU19qNmRyVWl5dFozM3RFTXlidWFHRi1pWHo3X1dZSXBfakQ0cElDVk1qd2QaA2FzZHICemiSAQIwAZoBFAoOdXNlcl90eXBlX3J1bGUQoMIemgEYChFjb21tdW5pdHktZmxhZ2dlZBDZt9oBmgEaCg5jb21tZW50YXRvcl9pZBCFiKX0gI2FlmCaARIKB2RlZmF1bHQQ+K2z6rzBggOaARAKC2RlZmF1bHRfYXBwEJBOmgERCgZyYW5rVjMQ45PD7LzBggOaARoKD3R0cF9ydWxlX3JlcmFuaxDg4pXvvMGCA5oBGgoOdGltZXN0YW1wX2Rlc2MQoMr0gcntzq4BmgE1Cip0aWtjYXN0X2NvbW11bml0eV9jb21tZW50XzE4ODY2X3Y3X3I2NTUwNjkQkerE7LzBggOaAToKL3Rpa2Nhc3RfY29tbXVuaXR5X2NvbW1lbnRfMTg4NjZfdjdfcjY1NTA2OV9kZXNjEO7oo/G8wYIDmgEaCg9pZGNfcnVsZV9yZXJhbmsQ4Jafgr3BggOaARYKC3YxM19yNzEyMDg4EOCWn4K9wYIDmgEWCgt2MTJfcjcwMjA3NRDglp+CvcGCA5oBFgoLdjEzX3I3NjUxNjYQ4Jafgr3BggOaARYKC3YxM19yNzY1MTY3EOCWn4K9wYIDmgEWCgt2MTNfcjc2NTE2ORDglp+CvcGCA5oBFgoLdjEzX3I3NjcxMjIQ4Jafgr3BggOaARYKC3YxM19yNzcwODA0EOCWn4K9wYIDmgEWCgt2MTNfcjc3MDgwNRDglp+CvcGCA5oBFgoLdjEzX3I3NzA4MDYQ4Jafgr3BggOaARYKC3YxM19yNzcwODA3EOCWn4K9wYIDmgEWCgt2MTNfcjc3MDgwOBDglp+CvcGCA5oBFgoLdjEzX3I3NzA4MTAQ4Jafgr3BggOaARoKD2lkY19ydWxlX3JlcmFuaxDglp+CvcGCA6IBAQA=",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:14:22.037528800"
}
],
"WebcastLiveIntroMessage": [
{
"eventData": "CiMKF1dlYmNhc3RMaXZlSW50cm9NZXNzYWdlEKGWofjy+rWEZRChlqH48vq1hGUYASIJR3JhbSB3IE1DKrcFCIWIpfSAjYWWYBoX8J+SgCBQb3JhIHVtaWVyYcSHIPCfkoBKvwQKpgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9Nk1YbjZlellUMzRxVWNzdU1xUTFHMTBRMWVZJTNECqYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTgxNEpPdU9DOGR5b1RkOVNWOU5CN1I2UmI2NCUzRAqsAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YRTNLaDI1QnlzMERVJTJGJTJGVWtyZWQlMkJMWnVCeFUlM0QSPDEwMHgxMDAvdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMYICAPICTE1TNHdMakFCQUFBQXFrRnQtRUpmRzRESFV1WXltUUJzU19qNmRyVWl5dFozM3RFTXlidWFHRi1pWHo3X1dZSXBfakQ0cElDVk1qd2QwAToeCAKqARkIAhIPcG1fbXRfaG9zdGxhYmVsGgRIb3N0QgJlbg==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:06:35.159195800"
},
{
"eventData": "CiMKF1dlYmNhc3RMaXZlSW50cm9NZXNzYWdlEKGWofjy+rWEZRChlqH48vq1hGUYASIJR3JhbSB3IE1DKrcFCIWIpfSAjYWWYBoX8J+SgCBQb3JhIHVtaWVyYcSHIPCfkoBKvwQKpgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9Nk1YbjZlellUMzRxVWNzdU1xUTFHMTBRMWVZJTNECqYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTgxNEpPdU9DOGR5b1RkOVNWOU5CN1I2UmI2NCUzRAqsAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YRTNLaDI1QnlzMERVJTJGJTJGVWtyZWQlMkJMWnVCeFUlM0QSPDEwMHgxMDAvdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMYICAPICTE1TNHdMakFCQUFBQXFrRnQtRUpmRzRESFV1WXltUUJzU19qNmRyVWl5dFozM3RFTXlidWFHRi1pWHo3X1dZSXBfakQ0cElDVk1qd2QwAToeCAKqARkIAhIPcG1fbXRfaG9zdGxhYmVsGgRIb3N0QgJlbg==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:07:36.363450600"
},
{
"eventData": "CiMKF1dlYmNhc3RMaXZlSW50cm9NZXNzYWdlEKGWofjy+rWEZRChlqH48vq1hGUYASIJR3JhbSB3IE1DKrcFCIWIpfSAjYWWYBoX8J+SgCBQb3JhIHVtaWVyYcSHIPCfkoBKvwQKpgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9Nk1YbjZlellUMzRxVWNzdU1xUTFHMTBRMWVZJTNECqYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTgxNEpPdU9DOGR5b1RkOVNWOU5CN1I2UmI2NCUzRAqsAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YRTNLaDI1QnlzMERVJTJGJTJGVWtyZWQlMkJMWnVCeFUlM0QSPDEwMHgxMDAvdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMYICAPICTE1TNHdMakFCQUFBQXFrRnQtRUpmRzRESFV1WXltUUJzU19qNmRyVWl5dFozM3RFTXlidWFHRi1pWHo3X1dZSXBfakQ0cElDVk1qd2QwAToeCAKqARkIAhIPcG1fbXRfaG9zdGxhYmVsGgRIb3N0QgJlbg==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:13:58.972664900"
},
{
"eventData": "CiMKF1dlYmNhc3RMaXZlSW50cm9NZXNzYWdlEKGWofjy+rWEZRChlqH48vq1hGUYASIJR3JhbSB3IE1DKrcFCIWIpfSAjYWWYBoX8J+SgCBQb3JhIHVtaWVyYcSHIPCfkoBKvwQKpgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9Nk1YbjZlellUMzRxVWNzdU1xUTFHMTBRMWVZJTNECqYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvYzJjYzgwOGQ5YmJjYTlmNTVjMzM4NzQwZDIyYzM0MjF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTgxNEpPdU9DOGR5b1RkOVNWOU5CN1I2UmI2NCUzRAqsAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4L2MyY2M4MDhkOWJiY2E5ZjU1YzMzODc0MGQyMmMzNDIxfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YRTNLaDI1QnlzMERVJTJGJTJGVWtyZWQlMkJMWnVCeFUlM0QSPDEwMHgxMDAvdG9zLW1hbGl2YS1hdnQtMDA2OC9jMmNjODA4ZDliYmNhOWY1NWMzMzg3NDBkMjJjMzQyMYICAPICTE1TNHdMakFCQUFBQXFrRnQtRUpmRzRESFV1WXltUUJzU19qNmRyVWl5dFozM3RFTXlidWFHRi1pWHo3X1dZSXBfakQ0cElDVk1qd2QwAToeCAKqARkIAhIPcG1fbXRfaG9zdGxhYmVsGgRIb3N0QgJlbg==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:32:09.430963500"
}
],
"WebcastRoomUserSeqMessage": [
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoZafuvz/lallGKGW59iz55WpZSDshp/NvDESogQSnQQIoIidor7Iw/BkGgVBbGVrc0qPAwqnAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MH5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SWpFYno1WnBmbVJxOUI0TXBnNWQxOVhNclRjJTNECqkBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83MjY5MTA3NDg3OTg1ODYwNjQwfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1yVFlybXNoeElXdzVOWGh4Smk3JTJGSm5FbjF2OCUzRBI3MTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MLoBAIICAKgCAbICCWFsZWtzODQ1OfICTE1TNHdMakFCQUFBQUQ0WVIwS1MxRVhfNlU3Z1k0aGoyVzlaMTItVUhtYXZ4a2lQR2ItV0lIYzFzbnZyYnd5V2lvSXY3NVg1VzRlVEqiQBM3MjY5MTA2OTU4MzA4MTY0NjQwGAESngUSmQUIhoiO8qqbjuBiGgttYW5pdG91MTIyMUqDBAqZAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YWCUyQnZlV3p1b1gyT01LbUpQRmNpSjV1T0NWYyUzRAqbAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1CUDJDUnd4JTJGM3VUJTJGVHlpUkRycTIzakY1c09zJTNECpcBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTR+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPU14ekJvbWpDRWM0RGJNeVdud3N1dWtjYXFFayUzRBItMTAweDEwMC9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0ugEAggIAqAIBsgILbWFuaXRvdTEyMjHyAkxNUzR3TGpBQkFBQUFDUlhtN2d5WHpqdnJOVzhiQVgwMWRIYjRQQ0JmcHBoUUJsTFlsN3QzaVYzNjN6Qi1mOXY2djZJMVByX2UtSjNxokATNzExNTc0OTkyMzEyMzA2OTk1OBgCGAI4AQ==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:08:13.650764700"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoZaf2OeClqllGKGW59iz55WpZSDStaDNvDESogQSnQQIoIidor7Iw/BkGgVBbGVrc0qPAwqnAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MH5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SWpFYno1WnBmbVJxOUI0TXBnNWQxOVhNclRjJTNECqkBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83MjY5MTA3NDg3OTg1ODYwNjQwfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1yVFlybXNoeElXdzVOWGh4Smk3JTJGSm5FbjF2OCUzRBI3MTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MLoBAIICAKgCAbICCWFsZWtzODQ1OfICTE1TNHdMakFCQUFBQUQ0WVIwS1MxRVhfNlU3Z1k0aGoyVzlaMTItVUhtYXZ4a2lQR2ItV0lIYzFzbnZyYnd5V2lvSXY3NVg1VzRlVEqiQBM3MjY5MTA2OTU4MzA4MTY0NjQwGAEYATgC",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:08:36.238853400"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoZavypSElqllGKGW59iz55WpZSCJi6HNvDESogQSnQQIoIidor7Iw/BkGgVBbGVrc0qPAwqnAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MH5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SWpFYno1WnBmbVJxOUI0TXBnNWQxOVhNclRjJTNECqkBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83MjY5MTA3NDg3OTg1ODYwNjQwfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1yVFlybXNoeElXdzVOWGh4Smk3JTJGSm5FbjF2OCUzRBI3MTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MLoBAIICAKgCAbICCWFsZWtzODQ1OfICTE1TNHdMakFCQUFBQUQ0WVIwS1MxRVhfNlU3Z1k0aGoyVzlaMTItVUhtYXZ4a2lQR2ItV0lIYzFzbnZyYnd5V2lvSXY3NVg1VzRlVEqiQBM3MjY5MTA2OTU4MzA4MTY0NjQwGAEYATgC",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:08:46.700698300"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoZabh4KFlqllGKGW59iz55WpZSC1wKHNvDESogQSnQQIoIidor7Iw/BkGgVBbGVrc0qPAwqnAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MH5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SWpFYno1WnBmbVJxOUI0TXBnNWQxOVhNclRjJTNECqkBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83MjY5MTA3NDg3OTg1ODYwNjQwfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1yVFlybXNoeElXdzVOWGh4Smk3JTJGSm5FbjF2OCUzRBI3MTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MLoBAIICAKgCAbICCWFsZWtzODQ1OfICTE1TNHdMakFCQUFBQUQ0WVIwS1MxRVhfNlU3Z1k0aGoyVzlaMTItVUhtYXZ4a2lQR2ItV0lIYzFzbnZyYnd5V2lvSXY3NVg1VzRlVEqiQBM3MjY5MTA2OTU4MzA4MTY0NjQwGAEYATgD",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:08:53.950839200"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJaq0vC6l6llGKGW59iz55WpZSD/p/rNvDEYATgK",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:33:08.727200600"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoZaTwq67l6llGKGW59iz55WpZSCzw/rNvDEYATgL",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:33:11.956418700"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJaYnoa8l6llGKGW59iz55WpZSDG7/rNvDEYAjgM",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:33:17.383803400"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoZanrPO9l6llGKGW59iz55WpZSCU5PvNvDEYATgM",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:33:32.712808600"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJah8LnJl6llGKGW59iz55WpZSCks4HOvDES0QQSzAQIhoiJ4Nqz7rtjGglkb21pbmlrNTRKtQMKtQFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWdpc28vZGQzNjI3ZTVlYTRmMTIzYzk5YjgwMDczZmQyM2JhYmF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTQzTmhEU3h4cExKVlNPYmpWOWNUakVQJTJCR25vJTNECrUBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1naXNvL2RkMzYyN2U1ZWE0ZjEyM2M5OWI4MDA3M2ZkMjNiYWJhfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1XZkxXRm5ha0EzWjc0a3hIa1N3Zm9IRmVTJTJGSSUzRBJDMTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZ2lzby9kZDM2MjdlNWVhNGYxMjNjOTliODAwNzNmZDIzYmFiYboBAIICAKgCAbICDmRvbWluaWt3YXNpbHVr8gJMTVM0d0xqQUJBQUFBaVpaMlpDQl94TjZlYUJwc0wyLU9xMy1yRTdmajV5ZkRWTnotZmZUUmUyWnlLd3dMdlh2ajF2all5RnJ6WXBzN6JAEzcxNjc0MDE0MTg4MzAyNjczOTgYARgCOA0=",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:35:05.042649"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJa7+vLPl6llGKGW59iz55WpZSDEyITOvDES2gQS1QQIhoirsOTthPleGhBCcmFqYW4gb2tvbmVyIFhESroDCrgBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC85NWYwNzg0ZDljMGQ0ZGY1ZTI2YzRmNWNjNzU3YmVjNn5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9em1nSEN4OXVSZXNYQ1hWaDZoZEJQJTJGMCUyRldMQSUzRAq2AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvOTVmMDc4NGQ5YzBkNGRmNWUyNmM0ZjVjYzc1N2JlYzZ+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPVJWQjNYM0N3Y1VDMkFJejIlMkZ3cFVqRDBhbjVNJTNEEkQxMDB4MTAwL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC85NWYwNzg0ZDljMGQ0ZGY1ZTI2YzRmNWNjNzU3YmVjNroBAIICAKgCAbICC2FudGVrMTI0NTcx8gJMTVM0d0xqQUJBQUFBM3M2akdBak5wbzFFdTdnWnV0Y3FPZWhIMkFzdGdYOWQwcFBJWHFYSG9KTnRDX29BcTJ5ZXNsb2tVVEpaazBUSKJAEzY4NDE1NTIxNDgyNzE2NDU3MDIYARgCOA4=",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:35:56.425306600"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoZbtiITbl6llGKGW59iz55WpZSDw/4nOvDEYATgO",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:37:25.577177500"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJaKs9fsl6llGKGW59iz55WpZSCa0ZLOvDESxgQSwQQIgICw8vjIy/wDGgTwn6ugSrgDCrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC8yMzYwZjk3ODViYWI3ZjFlMjBhYTMwYjZlMzA4M2E3Nn5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9RnFGTERxVWE0V0dLYUklMkJYc0Q3RklWQ3dsYkUlM0QKtgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzIzNjBmOTc4NWJhYjdmMWUyMGFhMzBiNmUzMDgzYTc2fmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1idEFla3VPR1NmJTJCZ282RFFwU05GNDNFM3lnUSUzRBJEMTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvMjM2MGY5Nzg1YmFiN2YxZTIwYWEzMGI2ZTMwODNhNza6AQCCAgCoAgGyAgYxanVsYWfyAkxNUzR3TGpBQkFBQUFydEh0azg5SV9HWTktUlZQc3E3VmtDV2s3SDJ4WmJLUVpoWmEwY2o0a3RxWE5uVHhhQm0zNENwV1FvWWxwT251okASMjg2MzEwOTM2MTc5NjM4MjcyGAEYATgO",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:39:46.883152900"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoZbI6NLtl6llGKGW59iz55WpZSCqipPOvDEYATgP",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:39:54.132292500"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJaukoXzl6llGKGW59iz55WpZSDt25XOvDESxQQSwAQIhoimzuOSnqdiGgNPTE9KtgMKtAFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2Q5MTFhNjkxNDk3ZmUzM2M5MmQwOTUxNGVlOTBhYjkwfmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1SYlZHdjVReHdwWW4zUDE2VW5lMlRJTG9wOTAlM0QKtgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2Q5MTFhNjkxNDk3ZmUzM2M5MmQwOTUxNGVlOTBhYjkwfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1uN3FjRm1HYUsyTyUyQnFsNXBiNmF5VDc4eG4ybyUzRBJEMTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvZDkxMWE2OTE0OTdmZTMzYzkyZDA5NTE0ZWU5MGFiOTC6AQCCAgCoAgGyAgdvbG9fdjEy8gJMTVM0d0xqQUJBQUFBalFUeHpRcEZXS0RNaHdDQ3QtWWpIQ1dIM3gxRlI4UW82bm4yVkNyRjFKZlVacTFEcnZNclF4Y0VRUF9lWnAzRaJAEzcwODM3MzE4NTA1MTAzMDQyNjIYARgCOBA=",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:40:37.563873900"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoZaS0rvzl6llGKGW59iz55WpZSC89pXOvDEYATgQ",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:40:40.781947100"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJaSot/9l6llGKGW59iz55WpZSCe+JrOvDESzwUSygUIhoDrtqn685FcGgNlbG9KvQQKpgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC82OTJiODk3YmEzYzUwNTNiMzEyNWFmZTMxY2E5YTRkYn5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9akdJc1VBbGxESmNmbWkwaHVzME9PNHVhT0xRJTNECqYBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvNjkyYjg5N2JhM2M1MDUzYjMxMjVhZmUzMWNhOWE0ZGJ+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUdsMTh0V0tCeXA1NUVBNU1oQ1Nhd0pIaVF3dyUzRAqqAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzY5MmI4OTdiYTNjNTA1M2IzMTI1YWZlMzFjYTlhNGRifmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1JWUo1ZVVabEJnN0MlMkZEVk1pbkttbCUyRno0MDFJJTNEEjwxMDB4MTAwL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvNjkyYjg5N2JhM2M1MDUzYjMxMjVhZmUzMWNhOWE0ZGK6AQCCAgCoAgGyAgpyYW5kb21tZW1q8gJMTVM0d0xqQUJBQUFBWlZsSldueTFLQ0l6T1c2bW4xcmZBOG0yNHhLd2VKRXlHS2g4SDFVclFnZ2hoTm1zaXZxTTV4Y21nSm14ZEFuY6JAEzY2MzkzNzg3NzkwNTUyNDMyNzAYARgCOBE=",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:42:03.040632200"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJbMro3+l6llGKGW59iz55WpZSCskJvOvDEYATgR",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:42:06.280761800"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoZbzooKEmKllGKGW59iz55WpZSD0/p3OvDES1QQS0AQIhoiD8tXni7lfGgZUb21zb25KuAMKtgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2IwYWI2N2Q4OGFhN2JhMDBmY2RlZGU5YjNlNmQxNWE0fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1hREYlMkJrb2tQQ0dKRjV5cDVTTnJCNVA3MjlJOCUzRAq2AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvYjBhYjY3ZDg4YWE3YmEwMGZjZGVkZTliM2U2ZDE1YTR+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTYxZ0Y3VFFVSUpqWDYlMkJ6aHRJcVpjOUdRUXlBJTNEEkQxMDB4MTAwL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9iMGFiNjdkODhhYTdiYTAwZmNkZWRlOWIzZTZkMTVhNLoBAIICAKgCAbICEnVzZXIxNzA4ODEwNzM0MDUwMvICTE1TNHdMakFCQUFBQXY4T1B0OWlNaFkzSWFFTlJoZThjOXE2RkdDOFg5cDJMbmhmSnZWSm5HOWlWelZ6VnhtUnlDUi1wZFNOaFFVV1aiQBM2ODc3NjExNTIxNTY4OTgyMDIyGAEYAjgS",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:42:52.821875300"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJbr0sSEmKllGKGW59iz55WpZSDwn57OvDEYATgS",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:42:57.643174900"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJaQheGVmKllGKGW59iz55WpZSDv1abOvDESyQQSxAQImoji2K2D5aVkGgEuSrYDCrQBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kY2IzZjYyYTg4NzFlZWY2OWViZTdjZDFiZGQ1YzM1OX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9cDdqVExCMFNvUEhJeWxta3dRMVE0eXBsOTZZJTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kY2IzZjYyYTg4NzFlZWY2OWViZTdjZDFiZGQ1YzM1OX5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9RHIlMkZmRVYzMm5jdnB5dXFoRTJxcVZ5WUpQTE0lM0QSRDEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2RjYjNmNjJhODg3MWVlZjY5ZWJlN2NkMWJkZDVjMzU5ugEAggIAqAIBsgINbGl0dGxlX2JveTAyMvICTE1TNHdMakFCQUFBQXc1TWtxMWxMazNvQ2ZidGVobnk0SlY1UkJfR3k5V3pYT3RaVmRrcVhXZXVoUzNRcjZycXBSdEtkazE5am1pcnOiQBM3MjI3MDMyODcwMTExOTcwMzMwGAEYATgS",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:45:15.031268700"
},
{
"eventData": "CjYKGVdlYmNhc3RSb29tVXNlclNlcU1lc3NhZ2UQoJauqP6VmKllGKGW59iz55WpZSDe5KbOvDEYATgT",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:45:17.450676400"
}
],
"WebcastMemberMessage": [
{
"eventData": "CtgGChRXZWJjYXN0TWVtYmVyTWVzc2FnZRChlrumyf6VqWUYoZbn2LPnlallILC4ns28MTABQpUGChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMi2gUICxIMCgcjOENFN0ZGIJADqgHGBQrDBQigiJ2ivsjD8GQaBUFsZWtzSscECrUBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83MjY5MTA3NDg3OTg1ODYwNjQwfnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUdnVUhmTHhYeVpLTkNwa2IwTkt4aERPQU5RMCUzRAqnAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MH5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SWpFYno1WnBmbVJxOUI0TXBnNWQxOVhNclRjJTNECqkBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83MjY5MTA3NDg3OTg1ODYwNjQwfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1yVFlybXNoeElXdzVOWGh4Smk3JTJGSm5FbjF2OCUzRBI3MTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MLIBBAgaEAO6AQCCAgCyAglhbGVrczg0NTnyAkxNUzR3TGpBQkFBQUFENFlSMEtTMUVYXzZVN2dZNGhqMlc5WjEyLVVIbWF2eGtpUEdiLVdJSGMxc252cmJ3eVdpb0l2NzVYNVc0ZVRKSAFQAbABArgBAcABARLDBQigiJ2ivsjD8GQaBUFsZWtzSscECrUBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83MjY5MTA3NDg3OTg1ODYwNjQwfnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUdnVUhmTHhYeVpLTkNwa2IwTkt4aERPQU5RMCUzRAqnAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MH5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SWpFYno1WnBmbVJxOUI0TXBnNWQxOVhNclRjJTNECqkBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83MjY5MTA3NDg3OTg1ODYwNjQwfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1yVFlybXNoeElXdzVOWGh4Smk3JTJGSm5FbjF2OCUzRBI3MTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI2OTEwNzQ4Nzk4NTg2MDY0MLIBBAgaEAO6AQCCAgCyAglhbGVrczg0NTnyAkxNUzR3TGpBQkFBQUFENFlSMEtTMUVYXzZVN2dZNGhqMlc5WjEyLVVIbWF2eGtpUEdiLVdJSGMxc252cmJ3eVdpb0l2NzVYNVc0ZVRKGAFQAZIBlQYKFWxpdmVfcm9vbV9lbnRlcl90b2FzdBIPezA6dXNlcn0gam9pbmVkGg4KCSNiOGZmZmZmZiCQAyLaBQgLEgwKByM4Q0U3RkYgkAOqAcYFCsMFCKCInaK+yMPwZBoFQWxla3NKxwQKtQFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzcyNjkxMDc0ODc5ODU4NjA2NDB+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9R2dVSGZMeFh5WktOQ3BrYjBOS3hoRE9BTlEwJTNECqcBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83MjY5MTA3NDg3OTg1ODYwNjQwfmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1JakViejVacGZtUnE5QjRNcGc1ZDE5WE1yVGMlM0QKqQFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzcyNjkxMDc0ODc5ODU4NjA2NDB+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPXJUWXJtc2h4SVd3NU5YaHhKaTclMkZKbkVuMXY4JTNEEjcxMDB4MTAwL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83MjY5MTA3NDg3OTg1ODYwNjQwsgEECBoQA7oBAIICALICCWFsZWtzODQ1OfICTE1TNHdMakFCQUFBQUQ0WVIwS1MxRVhfNlU3Z1k0aGoyVzlaMTItVUhtYXZ4a2lQR2ItV0lIYzFzbnZyYnd5V2lvSXY3NVg1VzRlVEqaARZob21lcGFnZV9ob3QtbGl2ZV9jZWxs",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:08:03.396935200"
},
{
"eventData": "CsoHChRXZWJjYXN0TWVtYmVyTWVzc2FnZRChlsfK8v+VqWUYoZbn2LPnlallIJ+Ln828MTABQocHChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMizAYICxIMCgcjOENFN0ZGIJADqgG4Bgq1BgiGiI7yqpuO4GIaC21hbml0b3UxMjIxSq8FCqkBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTR+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SUQlMkJvMVJHJTJCdkpPbENQWGNjUHQ1RkZCUUs1cyUzRAqZAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YWCUyQnZlV3p1b1gyT01LbUpQRmNpSjV1T0NWYyUzRAqbAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1CUDJDUnd4JTJGM3VUJTJGVHlpUkRycTIzakY1c09zJTNECpcBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTR+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPU14ekJvbWpDRWM0RGJNeVdud3N1dWtjYXFFayUzRBItMTAweDEwMC9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0sgEGCAcQChgBugEAggIAsgILbWFuaXRvdTEyMjHyAkxNUzR3TGpBQkFBQUFDUlhtN2d5WHpqdnJOVzhiQVgwMWRIYjRQQ0JmcHBoUUJsTFlsN3QzaVYzNjN6Qi1mOXY2djZJMVByX2UtSjNxSAFQAbABArgBAcABARK1BgiGiI7yqpuO4GIaC21hbml0b3UxMjIxSq8FCqkBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTR+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SUQlMkJvMVJHJTJCdkpPbENQWGNjUHQ1RkZCUUs1cyUzRAqZAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YWCUyQnZlV3p1b1gyT01LbUpQRmNpSjV1T0NWYyUzRAqbAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1CUDJDUnd4JTJGM3VUJTJGVHlpUkRycTIzakY1c09zJTNECpcBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTR+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPU14ekJvbWpDRWM0RGJNeVdud3N1dWtjYXFFayUzRBItMTAweDEwMC9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0sgEGCAcQChgBugEAggIAsgILbWFuaXRvdTEyMjHyAkxNUzR3TGpBQkFBQUFDUlhtN2d5WHpqdnJOVzhiQVgwMWRIYjRQQ0JmcHBoUUJsTFlsN3QzaVYzNjN6Qi1mOXY2djZJMVByX2UtSjNxGAJQAZIBhwcKFWxpdmVfcm9vbV9lbnRlcl90b2FzdBIPezA6dXNlcn0gam9pbmVkGg4KCSNiOGZmZmZmZiCQAyLMBggLEgwKByM4Q0U3RkYgkAOqAbgGCrUGCIaIjvKqm47gYhoLbWFuaXRvdTEyMjFKrwUKqQFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vbXVzaWNhbGx5LW1hbGl2YS1vYmovMTU5NDgwNTI1ODIxNjQ1NH50cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1JRCUyQm8xUkclMkJ2Sk9sQ1BYY2NQdDVGRkJRSzVzJTNECpkBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTR+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPVhYJTJCdmVXenVvWDJPTUttSlBGY2lKNXVPQ1ZjJTNECpsBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTR+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUJQMkNSd3glMkYzdVQlMkZUeWlSRHJxMjNqRjVzT3MlM0QKlwFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vbXVzaWNhbGx5LW1hbGl2YS1vYmovMTU5NDgwNTI1ODIxNjQ1NH5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9TXh6Qm9takNFYzREYk15V253c3V1a2NhcUVrJTNEEi0xMDB4MTAwL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTSyAQYIBxAKGAG6AQCCAgCyAgttYW5pdG91MTIyMfICTE1TNHdMakFCQUFBQUNSWG03Z3lYemp2ck5XOGJBWDAxZEhiNFBDQmZwcGhRQmxMWWw3dDNpVjM2M3pCLWY5djZ2NkkxUHJfZS1KM3GaAQlwdXNoLXB1c2iiAQVjbGljaw==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:08:13.651263600"
},
{
"eventData": "CpwIChRXZWJjYXN0TWVtYmVyTWVzc2FnZRCglsOaiYSWqWUYoZbn2LPnlallIOuPoc28MTABQtkHChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMingcICxIMCgcjOENFN0ZGIJADqgGKBwqHBwiGiKyWl8PO8mIaBnBvbGFuZEqEBgq6AWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzJlODYzYTY5NTUwMjY1OGM5NTc3M2MxNWZmYjU5MGJjfnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTRNQ2hwNlBQRlUlMkIwJTJCNHhQUzBtJTJGY2hLU2ZCVSUzRAqsAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzJlODYzYTY5NTUwMjY1OGM5NTc3M2MxNWZmYjU5MGJjfmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1IWVFuJTJCMUV4Zkw1QmglMkIyU0hQbUM4TEolMkZoZnclM0QKrAFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC8yZTg2M2E2OTU1MDI2NThjOTU3NzNjMTVmZmI1OTBiY35jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9M01rSllpVE5iVVFyR2dOZSUyRiUyQnZhJTJGZ1FQN3ZJJTNECqgBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvMmU4NjNhNjk1NTAyNjU4Yzk1NzczYzE1ZmZiNTkwYmN+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPVJuemRyWkQlMkJCZVVUenpUellWSGRoSURsb3lZJTNEEjwxMDB4MTAwL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvMmU4NjNhNjk1NTAyNjU4Yzk1NzczYzE1ZmZiNTkwYmOyAQcI8QwQDxgBugEAggIAsgIMYW50b25pa3Vyenlu8gJMTVM0d0xqQUJBQUFBd3lVV0FUT2RHNC1QdUYtenhhbFdoLUZzVE1YVzVScGpINzJJLUhtUjVYbzQ2OWVSTm15WFp5SDhLS2FvR1FVRkgBUAKwAQG4AQHAAQEShwcIhoislpfDzvJiGgZwb2xhbmRKhAYKugFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC8yZTg2M2E2OTU1MDI2NThjOTU3NzNjMTVmZmI1OTBiY350cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT00TUNocDZQUEZVJTJCMCUyQjR4UFMwbSUyRmNoS1NmQlUlM0QKrAFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC8yZTg2M2E2OTU1MDI2NThjOTU3NzNjMTVmZmI1OTBiY35jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SFlRbiUyQjFFeGZMNUJoJTJCMlNIUG1DOExKJTJGaGZ3JTNECqwBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvMmU4NjNhNjk1NTAyNjU4Yzk1NzczYzE1ZmZiNTkwYmN+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTNNa0pZaVROYlVRckdnTmUlMkYlMkJ2YSUyRmdRUDd2SSUzRAqoAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzJlODYzYTY5NTUwMjY1OGM5NTc3M2MxNWZmYjU5MGJjfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1SbnpkclpEJTJCQmVVVHp6VHpZVkhkaElEbG95WSUzRBI8MTAweDEwMC90b3MtbWFsaXZhLWF2dC0wMDY4LzJlODYzYTY5NTUwMjY1OGM5NTc3M2MxNWZmYjU5MGJjsgEHCPEMEA8YAboBAIICALICDGFudG9uaWt1cnp5bvICTE1TNHdMakFCQUFBQXd5VVdBVE9kRzQtUHVGLXp4YWxXaC1Gc1RNWFc1UnBqSDcySS1IbVI1WG80NjllUk5teVhaeUg4S0thb0dRVUYYAlABkgHZBwoVbGl2ZV9yb29tX2VudGVyX3RvYXN0Eg97MDp1c2VyfSBqb2luZWQaDgoJI2I4ZmZmZmZmIJADIp4HCAsSDAoHIzhDRTdGRiCQA6oBigcKhwcIhoislpfDzvJiGgZwb2xhbmRKhAYKugFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC8yZTg2M2E2OTU1MDI2NThjOTU3NzNjMTVmZmI1OTBiY350cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT00TUNocDZQUEZVJTJCMCUyQjR4UFMwbSUyRmNoS1NmQlUlM0QKrAFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC8yZTg2M2E2OTU1MDI2NThjOTU3NzNjMTVmZmI1OTBiY35jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SFlRbiUyQjFFeGZMNUJoJTJCMlNIUG1DOExKJTJGaGZ3JTNECqwBaHR0cHM6Ly9wMTYtc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvMmU4NjNhNjk1NTAyNjU4Yzk1NzczYzE1ZmZiNTkwYmN+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTNNa0pZaVROYlVRckdnTmUlMkYlMkJ2YSUyRmdRUDd2SSUzRAqoAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzJlODYzYTY5NTUwMjY1OGM5NTc3M2MxNWZmYjU5MGJjfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1SbnpkclpEJTJCQmVVVHp6VHpZVkhkaElEbG95WSUzRBI8MTAweDEwMC90b3MtbWFsaXZhLWF2dC0wMDY4LzJlODYzYTY5NTUwMjY1OGM5NTc3M2MxNWZmYjU5MGJjsgEHCPEMEA8YAboBAIICALICDGFudG9uaWt1cnp5bvICTE1TNHdMakFCQUFBQXd5VVdBVE9kRzQtUHVGLXp4YWxXaC1Gc1RNWFc1UnBqSDcySS1IbVI1WG80NjllUk5teVhaeUg4S0thb0dRVUaaARVpbm5lcl9wdXNoLWlubmVyX3B1c2iiAQVjbGljaw==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:08:47.493168800"
},
{
"eventData": "CuIGChRXZWJjYXN0TWVtYmVyTWVzc2FnZRCglqbQ8LqXqWUYoZbn2LPnlallIM6r+s28MTABQp8GChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMi5AUICxIMCgcjOENFN0ZGIJADqgHQBQrNBQiFiJeU282M42EaCUxlbnVzaWExMUrLBAq3AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI5OTM0NjUxNDEwNTU5Nzk4NX50cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1jYW5ZZTNZU3h1em9GNXVHbHJUV25lU3clMkJMRSUzRAqnAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI5OTM0NjUxNDEwNTU5Nzk4NX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9UlBzcEVkREtVMmFWTVlDWlRpSVR2QkRpSlprJTNECqsBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83Mjk5MzQ2NTE0MTA1NTk3OTg1fmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1KeGw4Y29DcHhlSXZja3o3MWFSbHl0eHAlMkYlMkY4JTNEEjcxMDB4MTAwL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC83Mjk5MzQ2NTE0MTA1NTk3OTg1sgEECAsQA7oBAIICALICC2p1c3R5bmFzeXN68gJMTVM0d0xqQUJBQUFBcXJWQkViS1RTWXVFZmVJeE5PSGx6WjhYLXVseDNIYVJYZnJZbmFtYl85Y1pOdW44R295ZWJFSXI4c2phRnE0dEgBUAKwAQG4AQHAAQESzQUIhYiXlNvNjONhGglMZW51c2lhMTFKywQKtwFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzcyOTkzNDY1MTQxMDU1OTc5ODV+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9Y2FuWWUzWVN4dXpvRjV1R2xyVFduZVN3JTJCTEUlM0QKpwFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzcyOTkzNDY1MTQxMDU1OTc5ODV+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPVJQc3BFZERLVTJhVk1ZQ1pUaUlUdkJEaUpaayUzRAqrAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI5OTM0NjUxNDEwNTU5Nzk4NX5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SnhsOGNvQ3B4ZUl2Y2t6NzFhUmx5dHhwJTJGJTJGOCUzRBI3MTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI5OTM0NjUxNDEwNTU5Nzk4NbIBBAgLEAO6AQCCAgCyAgtqdXN0eW5hc3lzevICTE1TNHdMakFCQUFBQXFyVkJFYktUU1l1RWZlSXhOT0hselo4WC11bHgzSGFSWGZyWW5hbWJfOWNaTnVuOEdveWViRUlyOHNqYUZxNHQYAlABkgGfBgoVbGl2ZV9yb29tX2VudGVyX3RvYXN0Eg97MDp1c2VyfSBqb2luZWQaDgoJI2I4ZmZmZmZmIJADIuQFCAsSDAoHIzhDRTdGRiCQA6oB0AUKzQUIhYiXlNvNjONhGglMZW51c2lhMTFKywQKtwFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzcyOTkzNDY1MTQxMDU1OTc5ODV+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9Y2FuWWUzWVN4dXpvRjV1R2xyVFduZVN3JTJCTEUlM0QKpwFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzcyOTkzNDY1MTQxMDU1OTc5ODV+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPVJQc3BFZERLVTJhVk1ZQ1pUaUlUdkJEaUpaayUzRAqrAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI5OTM0NjUxNDEwNTU5Nzk4NX5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SnhsOGNvQ3B4ZUl2Y2t6NzFhUmx5dHhwJTJGJTJGOCUzRBI3MTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvNzI5OTM0NjUxNDEwNTU5Nzk4NbIBBAgLEAO6AQCCAgCyAgtqdXN0eW5hc3lzevICTE1TNHdMakFCQUFBQXFyVkJFYktUU1l1RWZlSXhOT0hselo4WC11bHgzSGFSWGZyWW5hbWJfOWNaTnVuOEdveWViRUlyOHNqYUZxNHSaARNsaXZlX2VuZC1saXZlX2NvdmVyogEFY2xpY2s=",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:33:09.521317400"
},
{
"eventData": "CukHChRXZWJjYXN0TWVtYmVyTWVzc2FnZRChlsyE97uXqWUYoZbn2LPnlallIK3z+s28MTABQqYHChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMi6wYICxIMCgcjOENFN0ZGIJADqgHXBgrUBgiGiMS6yfvm6l0aJ/CfpKbigI3imYLvuI/wn6Sm4oCN4pmC77iP8J+kpuKAjeKZgu+4j0qvBQqpAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0fnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUlEJTJCbzFSRyUyQnZKT2xDUFhjY1B0NUZGQlFLNXMlM0QKmwFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vbXVzaWNhbGx5LW1hbGl2YS1vYmovMTU5NDgwNTI1ODIxNjQ1NH5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9QlAyQ1J3eCUyRjN1VCUyRlR5aVJEcnEyM2pGNXNPcyUzRAqZAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1YWCUyQnZlV3p1b1gyT01LbUpQRmNpSjV1T0NWYyUzRAqXAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS9tdXNpY2FsbHktbWFsaXZhLW9iai8xNTk0ODA1MjU4MjE2NDU0fmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1HbGh4d3A3WjY0b2VLU1ZpcEFzbTk5ZU1RajAlM0QSLTEwMHgxMDAvbXVzaWNhbGx5LW1hbGl2YS1vYmovMTU5NDgwNTI1ODIxNjQ1NLIBBQiLARBjugEAggIAsgIPc2lrZS55b3UudG91Z2h08gJMTVM0d0xqQUJBQUFBTWhrZ1JtcWxNNlhQeW1LSEZHOEU0OVVUMXFEV2RzVUxRdG45bHh2VjhDS1ZhczZKaHhWeHhDOGdIaU4xWm10aEgBUAKwAQG4AQHAAQES1AYIhojEusn75updGifwn6Sm4oCN4pmC77iP8J+kpuKAjeKZgu+4j/CfpKbigI3imYLvuI9KrwUKqQFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vbXVzaWNhbGx5LW1hbGl2YS1vYmovMTU5NDgwNTI1ODIxNjQ1NH50cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1JRCUyQm8xUkclMkJ2Sk9sQ1BYY2NQdDVGRkJRSzVzJTNECpsBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTR+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUJQMkNSd3glMkYzdVQlMkZUeWlSRHJxMjNqRjVzT3MlM0QKmQFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vbXVzaWNhbGx5LW1hbGl2YS1vYmovMTU5NDgwNTI1ODIxNjQ1NH5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9WFglMkJ2ZVd6dW9YMk9NS21KUEZjaUo1dU9DVmMlM0QKlwFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vbXVzaWNhbGx5LW1hbGl2YS1vYmovMTU5NDgwNTI1ODIxNjQ1NH5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9R2xoeHdwN1o2NG9lS1NWaXBBc205OWVNUWowJTNEEi0xMDB4MTAwL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTSyAQUIiwEQY7oBAIICALICD3Npa2UueW91LnRvdWdodPICTE1TNHdMakFCQUFBQU1oa2dSbXFsTTZYUHltS0hGRzhFNDlVVDFxRFdkc1VMUXRuOWx4dlY4Q0tWYXM2Smh4Vnh4QzhnSGlOMVptdGgYAlABkgGmBwoVbGl2ZV9yb29tX2VudGVyX3RvYXN0Eg97MDp1c2VyfSBqb2luZWQaDgoJI2I4ZmZmZmZmIJADIusGCAsSDAoHIzhDRTdGRiCQA6oB1wYK1AYIhojEusn75updGifwn6Sm4oCN4pmC77iP8J+kpuKAjeKZgu+4j/CfpKbigI3imYLvuI9KrwUKqQFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vbXVzaWNhbGx5LW1hbGl2YS1vYmovMTU5NDgwNTI1ODIxNjQ1NH50cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1JRCUyQm8xUkclMkJ2Sk9sQ1BYY2NQdDVGRkJRSzVzJTNECpsBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTR+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUJQMkNSd3glMkYzdVQlMkZUeWlSRHJxMjNqRjVzT3MlM0QKmQFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vbXVzaWNhbGx5LW1hbGl2YS1vYmovMTU5NDgwNTI1ODIxNjQ1NH5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9WFglMkJ2ZVd6dW9YMk9NS21KUEZjaUo1dU9DVmMlM0QKlwFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vbXVzaWNhbGx5LW1hbGl2YS1vYmovMTU5NDgwNTI1ODIxNjQ1NH5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9R2xoeHdwN1o2NG9lS1NWaXBBc205OWVNUWowJTNEEi0xMDB4MTAwL211c2ljYWxseS1tYWxpdmEtb2JqLzE1OTQ4MDUyNTgyMTY0NTSyAQUIiwEQY7oBAIICALICD3Npa2UueW91LnRvdWdodPICTE1TNHdMakFCQUFBQU1oa2dSbXFsTTZYUHltS0hGRzhFNDlVVDFxRFdkc1VMUXRuOWx4dlY4Q0tWYXM2Smh4Vnh4QzhnSGlOMVptdGiaARVsaXZlX21lcmdlLWxpdmVfY292ZXKiAQRkcmF3",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:33:18.203136100"
},
{
"eventData": "CpkHChRXZWJjYXN0TWVtYmVyTWVzc2FnZRChltn8pMmXqWUYoZbn2LPnlallIIK0gc68MTABQtYGChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMimwYICxIMCgcjOENFN0ZGIJADqgGHBgqEBgiGiIng2rPuu2MaCWRvbWluaWs1NEr9BArFAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZ2lzby9kZDM2MjdlNWVhNGYxMjNjOTliODAwNzNmZDIzYmFiYX50cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1hJTJCdmp3VWc1JTJCRkg4NGpwT1dFMDFIb3FMVGdZJTNECrUBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1naXNvL2RkMzYyN2U1ZWE0ZjEyM2M5OWI4MDA3M2ZkMjNiYWJhfmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT00M05oRFN4eHBMSlZTT2JqVjljVGpFUCUyQkdubyUzRAq1AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZ2lzby9kZDM2MjdlNWVhNGYxMjNjOTliODAwNzNmZDIzYmFiYX5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9V2ZMV0ZuYWtBM1o3NGt4SGtTd2ZvSEZlUyUyRkklM0QSQzEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWdpc28vZGQzNjI3ZTVlYTRmMTIzYzk5YjgwMDczZmQyM2JhYmGyAQYIZRA7GAG6AQCCAgCyAg5kb21pbmlrd2FzaWx1a/ICTE1TNHdMakFCQUFBQWlaWjJaQ0JfeE42ZWFCcHNMMi1PcTMtckU3Zmo1eWZEVk56LWZmVFJlMlp5S3d3THZYdmoxdmpZeUZyellwczdIAVACsAEBuAEBwAEBEoQGCIaIieDas+67YxoJZG9taW5pazU0Sv0ECsUBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1naXNvL2RkMzYyN2U1ZWE0ZjEyM2M5OWI4MDA3M2ZkMjNiYWJhfnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPWElMkJ2andVZzUlMkJGSDg0anBPV0UwMUhvcUxUZ1klM0QKtQFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWdpc28vZGQzNjI3ZTVlYTRmMTIzYzk5YjgwMDczZmQyM2JhYmF+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTQzTmhEU3h4cExKVlNPYmpWOWNUakVQJTJCR25vJTNECrUBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1naXNvL2RkMzYyN2U1ZWE0ZjEyM2M5OWI4MDA3M2ZkMjNiYWJhfmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1XZkxXRm5ha0EzWjc0a3hIa1N3Zm9IRmVTJTJGSSUzRBJDMTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZ2lzby9kZDM2MjdlNWVhNGYxMjNjOTliODAwNzNmZDIzYmFiYbIBBghlEDsYAboBAIICALICDmRvbWluaWt3YXNpbHVr8gJMTVM0d0xqQUJBQUFBaVpaMlpDQl94TjZlYUJwc0wyLU9xMy1yRTdmajV5ZkRWTnotZmZUUmUyWnlLd3dMdlh2ajF2all5RnJ6WXBzNxgCUAGSAdYGChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMimwYICxIMCgcjOENFN0ZGIJADqgGHBgqEBgiGiIng2rPuu2MaCWRvbWluaWs1NEr9BArFAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZ2lzby9kZDM2MjdlNWVhNGYxMjNjOTliODAwNzNmZDIzYmFiYX50cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1hJTJCdmp3VWc1JTJCRkg4NGpwT1dFMDFIb3FMVGdZJTNECrUBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1naXNvL2RkMzYyN2U1ZWE0ZjEyM2M5OWI4MDA3M2ZkMjNiYWJhfmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT00M05oRFN4eHBMSlZTT2JqVjljVGpFUCUyQkdubyUzRAq1AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZ2lzby9kZDM2MjdlNWVhNGYxMjNjOTliODAwNzNmZDIzYmFiYX5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9V2ZMV0ZuYWtBM1o3NGt4SGtTd2ZvSEZlUyUyRkklM0QSQzEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWdpc28vZGQzNjI3ZTVlYTRmMTIzYzk5YjgwMDczZmQyM2JhYmGyAQYIZRA7GAG6AQCCAgCyAg5kb21pbmlrd2FzaWx1a/ICTE1TNHdMakFCQUFBQWlaWjJaQ0JfeE42ZWFCcHNMMi1PcTMtckU3Zmo1eWZEVk56LWZmVFJlMlp5S3d3THZYdmoxdmpZeUZyellwczeaARZob21lcGFnZV9ob3QtbGl2ZV9jZWxs",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:35:05.044148700"
},
{
"eventData": "CqIHChRXZWJjYXN0TWVtYmVyTWVzc2FnZRChlpaS8c+XqWUYoZbn2LPnlallIKrMhM68MTABQt8GChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMipAYICxIMCgcjOENFN0ZGIJADqgGQBgqNBgiGiKuw5O2E+V4aEEJyYWphbiBva29uZXIgWERKgwUKxgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzk1ZjA3ODRkOWMwZDRkZjVlMjZjNGY1Y2M3NTdiZWM2fnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTNseVhFJTJGNWtVa0Npdlhab1YlMkZlS2lSeXliVGMlM0QKuAFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzk1ZjA3ODRkOWMwZDRkZjVlMjZjNGY1Y2M3NTdiZWM2fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT16bWdIQ3g5dVJlc1hDWFZoNmhkQlAlMkYwJTJGV0xBJTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC85NWYwNzg0ZDljMGQ0ZGY1ZTI2YzRmNWNjNzU3YmVjNn5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9UlZCM1gzQ3djVUMyQUl6MiUyRndwVWpEMGFuNU0lM0QSRDEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzk1ZjA3ODRkOWMwZDRkZjVlMjZjNGY1Y2M3NTdiZWM2sgEFCKkBEEe6AQCCAgCyAgthbnRlazEyNDU3MfICTE1TNHdMakFCQUFBQTNzNmpHQWpOcG8xRXU3Z1p1dGNxT2VoSDJBc3RnWDlkMHBQSVhxWEhvSk50Q19vQXEyeWVzbG9rVVRKWmswVEhIAVACsAEBuAEBwAEBEo0GCIaIq7Dk7YT5XhoQQnJhamFuIG9rb25lciBYREqDBQrGAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvOTVmMDc4NGQ5YzBkNGRmNWUyNmM0ZjVjYzc1N2JlYzZ+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9M2x5WEUlMkY1a1VrQ2l2WFpvViUyRmVLaVJ5eWJUYyUzRAq4AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvOTVmMDc4NGQ5YzBkNGRmNWUyNmM0ZjVjYzc1N2JlYzZ+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPXptZ0hDeDl1UmVzWENYVmg2aGRCUCUyRjAlMkZXTEElM0QKtgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzk1ZjA3ODRkOWMwZDRkZjVlMjZjNGY1Y2M3NTdiZWM2fmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1SVkIzWDNDd2NVQzJBSXoyJTJGd3BVakQwYW41TSUzRBJEMTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvOTVmMDc4NGQ5YzBkNGRmNWUyNmM0ZjVjYzc1N2JlYzayAQUIqQEQR7oBAIICALICC2FudGVrMTI0NTcx8gJMTVM0d0xqQUJBQUFBM3M2akdBak5wbzFFdTdnWnV0Y3FPZWhIMkFzdGdYOWQwcFBJWHFYSG9KTnRDX29BcTJ5ZXNsb2tVVEpaazBUSBgCUAGSAd8GChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMipAYICxIMCgcjOENFN0ZGIJADqgGQBgqNBgiGiKuw5O2E+V4aEEJyYWphbiBva29uZXIgWERKgwUKxgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzk1ZjA3ODRkOWMwZDRkZjVlMjZjNGY1Y2M3NTdiZWM2fnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTNseVhFJTJGNWtVa0Npdlhab1YlMkZlS2lSeXliVGMlM0QKuAFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzk1ZjA3ODRkOWMwZDRkZjVlMjZjNGY1Y2M3NTdiZWM2fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT16bWdIQ3g5dVJlc1hDWFZoNmhkQlAlMkYwJTJGV0xBJTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC85NWYwNzg0ZDljMGQ0ZGY1ZTI2YzRmNWNjNzU3YmVjNn5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9UlZCM1gzQ3djVUMyQUl6MiUyRndwVWpEMGFuNU0lM0QSRDEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzk1ZjA3ODRkOWMwZDRkZjVlMjZjNGY1Y2M3NTdiZWM2sgEFCKkBEEe6AQCCAgCyAgthbnRlazEyNDU3MfICTE1TNHdMakFCQUFBQTNzNmpHQWpOcG8xRXU3Z1p1dGNxT2VoSDJBc3RnWDlkMHBQSVhxWEhvSk50Q19vQXEyeWVzbG9rVVRKWmswVEiaARdzZWFyY2hfcmVzdWx0LWxpdmVfY2VsbA==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:35:57.223255400"
},
{
"eventData": "CooHChRXZWJjYXN0TWVtYmVyTWVzc2FnZRCgls2G0+yXqWUYoZbn2LPnlallINXUks68MTABQscGChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMijAYICxIMCgcjOENFN0ZGIJADqgH4BQr1BQiAgLDy+MjL/AMaBPCfq6BK/QQKwgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzIzNjBmOTc4NWJhYjdmMWUyMGFhMzBiNmUzMDgzYTc2fnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPWJiSTlobVJlZzVsOE1zSkcwTzl3MDJIc2YyUSUzRAq2AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvMjM2MGY5Nzg1YmFiN2YxZTIwYWEzMGI2ZTMwODNhNzZ+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUZxRkxEcVVhNFdHS2FJJTJCWHNEN0ZJVkN3bGJFJTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC8yMzYwZjk3ODViYWI3ZjFlMjBhYTMwYjZlMzA4M2E3Nn5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9YnRBZWt1T0dTZiUyQmdvNkRRcFNORjQzRTN5Z1ElM0QSRDEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzIzNjBmOTc4NWJhYjdmMWUyMGFhMzBiNmUzMDgzYTc2sgEECDgQc7oBAIICALICBjFqdWxhZ/ICTE1TNHdMakFCQUFBQXJ0SHRrODlJX0dZOS1SVlBzcTdWa0NXazdIMnhaYktRWmhaYTBjajRrdHFYTm5UeGFCbTM0Q3BXUW9ZbHBPbnVIAVACsAEBuAEBwAEBEvUFCICAsPL4yMv8AxoE8J+roEr9BArCAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvMjM2MGY5Nzg1YmFiN2YxZTIwYWEzMGI2ZTMwODNhNzZ+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9YmJJOWhtUmVnNWw4TXNKRzBPOXcwMkhzZjJRJTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC8yMzYwZjk3ODViYWI3ZjFlMjBhYTMwYjZlMzA4M2E3Nn5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9RnFGTERxVWE0V0dLYUklMkJYc0Q3RklWQ3dsYkUlM0QKtgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzIzNjBmOTc4NWJhYjdmMWUyMGFhMzBiNmUzMDgzYTc2fmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1idEFla3VPR1NmJTJCZ282RFFwU05GNDNFM3lnUSUzRBJEMTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvMjM2MGY5Nzg1YmFiN2YxZTIwYWEzMGI2ZTMwODNhNzayAQQIOBBzugEAggIAsgIGMWp1bGFn8gJMTVM0d0xqQUJBQUFBcnRIdGs4OUlfR1k5LVJWUHNxN1ZrQ1drN0gyeFpiS1FaaFphMGNqNGt0cVhOblR4YUJtMzRDcFdRb1lscE9udRgCUAGSAccGChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMijAYICxIMCgcjOENFN0ZGIJADqgH4BQr1BQiAgLDy+MjL/AMaBPCfq6BK/QQKwgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzIzNjBmOTc4NWJhYjdmMWUyMGFhMzBiNmUzMDgzYTc2fnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPWJiSTlobVJlZzVsOE1zSkcwTzl3MDJIc2YyUSUzRAq2AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvMjM2MGY5Nzg1YmFiN2YxZTIwYWEzMGI2ZTMwODNhNzZ+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUZxRkxEcVVhNFdHS2FJJTJCWHNEN0ZJVkN3bGJFJTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC8yMzYwZjk3ODViYWI3ZjFlMjBhYTMwYjZlMzA4M2E3Nn5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9YnRBZWt1T0dTZiUyQmdvNkRRcFNORjQzRTN5Z1ElM0QSRDEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwLzIzNjBmOTc4NWJhYjdmMWUyMGFhMzBiNmUzMDgzYTc2sgEECDgQc7oBAIICALICBjFqdWxhZ/ICTE1TNHdMakFCQUFBQXJ0SHRrODlJX0dZOS1SVlBzcTdWa0NXazdIMnhaYktRWmhaYTBjajRrdHFYTm5UeGFCbTM0Q3BXUW9ZbHBPbnWaARZob21lcGFnZV9ob3QtbGl2ZV9jZWxs",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:39:47.676401600"
},
{
"eventData": "Co4HChRXZWJjYXN0TWVtYmVyTWVzc2FnZRChlrmo+vKXqWUYoZbn2LPnlallIIfelc68MTABQssGChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMikAYICxIMCgcjOENFN0ZGIJADqgH8BQr5BQiGiKbO45Kep2IaA09MT0r/BArGAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvZDkxMWE2OTE0OTdmZTMzYzkyZDA5NTE0ZWU5MGFiOTB+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9bXlwMzBkJTJCUzNCRmRPZm4xV1ElMkZpbXA4WGdrMCUzRAq0AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvZDkxMWE2OTE0OTdmZTMzYzkyZDA5NTE0ZWU5MGFiOTB+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPVJiVkd2NVF4d3BZbjNQMTZVbmUyVElMb3A5MCUzRAq2AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvZDkxMWE2OTE0OTdmZTMzYzkyZDA5NTE0ZWU5MGFiOTB+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPW43cWNGbUdhSzJPJTJCcWw1cGI2YXlUNzh4bjJvJTNEEkQxMDB4MTAwL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kOTExYTY5MTQ5N2ZlMzNjOTJkMDk1MTRlZTkwYWI5MLIBBgjUExDJBroBAIICALICB29sb192MTLyAkxNUzR3TGpBQkFBQUFqUVR4elFwRldLRE1od0NDdC1ZakhDV0gzeDFGUjhRbzZubjJWQ3JGMUpmVVpxMURydk1yUXhjRVFQX2VacDNFSAFQArABAbgBAcABARL5BQiGiKbO45Kep2IaA09MT0r/BArGAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvZDkxMWE2OTE0OTdmZTMzYzkyZDA5NTE0ZWU5MGFiOTB+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9bXlwMzBkJTJCUzNCRmRPZm4xV1ElMkZpbXA4WGdrMCUzRAq0AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvZDkxMWE2OTE0OTdmZTMzYzkyZDA5NTE0ZWU5MGFiOTB+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPVJiVkd2NVF4d3BZbjNQMTZVbmUyVElMb3A5MCUzRAq2AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvZDkxMWE2OTE0OTdmZTMzYzkyZDA5NTE0ZWU5MGFiOTB+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPW43cWNGbUdhSzJPJTJCcWw1cGI2YXlUNzh4bjJvJTNEEkQxMDB4MTAwL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kOTExYTY5MTQ5N2ZlMzNjOTJkMDk1MTRlZTkwYWI5MLIBBgjUExDJBroBAIICALICB29sb192MTLyAkxNUzR3TGpBQkFBQUFqUVR4elFwRldLRE1od0NDdC1ZakhDV0gzeDFGUjhRbzZubjJWQ3JGMUpmVVpxMURydk1yUXhjRVFQX2VacDNFGAJQAZIBywYKFWxpdmVfcm9vbV9lbnRlcl90b2FzdBIPezA6dXNlcn0gam9pbmVkGg4KCSNiOGZmZmZmZiCQAyKQBggLEgwKByM4Q0U3RkYgkAOqAfwFCvkFCIaIps7jkp6nYhoDT0xPSv8ECsYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kOTExYTY5MTQ5N2ZlMzNjOTJkMDk1MTRlZTkwYWI5MH50cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1teXAzMGQlMkJTM0JGZE9mbjFXUSUyRmltcDhYZ2swJTNECrQBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kOTExYTY5MTQ5N2ZlMzNjOTJkMDk1MTRlZTkwYWI5MH5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9UmJWR3Y1UXh3cFluM1AxNlVuZTJUSUxvcDkwJTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kOTExYTY5MTQ5N2ZlMzNjOTJkMDk1MTRlZTkwYWI5MH5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9bjdxY0ZtR2FLMk8lMkJxbDVwYjZheVQ3OHhuMm8lM0QSRDEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2Q5MTFhNjkxNDk3ZmUzM2M5MmQwOTUxNGVlOTBhYjkwsgEGCNQTEMkGugEAggIAsgIHb2xvX3YxMvICTE1TNHdMakFCQUFBQWpRVHh6UXBGV0tETWh3Q0N0LVlqSENXSDN4MUZSOFFvNm5uMlZDckYxSmZVWnExRHJ2TXJReGNFUVBfZVpwM0WaARlnZW5lcmFsX3NlYXJjaC12aWRlb19oZWFkogEFY2xpY2s=",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:40:37.565374200"
},
{
"eventData": "CoQIChRXZWJjYXN0TWVtYmVyTWVzc2FnZRCglpuE1f2XqWUYoZbn2LPnlallIJn6ms68MTABQsEHChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMihgcICxIMCgcjOENFN0ZGIJADqgHyBgrvBgiGgOu2qfrzkVwaA2Vsb0r2BQq2AWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzY5MmI4OTdiYTNjNTA1M2IzMTI1YWZlMzFjYTlhNGRifnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPVYzM1ozJTJGRDFjcFBMbkI5Y3QxbHgyRVYxaXRjJTNECqYBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvNjkyYjg5N2JhM2M1MDUzYjMxMjVhZmUzMWNhOWE0ZGJ+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPWpHSXNVQWxsREpjZm1pMGh1czBPTzR1YU9MUSUzRAqmAWh0dHBzOi8vcDE2LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzY5MmI4OTdiYTNjNTA1M2IzMTI1YWZlMzFjYTlhNGRifmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1HbDE4dFdLQnlwNTVFQTVNaENTYXdKSGlRd3clM0QKqgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC82OTJiODk3YmEzYzUwNTNiMzEyNWFmZTMxY2E5YTRkYn5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9SVlKNWVVWmxCZzdDJTJGRFZNaW5LbWwlMkZ6NDAxSSUzRBI8MTAweDEwMC90b3MtbWFsaXZhLWF2dC0wMDY4LzY5MmI4OTdiYTNjNTA1M2IzMTI1YWZlMzFjYTlhNGRisgECEAO6AQCCAgCyAgpyYW5kb21tZW1q8gJMTVM0d0xqQUJBQUFBWlZsSldueTFLQ0l6T1c2bW4xcmZBOG0yNHhLd2VKRXlHS2g4SDFVclFnZ2hoTm1zaXZxTTV4Y21nSm14ZEFuY0gBUAKwAQG4AQHAAQES7wYIhoDrtqn685FcGgNlbG9K9gUKtgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC82OTJiODk3YmEzYzUwNTNiMzEyNWFmZTMxY2E5YTRkYn50cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1WMzNaMyUyRkQxY3BQTG5COWN0MWx4MkVWMWl0YyUzRAqmAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzY5MmI4OTdiYTNjNTA1M2IzMTI1YWZlMzFjYTlhNGRifmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1qR0lzVUFsbERKY2ZtaTBodXMwT080dWFPTFElM0QKpgFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC82OTJiODk3YmEzYzUwNTNiMzEyNWFmZTMxY2E5YTRkYn5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9R2wxOHRXS0J5cDU1RUE1TWhDU2F3SkhpUXd3JTNECqoBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvNjkyYjg5N2JhM2M1MDUzYjMxMjVhZmUzMWNhOWE0ZGJ+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUlZSjVlVVpsQmc3QyUyRkRWTWluS21sJTJGejQwMUklM0QSPDEwMHgxMDAvdG9zLW1hbGl2YS1hdnQtMDA2OC82OTJiODk3YmEzYzUwNTNiMzEyNWFmZTMxY2E5YTRkYrIBAhADugEAggIAsgIKcmFuZG9tbWVtavICTE1TNHdMakFCQUFBQVpWbEpXbnkxS0NJek9XNm1uMXJmQThtMjR4S3dlSkV5R0toOEgxVXJRZ2doaE5tc2l2cU01eGNtZ0pteGRBbmMYAlABkgHBBwoVbGl2ZV9yb29tX2VudGVyX3RvYXN0Eg97MDp1c2VyfSBqb2luZWQaDgoJI2I4ZmZmZmZmIJADIoYHCAsSDAoHIzhDRTdGRiCQA6oB8gYK7wYIhoDrtqn685FcGgNlbG9K9gUKtgFodHRwczovL3A3Ny1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC82OTJiODk3YmEzYzUwNTNiMzEyNWFmZTMxY2E5YTRkYn50cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1WMzNaMyUyRkQxY3BQTG5COWN0MWx4MkVWMWl0YyUzRAqmAWh0dHBzOi8vcDc3LXNpZ24tdmEudGlrdG9rY2RuLmNvbS90b3MtbWFsaXZhLWF2dC0wMDY4LzY5MmI4OTdiYTNjNTA1M2IzMTI1YWZlMzFjYTlhNGRifmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1qR0lzVUFsbERKY2ZtaTBodXMwT080dWFPTFElM0QKpgFodHRwczovL3AxNi1zaWduLXZhLnRpa3Rva2Nkbi5jb20vdG9zLW1hbGl2YS1hdnQtMDA2OC82OTJiODk3YmEzYzUwNTNiMzEyNWFmZTMxY2E5YTRkYn5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9R2wxOHRXS0J5cDU1RUE1TWhDU2F3SkhpUXd3JTNECqoBaHR0cHM6Ly9wNzctc2lnbi12YS50aWt0b2tjZG4uY29tL3Rvcy1tYWxpdmEtYXZ0LTAwNjgvNjkyYjg5N2JhM2M1MDUzYjMxMjVhZmUzMWNhOWE0ZGJ+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPUlZSjVlVVpsQmc3QyUyRkRWTWluS21sJTJGejQwMUklM0QSPDEwMHgxMDAvdG9zLW1hbGl2YS1hdnQtMDA2OC82OTJiODk3YmEzYzUwNTNiMzEyNWFmZTMxY2E5YTRkYrIBAhADugEAggIAsgIKcmFuZG9tbWVtavICTE1TNHdMakFCQUFBQVpWbEpXbnkxS0NJek9XNm1uMXJmQThtMjR4S3dlSkV5R0toOEgxVXJRZ2doaE5tc2l2cU01eGNtZ0pteGRBbmOaARZob21lcGFnZV9ob3QtbGl2ZV9jZWxs",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:42:03.041132700"
},
{
"eventData": "CqAHChRXZWJjYXN0TWVtYmVyTWVzc2FnZRCglp+O8oOYqWUYoZbn2LPnlallIPqCns68MTABQt0GChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMiogYICxIMCgcjOENFN0ZGIJADqgGOBgqLBgiGiIPy1eeLuV8aBlRvbXNvbkqFBQrKAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvYjBhYjY3ZDg4YWE3YmEwMGZjZGVkZTliM2U2ZDE1YTR+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9VGo3JTJCblhBeiUyRndEdSUyQm1iblhyaHBlWFNXJTJCajAlM0QKtgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2IwYWI2N2Q4OGFhN2JhMDBmY2RlZGU5YjNlNmQxNWE0fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1hREYlMkJrb2tQQ0dKRjV5cDVTTnJCNVA3MjlJOCUzRAq2AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvYjBhYjY3ZDg4YWE3YmEwMGZjZGVkZTliM2U2ZDE1YTR+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTYxZ0Y3VFFVSUpqWDYlMkJ6aHRJcVpjOUdRUXlBJTNEEkQxMDB4MTAwL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9iMGFiNjdkODhhYTdiYTAwZmNkZWRlOWIzZTZkMTVhNLIBBAhDEBC6AQCCAgCyAhJ1c2VyMTcwODgxMDczNDA1MDLyAkxNUzR3TGpBQkFBQUF2OE9QdDlpTWhZM0lhRU5SaGU4YzlxNkZHQzhYOXAyTG5oZkp2VkpuRzlpVnpWelZ4bVJ5Q1ItcGRTTmhRVVdWSAFQArABAbgBAcABARKLBgiGiIPy1eeLuV8aBlRvbXNvbkqFBQrKAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvYjBhYjY3ZDg4YWE3YmEwMGZjZGVkZTliM2U2ZDE1YTR+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9VGo3JTJCblhBeiUyRndEdSUyQm1iblhyaHBlWFNXJTJCajAlM0QKtgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2IwYWI2N2Q4OGFhN2JhMDBmY2RlZGU5YjNlNmQxNWE0fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1hREYlMkJrb2tQQ0dKRjV5cDVTTnJCNVA3MjlJOCUzRAq2AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvYjBhYjY3ZDg4YWE3YmEwMGZjZGVkZTliM2U2ZDE1YTR+YzVfMTAweDEwMC5qcGVnP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPTYxZ0Y3VFFVSUpqWDYlMkJ6aHRJcVpjOUdRUXlBJTNEEkQxMDB4MTAwL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9iMGFiNjdkODhhYTdiYTAwZmNkZWRlOWIzZTZkMTVhNLIBBAhDEBC6AQCCAgCyAhJ1c2VyMTcwODgxMDczNDA1MDLyAkxNUzR3TGpBQkFBQUF2OE9QdDlpTWhZM0lhRU5SaGU4YzlxNkZHQzhYOXAyTG5oZkp2VkpuRzlpVnpWelZ4bVJ5Q1ItcGRTTmhRVVdWGAJQAZIB3QYKFWxpdmVfcm9vbV9lbnRlcl90b2FzdBIPezA6dXNlcn0gam9pbmVkGg4KCSNiOGZmZmZmZiCQAyKiBggLEgwKByM4Q0U3RkYgkAOqAY4GCosGCIaIg/LV54u5XxoGVG9tc29uSoUFCsoBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9iMGFiNjdkODhhYTdiYTAwZmNkZWRlOWIzZTZkMTVhNH50cGx2LXRpa3Rvay1zaHJpbms6NzI6NzIud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1UajclMkJuWEF6JTJGd0R1JTJCbWJuWHJocGVYU1clMkJqMCUzRAq2AWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvYjBhYjY3ZDg4YWE3YmEwMGZjZGVkZTliM2U2ZDE1YTR+YzVfMTAweDEwMC53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPWFERiUyQmtva1BDR0pGNXlwNVNOckI1UDcyOUk4JTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9iMGFiNjdkODhhYTdiYTAwZmNkZWRlOWIzZTZkMTVhNH5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9NjFnRjdUUVVJSmpYNiUyQnpodElxWmM5R1FReUElM0QSRDEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2IwYWI2N2Q4OGFhN2JhMDBmY2RlZGU5YjNlNmQxNWE0sgEECEMQELoBAIICALICEnVzZXIxNzA4ODEwNzM0MDUwMvICTE1TNHdMakFCQUFBQXY4T1B0OWlNaFkzSWFFTlJoZThjOXE2RkdDOFg5cDJMbmhmSnZWSm5HOWlWelZ6VnhtUnlDUi1wZFNOaFFVV1aaARZob21lcGFnZV9ob3QtbGl2ZV9jZWxs",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:42:53.616185700"
},
{
"eventData": "Co4HChRXZWJjYXN0TWVtYmVyTWVzc2FnZRCglonZ0JWYqWUYoZbn2LPnlallIJbZps68MTABQssGChVsaXZlX3Jvb21fZW50ZXJfdG9hc3QSD3swOnVzZXJ9IGpvaW5lZBoOCgkjYjhmZmZmZmYgkAMikAYICxIMCgcjOENFN0ZGIJADqgH8BQr5BQiaiOLYrYPlpWQaAS5K/QQKxAFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2RjYjNmNjJhODg3MWVlZjY5ZWJlN2NkMWJkZDVjMzU5fnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPWlHSFByTnludTh3aTJNUSUyRmZBV1JQREc0ZURRJTNECrQBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kY2IzZjYyYTg4NzFlZWY2OWViZTdjZDFiZGQ1YzM1OX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9cDdqVExCMFNvUEhJeWxta3dRMVE0eXBsOTZZJTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kY2IzZjYyYTg4NzFlZWY2OWViZTdjZDFiZGQ1YzM1OX5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9RHIlMkZmRVYzMm5jdnB5dXFoRTJxcVZ5WUpQTE0lM0QSRDEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2RjYjNmNjJhODg3MWVlZjY5ZWJlN2NkMWJkZDVjMzU5sgEECBEQWLoBAIICALICDWxpdHRsZV9ib3kwMjLyAkxNUzR3TGpBQkFBQUF3NU1rcTFsTGszb0NmYnRlaG55NEpWNVJCX0d5OVd6WE90WlZka3FYV2V1aFMzUXI2cnFwUnRLZGsxOWptaXJzSAFQArABAbgBAcABARL5BQiaiOLYrYPlpWQaAS5K/QQKxAFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2RjYjNmNjJhODg3MWVlZjY5ZWJlN2NkMWJkZDVjMzU5fnRwbHYtdGlrdG9rLXNocmluazo3Mjo3Mi53ZWJwP3gtZXhwaXJlcz0xNzAwMDY3NjAwJngtc2lnbmF0dXJlPWlHSFByTnludTh3aTJNUSUyRmZBV1JQREc0ZURRJTNECrQBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kY2IzZjYyYTg4NzFlZWY2OWViZTdjZDFiZGQ1YzM1OX5jNV8xMDB4MTAwLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9cDdqVExCMFNvUEhJeWxta3dRMVE0eXBsOTZZJTNECrYBaHR0cHM6Ly9wMTYtc2lnbi11c2Vhc3QyYS50aWt0b2tjZG4uY29tL3Rvcy11c2Vhc3QyYS1hdnQtMDA2OC1ldXR0cC9kY2IzZjYyYTg4NzFlZWY2OWViZTdjZDFiZGQ1YzM1OX5jNV8xMDB4MTAwLmpwZWc/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9RHIlMkZmRVYzMm5jdnB5dXFoRTJxcVZ5WUpQTE0lM0QSRDEwMHgxMDAvdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2RjYjNmNjJhODg3MWVlZjY5ZWJlN2NkMWJkZDVjMzU5sgEECBEQWLoBAIICALICDWxpdHRsZV9ib3kwMjLyAkxNUzR3TGpBQkFBQUF3NU1rcTFsTGszb0NmYnRlaG55NEpWNVJCX0d5OVd6WE90WlZka3FYV2V1aFMzUXI2cnFwUnRLZGsxOWptaXJzGAJQAZIBywYKFWxpdmVfcm9vbV9lbnRlcl90b2FzdBIPezA6dXNlcn0gam9pbmVkGg4KCSNiOGZmZmZmZiCQAyKQBggLEgwKByM4Q0U3RkYgkAOqAfwFCvkFCJqI4titg+WlZBoBLkr9BArEAWh0dHBzOi8vcDE2LXNpZ24tdXNlYXN0MmEudGlrdG9rY2RuLmNvbS90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvZGNiM2Y2MmE4ODcxZWVmNjllYmU3Y2QxYmRkNWMzNTl+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/eC1leHBpcmVzPTE3MDAwNjc2MDAmeC1zaWduYXR1cmU9aUdIUHJOeW51OHdpMk1RJTJGZkFXUlBERzRlRFElM0QKtAFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2RjYjNmNjJhODg3MWVlZjY5ZWJlN2NkMWJkZDVjMzU5fmM1XzEwMHgxMDAud2VicD94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1wN2pUTEIwU29QSEl5bG1rd1ExUTR5cGw5NlklM0QKtgFodHRwczovL3AxNi1zaWduLXVzZWFzdDJhLnRpa3Rva2Nkbi5jb20vdG9zLXVzZWFzdDJhLWF2dC0wMDY4LWV1dHRwL2RjYjNmNjJhODg3MWVlZjY5ZWJlN2NkMWJkZDVjMzU5fmM1XzEwMHgxMDAuanBlZz94LWV4cGlyZXM9MTcwMDA2NzYwMCZ4LXNpZ25hdHVyZT1EciUyRmZFVjMybmN2cHl1cWhFMnFxVnlZSlBMTSUzRBJEMTAweDEwMC90b3MtdXNlYXN0MmEtYXZ0LTAwNjgtZXV0dHAvZGNiM2Y2MmE4ODcxZWVmNjllYmU3Y2QxYmRkNWMzNTmyAQQIERBYugEAggIAsgINbGl0dGxlX2JveTAyMvICTE1TNHdMakFCQUFBQXc1TWtxMWxMazNvQ2ZidGVobnk0SlY1UkJfR3k5V3pYT3RaVmRrcVhXZXVoUzNRcjZycXBSdEtkazE5am1pcnOaARVsaXZlX21lcmdlLWxpdmVfY292ZXKiAQRkcmF3",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:45:15.827938300"
}
],
"WebcastControlMessage": [
{
"eventData": "CjQKFVdlYmNhc3RDb250cm9sTWVzc2FnZRCglq+Gv7yWqWUYoZbn2LPnlallINDPvM28MTABEAEiAA==",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:16:17.730662700"
},
{
"eventData": "CjQKFVdlYmNhc3RDb250cm9sTWVzc2FnZRCgluru472WqWUYoZbn2LPnlallIJujvc28MTABEAI=",
"uniqueId": "dostawcavideo",
"ts": "2023-11-13T18:16:28.978931500"
}
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.0.3-Release</version>
<version>1.0.6-Release</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Tools-EventsWebViewer</artifactId>

View File

@@ -39,20 +39,30 @@ public class TikTokManager {
TikTokMessagessCollectorBuilder client;
MessageCollector msgCollector;
public static String dbName= "log";
public TikTokManager() {
msgCollector = new MessageCollector("ab");
msgCollector = new MessageCollector(dbName);
}
public void connect(String name) throws SQLException {
disconnect();
client = TikTokMessageCollectorClient.create(msgCollector, "ab")
client = TikTokMessageCollectorClient.create(msgCollector, dbName)
.addOnBuilder(liveClientBuilder ->
{
liveClientBuilder.onRoomInfo((liveClient, event) ->
{
});
liveClientBuilder.onGift((liveClient, event) ->
{
});
liveClientBuilder.onWebsocketUnhandledMessage((liveClient, event) ->
{
System.out.println("UNHANDLED MESSAGE! "+event.getMessage().getMethod());
});
})
.addUser(name);
client.buildAndRun();

View File

@@ -49,12 +49,12 @@ public class TikTokHandler {
context.status(200);
}
public void disconnect(Context context) throws SQLException {
public void disconnect(Context context){
tikTokManager.disconnect();
context.status(200);
}
public void events(Context context) throws SQLException {
public void events(Context context) {
var events = tikTokManager.getEventsNames();
var gson = getGson();
var result = gson.toJson(events);

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -54,6 +54,13 @@ public class CodeExample {
{
System.out.println(event.getComboState()+ " " + event.getCombo() + " " + event.getGift().getName());
})
.onRoomInfo((liveClient, event) ->
{
var roomInfo = event.getRoomInfo();
System.out.println("Room Id: "+roomInfo.getRoomId());
System.out.println("Likes: "+roomInfo.getLikesCount());
System.out.println("Viewers: "+roomInfo.getViewersCount());
})
.onJoin((liveClient, event) ->
{
System.out.println(event.getUser().getProfileName() + "Hello on my stream! ");
@@ -80,7 +87,6 @@ public class CodeExample {
settings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
settings.setLogLevel(Level.ALL); // Log level
settings.setPrintToConsole(true); // Printing all logs to console even if log level is Level.OFF
settings.setHandleExistingEvents(true); // Invokes all TikTok events that had occurred before connection
settings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
settings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection

View File

@@ -0,0 +1,681 @@
<div align="center" >
<a target="blank" >
<img src="https://raw.githubusercontent.com/jwdeveloper/TikTokLiveJava/develop-1_0_0/Tools-ReadmeGenerator/src/main/resources/logo.svg" width="15%" >
</img>
</a>
</div>
<div align="center" >
<h1>TikTok Live Java</h1>
❤️❤️🎁 *Connect to TikTok live in 3 lines* 🎁❤️❤️
<div align="center" >
<a href="https://jitpack.io/#jwdeveloper/TikTok-Live-Java" target="blank" >
<img src="https://jitpack.io/v/jwdeveloper/TikTok-Live-Java.svg" width="20%" >
</img>
</a>
<a href="https://discord.gg/e2XwPNTBBr" target="blank" >
<img src="https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white" >
</img>
</a>
<a target="blank" >
<img src="https://img.shields.io/badge/java-%23ED8B00.svg?style=for-the-badge&logo=openjdk&logoColor=white" >
</img>
</a>
</div>
</div>
# Introduction
A Java library inspired by [TikTokLive](https://github.com/isaackogan/TikTokLive) and [TikTokLiveSharp](https://github.com/frankvHoof93/TikTokLiveSharp). Use it to receive live stream events such as comments and gifts in realtime from [TikTok LIVE](https://www.tiktok.com/live) by connecting to TikTok's internal WebCast push service.
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
<div align="center">
<a href="https://www.youtube.com/watch?v=eerWGgUKc6c" align="right" target="blank"><img src="https://img.youtube.com/vi/eerWGgUKc6c/hqdefault.jpg" alt="IMAGE ALT TEXT" width="38%" align="right"></a>
</div>
Join the support [discord](https://discord.gg/e2XwPNTBBr) and visit the `#java-support` channel for questions, contributions and ideas. Feel free to make pull requests with missing/new features, fixes, etc
Do you prefer other programming languages?
- **Node** orginal: [TikTok-Live-Connector](https://github.com/isaackogan/TikTok-Live-Connector) by [@zerodytrash](https://github.com/zerodytrash)
- **Python** rewrite: [TikTokLive](https://github.com/isaackogan/TikTokLive) by [@isaackogan](https://github.com/isaackogan)
- **Go** rewrite: [GoTikTokLive](https://github.com/Davincible/gotiktoklive) by [@Davincible](https://github.com/Davincible)
- **C#** rewrite: [TikTokLiveSharp](https://github.com/frankvHoof93/TikTokLiveSharp) by [@frankvHoof93](https://github.com/frankvHoof93)
**NOTE:** This is not an official API. It's a reverse engineering project.
#### Overview
- [Getting started](#getting-started)
- [Events](#events)
- [Listeners](#listeners)
- [Contributing](#contributing)
## Getting started
1. Install the package via Maven
```xml
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
<artifactId>Client</artifactId>
<version>NOT_FOUND</version>
<scope>compile</scope>
</dependency>
</dependencies>
```
2. Create your first chat connection
```java
TikTokLive.newClient("bangbetmenygy")
.onGift((liveClient, event) ->
{
String message = switch (event.getGift()) {
case ROSE -> "ROSE!";
case GG -> "GOOD GAME";
case TIKTOK -> "Ye";
case CORGI -> "Nice gift";
default -> "Thank you for " + event.getGift().getName();
};
System.out.println(event.getUser().getProfileName() + " sends " + message);
})
.onGiftCombo((liveClient, event) ->
{
System.out.println(event.getComboState()+ " " + event.getCombo() + " " + event.getGift().getName());
})
.onRoomInfo((liveClient, event) ->
{
var roomInfo = event.getRoomInfo();
System.out.println("Room Id: "+roomInfo.getRoomId());
System.out.println("Likes: "+roomInfo.getLikesCount());
System.out.println("Viewers: "+roomInfo.getViewersCount());
})
.onJoin((liveClient, event) ->
{
System.out.println(event.getUser().getProfileName() + "Hello on my stream! ");
})
.onConnected((liveClient, event) ->
{
System.out.println("Connected to live ");
})
.onError((liveClient, event) ->
{
System.out.println("Error! " + event.getException().getMessage());
})
.buildAndConnect();
```
3. Configure (optional)
```java
TikTokLive.newClient("bangbetmenygy")
.configure((settings) ->
{
settings.setHostName("bangbetmenygy"); // This method is useful in case you want change hostname later
settings.setClientLanguage("en"); // Language
settings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
settings.setLogLevel(Level.ALL); // Log level
settings.setPrintToConsole(true); // Printing all logs to console even if log level is Level.OFF
settings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
settings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
//Optional: Sometimes not every message from chat are send to TikTokLiveJava to fix this issue you can set sessionId
// documentation how to obtain sessionId https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages
settings.setSessionId("86c3c8bf4b17ebb2d74bb7fa66fd0000");
//Optional:
//RoomId can be used as an override if you're having issues with HostId.
//You can find it in the HTML for the livestream-page
settings.setRoomId("XXXXXXXXXXXXXXXXX");
})
.buildAndConnect();
//
```
## Events
**Control**:
- [onConnected](#onconnected-tiktokconnectedevent)
- [onDisconnected](#ondisconnected-tiktokdisconnectedevent)
- [onReconnecting](#onreconnecting-tiktokreconnectingevent)
- [onError](#onerror-tiktokerrorevent)
**Message**:
- [onEvent](#onevent-tiktokevent)
- [onSubscribe](#onsubscribe-tiktoksubscribeevent)
- [onQuestion](#onquestion-tiktokquestionevent)
- [onFollow](#onfollow-tiktokfollowevent)
- [onLike](#onlike-tiktoklikeevent)
- [onLiveEnded](#onliveended-tiktokliveendedevent)
- [onRoomInfo](#onroominfo-tiktokroominfoevent)
- [onShare](#onshare-tiktokshareevent)
- [onGiftCombo](#ongiftcombo-tiktokgiftcomboevent)
- [onEmote](#onemote-tiktokemoteevent)
- [onGift](#ongift-tiktokgiftevent)
- [onComment](#oncomment-tiktokcommentevent)
- [onLivePaused](#onlivepaused-tiktoklivepausedevent)
- [onLiveUnpaused](#onliveunpaused-tiktokliveunpausedevent)
- [onJoin](#onjoin-tiktokjoinevent)
**Debug**:
- [onWebsocketUnhandledMessage](#onwebsocketunhandledmessage-tiktokwebsocketunhandledmessageevent)
- [onWebsocketResponse](#onwebsocketresponse-tiktokwebsocketresponseevent)
- [onWebsocketMessage](#onwebsocketmessage-tiktokwebsocketmessageevent)
# Examples
<br>
## onConnected [TikTokConnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokConnectedEvent.java)
Triggered when the connection is successfully established.
```java
TikTokLive.newClient("host-name")
.onConnected((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onDisconnected [TikTokDisconnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokDisconnectedEvent.java)
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.
```java
TikTokLive.newClient("host-name")
.onDisconnected((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onReconnecting [TikTokReconnectingEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokReconnectingEvent.java)
```java
TikTokLive.newClient("host-name")
.onReconnecting((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onError [TikTokErrorEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokErrorEvent.java)
General error event. You should handle this.
```java
TikTokLive.newClient("host-name")
.onError((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onEvent [TikTokEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/common/TikTokEvent.java)
Base class for all events
```java
TikTokLive.newClient("host-name")
.onEvent((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onSubscribe [TikTokSubscribeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokSubscribeEvent.java)
Triggers when a user creates a subscription.
```java
TikTokLive.newClient("host-name")
.onSubscribe((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onQuestion [TikTokQuestionEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokQuestionEvent.java)
Triggered every time someone asks a new question via the question feature.
```java
TikTokLive.newClient("host-name")
.onQuestion((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onFollow [TikTokFollowEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokFollowEvent.java)
Triggers when a user follows the streamer. Based on social event.
```java
TikTokLive.newClient("host-name")
.onFollow((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onLike [TikTokLikeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokLikeEvent.java)
Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
```java
TikTokLive.newClient("host-name")
.onLike((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onLiveEnded [TikTokLiveEndedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLiveEndedEvent.java)
Triggered when the live stream gets terminated by the host. Will also trigger the TikTokDisconnectedEvent event.
```java
TikTokLive.newClient("host-name")
.onLiveEnded((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onRoomInfo [TikTokRoomInfoEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/room/TikTokRoomInfoEvent.java)
```java
TikTokLive.newClient("host-name")
.onRoomInfo((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onShare [TikTokShareEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokShareEvent.java)
Triggers when a user shares the stream. Based on social event.
```java
TikTokLive.newClient("host-name")
.onShare((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onGiftCombo [TikTokGiftComboEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftComboEvent.java)
Triggered every time gift is sent
@see GiftSendType it has 3 states
<p>Example when user sends gift with combo</p>
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
<p>Combo: 4 -> comboState = GiftSendType.Active</p>
<p>Combo: 8 -> comboState = GiftSendType.Active</p>
<p>Combo: 12 -> comboState = GiftSendType.Finsihed</p>
Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
```java
TikTokLive.newClient("host-name")
.onGiftCombo((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onEmote [TikTokEmoteEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokEmoteEvent.java)
Triggered every time a subscriber sends an emote (sticker).
```java
TikTokLive.newClient("host-name")
.onEmote((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onGift [TikTokGiftEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftEvent.java)
Triggered when user sends gifts that has
no combo (most of expensive gifts)
or if combo has finished
```java
TikTokLive.newClient("host-name")
.onGift((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onComment [TikTokCommentEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokCommentEvent.java)
Triggered every time a new chat comment arrives.
```java
TikTokLive.newClient("host-name")
.onComment((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onLivePaused [TikTokLivePausedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLivePausedEvent.java)
```java
TikTokLive.newClient("host-name")
.onLivePaused((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onLiveUnpaused [TikTokLiveUnpausedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLiveUnpausedEvent.java)
```java
TikTokLive.newClient("host-name")
.onLiveUnpaused((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onJoin [TikTokJoinEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokJoinEvent.java)
```java
TikTokLive.newClient("host-name")
.onJoin((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onWebsocketUnhandledMessage [TikTokWebsocketUnhandledMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketUnhandledMessageEvent.java)
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
```java
TikTokLive.newClient("host-name")
.onWebsocketUnhandledMessage((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onWebsocketResponse [TikTokWebsocketResponseEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketResponseEvent.java)
```java
TikTokLive.newClient("host-name")
.onWebsocketResponse((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## onWebsocketMessage [TikTokWebsocketMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketMessageEvent.java)
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
```java
TikTokLive.newClient("host-name")
.onWebsocketMessage((liveClient, event) ->
{
})
.buildAndConnect();
```
<br>
## Listeners
```java
/**
*
* Listeners are an alternative way of handling events.
* I would to suggest to use then when logic of handing event
* is more complex
*
*/
public static void main(String[] args) throws IOException {
showLogo();
CustomListener customListener = new CustomListener();
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
.addListener(customListener)
.buildAndConnect();
System.in.read();
}
/**
*
* Method in TikTokEventListener should meet 4 requirements to be detected
* - 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 onLike(LiveClient liveClient, TikTokLikeEvent event) {
System.out.println(event.toString());
}
@TikTokEventHandler
public void onError(LiveClient liveClient, TikTokErrorEvent event) {
// event.getException().printStackTrace();
}
@TikTokEventHandler
public void onComment(LiveClient liveClient, TikTokCommentEvent event) {
var userName = event.getUser().getName();
var text = event.getText();
liveClient.getLogger().info(userName + ": " + text);
}
@TikTokEventHandler
public void onGift(LiveClient liveClient, TikTokGiftEvent event) {
var message = switch (event.getGift()) {
case ROSE -> "Thanks :)";
case APPETIZERS -> ":OO";
case APRIL -> ":D";
case TIKTOK -> ":P";
case CAP -> ":F";
default -> ":I";
};
liveClient.getLogger().info(message);
}
@TikTokEventHandler
public void onAnyEvent(LiveClient liveClient, TikTokEvent event) {
liveClient.getLogger().info(event.getClass().getSimpleName());
}
}
//
```
## Contributing
Your improvements are welcome! Feel free to open an <a href="https://github.com/jwdeveloper/TikTok-Live-Java/issues">issue</a> or <a href="https://github.com/jwdeveloper/TikTok-Live-Java/pulls">pull request</a>.

View File

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

View File

@@ -47,7 +47,8 @@ public class GiftsDownloader {
}
public List<GiftDto> getGiftsFromFile() {
var content = FilesUtility.loadFileContent("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\output_1_0_4.json");
var version = "";
var content = FilesUtility.loadFileContent("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\output.json");
Type mapType = new TypeToken<Map<Integer, GiftDto>>() {
}.getType();
var mapper = new Gson().fromJson(content, mapType);
@@ -85,7 +86,7 @@ public class GiftsDownloader {
var gson = new GsonBuilder().setPrettyPrinting()
.create();
var json = gson.toJson(outputHashMap);
FilesUtility.saveFile("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\output_1_0_4.json", json);
FilesUtility.saveFile("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\output.json", json);
System.out.println("Gifts saved to file!");
return outputHashMap.values().stream().toList();
}

View File

@@ -1,3 +1,25 @@
/*
* 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.gifts.downloader;
import com.google.gson.*;

View File

@@ -26,8 +26,10 @@ import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
import io.github.jwdeveloper.tiktok.mappers.events.TikTokGiftEventHandler;
import io.github.jwdeveloper.tiktok.mappers.events.TikTokRoomInfoEventHandler;
import io.github.jwdeveloper.tiktok.mappers.events.TikTokSocialMediaEventHandler;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
@@ -97,11 +99,9 @@ public class TikTokMockBuilder extends TikTokLiveClientBuilder {
var requestFactory = new TikTokHttpRequestFactory(cookie);
var apiClient = new TikTokHttpClient(cookie, requestFactory);
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler,
tiktokRoomInfo,
new TikTokGenericEventMapper(),
new TikTokGiftEventHandler(giftManager));
var webSocketClient = new WebsocketClientMock(logger, responses, webResponseHandler);
var mapper = createMapper(giftManager, tiktokRoomInfo);
var handler = new TikTokMessageHandler(tikTokEventHandler, mapper);
var webSocketClient = new WebsocketClientMock(logger, responses, handler);
return new LiveClientMock(tiktokRoomInfo,
apiService,

View File

@@ -1,4 +1,262 @@
[
{
"id": 5547,
"name": "Russian Crepes",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8525a07c6bf16a74eee66e9ad119b3b8.png~tplv-obj.png"
},
{
"id": 5793,
"name": "Play Samba",
"diamondCost": 99,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/fd3d6cc127464bacded6ed009074ae2f~tplv-obj.png"
},
{
"id": 5794,
"name": "Coconut Tree",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/eb0923dbab5251f4c2e0496b11b55c4f~tplv-obj.png"
},
{
"id": 5822,
"name": "Koala",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/22c8fa54da366c111f7bb915d4429e2d~tplv-obj.png"
},
{
"id": 5823,
"name": "Fairy Bread",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a42f9ac9cd6b26da03818ff65ac919f1~tplv-obj.png"
},
{
"id": 5831,
"name": "Flower Show",
"diamondCost": 500,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b6266323ef3ea0d313cbab6911ff8c46~tplv-obj.png"
},
{
"id": 5843,
"name": "Campfire",
"diamondCost": 388,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e280eb1b7fe92b4efe612d98064d5a2d~tplv-obj.png"
},
{
"id": 5852,
"name": "Soccer Ball",
"diamondCost": 39,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e1932db6aea81bbddc4e7dc0229ac155~tplv-obj.png"
},
{
"id": 5890,
"name": "Autumn leaves",
"diamondCost": 500,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/30adcaf443df63e3bfd2751ad251f87d~tplv-obj.png"
},
{
"id": 5893,
"name": "Footy",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/94f8ac5c7b6f90aba713b44ddac40bf1~tplv-obj.png"
},
{
"id": 5956,
"name": "Fishing Gear",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/1b2353958374f585e25b2f2344c6d0ad~tplv-obj.png"
},
{
"id": 5983,
"name": "Amazing",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/18256fd3f4402601dd07c83adae3e9a2~tplv-obj.png"
},
{
"id": 5991,
"name": "Banana leaf vessel",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8e635863e20cfa3651bd8a5b762ae72d~tplv-obj.png"
},
{
"id": 5992,
"name": "Frangipani",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7464fad59650123fe0989e426618847d~tplv-obj.png"
},
{
"id": 6006,
"name": "Cricket",
"diamondCost": 99,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/408d55c0526ada808be7db3e22c02a56~tplv-obj.png"
},
{
"id": 6034,
"name": "Flower",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9c20971eeb28b6b4ba37e57df3983da0~tplv-obj.png"
},
{
"id": 6050,
"name": "Love Bomb",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2a1c1b14f5e9f7be5d76fa4928f574f1~tplv-obj.png"
},
{
"id": 6113,
"name": "Taco ",
"diamondCost": 9,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/43d06db8c962623dbed6ecf70fb89ca8~tplv-obj.png"
},
{
"id": 6194,
"name": "Top Host",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5947dc37282c417b411c61f20ee7d6d4~tplv-obj.png"
},
{
"id": 6240,
"name": "ASMR",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/748e74c8309e08dbc5b03e03f28a0ea0~tplv-obj.png"
},
{
"id": 6411,
"name": "Snag",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/aa2d9b162c766a7fdf71fcead6d7bbcd~tplv-obj.png"
},
{
"id": 6416,
"name": "Choc Chip Cookie",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7dd2731de2e644301a329d3eb437b427~tplv-obj.png"
},
{
"id": 6428,
"name": "Crystal Ball",
"diamondCost": 1700,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7e4f9a99b7003ae05186f5324aae9fbf~tplv-obj.png"
},
{
"id": 6483,
"name": "Spinning Top",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/6cde70e04a6b40a9879f7b99ff191808~tplv-obj.png"
},
{
"id": 6486,
"name": "Cheems Dog",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/d2c9e50efa3b9ff1ed31c96440a9d3a1~tplv-obj.png"
},
{
"id": 6531,
"name": "Llama Greetings",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a6b95ce6350f5f4bdff6880ac6993789~tplv-obj.png"
},
{
"id": 6592,
"name": "TGIF",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2734231d880b5cd20149f4cc8c760279~tplv-obj.png"
},
{
"id": 6705,
"name": "Loved",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2a41781b0a29ba3c409c5dd83eed07f8~tplv-obj.png"
},
{
"id": 6744,
"name": "Fruits Hat ",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2316b31fc5259cc29f281d88fbca0568~tplv-obj.png"
},
{
"id": 6813,
"name": "Fantastic",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a1b2204b06aa19d45a0338e9f0099ea7~tplv-obj.png"
},
{
"id": 7218,
"name": "Rio de Janeiro",
"diamondCost": 9999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/34c0eb43c3d50e8ab64408171ebbe733~tplv-obj.png"
},
{
"id": 8225,
"name": "Coconut Drink",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ce27ad017f987240dc447e65ae866f4f~tplv-obj.png"
},
{
"id": 8267,
"name": "Good Evening",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0015a756ff783f37a2cf3b5d634b3cd6~tplv-obj.png"
},
{
"id": 8268,
"name": "Good Night",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b7b55087141bd5f965eb31a99a5f157b~tplv-obj.png"
},
{
"id": 8616,
"name": "Rainbow",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5fb7267489192fc77c4c8b647c124680~tplv-obj.png"
},
{
"id": 8638,
"name": "Festa Junina's Hat",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/61b32ccce11b289b3c1db7438dfb4450~tplv-obj.png"
},
{
"id": 8712,
"name": "Happy Father's Day",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/193eba78ded4d388a0b5a7ae95943796~tplv-obj.png"
},
{
"id": 9135,
"name": "Magic Forest",
"diamondCost": 6000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/63a758dbef9788f690e97cd65dbbb8d2~tplv-obj.png"
},
{
"id": 9333,
"name": "LIVE Fest Clappers",
"diamondCost": 100,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/63e85e00169ec5be3bfa90bb004cda5e.png~tplv-obj.png"
},
{
"id": 9334,
"name": "LIVE Fest",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1e98afffef90ed4b2cc9c9ebb88e3608.png~tplv-obj.png"
},
{
"id": 9514,
"name": "Storms at sea",
"diamondCost": 2200,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4918fbbdf220873dd8cae4c94d1ae037.png~tplv-obj.png"
},
{
"id": 9515,
"name": "Lightning Storm",
"diamondCost": 6000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6f673fbb0ae6860e2b1e254538c958ba.png~tplv-obj.png"
},
{
"id": 9516,
"name": "Mountains",
"diamondCost": 12000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/51a7d74bcb4a6417be59f0ffc0b77e96.png~tplv-obj.png"
},
{
"id": 7812,
"name": "Bravo",

File diff suppressed because it is too large Load Diff

View File

@@ -391,9 +391,9 @@
},
"5547": {
"id": 5547,
"name": "",
"name": "Russian Crepes",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/2ad/2ad28ef5a49c72186a45999319ff8caf/185c4643c32c2f28e4c6d06fc268c386.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8525a07c6bf16a74eee66e9ad119b3b8.png~tplv-obj.png"
},
"5556": {
"id": 5556,
@@ -925,15 +925,15 @@
},
"5793": {
"id": 5793,
"name": "",
"name": "Play Samba",
"diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/864/864f362bf1d66abf1acbb64bf0de43c8/0c5fad0d89d2b2a92ed30829059a59c3.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/fd3d6cc127464bacded6ed009074ae2f~tplv-obj.png"
},
"5794": {
"id": 5794,
"name": "",
"name": "Coconut Tree",
"diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/369/369b52ad98206ce414bf59b4fde0560f/12854f04151c6e0e76c172fb97c5514a.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/eb0923dbab5251f4c2e0496b11b55c4f~tplv-obj.png"
},
"5797": {
"id": 5797,
@@ -979,15 +979,15 @@
},
"5822": {
"id": 5822,
"name": "",
"name": "Koala",
"diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/29f/29f5ecab64a8a49be1a22330ccfd7235/1026d754a1c4337bf1dd008f396a4e4d.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/22c8fa54da366c111f7bb915d4429e2d~tplv-obj.png"
},
"5823": {
"id": 5823,
"name": "",
"name": "Fairy Bread",
"diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/101/1017a2225a5dad4a7d607fb22ed31eb9/c694724d0be38e01ed4c922050302e13.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a42f9ac9cd6b26da03818ff65ac919f1~tplv-obj.png"
},
"5826": {
"id": 5826,
@@ -1009,9 +1009,9 @@
},
"5831": {
"id": 5831,
"name": "",
"name": "Flower Show",
"diamondCost": 500,
"image": "https://storage.streamdps.com/iblock/ae4/ae4751eec1418b80b5fc49b296ef7df1/71f974c7842b768c05236b3a12530c3f.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b6266323ef3ea0d313cbab6911ff8c46~tplv-obj.png"
},
"5832": {
"id": 5832,
@@ -1051,9 +1051,9 @@
},
"5843": {
"id": 5843,
"name": "",
"name": "Campfire",
"diamondCost": 388,
"image": "https://storage.streamdps.com/iblock/583/583b77ae2c961d85a811a67f3966f2f5/591bdbe070b9f5d743f183253d54cdce.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e280eb1b7fe92b4efe612d98064d5a2d~tplv-obj.png"
},
"5850": {
"id": 5850,
@@ -1063,9 +1063,9 @@
},
"5852": {
"id": 5852,
"name": "",
"name": "Soccer Ball",
"diamondCost": 39,
"image": "https://storage.streamdps.com/iblock/368/368797349fb9ab0d2ad41f6b898c4bad/7c523b69e9c95c1f7e8be9df7b733fe0.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e1932db6aea81bbddc4e7dc0229ac155~tplv-obj.png"
},
"5860": {
"id": 5860,
@@ -1135,15 +1135,15 @@
},
"5890": {
"id": 5890,
"name": "",
"name": "Autumn leaves",
"diamondCost": 500,
"image": "https://storage.streamdps.com/iblock/538/53861f02a937f02242e9c8ea8c736472/4b4b7c48d0f712f11b643d604a54bd01.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/30adcaf443df63e3bfd2751ad251f87d~tplv-obj.png"
},
"5893": {
"id": 5893,
"name": "",
"name": "Footy",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/404/40436175c5ac3c124b3eefac8546d38f/75fd0dc90b620a607aa7b66729b9c0fd.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/94f8ac5c7b6f90aba713b44ddac40bf1~tplv-obj.png"
},
"5894": {
"id": 5894,
@@ -1297,9 +1297,9 @@
},
"5956": {
"id": 5956,
"name": "",
"name": "Fishing Gear",
"diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/0c5/0c55246326097edf2cd6418263a94cc7/e1641719baffc2067165fc1ad4a939cb.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/1b2353958374f585e25b2f2344c6d0ad~tplv-obj.png"
},
"5958": {
"id": 5958,
@@ -1363,9 +1363,9 @@
},
"5983": {
"id": 5983,
"name": "",
"name": "Amazing",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/c0f/c0fdf0e2672efd3f9b37794c43c13366/5d13e5d7bec8b0f3c549be78869e7a3d.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/18256fd3f4402601dd07c83adae3e9a2~tplv-obj.png"
},
"5984": {
"id": 5984,
@@ -1385,6 +1385,18 @@
"diamondCost": 555,
"image": "https://storage.streamdps.com/iblock/627/6271a3ecc3614860585a3aa1c337ca1f/6db1ca1d211999a95accf6f3325db5de.png"
},
"5991": {
"id": 5991,
"name": "Banana leaf vessel",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8e635863e20cfa3651bd8a5b762ae72d~tplv-obj.png"
},
"5992": {
"id": 5992,
"name": "Frangipani",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7464fad59650123fe0989e426618847d~tplv-obj.png"
},
"5994": {
"id": 5994,
"name": "Turkish coffee",
@@ -1423,9 +1435,9 @@
},
"6006": {
"id": 6006,
"name": "",
"name": "Cricket",
"diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/5f0/5f014a2af1e1eec44223880561052a23/951286a4458999e058c8b0d3a29b575b.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/408d55c0526ada808be7db3e22c02a56~tplv-obj.png"
},
"6007": {
"id": 6007,
@@ -1459,9 +1471,9 @@
},
"6034": {
"id": 6034,
"name": "",
"name": "Flower",
"diamondCost": 299,
"image": "https://storage.streamdps.com/iblock/caa/caa0e3e2cdc87759f657c515d839a7d9/9917cc4ca38657550f29759fa7df1439.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9c20971eeb28b6b4ba37e57df3983da0~tplv-obj.png"
},
"6036": {
"id": 6036,
@@ -1519,9 +1531,9 @@
},
"6050": {
"id": 6050,
"name": "",
"name": "Love Bomb",
"diamondCost": 299,
"image": "https://storage.streamdps.com/iblock/06d/06d0d3f807b08aec6b02ffccce87e541/5a93ead8cf35f9e5e6b5689b4f851ecd.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2a1c1b14f5e9f7be5d76fa4928f574f1~tplv-obj.png"
},
"6052": {
"id": 6052,
@@ -1669,9 +1681,9 @@
},
"6113": {
"id": 6113,
"name": "",
"name": "Taco ",
"diamondCost": 9,
"image": "https://storage.streamdps.com/iblock/6d8/6d809e8e6318e64b7e8c80fd325b7a0b/fa9bf2e6d0a5a19b945e6c4cc4e10af8.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/43d06db8c962623dbed6ecf70fb89ca8~tplv-obj.png"
},
"6116": {
"id": 6116,
@@ -1795,9 +1807,9 @@
},
"6194": {
"id": 6194,
"name": "",
"name": "Top Host",
"diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/99f/99ffb3ba22c1882f8f6433c6447b5f4c/e95f311b0e1b19324c2acad263a17d44.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5947dc37282c417b411c61f20ee7d6d4~tplv-obj.png"
},
"6199": {
"id": 6199,
@@ -1849,9 +1861,9 @@
},
"6240": {
"id": 6240,
"name": "",
"name": "ASMR",
"diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/ec6/ec66e855e1ee52c850d5458d96599d66/8fdbdc30beff2247ad4214392cab00dd.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/748e74c8309e08dbc5b03e03f28a0ea0~tplv-obj.png"
},
"6242": {
"id": 6242,
@@ -2083,9 +2095,9 @@
},
"6411": {
"id": 6411,
"name": "",
"name": "Snag",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/e7d/e7dd9a4fb21a968098e1e7e4ef07a840/3086f9317df9f35c2115570cfca1fdd0.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/aa2d9b162c766a7fdf71fcead6d7bbcd~tplv-obj.png"
},
"6414": {
"id": 6414,
@@ -2101,9 +2113,9 @@
},
"6416": {
"id": 6416,
"name": "",
"name": "Choc Chip Cookie",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/ce5/ce57f012363358333397b6c72704b466/aa71c1c351b698c09a151a434bfd2652.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7dd2731de2e644301a329d3eb437b427~tplv-obj.png"
},
"6417": {
"id": 6417,
@@ -2119,9 +2131,9 @@
},
"6428": {
"id": 6428,
"name": "",
"name": "Crystal Ball",
"diamondCost": 1700,
"image": "https://storage.streamdps.com/iblock/605/6057daf816ed32ad97ef0250fa02ae1e/92e61863514c008cd0332fa7c37cf2b9.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7e4f9a99b7003ae05186f5324aae9fbf~tplv-obj.png"
},
"6429": {
"id": 6429,
@@ -2245,9 +2257,9 @@
},
"6483": {
"id": 6483,
"name": "",
"name": "Spinning Top",
"diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/868/8683388d9e7b33f0f7955ebbf00dfff4/23de767c8a572ad27fd25f953ffe8069.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/6cde70e04a6b40a9879f7b99ff191808~tplv-obj.png"
},
"6484": {
"id": 6484,
@@ -2257,9 +2269,9 @@
},
"6486": {
"id": 6486,
"name": "",
"name": "Cheems Dog",
"diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/61e/61e0c2d7e7917f9dbd179034d3b4a330/ce9897ca21aae3a7648f18e67ee2bf2d.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/d2c9e50efa3b9ff1ed31c96440a9d3a1~tplv-obj.png"
},
"6487": {
"id": 6487,
@@ -2329,9 +2341,9 @@
},
"6531": {
"id": 6531,
"name": "",
"name": "Llama Greetings",
"diamondCost": 299,
"image": "https://storage.streamdps.com/iblock/40f/40f2ab7fa04f23d9d1e5e58840df0251/37793eb58b88e10afb8922056b9ac5a3.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a6b95ce6350f5f4bdff6880ac6993789~tplv-obj.png"
},
"6532": {
"id": 6532,
@@ -2465,6 +2477,12 @@
"diamondCost": 13999,
"image": "https://storage.streamdps.com/iblock/fb1/fb1096568dcc97c2575dec7441d0d651/245c4c7ce9bf5d5378586eb3a2478b42.webp"
},
"6592": {
"id": 6592,
"name": "TGIF",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2734231d880b5cd20149f4cc8c760279~tplv-obj.png"
},
"6593": {
"id": 6593,
"name": "",
@@ -2635,9 +2653,9 @@
},
"6705": {
"id": 6705,
"name": "",
"name": "Loved",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/5c9/5c911310d7572ad93edc87e69f149eb4/3eb87b251e73846115c5c09e3ed90804.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2a41781b0a29ba3c409c5dd83eed07f8~tplv-obj.png"
},
"6713": {
"id": 6713,
@@ -2695,9 +2713,9 @@
},
"6744": {
"id": 6744,
"name": "",
"name": "Fruits Hat ",
"diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/1a6/1a6a52e5b0020a731da399b55866e245/b15e38a68d456a82cc59a213b04020e3.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2316b31fc5259cc29f281d88fbca0568~tplv-obj.png"
},
"6751": {
"id": 6751,
@@ -2821,9 +2839,9 @@
},
"6813": {
"id": 6813,
"name": "",
"name": "Fantastic",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/3d2/3d2707e87e8c92a8e3302cc33abf1d9c/eee97c25a857060dc81f84f13917ea73.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a1b2204b06aa19d45a0338e9f0099ea7~tplv-obj.png"
},
"6820": {
"id": 6820,
@@ -3587,6 +3605,12 @@
"diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/5c3/5c37dce1eab0d67386329f3a2920a874/38104bd52d316ea76464433b3b07dea7.webp"
},
"7218": {
"id": 7218,
"name": "Rio de Janeiro",
"diamondCost": 9999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/34c0eb43c3d50e8ab64408171ebbe733~tplv-obj.png"
},
"7222": {
"id": 7222,
"name": "Full moon",
@@ -4271,6 +4295,12 @@
"diamondCost": 30,
"image": "https://storage.streamdps.com/iblock/e94/e944534be54186446d7c38563c772029/553d899c4bd4be31e7b051bb36e842f8.webp"
},
"8225": {
"id": 8225,
"name": "Coconut Drink",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ce27ad017f987240dc447e65ae866f4f~tplv-obj.png"
},
"8232": {
"id": 8232,
"name": "Gardening",
@@ -4343,6 +4373,18 @@
"diamondCost": 6000,
"image": "https://storage.streamdps.com/iblock/88d/88df4387d65bcc77b691098fd649bd59/ad401a92ddba9aae15bb777f9f38638d.webp"
},
"8267": {
"id": 8267,
"name": "Good Evening",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0015a756ff783f37a2cf3b5d634b3cd6~tplv-obj.png"
},
"8268": {
"id": 8268,
"name": "Good Night",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b7b55087141bd5f965eb31a99a5f157b~tplv-obj.png"
},
"8277": {
"id": 8277,
"name": "Love Drop",
@@ -4571,6 +4613,18 @@
"diamondCost": 5000,
"image": "https://storage.streamdps.com/iblock/48f/48f1a8d280e271929718525560ad42a8/3021d84608e0c5da388f1f6534011a6f.webp"
},
"8616": {
"id": 8616,
"name": "Rainbow",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5fb7267489192fc77c4c8b647c124680~tplv-obj.png"
},
"8638": {
"id": 8638,
"name": "Festa Junina\u0027s Hat",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/61b32ccce11b289b3c1db7438dfb4450~tplv-obj.png"
},
"8648": {
"id": 8648,
"name": "Window basket",
@@ -4595,6 +4649,12 @@
"diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/f34/f34b75494926337d0bede7003aee0af9/1cb25dfee5bac6dc49b19222ed6967f7.webp"
},
"8712": {
"id": 8712,
"name": "Happy Father\u0027s Day",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/193eba78ded4d388a0b5a7ae95943796~tplv-obj.png"
},
"8740": {
"id": 8740,
"name": "Crocodile",
@@ -4799,6 +4859,12 @@
"diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"
},
"9135": {
"id": 9135,
"name": "Magic Forest",
"diamondCost": 6000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/63a758dbef9788f690e97cd65dbbb8d2~tplv-obj.png"
},
"9138": {
"id": 9138,
"name": "Trending Figure",
@@ -4853,6 +4919,18 @@
"diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/3d9/3d98c2fbc96922da37a9d22881bb06b9/0a99af132ab8e3fe9806d2412abc6bf0.webp"
},
"9333": {
"id": 9333,
"name": "LIVE Fest Clappers",
"diamondCost": 100,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/63e85e00169ec5be3bfa90bb004cda5e.png~tplv-obj.png"
},
"9334": {
"id": 9334,
"name": "LIVE Fest",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1e98afffef90ed4b2cc9c9ebb88e3608.png~tplv-obj.png"
},
"9463": {
"id": 9463,
"name": "Fairy Wings",
@@ -4882,5 +4960,65 @@
"name": "Rhythmic Bear",
"diamondCost": 2999,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/16eacf541e4bd6816e88139d079519f5.png~tplv-obj.jpg"
},
"9498": {
"id": 9498,
"name": "Blooming Ribbons",
"diamondCost": 1000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f76750ab58ee30fc022c9e4e11d25c9d.png~tplv-obj.jpg"
},
"9499": {
"id": 9499,
"name": "Golden Party",
"diamondCost": 3000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/a00450f3e3aa1f01b62774950e5729c3.png~tplv-obj.jpg"
},
"9500": {
"id": 9500,
"name": "Flying Jets",
"diamondCost": 5000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1d067d13988e8754ed6adbebd89b9ee8.png~tplv-obj.jpg"
},
"9501": {
"id": 9501,
"name": "Yacht",
"diamondCost": 20000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/e69e2626f6ff43d1c1f2b8ae5ea42514.png~tplv-obj.jpg"
},
"9514": {
"id": 9514,
"name": "Storms at sea",
"diamondCost": 2200,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4918fbbdf220873dd8cae4c94d1ae037.png~tplv-obj.png"
},
"9515": {
"id": 9515,
"name": "Lightning Storm",
"diamondCost": 6000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6f673fbb0ae6860e2b1e254538c958ba.png~tplv-obj.png"
},
"9516": {
"id": 9516,
"name": "Mountains",
"diamondCost": 12000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/51a7d74bcb4a6417be59f0ffc0b77e96.png~tplv-obj.png"
},
"9522": {
"id": 9522,
"name": "Exclusive Spark",
"diamondCost": 1000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f0bda1eb6856e2feea9cfcb6c575c8a0.png~tplv-obj.jpg"
},
"9523": {
"id": 9523,
"name": "Exclusive Jet",
"diamondCost": 5000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1cc167a00aa4d5dfe48018afb38c3daa.png~tplv-obj.jpg"
},
"9524": {
"id": 9524,
"name": "Exclusive Yacht",
"diamondCost": 20000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/da8c85d5ae09ebf320216202e8fa015d.png~tplv-obj.jpg"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -391,9 +391,9 @@
},
"5547": {
"id": 5547,
"name": "",
"name": "Russian Crepes",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/2ad/2ad28ef5a49c72186a45999319ff8caf/185c4643c32c2f28e4c6d06fc268c386.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8525a07c6bf16a74eee66e9ad119b3b8.png~tplv-obj.png"
},
"5556": {
"id": 5556,
@@ -925,15 +925,15 @@
},
"5793": {
"id": 5793,
"name": "",
"name": "Play Samba",
"diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/864/864f362bf1d66abf1acbb64bf0de43c8/0c5fad0d89d2b2a92ed30829059a59c3.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/fd3d6cc127464bacded6ed009074ae2f~tplv-obj.png"
},
"5794": {
"id": 5794,
"name": "",
"name": "Coconut Tree",
"diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/369/369b52ad98206ce414bf59b4fde0560f/12854f04151c6e0e76c172fb97c5514a.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/eb0923dbab5251f4c2e0496b11b55c4f~tplv-obj.png"
},
"5797": {
"id": 5797,
@@ -979,15 +979,15 @@
},
"5822": {
"id": 5822,
"name": "",
"name": "Koala",
"diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/29f/29f5ecab64a8a49be1a22330ccfd7235/1026d754a1c4337bf1dd008f396a4e4d.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/22c8fa54da366c111f7bb915d4429e2d~tplv-obj.png"
},
"5823": {
"id": 5823,
"name": "",
"name": "Fairy Bread",
"diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/101/1017a2225a5dad4a7d607fb22ed31eb9/c694724d0be38e01ed4c922050302e13.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a42f9ac9cd6b26da03818ff65ac919f1~tplv-obj.png"
},
"5826": {
"id": 5826,
@@ -1009,9 +1009,9 @@
},
"5831": {
"id": 5831,
"name": "",
"name": "Flower Show",
"diamondCost": 500,
"image": "https://storage.streamdps.com/iblock/ae4/ae4751eec1418b80b5fc49b296ef7df1/71f974c7842b768c05236b3a12530c3f.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b6266323ef3ea0d313cbab6911ff8c46~tplv-obj.png"
},
"5832": {
"id": 5832,
@@ -1051,9 +1051,9 @@
},
"5843": {
"id": 5843,
"name": "",
"name": "Campfire",
"diamondCost": 388,
"image": "https://storage.streamdps.com/iblock/583/583b77ae2c961d85a811a67f3966f2f5/591bdbe070b9f5d743f183253d54cdce.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e280eb1b7fe92b4efe612d98064d5a2d~tplv-obj.png"
},
"5850": {
"id": 5850,
@@ -1063,9 +1063,9 @@
},
"5852": {
"id": 5852,
"name": "",
"name": "Soccer Ball",
"diamondCost": 39,
"image": "https://storage.streamdps.com/iblock/368/368797349fb9ab0d2ad41f6b898c4bad/7c523b69e9c95c1f7e8be9df7b733fe0.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e1932db6aea81bbddc4e7dc0229ac155~tplv-obj.png"
},
"5860": {
"id": 5860,
@@ -1135,15 +1135,15 @@
},
"5890": {
"id": 5890,
"name": "",
"name": "Autumn leaves",
"diamondCost": 500,
"image": "https://storage.streamdps.com/iblock/538/53861f02a937f02242e9c8ea8c736472/4b4b7c48d0f712f11b643d604a54bd01.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/30adcaf443df63e3bfd2751ad251f87d~tplv-obj.png"
},
"5893": {
"id": 5893,
"name": "",
"name": "Footy",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/404/40436175c5ac3c124b3eefac8546d38f/75fd0dc90b620a607aa7b66729b9c0fd.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/94f8ac5c7b6f90aba713b44ddac40bf1~tplv-obj.png"
},
"5894": {
"id": 5894,
@@ -1297,9 +1297,9 @@
},
"5956": {
"id": 5956,
"name": "",
"name": "Fishing Gear",
"diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/0c5/0c55246326097edf2cd6418263a94cc7/e1641719baffc2067165fc1ad4a939cb.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/1b2353958374f585e25b2f2344c6d0ad~tplv-obj.png"
},
"5958": {
"id": 5958,
@@ -1363,9 +1363,9 @@
},
"5983": {
"id": 5983,
"name": "",
"name": "Amazing",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/c0f/c0fdf0e2672efd3f9b37794c43c13366/5d13e5d7bec8b0f3c549be78869e7a3d.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/18256fd3f4402601dd07c83adae3e9a2~tplv-obj.png"
},
"5984": {
"id": 5984,
@@ -1385,6 +1385,18 @@
"diamondCost": 555,
"image": "https://storage.streamdps.com/iblock/627/6271a3ecc3614860585a3aa1c337ca1f/6db1ca1d211999a95accf6f3325db5de.png"
},
"5991": {
"id": 5991,
"name": "Banana leaf vessel",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8e635863e20cfa3651bd8a5b762ae72d~tplv-obj.png"
},
"5992": {
"id": 5992,
"name": "Frangipani",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7464fad59650123fe0989e426618847d~tplv-obj.png"
},
"5994": {
"id": 5994,
"name": "Turkish coffee",
@@ -1423,9 +1435,9 @@
},
"6006": {
"id": 6006,
"name": "",
"name": "Cricket",
"diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/5f0/5f014a2af1e1eec44223880561052a23/951286a4458999e058c8b0d3a29b575b.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/408d55c0526ada808be7db3e22c02a56~tplv-obj.png"
},
"6007": {
"id": 6007,
@@ -1459,9 +1471,9 @@
},
"6034": {
"id": 6034,
"name": "",
"name": "Flower",
"diamondCost": 299,
"image": "https://storage.streamdps.com/iblock/caa/caa0e3e2cdc87759f657c515d839a7d9/9917cc4ca38657550f29759fa7df1439.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9c20971eeb28b6b4ba37e57df3983da0~tplv-obj.png"
},
"6036": {
"id": 6036,
@@ -1519,9 +1531,9 @@
},
"6050": {
"id": 6050,
"name": "",
"name": "Love Bomb",
"diamondCost": 299,
"image": "https://storage.streamdps.com/iblock/06d/06d0d3f807b08aec6b02ffccce87e541/5a93ead8cf35f9e5e6b5689b4f851ecd.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2a1c1b14f5e9f7be5d76fa4928f574f1~tplv-obj.png"
},
"6052": {
"id": 6052,
@@ -1669,9 +1681,9 @@
},
"6113": {
"id": 6113,
"name": "",
"name": "Taco ",
"diamondCost": 9,
"image": "https://storage.streamdps.com/iblock/6d8/6d809e8e6318e64b7e8c80fd325b7a0b/fa9bf2e6d0a5a19b945e6c4cc4e10af8.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/43d06db8c962623dbed6ecf70fb89ca8~tplv-obj.png"
},
"6116": {
"id": 6116,
@@ -1795,9 +1807,9 @@
},
"6194": {
"id": 6194,
"name": "",
"name": "Top Host",
"diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/99f/99ffb3ba22c1882f8f6433c6447b5f4c/e95f311b0e1b19324c2acad263a17d44.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5947dc37282c417b411c61f20ee7d6d4~tplv-obj.png"
},
"6199": {
"id": 6199,
@@ -1849,9 +1861,9 @@
},
"6240": {
"id": 6240,
"name": "",
"name": "ASMR",
"diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/ec6/ec66e855e1ee52c850d5458d96599d66/8fdbdc30beff2247ad4214392cab00dd.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/748e74c8309e08dbc5b03e03f28a0ea0~tplv-obj.png"
},
"6242": {
"id": 6242,
@@ -2083,9 +2095,9 @@
},
"6411": {
"id": 6411,
"name": "",
"name": "Snag",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/e7d/e7dd9a4fb21a968098e1e7e4ef07a840/3086f9317df9f35c2115570cfca1fdd0.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/aa2d9b162c766a7fdf71fcead6d7bbcd~tplv-obj.png"
},
"6414": {
"id": 6414,
@@ -2101,9 +2113,9 @@
},
"6416": {
"id": 6416,
"name": "",
"name": "Choc Chip Cookie",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/ce5/ce57f012363358333397b6c72704b466/aa71c1c351b698c09a151a434bfd2652.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7dd2731de2e644301a329d3eb437b427~tplv-obj.png"
},
"6417": {
"id": 6417,
@@ -2119,9 +2131,9 @@
},
"6428": {
"id": 6428,
"name": "",
"name": "Crystal Ball",
"diamondCost": 1700,
"image": "https://storage.streamdps.com/iblock/605/6057daf816ed32ad97ef0250fa02ae1e/92e61863514c008cd0332fa7c37cf2b9.png"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7e4f9a99b7003ae05186f5324aae9fbf~tplv-obj.png"
},
"6429": {
"id": 6429,
@@ -2245,9 +2257,9 @@
},
"6483": {
"id": 6483,
"name": "",
"name": "Spinning Top",
"diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/868/8683388d9e7b33f0f7955ebbf00dfff4/23de767c8a572ad27fd25f953ffe8069.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/6cde70e04a6b40a9879f7b99ff191808~tplv-obj.png"
},
"6484": {
"id": 6484,
@@ -2257,9 +2269,9 @@
},
"6486": {
"id": 6486,
"name": "",
"name": "Cheems Dog",
"diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/61e/61e0c2d7e7917f9dbd179034d3b4a330/ce9897ca21aae3a7648f18e67ee2bf2d.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/d2c9e50efa3b9ff1ed31c96440a9d3a1~tplv-obj.png"
},
"6487": {
"id": 6487,
@@ -2329,9 +2341,9 @@
},
"6531": {
"id": 6531,
"name": "",
"name": "Llama Greetings",
"diamondCost": 299,
"image": "https://storage.streamdps.com/iblock/40f/40f2ab7fa04f23d9d1e5e58840df0251/37793eb58b88e10afb8922056b9ac5a3.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a6b95ce6350f5f4bdff6880ac6993789~tplv-obj.png"
},
"6532": {
"id": 6532,
@@ -2465,6 +2477,12 @@
"diamondCost": 13999,
"image": "https://storage.streamdps.com/iblock/fb1/fb1096568dcc97c2575dec7441d0d651/245c4c7ce9bf5d5378586eb3a2478b42.webp"
},
"6592": {
"id": 6592,
"name": "TGIF",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2734231d880b5cd20149f4cc8c760279~tplv-obj.png"
},
"6593": {
"id": 6593,
"name": "",
@@ -2635,9 +2653,9 @@
},
"6705": {
"id": 6705,
"name": "",
"name": "Loved",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/5c9/5c911310d7572ad93edc87e69f149eb4/3eb87b251e73846115c5c09e3ed90804.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2a41781b0a29ba3c409c5dd83eed07f8~tplv-obj.png"
},
"6713": {
"id": 6713,
@@ -2695,9 +2713,9 @@
},
"6744": {
"id": 6744,
"name": "",
"name": "Fruits Hat ",
"diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/1a6/1a6a52e5b0020a731da399b55866e245/b15e38a68d456a82cc59a213b04020e3.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2316b31fc5259cc29f281d88fbca0568~tplv-obj.png"
},
"6751": {
"id": 6751,
@@ -2821,9 +2839,9 @@
},
"6813": {
"id": 6813,
"name": "",
"name": "Fantastic",
"diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/3d2/3d2707e87e8c92a8e3302cc33abf1d9c/eee97c25a857060dc81f84f13917ea73.webp"
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a1b2204b06aa19d45a0338e9f0099ea7~tplv-obj.png"
},
"6820": {
"id": 6820,
@@ -3587,6 +3605,12 @@
"diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/5c3/5c37dce1eab0d67386329f3a2920a874/38104bd52d316ea76464433b3b07dea7.webp"
},
"7218": {
"id": 7218,
"name": "Rio de Janeiro",
"diamondCost": 9999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/34c0eb43c3d50e8ab64408171ebbe733~tplv-obj.png"
},
"7222": {
"id": 7222,
"name": "Full moon",
@@ -4271,6 +4295,12 @@
"diamondCost": 30,
"image": "https://storage.streamdps.com/iblock/e94/e944534be54186446d7c38563c772029/553d899c4bd4be31e7b051bb36e842f8.webp"
},
"8225": {
"id": 8225,
"name": "Coconut Drink",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ce27ad017f987240dc447e65ae866f4f~tplv-obj.png"
},
"8232": {
"id": 8232,
"name": "Gardening",
@@ -4343,6 +4373,18 @@
"diamondCost": 6000,
"image": "https://storage.streamdps.com/iblock/88d/88df4387d65bcc77b691098fd649bd59/ad401a92ddba9aae15bb777f9f38638d.webp"
},
"8267": {
"id": 8267,
"name": "Good Evening",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0015a756ff783f37a2cf3b5d634b3cd6~tplv-obj.png"
},
"8268": {
"id": 8268,
"name": "Good Night",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b7b55087141bd5f965eb31a99a5f157b~tplv-obj.png"
},
"8277": {
"id": 8277,
"name": "Love Drop",
@@ -4571,6 +4613,18 @@
"diamondCost": 5000,
"image": "https://storage.streamdps.com/iblock/48f/48f1a8d280e271929718525560ad42a8/3021d84608e0c5da388f1f6534011a6f.webp"
},
"8616": {
"id": 8616,
"name": "Rainbow",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5fb7267489192fc77c4c8b647c124680~tplv-obj.png"
},
"8638": {
"id": 8638,
"name": "Festa Junina\u0027s Hat",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/61b32ccce11b289b3c1db7438dfb4450~tplv-obj.png"
},
"8648": {
"id": 8648,
"name": "Window basket",
@@ -4595,6 +4649,12 @@
"diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/f34/f34b75494926337d0bede7003aee0af9/1cb25dfee5bac6dc49b19222ed6967f7.webp"
},
"8712": {
"id": 8712,
"name": "Happy Father\u0027s Day",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/193eba78ded4d388a0b5a7ae95943796~tplv-obj.png"
},
"8740": {
"id": 8740,
"name": "Crocodile",
@@ -4799,6 +4859,12 @@
"diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"
},
"9135": {
"id": 9135,
"name": "Magic Forest",
"diamondCost": 6000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/63a758dbef9788f690e97cd65dbbb8d2~tplv-obj.png"
},
"9138": {
"id": 9138,
"name": "Trending Figure",
@@ -4853,6 +4919,18 @@
"diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/3d9/3d98c2fbc96922da37a9d22881bb06b9/0a99af132ab8e3fe9806d2412abc6bf0.webp"
},
"9333": {
"id": 9333,
"name": "LIVE Fest Clappers",
"diamondCost": 100,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/63e85e00169ec5be3bfa90bb004cda5e.png~tplv-obj.png"
},
"9334": {
"id": 9334,
"name": "LIVE Fest",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1e98afffef90ed4b2cc9c9ebb88e3608.png~tplv-obj.png"
},
"9463": {
"id": 9463,
"name": "Fairy Wings",
@@ -4882,5 +4960,65 @@
"name": "Rhythmic Bear",
"diamondCost": 2999,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/16eacf541e4bd6816e88139d079519f5.png~tplv-obj.jpg"
},
"9498": {
"id": 9498,
"name": "Blooming Ribbons",
"diamondCost": 1000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f76750ab58ee30fc022c9e4e11d25c9d.png~tplv-obj.jpg"
},
"9499": {
"id": 9499,
"name": "Golden Party",
"diamondCost": 3000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/a00450f3e3aa1f01b62774950e5729c3.png~tplv-obj.jpg"
},
"9500": {
"id": 9500,
"name": "Flying Jets",
"diamondCost": 5000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1d067d13988e8754ed6adbebd89b9ee8.png~tplv-obj.jpg"
},
"9501": {
"id": 9501,
"name": "Yacht",
"diamondCost": 20000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/e69e2626f6ff43d1c1f2b8ae5ea42514.png~tplv-obj.jpg"
},
"9514": {
"id": 9514,
"name": "Storms at sea",
"diamondCost": 2200,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4918fbbdf220873dd8cae4c94d1ae037.png~tplv-obj.png"
},
"9515": {
"id": 9515,
"name": "Lightning Storm",
"diamondCost": 6000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6f673fbb0ae6860e2b1e254538c958ba.png~tplv-obj.png"
},
"9516": {
"id": 9516,
"name": "Mountains",
"diamondCost": 12000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/51a7d74bcb4a6417be59f0ffc0b77e96.png~tplv-obj.png"
},
"9522": {
"id": 9522,
"name": "Exclusive Spark",
"diamondCost": 1000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f0bda1eb6856e2feea9cfcb6c575c8a0.png~tplv-obj.jpg"
},
"9523": {
"id": 9523,
"name": "Exclusive Jet",
"diamondCost": 5000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1cc167a00aa4d5dfe48018afb38c3daa.png~tplv-obj.jpg"
},
"9524": {
"id": 9524,
"name": "Exclusive Yacht",
"diamondCost": 20000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/da8c85d5ae09ebf320216202e8fa015d.png~tplv-obj.jpg"
}
}

94
collaboration.md Normal file
View File

@@ -0,0 +1,94 @@
# Collaboration Guide
Are you willing to help or improve TikTokLiveJava?
### Project setup
1. Clone project to your favorite IDE (IntelliJ recommended) https://github.com/jwdeveloper/TikTokLiveJava.git
2. After project is cloned you can encounter error that some classes are missing
Don't worry this is normal! To fix that use `Maven compile` command for the
root project
### How does library works?
We can divide working of library to 4 important parts
- Getting info about live from TikTok
Library is making 3 https
- first for getting live `Room_ID`
- second for getting more specific live metadata such as live title, host name...
- third to `Sign API` that returns access token that is later use for connecting
to TikTok websocket
- Connecting to TikTok websocket (PushServer)
After successful connection TikTok starts to send `ProtocolBuffer`
messages in binary format. This is very important to understand `ProtocolBuffer`
it is not complicated :). All the proto files are included under `API/src/main/proto`
After using `Maven compile` command on project, java classes are generated from
those files. so then we can easily map incoming bytes to class, for examples
`WebcastGiftMessage message = WebcastGiftMessage.parseFrom(incomingBytesArray)`
- Mapping TikTok data to events
at this point we have TikTok data inside protocol-buffer classes now we want
to map it to TikTokLiveJava events. Why? because `protocol-buffer classes` might
be changed at any point, but we want to keep library code structure keep consistent
so for example `WebcastGiftMessage` is mapped manually to `TikTokGiftEvent`
- trigger events
when the events objects are done last step is to trigger then and that's it
`tikTokEventObserver.publish(liveClient, tiktokGiftEvent)`
### Project structure
project is made from few modules the most important one are
#### API
Contains interfaces and data classes, all code that is ment
to be visible and use for the Library user should be included
in this project
- All the events can be found user `io.github.jwdeveloper.tiktok.data.events`
- All the class data that are used in events is under `io.github.jwdeveloper.tiktok.data.models`
#### Client
Contains implementation of `API` modules interfaces and all the code
important classes
- `TikTokLiveClient` core class that is use to connect/disconnect from TikTok
- `TikTokLiveClientBuilder` preparing `TikTokLiveClient` class
- `TikTokApiService` use for Http requests to TikTok/Sign API
- `TikTokWebSocketClient` receiving all ProtocolBuffer messages from TikTok
- `TikTokMessageHandlerRegistration` register all mappings TikTok data -> TikTokLiveJava events
- `TikTokEventObserver` used to register and trigger TikTok events
There are also few more modules made purely for testing and debbuging code
#### Examples
Project made to show up new features and present basic
example for library. While developing new features you
can use it as playground
#### Tools
Project that contains code generators for automation teadios boilder plate
It contains very useful class `GenerateGiftsEnum` that download gifts json from TikTok
and generates code for `Gift` enum that is later added to `API` module at path `io.github.jwdeveloper.tiktok.data.models.gifts.Gift`
#### Tools-EventsCollector
Tool that can be used to store all events from live to sqlLite database or Json file
It is very handy for later debuging events data
#### Tools-EventsWebViewer
Tools that runs website that collects and display pure data from TikTok incoming events
very useful for debuging
#### Tools-ReadmeGenerator
Generates readme file from template

BIN
dupa.db Normal file

Binary file not shown.

BIN
link.db Normal file

Binary file not shown.

BIN
log.db Normal file

Binary file not shown.

View File

@@ -7,7 +7,7 @@
<groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>TikTokLiveJava</artifactId>
<packaging>pom</packaging>
<version>1.0.3-Release</version>
<version>1.0.6-Release</version>
<modules>
<module>API</module>
<module>Client</module>