Compare commits

...

16 Commits

Author SHA1 Message Date
kohlerpop1
39c3b5b1bc Final Proxy Commit! 2024-01-14 20:55:00 +01:00
kohlerpop1
f40a26ad7c Push for proxy test pt 4! 2024-01-14 20:55:00 +01:00
kohlerpop1
4fab46b3d9 Push for proxy test pt 3! 2024-01-14 20:55:00 +01:00
kohlerpop1
a89e2c2e08 Push for proxy test pt 2! 2024-01-14 20:55:00 +01:00
kohlerpop1
bc8c56982f Push for proxy test! 2024-01-14 20:55:00 +01:00
kohlerpop1
fa5385d893 Added convenience methods back to TikTokLive and changed sing to sign where misspelled! 2024-01-14 20:55:00 +01:00
Jacek W
548a585e90 Update README.md 2024-01-06 17:55:51 +01:00
Jacek W
2667f04a1c Update README.md 2024-01-05 17:27:12 +01:00
GitHub Action
0a857594ea Update version in pom.xml 2024-01-05 16:26:35 +00:00
JW
b0593ba95c - refactor of the Http client
Changes:

Http-client settings in configure method

```
    TikTokLive.newClient("X")
                .configure(liveClientSettings ->
                {
                   var httpSetting = liveClientSettings.getHttpSettings();
                    httpSetting.setTimeout(Duration.ofSeconds(12));
                });
```

`TikTokLive.requests()` Easy and quick way of making
http request to tiktok
```
    var giftsResponse =TikTokLive.request.fetchGiftsData();
 ```

 Removed:
     TikTokLive.isLiveOnline(String hostName);
     TikTokLive.isHostNameValidAsync(String hostName);

     instead you can use
     ```
     TikTokLive.requests().fetchLiveUserData("Mike").getUserStatus()
     ```
2024-01-05 17:21:55 +01:00
JW
c23faffcde - refactor of the Http client
Changes:

Http-client settings in configure method

```
    TikTokLive.newClient("X")
                .configure(liveClientSettings ->
                {
                   var httpSetting = liveClientSettings.getHttpSettings();
                    httpSetting.setTimeout(Duration.ofSeconds(12));
                });
```

`TikTokLive.requests()` Easy and quick way of making
http request to tiktok
```
    var giftsResponse =TikTokLive.request.fetchGiftsData();
 ```

 Removed:
     TikTokLive.isLiveOnline(String hostName);
     TikTokLive.isHostNameValidAsync(String hostName);

     instead you can use
     ```
     TikTokLive.requests().fetchLiveUserData("Mike").getUserStatus()
     ```
2024-01-05 17:21:55 +01:00
JW
f7a92d5015 - refactor of the Http client
Changes:

Http-client settings in configure method

```
    TikTokLive.newClient("X")
                .configure(liveClientSettings ->
                {
                   var httpSetting = liveClientSettings.getHttpSettings();
                    httpSetting.setTimeout(Duration.ofSeconds(12));
                });
```

`TikTokLive.requests()` Easy and quick way of making
http request to tiktok
```
    var giftsResponse =TikTokLive.request.fetchGiftsData();
 ```

 Removed:
     TikTokLive.isLiveOnline(String hostName);
     TikTokLive.isHostNameValidAsync(String hostName);

     instead you can use
     ```
     TikTokLive.requests().fetchLiveUserData("Mike").getUserStatus()
     ```
2024-01-05 17:21:55 +01:00
GitHub Action
6a42da9ecb Update version in pom.xml 2024-01-05 16:21:21 +00:00
kohlerpop1
1308b86567 Made User#attributes final as its only set once and moved each constructor assignment to field declaration! 2024-01-05 17:06:50 +01:00
kohlerpop1
20ba88c0ac Removed useless lines, made Picture#toString, and optimized TikTokGiftManager#findById & TikTokGiftManager#findByName! 2024-01-05 17:06:50 +01:00
GitHub Action
77533ea4be Update version in pom.xml 2023-12-22 21:11:06 +00:00
88 changed files with 9441 additions and 1826 deletions

View File

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

View File

@@ -1,91 +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;
import lombok.Data;
import java.time.Duration;
import java.util.Map;
import java.util.logging.Level;
@Data
public class ClientSettings {
/**
* Timeout for Connections
*/
private Duration timeout;
/**
* ISO-Language for Client
*/
private String clientLanguage;
/**
* Whether to Retry if Connection Fails
*/
private boolean retryOnConnectionFailure;
/**
* Before retrying connect, wait for select amount of time
*/
private Duration retryConnectionTimeout;
/**
* Whether to print Logs to Console
*/
private boolean printToConsole = true;
/**
* LoggingLevel for Logs
*/
private Level logLevel;
/**
* Optional: Use it if you need to change TikTok live hostname in builder
*/
private String hostName;
/**
* Parameters used in requests to TikTok api
*/
private Map<String, Object> clientParameters;
/*
* Optional: Sometimes not every messages 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
*/
private String sessionId;
/*
* Optional: By default roomID is fetched before connect to live, but you can set it manually
*
*/
private String roomId;
}

View File

@@ -0,0 +1,66 @@
/*
* 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.*;
import java.net.*;
@Data
@AllArgsConstructor
public class ProxyData
{
private final String address;
private final int port;
public static ProxyData map(String string) {
if (string == null || string.isBlank())
throw new IllegalArgumentException("Provided address cannot be null or empty!");
int portIndex = string.lastIndexOf(':');
try {
String address = string.substring(0, portIndex);
int port = Integer.parseInt(string.substring(portIndex+1));
// Port validation
if (port < 0 || port > 65535)
throw new IndexOutOfBoundsException("Port out of range: "+port);
// IP Validation
InetAddress res = InetAddress.getByName(address);
return new ProxyData(address, port);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Port must be a valid integer!");
} catch (UnknownHostException e) {
throw new IllegalArgumentException("Address must be valid IPv4, IPv6, or domain name!");
}
}
public ProxyData clone() {
return new ProxyData(address, port);
}
public InetSocketAddress toSocketAddress() {
return new InetSocketAddress(address, port);
}
}

View File

@@ -24,7 +24,7 @@ package io.github.jwdeveloper.tiktok.data.events;
import io.github.jwdeveloper.tiktok.annotations.EventMeta; import io.github.jwdeveloper.tiktok.annotations.EventMeta;
import io.github.jwdeveloper.tiktok.annotations.EventType; import io.github.jwdeveloper.tiktok.annotations.EventType;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
import lombok.Getter;
/** /**
* Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic. * Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic.
@@ -32,4 +32,12 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokLiveClientEvent;
*/ */
@EventMeta(eventType = EventType.Control) @EventMeta(eventType = EventType.Control)
public class TikTokDisconnectedEvent extends TikTokLiveClientEvent { public class TikTokDisconnectedEvent extends TikTokLiveClientEvent {
} @Getter private final String reason;
public TikTokDisconnectedEvent(String reason) {
this.reason = reason.isBlank() ? "None" : reason;
}
public TikTokDisconnectedEvent() {
this("None");
}
}

View File

@@ -28,15 +28,10 @@ import lombok.Getter;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class Picture { public class Picture {
@Getter @Getter
@@ -49,7 +44,6 @@ public class Picture {
} }
public static Picture map(io.github.jwdeveloper.tiktok.messages.data.Image profilePicture) { public static Picture map(io.github.jwdeveloper.tiktok.messages.data.Image profilePicture) {
var index = profilePicture.getUrlListCount() - 1; var index = profilePicture.getUrlListCount() - 1;
if (index < 0) { if (index < 0) {
return new Picture(""); return new Picture("");
@@ -74,12 +68,11 @@ public class Picture {
return CompletableFuture.supplyAsync(this::downloadImage); return CompletableFuture.supplyAsync(this::downloadImage);
} }
private BufferedImage download(String urlString) private BufferedImage download(String urlString) {
{ if (urlString.isEmpty()) {
if(urlString.isEmpty())
{
return null; return null;
} }
var baos = new ByteArrayOutputStream(); var baos = new ByteArrayOutputStream();
try (var is = new URL(urlString).openStream()) { try (var is = new URL(urlString).openStream()) {
var byteChunk = new byte[4096]; var byteChunk = new byte[4096];
@@ -103,4 +96,9 @@ public class Picture {
public static Picture Empty() { public static Picture Empty() {
return new Picture(""); return new Picture("");
} }
}
@Override
public String toString() {
return "Picture{link='" + link + "', image=" + image + "}";
}
}

View File

@@ -37,6 +37,4 @@ public class Badge {
public static Badge empty() { public static Badge empty() {
return new Badge(); return new Badge();
} }
}
}

View File

@@ -41,6 +41,10 @@ public enum Gift {
LOVE_CHAT(6205, "Love Chat", 400, "https://storage.streamdps.com/iblock/440/4402267722e227b72adc97db92504b75/ae0f562146e701f32ae96761ac67c5cc.png"), LOVE_CHAT(6205, "Love Chat", 400, "https://storage.streamdps.com/iblock/440/4402267722e227b72adc97db92504b75/ae0f562146e701f32ae96761ac67c5cc.png"),
SPRING_TRAIN(8152, "Spring train", 3999, "https://storage.streamdps.com/iblock/035/035862dc0952468fc95f02995cec0f22/eeb69650806ea4c2e22558ef4b5e2b47.webp"),
CHRISTMAS_MARKET_G(7377, "Christmas Market G", 2000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/f498f29ef628c8318006a9ff2f49bf08~tplv-obj.png"),
CHICK(8165, "Chick", 10, "https://storage.streamdps.com/iblock/54e/54e5c232c74094c8e4b4d5678552f756/8132c0b012e7100540e1f1e2a5b3265d.webp"), CHICK(8165, "Chick", 10, "https://storage.streamdps.com/iblock/54e/54e5c232c74094c8e4b4d5678552f756/8132c0b012e7100540e1f1e2a5b3265d.webp"),
DOUBLE_TROUBLE(8038, "Double trouble", 2988, "https://storage.streamdps.com/iblock/a23/a23f89b59cebf6d82ba64437e0ce52c9/d13464a899047febd2bd3db61835cb1b.webp"), DOUBLE_TROUBLE(8038, "Double trouble", 2988, "https://storage.streamdps.com/iblock/a23/a23f89b59cebf6d82ba64437e0ce52c9/d13464a899047febd2bd3db61835cb1b.webp"),
@@ -49,6 +53,8 @@ public enum Gift {
FALCON_6367(6367, "Falcon", 10999, "https://storage.streamdps.com/iblock/f88/f886e7678bef35f8c762a323386e6d23/7249e0af64c78d1d569a8d7a86ab58cd.png"), FALCON_6367(6367, "Falcon", 10999, "https://storage.streamdps.com/iblock/f88/f886e7678bef35f8c762a323386e6d23/7249e0af64c78d1d569a8d7a86ab58cd.png"),
HAPPY_FRIDAY(8265, "Happy Friday", 399, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/65e8fcb76825b9ec36a24faf9a3e9495~tplv-obj.png"),
SNEAKERHEAD(7394, "Sneakerhead", 1, "https://storage.streamdps.com/iblock/f64/f648c76bae6ef273077c74cc9312b126/87f4891550b2cfd3e49973f7f87dbdb2.webp"), SNEAKERHEAD(7394, "Sneakerhead", 1, "https://storage.streamdps.com/iblock/f64/f648c76bae6ef273077c74cc9312b126/87f4891550b2cfd3e49973f7f87dbdb2.webp"),
PANTHER_PAWS(7204, "Panther Paws", 199, "https://storage.streamdps.com/iblock/6e0/6e097d88e5e088d0228c702456e58450/72afb8bfa2231766da6817e911702d4b.webp"), PANTHER_PAWS(7204, "Panther Paws", 199, "https://storage.streamdps.com/iblock/6e0/6e097d88e5e088d0228c702456e58450/72afb8bfa2231766da6817e911702d4b.webp"),
@@ -73,6 +79,8 @@ public enum Gift {
PLAY_SAMBA(5793, "Play Samba", 99, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/fd3d6cc127464bacded6ed009074ae2f~tplv-obj.png"), PLAY_SAMBA(5793, "Play Samba", 99, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/fd3d6cc127464bacded6ed009074ae2f~tplv-obj.png"),
WOOLY_HAT(7458, "Wooly Hat", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a234d0187047fa48805c8ea2e1f1f756~tplv-obj.png"),
LITTLE_CROWN(6097, "Little Crown", 99, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/cf3db11b94a975417043b53401d0afe1~tplv-obj.jpg"), 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"), RUBY_RED(8434, "Ruby red", 88, "https://storage.streamdps.com/iblock/405/405fcf52a1de3d14ab9834c1f30cc330/0deed9ee2c79ba6bf2005b0ce667bf60.webp"),
@@ -81,6 +89,8 @@ public enum Gift {
COTTON_CANDY(7265, "Cotton Candy", 700, "https://storage.streamdps.com/iblock/51f/51f64a93c515f4a45169f24a52179f2f/730beb9631b1af4edfaf714d7686df04.webp"), COTTON_CANDY(7265, "Cotton Candy", 700, "https://storage.streamdps.com/iblock/51f/51f64a93c515f4a45169f24a52179f2f/730beb9631b1af4edfaf714d7686df04.webp"),
HOT(6756, "Hot", 10, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ec679890070187b61620b9662afb814e~tplv-obj.png"),
KNIGHT_HELMET(8672, "Knight Helmet", 199, "https://storage.streamdps.com/iblock/291/2915da07301fcb6a9a4d3e515931c2c8/31ebb4cad7a264fe9657a3ddfaca4eaa.webp"), KNIGHT_HELMET(8672, "Knight Helmet", 199, "https://storage.streamdps.com/iblock/291/2915da07301fcb6a9a4d3e515931c2c8/31ebb4cad7a264fe9657a3ddfaca4eaa.webp"),
SUB_STAR(7072, "Sub Star", 1, "https://storage.streamdps.com/iblock/98f/98fea40fc19cc9dbd9a083b0844c163b/af7dd985812299d89f6cfa49c84e7eaf.webp"), SUB_STAR(7072, "Sub Star", 1, "https://storage.streamdps.com/iblock/98f/98fea40fc19cc9dbd9a083b0844c163b/af7dd985812299d89f6cfa49c84e7eaf.webp"),
@@ -97,6 +107,8 @@ public enum Gift {
MIKE(7789, "Mike", 4000, "https://storage.streamdps.com/iblock/de0/de0da7b6ce6ba19125b1c4eb2fd2966a/6804a72c00714de05f9239be7bd5b515.webp"), MIKE(7789, "Mike", 4000, "https://storage.streamdps.com/iblock/de0/de0da7b6ce6ba19125b1c4eb2fd2966a/6804a72c00714de05f9239be7bd5b515.webp"),
STAY_WARM(9682, "Stay Warm", 450, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/abd104eb08ce0c351292036d8897fb8d.png~tplv-obj.png"),
HEADPHONE(6609, "Headphone", 199, "https://storage.streamdps.com/iblock/ce9/ce95ea6922db1e776296819861d69ddb/b0b11c041a28d46e51ff1ed8f288fe91.webp"), HEADPHONE(6609, "Headphone", 199, "https://storage.streamdps.com/iblock/ce9/ce95ea6922db1e776296819861d69ddb/b0b11c041a28d46e51ff1ed8f288fe91.webp"),
HEADPHONE_8017(8017, "Headphone", 199, "https://storage.streamdps.com/iblock/055/05573a16af395b896b26847bc77fbb5e/55c0f27976902374940cfb54f22728d0.webp"), HEADPHONE_8017(8017, "Headphone", 199, "https://storage.streamdps.com/iblock/055/05573a16af395b896b26847bc77fbb5e/55c0f27976902374940cfb54f22728d0.webp"),
@@ -105,6 +117,8 @@ public enum Gift {
ICE_CREAM_8963(8963, "Ice cream", 5, "https://storage.streamdps.com/iblock/f72/f726165be6e93bdc69724375e7931dde/2e749d8d397b3ce5e6bcc90402f27c7d.webp"), ICE_CREAM_8963(8963, "Ice cream", 5, "https://storage.streamdps.com/iblock/f72/f726165be6e93bdc69724375e7931dde/2e749d8d397b3ce5e6bcc90402f27c7d.webp"),
_2024_GLASSES(9640, "2024 Glasses", 224, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/512d2e9934cbae8d1019a391814edbd2.png~tplv-obj.jpg"),
GIVE_IT_ALL(6649, "Give It All", 1, "https://storage.streamdps.com/iblock/de8/de8468d1003361452021c2d4796bb0f6/574aa0cdd7b418a2a3af2ca4739e9e7f.webp"), GIVE_IT_ALL(6649, "Give It All", 1, "https://storage.streamdps.com/iblock/de8/de8468d1003361452021c2d4796bb0f6/574aa0cdd7b418a2a3af2ca4739e9e7f.webp"),
MARVELOUS_CONFETTI(7121, "Marvelous Confetti", 100, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/fccc851d351716bc8b34ec65786c727d~tplv-obj.jpg"), MARVELOUS_CONFETTI(7121, "Marvelous Confetti", 100, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/fccc851d351716bc8b34ec65786c727d~tplv-obj.jpg"),
@@ -145,12 +159,16 @@ public enum Gift {
WATERMELON(8826, "Watermelon", 10, "https://storage.streamdps.com/iblock/84e/84e29ce96978961b12f1e88dd985b938/08e2a0ac2c2e2794aa2558e67d387639.webp"), WATERMELON(8826, "Watermelon", 10, "https://storage.streamdps.com/iblock/84e/84e29ce96978961b12f1e88dd985b938/08e2a0ac2c2e2794aa2558e67d387639.webp"),
PEGASUS(9427, "Pegasus", 42999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f600a2495ab5d250e7da2066484a9383.png~tplv-obj.jpg"),
SHOW_TIME(6907, "Show Time", 3999, "https://storage.streamdps.com/iblock/d72/d722e6d78821a169ff9a6d128127c696/f457c04596d723f9033842f3417b6a72.webp"), SHOW_TIME(6907, "Show Time", 3999, "https://storage.streamdps.com/iblock/d72/d722e6d78821a169ff9a6d128127c696/f457c04596d723f9033842f3417b6a72.webp"),
LOVE_FOCUS(6436, "Love Focus", 199, "https://storage.streamdps.com/iblock/cd1/cd1096cb1507fe07b633dad0b0aee967/d6b2e544219ed4d3c3263d319ab9bc5f.png"), LOVE_FOCUS(6436, "Love Focus", 199, "https://storage.streamdps.com/iblock/cd1/cd1096cb1507fe07b633dad0b0aee967/d6b2e544219ed4d3c3263d319ab9bc5f.png"),
CHICKEN_LEG(6209, "Chicken Leg", 10, "https://storage.streamdps.com/iblock/ef7/ef776169ede6c4a635cef2b3ab35d29a/7683229a73330c04463d2b97984ea114.png"), CHICKEN_LEG(6209, "Chicken Leg", 10, "https://storage.streamdps.com/iblock/ef7/ef776169ede6c4a635cef2b3ab35d29a/7683229a73330c04463d2b97984ea114.png"),
KING_CAKE_(6112, "King Cake ", 9, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/aa99da9f6b499ff879c3860e888a53ae~tplv-obj.png"),
BEACH_DAY(6431, "Beach Day", 2999, "https://storage.streamdps.com/iblock/c2d/c2df4a57f2ab16e641630b7077b40900/ba3cf6fd32d224f0014bd395b011f7a0.webp"), BEACH_DAY(6431, "Beach Day", 2999, "https://storage.streamdps.com/iblock/c2d/c2df4a57f2ab16e641630b7077b40900/ba3cf6fd32d224f0014bd395b011f7a0.webp"),
CUBE(9184, "Cube", 10, "https://storage.streamdps.com/iblock/69d/69dab4e352882c0bd29c3864e24d80de/258857221189c76260b6af5eeb43e93b.webp"), CUBE(9184, "Cube", 10, "https://storage.streamdps.com/iblock/69d/69dab4e352882c0bd29c3864e24d80de/258857221189c76260b6af5eeb43e93b.webp"),
@@ -159,10 +177,16 @@ public enum Gift {
SPEEDBOAT(5763, "Speedboat", 1888, "https://storage.streamdps.com/iblock/55f/55f832ac0d4e25f2527b2cf87ae8af08/ec99908e1787ae32c1387a20db7ca5ac.png"), SPEEDBOAT(5763, "Speedboat", 1888, "https://storage.streamdps.com/iblock/55f/55f832ac0d4e25f2527b2cf87ae8af08/ec99908e1787ae32c1387a20db7ca5ac.png"),
SNOWMAN(7551, "Snowman", 99, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e094e0fafc14aaf127fa0d0a7926619a~tplv-obj.png"),
YELLOW_BUS(8263, "Yellow Bus", 6000, "https://storage.streamdps.com/iblock/88d/88df4387d65bcc77b691098fd649bd59/ad401a92ddba9aae15bb777f9f38638d.webp"), YELLOW_BUS(8263, "Yellow Bus", 6000, "https://storage.streamdps.com/iblock/88d/88df4387d65bcc77b691098fd649bd59/ad401a92ddba9aae15bb777f9f38638d.webp"),
ROSA_NEBULA(8912, "Rosa Nebula", 15000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f722088231103b66875dae33f13f8719.png~tplv-obj.jpg"), ROSA_NEBULA(8912, "Rosa Nebula", 15000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f722088231103b66875dae33f13f8719.png~tplv-obj.jpg"),
I_M_HERE(9354, "I'm here", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/7006392a82d57452d5ef08dd90e169c1.png~tplv-obj.png"),
HOT_CHOCO_GDM_23(7523, "Hot Choco GDM 23", 30, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/f62f5912077d9af84256de288399125a~tplv-obj.png"),
KISS(5284, "Kiss", 150, "https://storage.streamdps.com/iblock/d3d/d3df4a0ecebd25c21e7ce5a6f910f8f1/d9ce143ac4707f74d8b1fe4708a92ab3.png"), KISS(5284, "Kiss", 150, "https://storage.streamdps.com/iblock/d3d/d3df4a0ecebd25c21e7ce5a6f910f8f1/d9ce143ac4707f74d8b1fe4708a92ab3.png"),
KISS_5481(5481, "Kiss", 150, "https://storage.streamdps.com/iblock/5cc/5cca201687ef878daf36dfe39fd26807/b2171e9cc191783679794f42246c4ceb.webp"), KISS_5481(5481, "Kiss", 150, "https://storage.streamdps.com/iblock/5cc/5cca201687ef878daf36dfe39fd26807/b2171e9cc191783679794f42246c4ceb.webp"),
@@ -181,6 +205,8 @@ public enum Gift {
COWBOY_HAT(8842, "Cowboy Hat", 199, "https://storage.streamdps.com/iblock/5f3/5f3df5eccbc82f458fdacd0f82d13e40/40980853c80e3da0e902a1db49ea9798.webp"), COWBOY_HAT(8842, "Cowboy Hat", 199, "https://storage.streamdps.com/iblock/5f3/5f3df5eccbc82f458fdacd0f82d13e40/40980853c80e3da0e902a1db49ea9798.webp"),
TURKEY_FACE_GDDEC(9581, "Turkey Face GDDec", 399, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/65349d1ef783fc207c1d2b54a8d521a7.png~tplv-obj.png"),
FESTA_JUNINA_S_HAT(8638, "Festa Junina's Hat", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/61b32ccce11b289b3c1db7438dfb4450~tplv-obj.png"), 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"), SPORTS_CAR(6089, "Sports Car", 7000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/e7ce188da898772f18aaffe49a7bd7db~tplv-obj.jpg"),
@@ -191,6 +217,8 @@ public enum Gift {
CHOCO_PIE(6503, "Choco Pie", 10, "https://storage.streamdps.com/iblock/5a7/5a7610069bd417a2847f34c6c0b2821d/5faa955edd066d1140abb048f32be815.webp"), CHOCO_PIE(6503, "Choco Pie", 10, "https://storage.streamdps.com/iblock/5a7/5a7610069bd417a2847f34c6c0b2821d/5faa955edd066d1140abb048f32be815.webp"),
I_M_BLUE(7707, "I'm blue", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c560ec76d5599198aaea9377c5ffab6e~tplv-obj.png"),
WHALE_DIVING(6084, "Whale diving", 1750, "https://storage.streamdps.com/iblock/5b2/5b27c388fe0d4dbe0a5f0a44ba7a8410/602a5a7cf538240f48ccf47c13237aa2.png"), WHALE_DIVING(6084, "Whale diving", 1750, "https://storage.streamdps.com/iblock/5b2/5b27c388fe0d4dbe0a5f0a44ba7a8410/602a5a7cf538240f48ccf47c13237aa2.png"),
WHALE_DIVING_6820(6820, "Whale diving", 2150, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/46fa70966d8e931497f5289060f9a794~tplv-obj.jpg"), WHALE_DIVING_6820(6820, "Whale diving", 2150, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/46fa70966d8e931497f5289060f9a794~tplv-obj.jpg"),
@@ -209,8 +237,12 @@ public enum Gift {
PEARL(5664, "Pearl", 800, "https://storage.streamdps.com/iblock/d42/d4241b9de546fb190964c12adeecabca/d03fe09dd3400422c55953555066487e.png"), PEARL(5664, "Pearl", 800, "https://storage.streamdps.com/iblock/d42/d4241b9de546fb190964c12adeecabca/d03fe09dd3400422c55953555066487e.png"),
PLAY_FOR_YOU(9535, "Play for you", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/182659e90a3432aa155e61c9c0d89df0.png~tplv-obj.png"),
LET_US_DANCE(7196, "Let Us Dance", 1999, "https://storage.streamdps.com/iblock/cae/caeaf097812661e65ff761aa60d5300a/444a1217ff8fbdeaf8e4682405871c7a.webp"), LET_US_DANCE(7196, "Let Us Dance", 1999, "https://storage.streamdps.com/iblock/cae/caeaf097812661e65ff761aa60d5300a/444a1217ff8fbdeaf8e4682405871c7a.webp"),
_2024_COUNTDOWN(9641, "2024 Countdown", 2024, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/a358a3ce18241dcc6e7d0b02d091d563.png~tplv-obj.jpg"),
MINI_SPEAKER(6042, "Mini Speaker", 1, "https://storage.streamdps.com/iblock/1b1/1b117cbff78bfb7f50ba4d90a16c6112/30f4b176fd30683e3cbfc9013fe96d82.png"), MINI_SPEAKER(6042, "Mini Speaker", 1, "https://storage.streamdps.com/iblock/1b1/1b117cbff78bfb7f50ba4d90a16c6112/30f4b176fd30683e3cbfc9013fe96d82.png"),
FLORAL_BLOOM(5788, "Floral Bloom", 1500, "https://storage.streamdps.com/iblock/858/85827a8e5266c8d4c697d9aa930fead6/149392b39b041febde90bc4ea80ce1a5.png"), FLORAL_BLOOM(5788, "Floral Bloom", 1500, "https://storage.streamdps.com/iblock/858/85827a8e5266c8d4c697d9aa930fead6/149392b39b041febde90bc4ea80ce1a5.png"),
@@ -233,10 +265,14 @@ public enum Gift {
ARCADE_GAME_7041(7041, "Arcade Game", 1200, "https://storage.streamdps.com/iblock/fd0/fd0785612b024900444a0a69083400ff/3181d6af50b05dd65a7ba75902bb5b94.webp"), ARCADE_GAME_7041(7041, "Arcade Game", 1200, "https://storage.streamdps.com/iblock/fd0/fd0785612b024900444a0a69083400ff/3181d6af50b05dd65a7ba75902bb5b94.webp"),
GORGEOUS_TROPHY(6741, "Gorgeous Trophy", 7000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/279c9495c2150e333bc4bc13761d177e~tplv-obj.png"),
IT_S_CORN(6928, "It's corn", 1, "https://storage.streamdps.com/iblock/d48/d48869b41c99cf004857fb74aff97552/75f200300cdaf3424287814ec55e9656.webp"), IT_S_CORN(6928, "It's corn", 1, "https://storage.streamdps.com/iblock/d48/d48869b41c99cf004857fb74aff97552/75f200300cdaf3424287814ec55e9656.webp"),
SUSHI_SET(7226, "Sushi Set", 20, "https://storage.streamdps.com/iblock/097/09752a51af505fbde2e9aa853d1ada62/3b981d4797111c44c45fbd8de5201fbe.webp"), SUSHI_SET(7226, "Sushi Set", 20, "https://storage.streamdps.com/iblock/097/09752a51af505fbde2e9aa853d1ada62/3b981d4797111c44c45fbd8de5201fbe.webp"),
YEAH_NAH(9576, "Yeah Nah", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4b20c5aab3841657a343be3769307805.png~tplv-obj.png"),
BIRTHDAY_GLASSES(6776, "Birthday Glasses", 199, "https://storage.streamdps.com/iblock/98d/98deaf0a4a818ba6b0333ca9aee4db59/97520c1ceae957c77ef1dbcc0f092187.webp"), BIRTHDAY_GLASSES(6776, "Birthday Glasses", 199, "https://storage.streamdps.com/iblock/98d/98deaf0a4a818ba6b0333ca9aee4db59/97520c1ceae957c77ef1dbcc0f092187.webp"),
SOCKS_AND_SANDALS(6618, "Socks and Sandals", 150, "https://storage.streamdps.com/iblock/da2/da28ef4030197f812686f10b2c3f06c7/7cb8ebff6f6028e2a56b2c0c268c3620.webp"), SOCKS_AND_SANDALS(6618, "Socks and Sandals", 150, "https://storage.streamdps.com/iblock/da2/da28ef4030197f812686f10b2c3f06c7/7cb8ebff6f6028e2a56b2c0c268c3620.webp"),
@@ -265,6 +301,8 @@ public enum Gift {
TIKTOK_VOLCANO(6869, "TikTok Volcano", 4000, "https://storage.streamdps.com/iblock/e6d/e6d4c0d014c552ec6e8eccb804a7659f/9678f5e24b6e9b069b43c4f84a536d9f.webp"), TIKTOK_VOLCANO(6869, "TikTok Volcano", 4000, "https://storage.streamdps.com/iblock/e6d/e6d4c0d014c552ec6e8eccb804a7659f/9678f5e24b6e9b069b43c4f84a536d9f.webp"),
KITTEN_PAW(9647, "Kitten Paw", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/332520d7b5085ce591396c8d2bb9d352.png~tplv-obj.png"),
_2023(7604, "2023", 1, "https://storage.streamdps.com/iblock/8fb/8fba3d5f6bf547ba8c94d3f393992d46/e3cfc1cfea30d7c139f7c4943f5d3b26.webp"), _2023(7604, "2023", 1, "https://storage.streamdps.com/iblock/8fb/8fba3d5f6bf547ba8c94d3f393992d46/e3cfc1cfea30d7c139f7c4943f5d3b26.webp"),
ROMAN_EMPIRE(7166, "Roman Empire", 199, "https://storage.streamdps.com/iblock/c77/c778c4e5cd1c68a50dcc06e4bfc3aa08/48edf8b190d98b0a3cc4623e6cc9a22c.webp"), ROMAN_EMPIRE(7166, "Roman Empire", 199, "https://storage.streamdps.com/iblock/c77/c778c4e5cd1c68a50dcc06e4bfc3aa08/48edf8b190d98b0a3cc4623e6cc9a22c.webp"),
@@ -285,6 +323,8 @@ public enum Gift {
PIZZA(7055, "Pizza", 40, "https://storage.streamdps.com/iblock/c9d/c9d7f483cc0059a1e8165bfbd1341688/307a559eb2b371b92b8ea36ae96bfa30.webp"), PIZZA(7055, "Pizza", 40, "https://storage.streamdps.com/iblock/c9d/c9d7f483cc0059a1e8165bfbd1341688/307a559eb2b371b92b8ea36ae96bfa30.webp"),
CHRISTMAS_POTATO(9587, "Christmas Potato", 10, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/5448f1f5157d3a4a88e0f57acf3dbfe0.png~tplv-obj.png"),
AMUSEMENT_PARK(9466, "Amusement Park", 17000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/12ecc01c2984c5d85bb508e80103a3cb.png~tplv-obj.jpg"), AMUSEMENT_PARK(9466, "Amusement Park", 17000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/12ecc01c2984c5d85bb508e80103a3cb.png~tplv-obj.jpg"),
CLUB(6417, "Club", 2000, "https://storage.streamdps.com/iblock/49b/49be18ae5914346ffcaf15a519ba9c1c/41326cb23d22010f0c4a8edf5bd27615.webp"), CLUB(6417, "Club", 2000, "https://storage.streamdps.com/iblock/49b/49be18ae5914346ffcaf15a519ba9c1c/41326cb23d22010f0c4a8edf5bd27615.webp"),
@@ -293,11 +333,15 @@ public enum Gift {
DANCING_CAPYBARAS(8806, "Dancing Capybaras", 2200, "https://storage.streamdps.com/iblock/ac2/ac2606f1dc2504c9a1b7974f40074c87/c243031480e8f2e4bbd8e7a43228ff1f.webp"), DANCING_CAPYBARAS(8806, "Dancing Capybaras", 2200, "https://storage.streamdps.com/iblock/ac2/ac2606f1dc2504c9a1b7974f40074c87/c243031480e8f2e4bbd8e7a43228ff1f.webp"),
HUSKY(7920, "Husky", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a2f5d595e9d96aec19a7c0ed5fa9b017~tplv-obj.png"),
DUCK(6265, "Duck", 299, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/e172f660a1d4f95813a3ace0fde42323~tplv-obj.jpg"), DUCK(6265, "Duck", 299, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/e172f660a1d4f95813a3ace0fde42323~tplv-obj.jpg"),
XMAS_MISHKA_BEAR(9617, "Xmas Mishka Bear", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/700c1c8817847317407cc2b8c6c9da42.png~tplv-obj.png"),
FLOWER_OVERFLOW(6148, "Flower Overflow", 4000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/743c4bb44e7e0bf251a7f2f5ada231ee~tplv-obj.jpg"), FLOWER_OVERFLOW(6148, "Flower Overflow", 4000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/743c4bb44e7e0bf251a7f2f5ada231ee~tplv-obj.jpg"),
PINK_SHOES(8815, "Pink shoes", 5, "https://storage.streamdps.com/iblock/387/387c559abfc868aa8f7d605a25748c14/06e08ba736cb17076b9c314058160ad2.webp"), PINK_SHOES(8890, "Pink Shoes", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/cba8a7c718988bd51c7b6055e9ab1ec4.png~tplv-obj.png"),
PINK_SHOES_8843(8843, "Pink shoes", 5, "https://storage.streamdps.com/iblock/e32/e328784531bfcd4773983c6a8e205a44/a3b5a6f4fa914fdf10b754ee59dc34a4.webp"), PINK_SHOES_8843(8843, "Pink shoes", 5, "https://storage.streamdps.com/iblock/e32/e328784531bfcd4773983c6a8e205a44/a3b5a6f4fa914fdf10b754ee59dc34a4.webp"),
@@ -313,8 +357,14 @@ public enum Gift {
SUNDAY_ROAST(6634, "Sunday Roast", 199, "https://storage.streamdps.com/iblock/218/218658dfe16bf8eeb11824cae5788028/95bbb526ea861ef2ba3dbe020431374f.webp"), SUNDAY_ROAST(6634, "Sunday Roast", 199, "https://storage.streamdps.com/iblock/218/218658dfe16bf8eeb11824cae5788028/95bbb526ea861ef2ba3dbe020431374f.webp"),
_2024_JOYLENS(9643, "2024 JoyLens", 224, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/36d82bbcd87c1914df84262d9bdd9b95.png~tplv-obj.jpg"),
LEDERHOSEN(6975, "Lederhosen", 10, "https://storage.streamdps.com/iblock/7c7/7c72a908dce6d9df4db0a6159be1751b/2ff181aa1fae6088a37f942d51401176.webp"), LEDERHOSEN(6975, "Lederhosen", 10, "https://storage.streamdps.com/iblock/7c7/7c72a908dce6d9df4db0a6159be1751b/2ff181aa1fae6088a37f942d51401176.webp"),
LOVE_U(7697, "LOVE U", 899, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/79d45877691333e2ba69a9098406e95c~tplv-obj.png"),
_2024(9639, "2024", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/484a44bbe62ce47687d1da31a6602bbd.png~tplv-obj.jpg"),
MATE_TEA(7089, "Mate tea", 10, "https://storage.streamdps.com/iblock/506/506e98699cdfefd679b35ea5170823b0/a95e9e3721c9b86e3342169b3211b30e.webp"), MATE_TEA(7089, "Mate tea", 10, "https://storage.streamdps.com/iblock/506/506e98699cdfefd679b35ea5170823b0/a95e9e3721c9b86e3342169b3211b30e.webp"),
TEAM_BRACELET(9139, "Team Bracelet", 2, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/54cb1eeca369e5bea1b97707ca05d189.png~tplv-obj.png"), TEAM_BRACELET(9139, "Team Bracelet", 2, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/54cb1eeca369e5bea1b97707ca05d189.png~tplv-obj.png"),
@@ -333,12 +383,16 @@ public enum Gift {
BIGFOOT(9147, "Bigfoot", 3000, "https://storage.streamdps.com/iblock/f95/f95a4fcfa57150610fa50542db5b0990/ecb879cd751e580d3fe92770788c1735.webp"), BIGFOOT(9147, "Bigfoot", 3000, "https://storage.streamdps.com/iblock/f95/f95a4fcfa57150610fa50542db5b0990/ecb879cd751e580d3fe92770788c1735.webp"),
BOO_THE_GHOST(9304, "Boo the Ghost", 88, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/cb909c78f2412e4927ea68d6af8e048f.png~tplv-obj.png"),
SO_BEAUTIFUL(7024, "So Beautiful", 1, "https://storage.streamdps.com/iblock/ad6/ad67c8d6c93ff4c375568b0bfabbed6f/c68dfd6fda7e8bd84f0bc7fa9ce47af0.webp"), SO_BEAUTIFUL(7024, "So Beautiful", 1, "https://storage.streamdps.com/iblock/ad6/ad67c8d6c93ff4c375568b0bfabbed6f/c68dfd6fda7e8bd84f0bc7fa9ce47af0.webp"),
SUNGLASSES(5509, "Sunglasses", 199, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/08af67ab13a8053269bf539fd27f3873.png~tplv-obj.jpg"), SUNGLASSES(5509, "Sunglasses", 199, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/08af67ab13a8053269bf539fd27f3873.png~tplv-obj.jpg"),
PANDA(37, "Panda", 5, "https://storage.streamdps.com/iblock/833/833aadcba552a8a2cc779dd8d4c537c7/f952c72ee1f40e4fcd07d713b3da6565.png"), PANDA(37, "Panda", 5, "https://storage.streamdps.com/iblock/833/833aadcba552a8a2cc779dd8d4c537c7/f952c72ee1f40e4fcd07d713b3da6565.png"),
MISS_YOU(8803, "Miss You", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/3c53396b922691a7520698f47105a753.png~tplv-obj.png"),
TIKTOK_UNIVERSE(6038, "TikTok Universe", 34999, "https://storage.streamdps.com/iblock/a79/a79204e0fab55cdc35ca0bdfa019face/8f06121e1c15be8566b3fc02982a2027.png"), TIKTOK_UNIVERSE(6038, "TikTok Universe", 34999, "https://storage.streamdps.com/iblock/a79/a79204e0fab55cdc35ca0bdfa019face/8f06121e1c15be8566b3fc02982a2027.png"),
TIKTOK_UNIVERSE_6039(6039, "TikTok Universe", 34999, "https://storage.streamdps.com/iblock/49d/49d934dc15cf5efc3ebef902a5974d56/04799e79cb4bd04a20d77d2f3fa9922d.png"), TIKTOK_UNIVERSE_6039(6039, "TikTok Universe", 34999, "https://storage.streamdps.com/iblock/49d/49d934dc15cf5efc3ebef902a5974d56/04799e79cb4bd04a20d77d2f3fa9922d.png"),
@@ -353,6 +407,8 @@ public enum Gift {
PINCH_CHEEK(6694, "Pinch Cheek", 199, "https://storage.streamdps.com/iblock/f6c/f6c95968ca266cbb2527af09989eaea0/27be132509198253b5c48e5495038e5b.png"), PINCH_CHEEK(6694, "Pinch Cheek", 199, "https://storage.streamdps.com/iblock/f6c/f6c95968ca266cbb2527af09989eaea0/27be132509198253b5c48e5495038e5b.png"),
HOLIDAY_STOCKING(7504, "Holiday Stocking", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e05de50999ebb446e15c4947b30d3140~tplv-obj.png"),
MARVIN_THE_MONKEY(6843, "Marvin the Monkey", 10, "https://storage.streamdps.com/iblock/31a/31a03cf8430fa062064dd9e544910de2/e7939198db3920aeaf3d95167712af0e.webp"), MARVIN_THE_MONKEY(6843, "Marvin the Monkey", 10, "https://storage.streamdps.com/iblock/31a/31a03cf8430fa062064dd9e544910de2/e7939198db3920aeaf3d95167712af0e.webp"),
ELEPHANT_TRUNK(8260, "Elephant trunk", 299, "https://storage.streamdps.com/iblock/1ea/1eafea22e99969312cda7c142d8eb3c5/59f72e0dce1bc4fcf83a34f56872b492.webp"), ELEPHANT_TRUNK(8260, "Elephant trunk", 299, "https://storage.streamdps.com/iblock/1ea/1eafea22e99969312cda7c142d8eb3c5/59f72e0dce1bc4fcf83a34f56872b492.webp"),
@@ -369,6 +425,8 @@ public enum Gift {
ROSE(5655, "Rose", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/eba3a9bb85c33e017f3648eaf88d7189~tplv-obj.jpg"), ROSE(5655, "Rose", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/eba3a9bb85c33e017f3648eaf88d7189~tplv-obj.jpg"),
THE_VAN_CAT(9650, "The Van Cat", 799, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6973dd1b6d3dee3ca3f0ebac3c1d2977.png~tplv-obj.png"),
TRENDING_FIGURE(9138, "Trending Figure", 999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/df7b556ccf369bf9a42fe83ec8a77acf.png~tplv-obj.jpg"), TRENDING_FIGURE(9138, "Trending Figure", 999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/df7b556ccf369bf9a42fe83ec8a77acf.png~tplv-obj.jpg"),
ROSA(7997, "Rosa", 10, "https://storage.streamdps.com/iblock/486/486a2490c987c2bb97b6068fd5aac5ab/49d9045fcfe94bbfbd08c3363bb4512a.webp"), ROSA(7997, "Rosa", 10, "https://storage.streamdps.com/iblock/486/486a2490c987c2bb97b6068fd5aac5ab/49d9045fcfe94bbfbd08c3363bb4512a.webp"),
@@ -385,12 +443,16 @@ public enum Gift {
COTTON_S_SHELL(8352, "Cotton's Shell", 5, "https://storage.streamdps.com/iblock/766/7665d59f0ef96aecd2dac6fc5b0c19a4/3b169a12b4f8686c68d596f6d47d2f77.webp"), COTTON_S_SHELL(8352, "Cotton's Shell", 5, "https://storage.streamdps.com/iblock/766/7665d59f0ef96aecd2dac6fc5b0c19a4/3b169a12b4f8686c68d596f6d47d2f77.webp"),
KIWI_BIRD(9667, "Kiwi Bird", 10, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/b73cb4aaa76a33efd881192589d65351.png~tplv-obj.png"),
FLAME_HEART(9087, "Flame heart", 1, "https://storage.streamdps.com/iblock/10d/10df10624cdeebe8ff5e0e89e8c8e960/28b8da2878a420f8465cbbc1ec1e6b58.webp"), 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"), 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"), TIKTOK_SHUTTLE(6751, "TikTok Shuttle", 20000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/8ef48feba8dd293a75ae9d4376fb17c9~tplv-obj.jpg"),
INDEPENDENCE_DAY(6633, "Independence Day", 10, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b967993872a6e40f3477d30545f8d2eb~tplv-obj.png"),
MAGGIE(7911, "Maggie", 15000, "https://storage.streamdps.com/iblock/a12/a12a1b23f1f6a19d728de84e1f43e21d/ff288346e9855a9bb6deb4450491028f.webp"), MAGGIE(7911, "Maggie", 15000, "https://storage.streamdps.com/iblock/a12/a12a1b23f1f6a19d728de84e1f43e21d/ff288346e9855a9bb6deb4450491028f.webp"),
PANDA_SKYDIVING(8812, "Panda skydiving", 2000, "https://storage.streamdps.com/iblock/a29/a29903a975ce45f7b9939b510412fcee/051afc0510a7349a9ebfcde9e0fdec24.webp"), PANDA_SKYDIVING(8812, "Panda skydiving", 2000, "https://storage.streamdps.com/iblock/a29/a29903a975ce45f7b9939b510412fcee/051afc0510a7349a9ebfcde9e0fdec24.webp"),
@@ -401,6 +463,8 @@ public enum Gift {
GAMER_CYBER_MASK(7895, "Gamer Cyber Mask", 399, "https://storage.streamdps.com/iblock/383/383652cc1fd3cae9402eeae3a8f5ee1e/df8a16397bb0ed28c0e522b4cfb26500.webp"), GAMER_CYBER_MASK(7895, "Gamer Cyber Mask", 399, "https://storage.streamdps.com/iblock/383/383652cc1fd3cae9402eeae3a8f5ee1e/df8a16397bb0ed28c0e522b4cfb26500.webp"),
XMAS_IN_LONDON(9680, "Xmas in London", 20000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/876204a6ad0b1b0e4675d9be42439183.png~tplv-obj.png"),
HAPPY_FATHER_S_DAY(8712, "Happy Father's Day", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/193eba78ded4d388a0b5a7ae95943796~tplv-obj.png"), 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(7542, "KO", 20, "https://storage.streamdps.com/iblock/e5e/e5efb63a21695a08d9647508aca3c95e/cffda8af4cc1a9f4a66eb01b11f4db85.webp"),
@@ -417,6 +481,8 @@ public enum Gift {
DON_T_DO_IT(7688, "Dont Do It", 500, "https://storage.streamdps.com/iblock/dca/dcac97e4190d46d113f4bdf2918ee173/4fae166b3f3273b9dbbc2a86bea0ec18.webp"), DON_T_DO_IT(7688, "Dont Do It", 500, "https://storage.streamdps.com/iblock/dca/dcac97e4190d46d113f4bdf2918ee173/4fae166b3f3273b9dbbc2a86bea0ec18.webp"),
BIRDS(5514, "Birds", 600, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0911b5726d912dabbf6ee4b0383352ea.png~tplv-obj.png"),
GOLDEN_TRUMPET(8767, "Golden Trumpet", 15, "https://storage.streamdps.com/iblock/a44/a4441a11d3cb073e855088a4eff72fdb/020b0d041c38b00b730b28806dbe6cc5.webp"), GOLDEN_TRUMPET(8767, "Golden Trumpet", 15, "https://storage.streamdps.com/iblock/a44/a4441a11d3cb073e855088a4eff72fdb/020b0d041c38b00b730b28806dbe6cc5.webp"),
HANDS_UP(8244, "Hands Up", 499, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/f4d906542408e6c87cf0a42f7426f0c6~tplv-obj.jpg"), HANDS_UP(8244, "Hands Up", 499, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/f4d906542408e6c87cf0a42f7426f0c6~tplv-obj.jpg"),
@@ -475,6 +541,8 @@ public enum Gift {
FOOTBALL_HELMET(7851, "Football Helmet", 50, "https://storage.streamdps.com/iblock/9cc/9cce61670c1a81b7954fcf3520dc15a2/b78182e9fd2ff1c6ae1256abd8e2e2bf.webp"), FOOTBALL_HELMET(7851, "Football Helmet", 50, "https://storage.streamdps.com/iblock/9cc/9cce61670c1a81b7954fcf3520dc15a2/b78182e9fd2ff1c6ae1256abd8e2e2bf.webp"),
NEMO(9704, "Nemo", 15, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/68fcf30cb3fb07e9546f5e7fbc2b0ac0.png~tplv-obj.png"),
SCORPIO_STAR_SIGN(7159, "Scorpio Star Sign", 9999, "https://storage.streamdps.com/iblock/c91/c91f3a3685b5c54d9e96d5f9443c4fda/50c48574ff60f328b7a50b80cd9aa4b8.webp"), 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"), SOCCER_BALL(5852, "Soccer Ball", 39, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e1932db6aea81bbddc4e7dc0229ac155~tplv-obj.png"),
@@ -487,8 +555,12 @@ public enum Gift {
HANGING_LIGHTS(5937, "Hanging Lights", 199, "https://storage.streamdps.com/iblock/e03/e03da22fa8c302dbf1d9439c65380549/6d9f912b5a9253f91c01ed58e3ccbe47.png"), HANGING_LIGHTS(5937, "Hanging Lights", 199, "https://storage.streamdps.com/iblock/e03/e03da22fa8c302dbf1d9439c65380549/6d9f912b5a9253f91c01ed58e3ccbe47.png"),
VACATION(8804, "Vacation", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/8f46e8eef9cbd5304fb802104c2b4ef4.png~tplv-obj.png"),
FOOTY(5893, "Footy", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/94f8ac5c7b6f90aba713b44ddac40bf1~tplv-obj.png"), FOOTY(5893, "Footy", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/94f8ac5c7b6f90aba713b44ddac40bf1~tplv-obj.png"),
GRUMPY_GLASSES(7846, "Grumpy Glasses", 99, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/6f38f8ed7442f69a105788b5c0c74a38~tplv-obj.png"),
BATIK_CLOTHES(5461, "Batik Clothes", 1000, "https://storage.streamdps.com/iblock/46d/46d0f497391a934d27d9b993f444d8b2/121af719b172eed61d8a75c1b1341c9d.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"), DANCING_QUEENS(9240, "Dancing queens", 20000, "https://storage.streamdps.com/iblock/c79/c793af446369ecef5238e73312c84ccd/464a76f3e6eaee9afc771f45a4bba9df.webp"),
@@ -581,12 +653,16 @@ public enum Gift {
BIRTHDAY_CAKE_9097(9097, "Birthday Cake", 1, "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"), BIRTHDAY_CAKE_9097(9097, "Birthday Cake", 1, "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"),
WITCHY_KITTY(7084, "Witchy Kitty", 30, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/dfce46f99a1206cca84f9092603e4783~tplv-obj.png"),
BANANA_LEAF_VESSEL(5991, "Banana leaf vessel", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8e635863e20cfa3651bd8a5b762ae72d~tplv-obj.png"), 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"), 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"), CONFETTI(5585, "Confetti", 100, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/cb4e11b3834e149f08e1cdcc93870b26~tplv-obj.jpg"),
PANETTONE_GDM_23(7477, "Panettone GDM 23", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/64ce2413a362442819b4551703b7b26c~tplv-obj.png"),
MATCH__MATCH_(7068, "Match! Match!", 200, "https://storage.streamdps.com/iblock/cb4/cb43e14c94694d3d3ae355bdfc517afd/494cd902b8018b35b6dc0f0016c89694.webp"), MATCH__MATCH_(7068, "Match! Match!", 200, "https://storage.streamdps.com/iblock/cb4/cb43e14c94694d3d3ae355bdfc517afd/494cd902b8018b35b6dc0f0016c89694.webp"),
SHINY_AIR_BALLOON(7123, "Shiny air balloon", 1000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/9e7ebdca64b8f90fcc284bb04ab92d24~tplv-obj.jpg"), SHINY_AIR_BALLOON(7123, "Shiny air balloon", 1000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/9e7ebdca64b8f90fcc284bb04ab92d24~tplv-obj.jpg"),
@@ -599,12 +675,18 @@ public enum Gift {
SUNSET_SPEEDWAY(6203, "Sunset Speedway", 10000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/df63eee488dc0994f6f5cb2e65f2ae49~tplv-obj.jpg"), SUNSET_SPEEDWAY(6203, "Sunset Speedway", 10000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/df63eee488dc0994f6f5cb2e65f2ae49~tplv-obj.jpg"),
NEW_YEAR_JOURNEY(9645, "New Year Journey", 12024, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/0ef9654d92354172fb9b3b364827940c.png~tplv-obj.jpg"),
DANCING_ADAM(7468, "Dancing Adam", 5000, "https://storage.streamdps.com/iblock/f5c/f5cda80a1f9853c49226a450faf26e8f/6318d17d7a2526f521123402d19a4c3e.webp"), DANCING_ADAM(7468, "Dancing Adam", 5000, "https://storage.streamdps.com/iblock/f5c/f5cda80a1f9853c49226a450faf26e8f/6318d17d7a2526f521123402d19a4c3e.webp"),
SCEPTRE(5300, "Sceptre", 150, "https://storage.streamdps.com/iblock/080/080d7e9dc934f98dd8cf5dce3b5075b2/a62a3963f6d2822177763b51d4328d37.png"), SCEPTRE(5300, "Sceptre", 150, "https://storage.streamdps.com/iblock/080/080d7e9dc934f98dd8cf5dce3b5075b2/a62a3963f6d2822177763b51d4328d37.png"),
SCEPTRE_7364(7364, "Sceptre", 150, "https://storage.streamdps.com/iblock/d2d/d2d1b0359f480a7db08e490364d056b2/bcb44a039dfa4d148af6cde9f233ea13.webp"), SCEPTRE_7364(7364, "Sceptre", 150, "https://storage.streamdps.com/iblock/d2d/d2d1b0359f480a7db08e490364d056b2/bcb44a039dfa4d148af6cde9f233ea13.webp"),
GOBBLE_GOBBLE(9604, "Gobble Gobble", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/ada9babc0b55cf005e8c8d13dfc30b42.png~tplv-obj.png"),
REINDEER(9670, "Reindeer", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4565fa0cd1dbf76463144b0d4cc50bf1.png~tplv-obj.png"),
SEAL_AND_WHALE(8381, "Seal and Whale", 34500, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/3781e9159ff09272826d3f2216ba36ef.png~tplv-obj.jpg"), SEAL_AND_WHALE(8381, "Seal and Whale", 34500, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/3781e9159ff09272826d3f2216ba36ef.png~tplv-obj.jpg"),
HAPPY_PARTY(8247, "Happy Party", 6999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/41774a8ba83c59055e5f2946d51215b4~tplv-obj.jpg"), HAPPY_PARTY(8247, "Happy Party", 6999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/41774a8ba83c59055e5f2946d51215b4~tplv-obj.jpg"),
@@ -615,8 +697,6 @@ public enum Gift {
CELEBRATION_TIME(6790, "Celebration Time", 6999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/e73e786041d8218d8e9dbbc150855f1b~tplv-obj.jpg"), 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"), 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"), PYRAMIDS(8416, "Pyramids", 15000, "https://storage.streamdps.com/iblock/988/988ffe82e8f3b235bd91dac1e31e708d/ad0365d14ba0480e5d6d60f6eb798608.webp"),
@@ -631,8 +711,12 @@ public enum Gift {
HI_JULY(6603, "Hi July", 1, "https://storage.streamdps.com/iblock/e03/e0301a9670584be92d945ff3cb889b99/0fbb7b11f916953201588b5bfbcb3f5a.png"), HI_JULY(6603, "Hi July", 1, "https://storage.streamdps.com/iblock/e03/e0301a9670584be92d945ff3cb889b99/0fbb7b11f916953201588b5bfbcb3f5a.png"),
SUMMER_IRIS_(6655, "Summer Iris ", 30, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/cb591f5b5729fa6e64cac57c78724981~tplv-obj.png"),
LIGHTNING_BOLT_(6652, "Lightning Bolt ", 1, "https://storage.streamdps.com/iblock/265/2655cafe6afc1fa0fca76a732bad4730/bfb4abdf65da281c7ccf0b682f3406a3.webp"), LIGHTNING_BOLT_(6652, "Lightning Bolt ", 1, "https://storage.streamdps.com/iblock/265/2655cafe6afc1fa0fca76a732bad4730/bfb4abdf65da281c7ccf0b682f3406a3.webp"),
AURORA(8754, "Aurora", 12000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1f59f5593ce135325c1a034825cec18c.png~tplv-obj.png"),
CAMPING_NIGHT(6520, "Camping Night", 13999, "https://storage.streamdps.com/iblock/be3/be3c39c622d80d029c5e752134ac6978/c95701f2e894403ca47de971f2ced0d8.png"), CAMPING_NIGHT(6520, "Camping Night", 13999, "https://storage.streamdps.com/iblock/be3/be3c39c622d80d029c5e752134ac6978/c95701f2e894403ca47de971f2ced0d8.png"),
MAKE_IT_RAIN(5336, "Make it rain", 500, "https://storage.streamdps.com/iblock/770/770e03c64144e6d7830e884cd7140a8a/47af803e978121e760d649d47e67de50.png"), MAKE_IT_RAIN(5336, "Make it rain", 500, "https://storage.streamdps.com/iblock/770/770e03c64144e6d7830e884cd7140a8a/47af803e978121e760d649d47e67de50.png"),
@@ -657,10 +741,14 @@ public enum Gift {
STORMS_AT_SEA(9514, "Storms at sea", 2200, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4918fbbdf220873dd8cae4c94d1ae037.png~tplv-obj.png"), STORMS_AT_SEA(9514, "Storms at sea", 2200, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4918fbbdf220873dd8cae4c94d1ae037.png~tplv-obj.png"),
CHRISTMAS_WREATH_G(7527, "Christmas Wreath G", 10, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7842b50135e089334fc40d9705bb53c7~tplv-obj.png"),
SUPERHERO_FIGHT(8814, "Superhero fight", 30000, "https://storage.streamdps.com/iblock/d6b/d6b1c955153c8f8c5048d6c8f0d1b418/97d04b889e64328e9ab07224f6072b5f.webp"), 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"), COOKIE(6883, "Cookie", 5, "https://storage.streamdps.com/iblock/fd2/fd20c8c619b1d43efb9f2fe1923c48a7/45c056f74c9f214dc55d464eab43b224.webp"),
ELF_GDM_23(9363, "Elf GDM 23", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/60e5289b379660cc562742cf987a2d35.png~tplv-obj.png"),
DOG_BONE(8108, "Dog Bone", 10, "https://storage.streamdps.com/iblock/8ba/8badf8e0a5bcbf8d98ed6c4fc0e16c69/b0a8a8020986eb564713c042d23f83b2.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"), RUSSIAN_CREPES(5547, "Russian Crepes", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8525a07c6bf16a74eee66e9ad119b3b8.png~tplv-obj.png"),
@@ -679,12 +767,16 @@ public enum Gift {
ICE_CREAM_CONE(5827, "Ice Cream Cone", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/968820bc85e274713c795a6aef3f7c67~tplv-obj.jpg"), ICE_CREAM_CONE(5827, "Ice Cream Cone", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/968820bc85e274713c795a6aef3f7c67~tplv-obj.jpg"),
GOOD_MORNING(8269, "Good Morning", 399, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5c1a28f3aa7eefc27491f3020748ce54~tplv-obj.png"),
FLY_LOVE(8248, "Fly Love", 19999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/a598ba4c7024f4d46c1268be4d82f901~tplv-obj.jpg"), FLY_LOVE(8248, "Fly Love", 19999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/a598ba4c7024f4d46c1268be4d82f901~tplv-obj.jpg"),
BEACH_DATE(6132, "Beach Date", 899, "https://storage.streamdps.com/iblock/504/504a5dfef033a7e90e4f07987b0c0f28/70ec484fc4c798d3e09a7fbcae83ee95.png"), BEACH_DATE(6132, "Beach Date", 899, "https://storage.streamdps.com/iblock/504/504a5dfef033a7e90e4f07987b0c0f28/70ec484fc4c798d3e09a7fbcae83ee95.png"),
TRAVEL_WITH_YOU(6233, "Travel with You", 999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/753098e5a8f45afa965b73616c04cf89~tplv-obj.jpg"), TRAVEL_WITH_YOU(6233, "Travel with You", 999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/753098e5a8f45afa965b73616c04cf89~tplv-obj.jpg"),
GINGEBREAD_MAN(9671, "Gingebread Man", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/2399f65414f77419ec7d5e9274dc8e0e.png~tplv-obj.png"),
CHOCOLATE_STICK(6002, "Chocolate Stick", 1, "https://storage.streamdps.com/iblock/5c9/5c9487af2038c340fdbeb0b9ea4ff83e/b377ae8024881b93822f7b0a6bfe04e8.png"), CHOCOLATE_STICK(6002, "Chocolate Stick", 1, "https://storage.streamdps.com/iblock/5c9/5c9487af2038c340fdbeb0b9ea4ff83e/b377ae8024881b93822f7b0a6bfe04e8.png"),
DJ_ALIEN(8988, "DJ Alien", 5000, "https://storage.streamdps.com/iblock/67c/67cd7b9372f25b4f3558eacdfb83dc8b/059b6bf7b8c268d525fd9295fac0eb61.webp"), DJ_ALIEN(8988, "DJ Alien", 5000, "https://storage.streamdps.com/iblock/67c/67cd7b9372f25b4f3558eacdfb83dc8b/059b6bf7b8c268d525fd9295fac0eb61.webp"),
@@ -703,12 +795,16 @@ public enum Gift {
TULIP_BOX(5325, "Tulip Box", 200, "https://storage.streamdps.com/iblock/d44/d4471e5deb9cb5831f846ca4c9df9c5d/7d1236ecd67b3e655c3dfd72673a423d.png"), TULIP_BOX(5325, "Tulip Box", 200, "https://storage.streamdps.com/iblock/d44/d4471e5deb9cb5831f846ca4c9df9c5d/7d1236ecd67b3e655c3dfd72673a423d.png"),
COOL_(9583, "Cool!", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/424c61f16c16919f169fd0352bd24661.png~tplv-obj.png"),
SQUIRREL(7213, "Squirrel", 1, "https://storage.streamdps.com/iblock/5c3/5c37dce1eab0d67386329f3a2920a874/38104bd52d316ea76464433b3b07dea7.webp"), 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"), 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"), METEOR_SHOWER(6563, "Meteor Shower", 3000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/71883933511237f7eaa1bf8cd12ed575~tplv-obj.jpg"),
GINGERMAN_PARTY(9668, "Gingerman Party", 1200, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/008a9554e736642f1b2dca9f198bb710.png~tplv-obj.png"),
CAKE(5720, "Cake", 20, "https://storage.streamdps.com/iblock/edb/edbe349c5a4be01ec1fbf2225d0f48dc/4169ef7f0263177384205df6663451c8.png"), CAKE(5720, "Cake", 20, "https://storage.streamdps.com/iblock/edb/edbe349c5a4be01ec1fbf2225d0f48dc/4169ef7f0263177384205df6663451c8.png"),
MARCH(7976, "March", 1, "https://storage.streamdps.com/iblock/ba4/ba44cb084cab8c9c63b4513a145813f4/56531d239586a3d4552859cb2b23314d.webp"), MARCH(7976, "March", 1, "https://storage.streamdps.com/iblock/ba4/ba44cb084cab8c9c63b4513a145813f4/56531d239586a3d4552859cb2b23314d.webp"),
@@ -721,12 +817,16 @@ public enum Gift {
STAR(6432, "Star", 99, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/485175fda92f4d2f862e915cbcf8f5c4~tplv-obj.jpg"), STAR(6432, "Star", 99, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/485175fda92f4d2f862e915cbcf8f5c4~tplv-obj.jpg"),
SPRING_TRAIN(8152, "Spring train", 3999, "https://storage.streamdps.com/iblock/035/035862dc0952468fc95f02995cec0f22/eeb69650806ea4c2e22558ef4b5e2b47.webp"),
DALLAH(8097, "Dallah", 10, "https://storage.streamdps.com/iblock/402/402ec89b471788374f63bd0d906e49c2/bbb7055a407d84bd3be843f5ca9fdc4b.webp"), DALLAH(8097, "Dallah", 10, "https://storage.streamdps.com/iblock/402/402ec89b471788374f63bd0d906e49c2/bbb7055a407d84bd3be843f5ca9fdc4b.webp"),
GB_NORTH_POLE(9657, "GB North Pole", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/79715a53c41619e7b205eb26e57926d4.png~tplv-obj.png"),
CHRISTMAS_CAROUSEG(7525, "Christmas CarouseG", 2000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b5ba3941f7389da7495b659e888ea61a~tplv-obj.png"),
THUNDER_HAMMER(6635, "Thunder Hammer", 1, "https://storage.streamdps.com/iblock/401/401ff4c96ee1f2301db5a6fed5d53103/830012ba80bac708f9281417ede8696c.png"), THUNDER_HAMMER(6635, "Thunder Hammer", 1, "https://storage.streamdps.com/iblock/401/401ff4c96ee1f2301db5a6fed5d53103/830012ba80bac708f9281417ede8696c.png"),
FESTIVE_TINY_DINY(9615, "Festive Tiny Diny", 15, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f2a8c2967c7153e9077bb469f2e42317.png~tplv-obj.png"),
WOLF(8778, "Wolf", 5000, "https://storage.streamdps.com/iblock/70f/70fa80dd2d07f44f28db148328735a6b/68c7215817c6143ac33036933fcf777d.webp"), WOLF(8778, "Wolf", 5000, "https://storage.streamdps.com/iblock/70f/70fa80dd2d07f44f28db148328735a6b/68c7215817c6143ac33036933fcf777d.webp"),
DAISIES(6447, "Daisies", 1, "https://storage.streamdps.com/iblock/e11/e110e47562d77ab5fa26cc31e840f801/a4a1823ef2c1bc65c4dc2a4e82ec446b.png"), DAISIES(6447, "Daisies", 1, "https://storage.streamdps.com/iblock/e11/e110e47562d77ab5fa26cc31e840f801/a4a1823ef2c1bc65c4dc2a4e82ec446b.png"),
@@ -735,6 +835,12 @@ public enum Gift {
CAMPING(6322, "Camping", 250, "https://storage.streamdps.com/iblock/9a9/9a9370a392311149be37e7c40c3e960d/ecb9dcdacf3a2ae0abef79baf0c4f41c.webp"), CAMPING(6322, "Camping", 250, "https://storage.streamdps.com/iblock/9a9/9a9370a392311149be37e7c40c3e960d/ecb9dcdacf3a2ae0abef79baf0c4f41c.webp"),
LUCKY_AIRDROP_BOX(9717, "Lucky Airdrop Box", 999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6ae56f08ae3ee57ea2dda0025bfd39d3.png~tplv-obj.jpg"),
GOLDEN(7921, "Golden", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b97f58dcb0250489ae98529bcb0542ca~tplv-obj.png"),
BALLET_DANCER(5549, "Ballet Dancer", 500, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c09cc8ce49476d2c46e9c8af6189d5f4.png~tplv-obj.png"),
FAIRY_WINGS(9463, "Fairy Wings", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/e504dc2f313b8c6df9e99a848e1b3a99.png~tplv-obj.png"), FAIRY_WINGS(9463, "Fairy Wings", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/e504dc2f313b8c6df9e99a848e1b3a99.png~tplv-obj.png"),
TICKET(6856, "Ticket", 10, "https://storage.streamdps.com/iblock/434/434746bffe494ac6ad2eb5e7e4384955/92e426ea0b4d4a9f89d7e2786115cd20.webp"), TICKET(6856, "Ticket", 10, "https://storage.streamdps.com/iblock/434/434746bffe494ac6ad2eb5e7e4384955/92e426ea0b4d4a9f89d7e2786115cd20.webp"),
@@ -751,10 +857,14 @@ public enum Gift {
RIO_DE_JANEIRO(7218, "Rio de Janeiro", 9999, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/34c0eb43c3d50e8ab64408171ebbe733~tplv-obj.png"), RIO_DE_JANEIRO(7218, "Rio de Janeiro", 9999, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/34c0eb43c3d50e8ab64408171ebbe733~tplv-obj.png"),
REALLY_CURIOUS(9703, "Really Curious", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/793ba68723567b695b12f2ef08dc1484.png~tplv-obj.png"),
BLOOMING_RIBBONS(9498, "Blooming Ribbons", 1000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f76750ab58ee30fc022c9e4e11d25c9d.png~tplv-obj.jpg"), 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"), CORNFLOWER(8186, "Cornflower", 5, "https://storage.streamdps.com/iblock/025/025c50c390f6a12148a69728284c7298/36b50fe529db9d7db028b0774842e103.webp"),
SPIN_WITH_ME_GDM(9152, "Spin with me GDM", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/149ac2e87d05490d7d251149cefe27a2.png~tplv-obj.png"),
ASMR_TIME_(6990, "ASMR Time ", 10, "https://storage.streamdps.com/iblock/49d/49dccba4525df92ed17678cc6ea47e95/b2c8c52d5294bb531d7d87a4c3ff97fe.webp"), ASMR_TIME_(6990, "ASMR Time ", 10, "https://storage.streamdps.com/iblock/49d/49dccba4525df92ed17678cc6ea47e95/b2c8c52d5294bb531d7d87a4c3ff97fe.webp"),
POOL_PARTY(5938, "Pool Party", 4999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/4147c5bcfad9623c693f83d5d6cba1f7~tplv-obj.jpg"), POOL_PARTY(5938, "Pool Party", 4999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/4147c5bcfad9623c693f83d5d6cba1f7~tplv-obj.jpg"),
@@ -793,6 +903,8 @@ public enum Gift {
SPACESHIP(6588, "Spaceship", 13999, "https://storage.streamdps.com/iblock/fb1/fb1096568dcc97c2575dec7441d0d651/245c4c7ce9bf5d5378586eb3a2478b42.webp"), SPACESHIP(6588, "Spaceship", 13999, "https://storage.streamdps.com/iblock/fb1/fb1096568dcc97c2575dec7441d0d651/245c4c7ce9bf5d5378586eb3a2478b42.webp"),
PINATA(6800, "Pinata", 699, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c8a18d43dc9fb4598d7e991ebeb958ae~tplv-obj.png"),
BIRTHDAY_CROWN(9096, "Birthday Crown", 99, "https://storage.streamdps.com/iblock/c07/c073f2d950a252aa24b7343655208c8a/68f6af6dc16ab51396cef18f50a43792.webp"), BIRTHDAY_CROWN(9096, "Birthday Crown", 99, "https://storage.streamdps.com/iblock/c07/c073f2d950a252aa24b7343655208c8a/68f6af6dc16ab51396cef18f50a43792.webp"),
LION_S_MANE(7985, "Lion's Mane", 500, "https://storage.streamdps.com/iblock/267/2670a5a8c9666b7afffb3255c2c104ee/abe9a0e7a6ef8b83d94df90f3a356748.webp"), LION_S_MANE(7985, "Lion's Mane", 500, "https://storage.streamdps.com/iblock/267/2670a5a8c9666b7afffb3255c2c104ee/abe9a0e7a6ef8b83d94df90f3a356748.webp"),
@@ -819,8 +931,12 @@ public enum Gift {
NEW_UNIVERSE(9081, "New Universe", 1, "https://storage.streamdps.com/iblock/ff9/ff906a964a6ad9c4504438302d9354b8/3ee4796c239930c395afb3d7ef10295a.webp"), NEW_UNIVERSE(9081, "New Universe", 1, "https://storage.streamdps.com/iblock/ff9/ff906a964a6ad9c4504438302d9354b8/3ee4796c239930c395afb3d7ef10295a.webp"),
SPARKLING_COUNTDOWN(9644, "Sparkling Countdown", 2024, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/d6b4539ed9683707bdefe268f6575e74.png~tplv-obj.jpg"),
DRUMS(7882, "Drums", 1000, "https://storage.streamdps.com/iblock/449/449c40e5064f776737e24fd6460195a1/477a014b033108643c2d674b2cce2d0a.webp"), DRUMS(7882, "Drums", 1000, "https://storage.streamdps.com/iblock/449/449c40e5064f776737e24fd6460195a1/477a014b033108643c2d674b2cce2d0a.webp"),
ELFS_HAT_(9706, "Elfs Hat ", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9857a040c92b34d6a261201a93c185f.png~tplv-obj.png"),
PUMPKIN_PIE(7396, "Pumpkin Pie", 5, "https://storage.streamdps.com/iblock/abf/abf5efb8fac6f64568b472c3afdb3e25/f85e4ef55b8c7d03f81351babd833c69.webp"), PUMPKIN_PIE(7396, "Pumpkin Pie", 5, "https://storage.streamdps.com/iblock/abf/abf5efb8fac6f64568b472c3afdb3e25/f85e4ef55b8c7d03f81351babd833c69.webp"),
EMAIL_MESSAGE(6199, "Email Message", 1000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/c959df6dbffd6f07849d22d2c3c07861~tplv-obj.jpg"), EMAIL_MESSAGE(6199, "Email Message", 1000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/c959df6dbffd6f07849d22d2c3c07861~tplv-obj.jpg"),
@@ -831,10 +947,14 @@ public enum Gift {
HI_MARCH(7977, "Hi March", 88, "https://storage.streamdps.com/iblock/e22/e2266686271c7a90ff04517f248c6f73/0459d679c01a5bfa5a4be1d61ec81ec8.webp"), HI_MARCH(7977, "Hi March", 88, "https://storage.streamdps.com/iblock/e22/e2266686271c7a90ff04517f248c6f73/0459d679c01a5bfa5a4be1d61ec81ec8.webp"),
CANDY_CANE_GUN(7498, "Candy Cane Gun", 799, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/58ef7964e32adc5fc47c5706a02e4ff0~tplv-obj.png"),
FANTASTIC(6813, "Fantastic", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a1b2204b06aa19d45a0338e9f0099ea7~tplv-obj.png"), 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"), HEDGEHOG(6868, "Hedgehog", 299, "https://storage.streamdps.com/iblock/841/841e924150793d6961df0a1c89cc67ca/5886839b7de0b1289303081f9af380f8.webp"),
JAKARTA_ROUNDABOUT(6452, "Jakarta Roundabout", 16999, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/31f67910fc5858cf087da65746f1f9f3~tplv-obj.png"),
LIVE_FEST(9334, "LIVE Fest", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1e98afffef90ed4b2cc9c9ebb88e3608.png~tplv-obj.png"), 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"), I_LOVE_TR(7139, "I LOVE TR", 1, "https://storage.streamdps.com/iblock/84d/84d68e92c471e7da792aa98d856c824c/7728ac60043efb9c96e2ce0f77dbef31.webp"),
@@ -869,10 +989,16 @@ public enum Gift {
CRYSTAL_BALL(6428, "Crystal Ball", 1700, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7e4f9a99b7003ae05186f5324aae9fbf~tplv-obj.png"), CRYSTAL_BALL(6428, "Crystal Ball", 1700, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7e4f9a99b7003ae05186f5324aae9fbf~tplv-obj.png"),
HAPPY_WEEKEND(8264, "Happy Weekend", 599, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b04f104e717798235cd3edaa6703e6a3~tplv-obj.png"),
PHOENIX(7319, "Phoenix", 25999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/ef248375c4167d70c1642731c732c982~tplv-obj.jpg"), 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"), BOUQUET_FLOWER(5780, "Bouquet Flower", 30, "https://storage.streamdps.com/iblock/ceb/cebb5d5f7004d6ccf9336ae20281be88/5061b1767c2325fe6704eb08d97c5cb8.png"),
PUMPKIN_SPICE_LATTE(9242, "Pumpkin Spice Latte", 10, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0636d91615f7417ddd5f29438bf5debe~tplv-obj.png"),
SHIBA_COOKIE(9770, "Shiba Cookie", 10, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4ea5282e7f61cbeee1214422d40ad407.png~tplv-obj.png"),
CHILI(7086, "Chili", 1, "https://storage.streamdps.com/iblock/4e4/4e476335c1d0a47efc33a40688d0fc75/ab85d5eccda4bf6509874c9533739b62.webp"), CHILI(7086, "Chili", 1, "https://storage.streamdps.com/iblock/4e4/4e476335c1d0a47efc33a40688d0fc75/ab85d5eccda4bf6509874c9533739b62.webp"),
GO_SNACKING(7021, "Go Snacking", 1, "https://storage.streamdps.com/iblock/666/6661d244aca6ec5f3de19372316e871e/f967ba18a333cd1489396cb608371824.webp"), GO_SNACKING(7021, "Go Snacking", 1, "https://storage.streamdps.com/iblock/666/6661d244aca6ec5f3de19372316e871e/f967ba18a333cd1489396cb608371824.webp"),
@@ -883,6 +1009,8 @@ public enum Gift {
CHILL(6704, "Chill", 5, "https://storage.streamdps.com/iblock/7df/7dfcee6b2702691bf9c8ca0966b3c4b1/144aa8fff9ce8c64aa7fcb507bf6c1cd.webp"), CHILL(6704, "Chill", 5, "https://storage.streamdps.com/iblock/7df/7dfcee6b2702691bf9c8ca0966b3c4b1/144aa8fff9ce8c64aa7fcb507bf6c1cd.webp"),
GINGERBREAD_MAN(9656, "Gingerbread man", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/af01db3e3cb9f54ea2cb421fab6062bc.png~tplv-obj.png"),
TAKE_A_DRIVE(7624, "Take a Drive", 1200, "https://storage.streamdps.com/iblock/fb5/fb50bcd0bb83c3a338d7d5196a7e987c/aa0e7affca4b6d34877244af7f5b611c.webp"), TAKE_A_DRIVE(7624, "Take a Drive", 1200, "https://storage.streamdps.com/iblock/fb5/fb50bcd0bb83c3a338d7d5196a7e987c/aa0e7affca4b6d34877244af7f5b611c.webp"),
TAKE_A_DRIVE_7631(7631, "Take a Drive", 1200, "https://storage.streamdps.com/iblock/c5b/c5b1ae3782864918bcb70d9e92046b87/8f3b4f952004f1aaef4bccfd69b19568.webp"), TAKE_A_DRIVE_7631(7631, "Take a Drive", 1200, "https://storage.streamdps.com/iblock/c5b/c5b1ae3782864918bcb70d9e92046b87/8f3b4f952004f1aaef4bccfd69b19568.webp"),
@@ -901,6 +1029,8 @@ public enum Gift {
BALALAIKA(5927, "Balalaika", 100, "https://storage.streamdps.com/iblock/d88/d88bc38371769262c006dccbaa43c9ff/1e0f5adda0546879e07126492ba6001c.webp"), BALALAIKA(5927, "Balalaika", 100, "https://storage.streamdps.com/iblock/d88/d88bc38371769262c006dccbaa43c9ff/1e0f5adda0546879e07126492ba6001c.webp"),
POPCORN(9111, "Popcorn", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/676d2d4c31a8979f1fd06cdf5ecd922f~tplv-obj.png"),
DRACO(8613, "Draco", 5000, "https://storage.streamdps.com/iblock/48f/48f1a8d280e271929718525560ad42a8/3021d84608e0c5da388f1f6534011a6f.webp"), DRACO(8613, "Draco", 5000, "https://storage.streamdps.com/iblock/48f/48f1a8d280e271929718525560ad42a8/3021d84608e0c5da388f1f6534011a6f.webp"),
SPEEDSTER(8418, "Speedster", 15000, "https://storage.streamdps.com/iblock/96a/96a5a249a1701c3c03e0b2427bad3b2f/63fb5582c89c17f275fc99505505b719.webp"), SPEEDSTER(8418, "Speedster", 15000, "https://storage.streamdps.com/iblock/96a/96a5a249a1701c3c03e0b2427bad3b2f/63fb5582c89c17f275fc99505505b719.webp"),
@@ -941,8 +1071,6 @@ public enum Gift {
COOPER_SKATES_HOME(6865, "Cooper Skates Home", 599, "https://storage.streamdps.com/iblock/041/04184b09ec8e7bf137d33cf57ce4eec9/3c2e360b023b9980e54e9d9a394883b9.webp"), 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(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"), BIRTHDAY_PARTY_9095(9095, "Birthday Party", 6999, "https://storage.streamdps.com/iblock/d0d/d0d1164a9ed81239b70cb25b93927023/d0dba293643c67dc33c1f4dda04e5b50.webp"),
@@ -963,10 +1091,14 @@ public enum Gift {
STAR_THRONE_8420(8420, "Star Throne", 7999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/30063f6bc45aecc575c49ff3dbc33831~tplv-obj.jpg"), STAR_THRONE_8420(8420, "Star Throne", 7999, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/30063f6bc45aecc575c49ff3dbc33831~tplv-obj.jpg"),
MISTLETOE_GDM_23(7475, "Mistletoe GDM 23", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/3527969b8c27e3194e61ff0787a9c3c2~tplv-obj.png"),
PLANET(5954, "Planet", 15000, "https://storage.streamdps.com/iblock/dc5/dc50bbe9b153d9f714919d386325a223/b296c2101cb24bc65e8abd2977d6c123.png"), PLANET(5954, "Planet", 15000, "https://storage.streamdps.com/iblock/dc5/dc50bbe9b153d9f714919d386325a223/b296c2101cb24bc65e8abd2977d6c123.png"),
DISCO_BALL(5540, "Disco Ball", 1000, "https://storage.streamdps.com/iblock/3e5/3e5e6d701c936bef5b85a0315b841184/e46e6c47d88c9bb81d27eb700456137a.webp"), DISCO_BALL(5540, "Disco Ball", 1000, "https://storage.streamdps.com/iblock/3e5/3e5e6d701c936bef5b85a0315b841184/e46e6c47d88c9bb81d27eb700456137a.webp"),
DISCO_BALL_8250(8250, "Disco ball", 1000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a53d3ef956eb2f1aa7a7db46024c70bb~tplv-obj.png"),
OUD(5301, "Oud", 300, "https://storage.streamdps.com/iblock/6ba/6ba340c152f9154c8d7c45d18bcb5914/6be86ee5d8a8ebaa17d93b766589b151.png"), OUD(5301, "Oud", 300, "https://storage.streamdps.com/iblock/6ba/6ba340c152f9154c8d7c45d18bcb5914/6be86ee5d8a8ebaa17d93b766589b151.png"),
SUITCASE(8597, "Suitcase", 199, "https://storage.streamdps.com/iblock/50f/50f04937063753d6de255d2b5a080c1c/4f101c7c50ddbe8bd26a2ce5f8c16896.webp"), SUITCASE(8597, "Suitcase", 199, "https://storage.streamdps.com/iblock/50f/50f04937063753d6de255d2b5a080c1c/4f101c7c50ddbe8bd26a2ce5f8c16896.webp"),
@@ -981,6 +1113,8 @@ public enum Gift {
DAFFODILS(6435, "Daffodils", 99, "https://storage.streamdps.com/iblock/2ed/2edf26fa90a7b3ca44c0d7c77a765c77/c333c68579488e9a36f4130481932b7c.png"), DAFFODILS(6435, "Daffodils", 99, "https://storage.streamdps.com/iblock/2ed/2edf26fa90a7b3ca44c0d7c77a765c77/c333c68579488e9a36f4130481932b7c.png"),
MARACAS(7032, "Maracas", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/00204efcf0573192ad5d872c7beeaf5b~tplv-obj.png"),
TINY_DINY(6560, "Tiny Diny", 10, "https://storage.streamdps.com/iblock/504/50412c09b6d36020e28ee09ceb45f22b/aa96e43206d46ed5f25e8f476f67da45.png"), TINY_DINY(6560, "Tiny Diny", 10, "https://storage.streamdps.com/iblock/504/50412c09b6d36020e28ee09ceb45f22b/aa96e43206d46ed5f25e8f476f67da45.png"),
TINY_DINY_7591(7591, "Tiny Diny", 10, "https://storage.streamdps.com/iblock/b24/b24309d4ea6722875678e492ae12fb3f/864ac7928a78b43be2d1ee93915a53f5.webp"), TINY_DINY_7591(7591, "Tiny Diny", 10, "https://storage.streamdps.com/iblock/b24/b24309d4ea6722875678e492ae12fb3f/864ac7928a78b43be2d1ee93915a53f5.webp"),
@@ -993,10 +1127,16 @@ public enum Gift {
TTEOKBOKKI(5645, "Tteokbokki", 5, "https://storage.streamdps.com/iblock/81c/81ca5954462f21f506095fe410dd2aaf/c07e9b0bb8d0559874b780495cc0e451.png"), TTEOKBOKKI(5645, "Tteokbokki", 5, "https://storage.streamdps.com/iblock/81c/81ca5954462f21f506095fe410dd2aaf/c07e9b0bb8d0559874b780495cc0e451.png"),
CRYSTAL_HEART(5559, "Crystal Heart", 499, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ae46ac6582a606009643440fe4138eb4.png~tplv-obj.png"),
LOLLIPOP(5657, "Lollipop", 10, "https://storage.streamdps.com/iblock/857/85755cf3d5e2e5349efff7eeedbfff46/b5e02fcff0a73b906d530028d460e59d.png"), LOLLIPOP(5657, "Lollipop", 10, "https://storage.streamdps.com/iblock/857/85755cf3d5e2e5349efff7eeedbfff46/b5e02fcff0a73b906d530028d460e59d.png"),
FLOWER_FESTIVAL(8442, "Flower Festival", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9bfe63e39b581a69ff944758c3eae5a0~tplv-obj.png"),
GRAPES(7234, "Grapes", 1, "https://storage.streamdps.com/iblock/442/442580106ac8748b79ef450eb25b5981/df624c619c48b583adee184bca134c80.webp"), GRAPES(7234, "Grapes", 1, "https://storage.streamdps.com/iblock/442/442580106ac8748b79ef450eb25b5981/df624c619c48b583adee184bca134c80.webp"),
TSAR(5524, "Tsar", 100, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/cb1c3e6263d4b6c08301f8798dcb5a9b.png~tplv-obj.png"),
LLAMA_GREETINGS(6531, "Llama Greetings", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a6b95ce6350f5f4bdff6880ac6993789~tplv-obj.png"), 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"), SAM_THE_WHALE(8391, "Sam the Whale", 30000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/f48a1887eb88238738996bb997b31c0f.png~tplv-obj.jpg"),
@@ -1017,6 +1157,8 @@ public enum Gift {
GOOD_NIGHT(8268, "Good Night", 399, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b7b55087141bd5f965eb31a99a5f157b~tplv-obj.png"), GOOD_NIGHT(8268, "Good Night", 399, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b7b55087141bd5f965eb31a99a5f157b~tplv-obj.png"),
TRAIN_TO_2024(9642, "Train to 2024", 12024, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/0cb12913e0a96bbcc45f97b450e74cd3.png~tplv-obj.jpg"),
ALIEN_PEACE_SIGN(7831, "Alien Peace Sign", 1, "https://storage.streamdps.com/iblock/5f7/5f7b29f5c7a4ca3a4dbbe8dc0e195459/cd83433a0f1697a0b66a891cbd7cf1af.webp"), 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"), THE_MAGIC_LAMP(7161, "The Magic Lamp", 1000, "https://storage.streamdps.com/iblock/e0d/e0d45fccd69220f321531383d97f51fc/4296cc4b886f31bb5b2cf106ebf640ab.webp"),
@@ -1025,6 +1167,8 @@ public enum Gift {
TIARA(8496, "Tiara", 299, "https://storage.streamdps.com/iblock/1b1/1b1ee7b697bae41ee2cbf834d1f1099e/303eec791a710c2417bb5075529681d9.webp"), TIARA(8496, "Tiara", 299, "https://storage.streamdps.com/iblock/1b1/1b1ee7b697bae41ee2cbf834d1f1099e/303eec791a710c2417bb5075529681d9.webp"),
THE_CROWN(8207, "The Crown", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5bf798f92fe96ba53c0f4d28f052f9bb~tplv-obj.png"),
COFFEE(5333, "Coffee", 1, "https://storage.streamdps.com/iblock/920/920b64634d946a2238950c353c16df81/0fe22d9bdee1bd6d9d77f66bcd8cf45a.png"), COFFEE(5333, "Coffee", 1, "https://storage.streamdps.com/iblock/920/920b64634d946a2238950c353c16df81/0fe22d9bdee1bd6d9d77f66bcd8cf45a.png"),
COFFEE_5479(5479, "Coffee", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/02492214b9bd50fee2d69fd0d089c025.png~tplv-obj.jpg"), COFFEE_5479(5479, "Coffee", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/02492214b9bd50fee2d69fd0d089c025.png~tplv-obj.jpg"),
@@ -1033,6 +1177,8 @@ public enum Gift {
COFFEE_5961(5961, "Coffee", 30, "https://storage.streamdps.com/iblock/87b/87b2a811f1ca8c09060e2bd63a3b3be7/ae6288eb1eab67474807c64b9d69b5e6.webp"), COFFEE_5961(5961, "Coffee", 30, "https://storage.streamdps.com/iblock/87b/87b2a811f1ca8c09060e2bd63a3b3be7/ae6288eb1eab67474807c64b9d69b5e6.webp"),
MAGIC_HAT(6393, "Magic Hat", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b156ffd21bb3849a52144ab1688bbc43~tplv-obj.png"),
HAND_HEART(5924, "Hand Heart", 100, "https://storage.streamdps.com/iblock/5ce/5cebff2a4b737063778ac5374e9e4792/f9bf5c945eb61002916feff420a1cc3a.png"), HAND_HEART(5924, "Hand Heart", 100, "https://storage.streamdps.com/iblock/5ce/5cebff2a4b737063778ac5374e9e4792/f9bf5c945eb61002916feff420a1cc3a.png"),
HAND_HEART_6968(6968, "Hand Heart", 100, "https://storage.streamdps.com/iblock/9f0/9f0bfed08f1d3b9e852469d6a4debeda/519497b062ded1019c958d5d0b352a7e.webp"), HAND_HEART_6968(6968, "Hand Heart", 100, "https://storage.streamdps.com/iblock/9f0/9f0bfed08f1d3b9e852469d6a4debeda/519497b062ded1019c958d5d0b352a7e.webp"),
@@ -1063,6 +1209,8 @@ public enum Gift {
TIKTOK_CROWN(8873, "TikTok Crown", 299, "https://storage.streamdps.com/iblock/a79/a790613bdf2e83725d0519bbf289529d/83bb670c15ab91b9192c50300f4c8054.webp"), TIKTOK_CROWN(8873, "TikTok Crown", 299, "https://storage.streamdps.com/iblock/a79/a790613bdf2e83725d0519bbf289529d/83bb670c15ab91b9192c50300f4c8054.webp"),
KFC_CHICKEN(9771, "KFC Chicken", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9d59ccd2328b8a46841b3b1c87d9e55.png~tplv-obj.png"),
LOVED(6705, "Loved", 5, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/2a41781b0a29ba3c409c5dd83eed07f8~tplv-obj.png"), 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(6840, "On Fire", 200, "https://storage.streamdps.com/iblock/cba/cba95075d6b63b84fbc52abb9d1d8208/d93ecc0b966bf972f01e77339a68e124.webp"),
@@ -1081,22 +1229,38 @@ public enum Gift {
FERRIS_WHEEL(5652, "Ferris Wheel", 3000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/3c7291ad4c2a6d4f70505c3e296ecebe~tplv-obj.jpg"), FERRIS_WHEEL(5652, "Ferris Wheel", 3000, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/3c7291ad4c2a6d4f70505c3e296ecebe~tplv-obj.jpg"),
DE_NORTH_POLE(9658, "DE North Pole", 199, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/130e17b5b561a93cefbd236586881477.png~tplv-obj.png"),
RUGBY_BALL(6249, "Rugby Ball", 10, "https://storage.streamdps.com/iblock/d53/d53d3efae1c69b949373db455da077cf/fa22f0507a304597b013268524a8573f.png"), RUGBY_BALL(6249, "Rugby Ball", 10, "https://storage.streamdps.com/iblock/d53/d53d3efae1c69b949373db455da077cf/fa22f0507a304597b013268524a8573f.png"),
TROPHY(5712, "Trophy", 500, "https://storage.streamdps.com/iblock/26f/26f17d2bc63c5e3f218ea2f25b245fa2/95d88e55486d8188f4b73c75def4354c.png"), TROPHY(5712, "Trophy", 500, "https://storage.streamdps.com/iblock/26f/26f17d2bc63c5e3f218ea2f25b245fa2/95d88e55486d8188f4b73c75def4354c.png"),
ACROSS_THE_BOARD(8793, "Across the board", 450, "https://storage.streamdps.com/iblock/285/285070af9d4f72b74e7d74c22157f2d9/67d9fa3239a7f9a09ef78c832a66e624.webp"), ACROSS_THE_BOARD(8793, "Across the board", 450, "https://storage.streamdps.com/iblock/285/285070af9d4f72b74e7d74c22157f2d9/67d9fa3239a7f9a09ef78c832a66e624.webp"),
GOOD_AFTERNOON(8266, "Good Afternoon", 399, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/bff3b908c4dd9cf19ab431cc99dc7940~tplv-obj.png"),
GARDEN_GNOME(7002, "Garden Gnome", 1, "https://storage.streamdps.com/iblock/c1e/c1efcf386f4ffc5626e0be1ef1ecd93a/210fa9d66c1f0c1968608b40c4e698ea.webp"), GARDEN_GNOME(7002, "Garden Gnome", 1, "https://storage.streamdps.com/iblock/c1e/c1efcf386f4ffc5626e0be1ef1ecd93a/210fa9d66c1f0c1968608b40c4e698ea.webp"),
MIMI___FIFI(9672, "Mimi & Fifi", 5000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/0a72d0084695d03586fea7d854dc3a47.png~tplv-obj.png"),
CANDY_CANE(9698, "Candy Cane", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1fa0a4ed666304c78a46de200b85c84b.png~tplv-obj.png"),
FAKE_SMILE(9536, "Fake smile", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/35ce62173962e33834703212d0b845a7.png~tplv-obj.png"),
SO_CUTE(9355, "So cute", 1, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/d40d31241efcf57c630e894bb3007b8a.png~tplv-obj.png"),
LILI_THE_LEOPARD(9467, "Lili the Leopard", 6599, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/7be03e1af477d1dbc6eb742d0c969372.png~tplv-obj.jpg"), LILI_THE_LEOPARD(9467, "Lili the Leopard", 6599, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/7be03e1af477d1dbc6eb742d0c969372.png~tplv-obj.jpg"),
MUSIC_BOX(5964, "Music Box", 2399, "https://storage.streamdps.com/iblock/f01/f01f2da5e18be863eb7e3a1375bb6206/499e06f8f76e5e90964184c25365cdec.png"), MUSIC_BOX(5964, "Music Box", 2399, "https://storage.streamdps.com/iblock/f01/f01f2da5e18be863eb7e3a1375bb6206/499e06f8f76e5e90964184c25365cdec.png"),
ELF_S_HAT_(9625, "Elf's Hat ", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9857a040c92b34d6a261201a93c185f.png~tplv-obj.png"),
PRINCE(7398, "Prince", 500, "https://storage.streamdps.com/iblock/38b/38b4963191222c66267858149e662b7d/d98b625b2a3a261d2c12caaae61b479f.webp"), PRINCE(7398, "Prince", 500, "https://storage.streamdps.com/iblock/38b/38b4963191222c66267858149e662b7d/d98b625b2a3a261d2c12caaae61b479f.webp"),
DASH(6757, "Dash", 299, "https://storage.streamdps.com/iblock/b35/b356ce71b1272dffc836a14df85700d2/16e177319d9f5cf312440139715612f5.webp"), DASH(6757, "Dash", 299, "https://storage.streamdps.com/iblock/b35/b356ce71b1272dffc836a14df85700d2/16e177319d9f5cf312440139715612f5.webp"),
SNOWGLOBE(9688, "Snowglobe", 499, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/ea5ac5f8e186897456bed2e78fc78ca5.png~tplv-obj.png"),
BABY_FOX(8552, "Baby fox", 20, "https://storage.streamdps.com/iblock/b7d/b7df9be24aa630c9b04db3974f103a73/17a445fd5256e13281e64c718b5112fe.webp"), BABY_FOX(8552, "Baby fox", 20, "https://storage.streamdps.com/iblock/b7d/b7df9be24aa630c9b04db3974f103a73/17a445fd5256e13281e64c718b5112fe.webp"),
RAYA_RICE(6383, "Raya Rice", 1, "https://storage.streamdps.com/iblock/e0c/e0c375df5bdce1c926f46244ced54ecc/1bd688843c1c24370b8c4a74686c2c0d.png"), RAYA_RICE(6383, "Raya Rice", 1, "https://storage.streamdps.com/iblock/e0c/e0c375df5bdce1c926f46244ced54ecc/1bd688843c1c24370b8c4a74686c2c0d.png"),
@@ -1119,12 +1283,16 @@ public enum Gift {
GOLD_NECKLACE(5599, "Gold necklace", 200, "https://storage.streamdps.com/iblock/aa2/aa26035cd47797211a9ce1b5e51fd7ac/85e66a118c564c318e369974510f371d.png"), GOLD_NECKLACE(5599, "Gold necklace", 200, "https://storage.streamdps.com/iblock/aa2/aa26035cd47797211a9ce1b5e51fd7ac/85e66a118c564c318e369974510f371d.png"),
HOLIDAY_CAROUSEL(9678, "Holiday Carousel", 2000, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/b5ba3941f7389da7495b659e888ea61a.png~tplv-obj.png"),
MPL_TROPHY(7119, "MPL Trophy", 450, "https://storage.streamdps.com/iblock/981/9816c81ee3e2fdc62ac221051e9ec290/75707f488be3f80faf5affd1cef38deb.webp"), MPL_TROPHY(7119, "MPL Trophy", 450, "https://storage.streamdps.com/iblock/981/9816c81ee3e2fdc62ac221051e9ec290/75707f488be3f80faf5affd1cef38deb.webp"),
OCTOPUS(8417, "Octopus", 10000, "https://storage.streamdps.com/iblock/419/4197c396a3fcdd28f0477d9af50cd964/1196ad0f243ca976832319a46c7935ed.webp"), OCTOPUS(8417, "Octopus", 10000, "https://storage.streamdps.com/iblock/419/4197c396a3fcdd28f0477d9af50cd964/1196ad0f243ca976832319a46c7935ed.webp"),
PIM_BEAR(9043, "Pim Bear", 1500, "https://storage.streamdps.com/iblock/204/2043f85b8f2e2ee638ff3a1799eda329/2319b052e0e64799842751d9fee4d438.webp"), PIM_BEAR(9043, "Pim Bear", 1500, "https://storage.streamdps.com/iblock/204/2043f85b8f2e2ee638ff3a1799eda329/2319b052e0e64799842751d9fee4d438.webp"),
FALLING_FOR_YOU(8005, "Falling For You", 299, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a198bd39d2511dbba6a68867740e3ff9~tplv-obj.png"),
SIGNATURE_JET(7124, "Signature Jet", 4888, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/fe27eba54a50c0a687e3dc0f2c02067d~tplv-obj.jpg"), SIGNATURE_JET(7124, "Signature Jet", 4888, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/fe27eba54a50c0a687e3dc0f2c02067d~tplv-obj.jpg"),
CAP(6104, "Cap", 99, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/6c2ab2da19249ea570a2ece5e3377f04~tplv-obj.jpg"), CAP(6104, "Cap", 99, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/6c2ab2da19249ea570a2ece5e3377f04~tplv-obj.jpg"),
@@ -1141,6 +1309,8 @@ public enum Gift {
SUPERB_TEAM(8202, "Superb Team", 1, "https://storage.streamdps.com/iblock/e6e/e6e8cdd5e84f701dc627b8cc3e280d4c/29ce845878feb46152b20a75a3259d56.webp"), SUPERB_TEAM(8202, "Superb Team", 1, "https://storage.streamdps.com/iblock/e6e/e6e8cdd5e84f701dc627b8cc3e280d4c/29ce845878feb46152b20a75a3259d56.webp"),
MAGIC_POTION(7105, "Magic Potion", 499, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e055625e9239df7e833702c768e033d2~tplv-obj.png"),
GLOWING_JELLYFISH(8978, "Glowing Jellyfish", 1000, "https://storage.streamdps.com/iblock/e65/e65b1f71b4fe5709b454299439cb2674/36471857a2ba78694be934a54a0fa8d2.webp"), GLOWING_JELLYFISH(8978, "Glowing Jellyfish", 1000, "https://storage.streamdps.com/iblock/e65/e65b1f71b4fe5709b454299439cb2674/36471857a2ba78694be934a54a0fa8d2.webp"),
RAINING_GIFTS(8769, "Raining gifts", 999, "https://storage.streamdps.com/iblock/916/91661303a8dc3660acaf2f4e47a94f75/221a1f185676496ebcdbaf55f90aeb70.webp"), RAINING_GIFTS(8769, "Raining gifts", 999, "https://storage.streamdps.com/iblock/916/91661303a8dc3660acaf2f4e47a94f75/221a1f185676496ebcdbaf55f90aeb70.webp"),
@@ -1163,8 +1333,6 @@ public enum Gift {
CAKE_SLICE(6784, "Cake Slice", 1, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/f681afb4be36d8a321eac741d387f1e2~tplv-obj.jpg"), 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"), 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"), LOVE_YOU_6671(6671, "Love You", 199, "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/134e51c00f46e01976399883ca4e4798~tplv-obj.jpg"),
@@ -1199,6 +1367,8 @@ public enum Gift {
HOT_AIR_BALLOON(5976, "Hot Air Balloon", 999, "https://storage.streamdps.com/iblock/33a/33a5eb58a8dd71677072c9482aad209a/61be5fe5d3d639e3729edbf003a536c7.png"), HOT_AIR_BALLOON(5976, "Hot Air Balloon", 999, "https://storage.streamdps.com/iblock/33a/33a5eb58a8dd71677072c9482aad209a/61be5fe5d3d639e3729edbf003a536c7.png"),
RABBIT_AND_MOCHI(9303, "Rabbit and Mochi", 999, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/213ef2549fbb10ec783c95a41d28cf0a.png~tplv-obj.png"),
TEA(5303, "Tea", 50, "https://storage.streamdps.com/iblock/240/24051d7263606ed2b02f24f8455cb0a5/4f1cc7de604a1369c5770cc02cbee920.png"), TEA(5303, "Tea", 50, "https://storage.streamdps.com/iblock/240/24051d7263606ed2b02f24f8455cb0a5/4f1cc7de604a1369c5770cc02cbee920.png"),
TEA_6726(6726, "Tea", 20, "https://storage.streamdps.com/iblock/b0b/b0ba111b6319a8c9e384d5ca7b814e4c/6cd6f620512cd42711bc1235124b3265.webp"), TEA_6726(6726, "Tea", 20, "https://storage.streamdps.com/iblock/b0b/b0ba111b6319a8c9e384d5ca7b814e4c/6cd6f620512cd42711bc1235124b3265.webp"),
@@ -1211,6 +1381,8 @@ public enum Gift {
PIRATE_S_SHIP(7598, "Pirates Ship", 15000, "https://storage.streamdps.com/iblock/475/4753e54cae562b34edbf1a157cd60b21/722409ec69cfaf707d611b0987799296.webp"), PIRATE_S_SHIP(7598, "Pirates Ship", 15000, "https://storage.streamdps.com/iblock/475/4753e54cae562b34edbf1a157cd60b21/722409ec69cfaf707d611b0987799296.webp"),
DOMBRA(6426, "Dombra", 20, "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ccd9fea1988521d1e81051a916800d6c~tplv-obj.png"),
GRIFFIN(7987, "Griffin", 25999, "https://storage.streamdps.com/iblock/609/6092240118fdb3ad46036c0533dd23c8/0f700fd4e875174d01ad04a8db2ae94e.webp"), GRIFFIN(7987, "Griffin", 25999, "https://storage.streamdps.com/iblock/609/6092240118fdb3ad46036c0533dd23c8/0f700fd4e875174d01ad04a8db2ae94e.webp"),
BEACH_HUT(6719, "Beach Hut", 5000, "https://storage.streamdps.com/iblock/227/22716035cef6112f66035eca2b60fa31/ffce7cd46aaa6c2b27ccba610cf35a39.webp"), BEACH_HUT(6719, "Beach Hut", 5000, "https://storage.streamdps.com/iblock/227/22716035cef6112f66035eca2b60fa31/ffce7cd46aaa6c2b27ccba610cf35a39.webp"),

View File

@@ -43,13 +43,12 @@ public class User {
private long followers; private long followers;
private List<Badge> badges; private List<Badge> badges;
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
private Set<UserAttribute> attributes; private final Set<UserAttribute> attributes = new HashSet<>();
public List<UserAttribute> getAttributes() { public List<UserAttribute> getAttributes() {
return attributes.stream().toList(); return attributes.stream().toList();
} }
public boolean hasAttribute(UserAttribute userFlag) { public boolean hasAttribute(UserAttribute userFlag) {
return attributes.contains(userFlag); return attributes.contains(userFlag);
} }
@@ -106,7 +105,6 @@ public class User {
this.following = following; this.following = following;
this.followers = followers; this.followers = followers;
this.badges = badges; this.badges = badges;
this.attributes = new HashSet<>();
} }
public User(Long id, public User(Long id,
@@ -123,14 +121,12 @@ public class User {
this.following = following; this.following = following;
this.followers = followers; this.followers = followers;
this.badges = badges; this.badges = badges;
this.attributes = new HashSet<>();
} }
public User(Long userId, public User(Long userId,
String nickName) { String nickName) {
this.id = userId; this.id = userId;
this.name = nickName; this.name = nickName;
this.attributes = new HashSet<>();
} }
public User(Long userId, public User(Long userId,
@@ -213,4 +209,4 @@ public class User {
0, 0,
List.of(Badge.empty())); List.of(Badge.empty()));
} }
} }

View File

@@ -20,17 +20,38 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.live; package io.github.jwdeveloper.tiktok.data.requests;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift; import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.data.models.users.User; import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import java.util.List; import java.util.List;
public interface TrackedUser public class GiftsData
{ {
List<TikTokEvent> getInvokedEvents(); @Getter
List<Gift> getGifs(); public final class Request
User getUserData(); {
}
@Getter
@AllArgsConstructor
public static final class Response
{
private String json;
private List<GiftModel> gifts;
}
@Data
public static class GiftModel
{
private int id;
private String name;
private int diamondCost;
private String image;
}
} }

View File

@@ -20,16 +20,28 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.http; package io.github.jwdeveloper.tiktok.data.requests;
import java.util.Map; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
public interface TikTokHttpRequest { import java.net.URI;
TikTokHttpRequest setQueries(Map<String, Object> queries); import java.time.Duration;
TikTokHttpRequest setHeader(String key, String value); public class LiveConnectionData {
String get(String url); @Getter
@AllArgsConstructor
String post(String url); public static class Request {
private String roomId;
}
@Getter
@AllArgsConstructor
public static class Response {
private String websocketCookies;
private URI websocketUrl;
private WebcastResponse webcastResponse;
}
} }

View File

@@ -20,26 +20,35 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.live; package io.github.jwdeveloper.tiktok.data.requests;
import io.github.jwdeveloper.tiktok.data.models.users.User; import io.github.jwdeveloper.tiktok.data.models.users.User;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.Getter;
@Data public class LiveData {
public class LiveRoomMeta { @Getter
@AllArgsConstructor
public static class Request {
private String roomId;
}
private LiveRoomStatus status; @Data
private boolean ageRestricted; public static class Response {
private String titie; private String json;
private int likeCount; private LiveStatus liveStatus;
private int totalViewers; private String title;
private int viewers; private int likes;
private User host; private int viewers;
private int totalViewers;
private boolean ageRestricted;
private User host;
}
public enum LiveRoomStatus public enum LiveStatus {
{
HostNotFound, HostNotFound,
HostOnline, HostOnline,
HostOffline HostOffline,
} }
} }

View File

@@ -0,0 +1,58 @@
/*
* 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.requests;
import lombok.*;
public class LiveUserData {
@Getter
@AllArgsConstructor
public static class Request {
private String userName;
}
@Getter
@AllArgsConstructor
public static class Response {
private String json;
private UserStatus userStatus;
private String roomId;
private long startedAtTimeStamp;
public boolean isLiveOnline() {
return userStatus == LiveUserData.UserStatus.Live || userStatus == LiveUserData.UserStatus.LivePaused;
}
public boolean isHostNameValid() {
return userStatus != LiveUserData.UserStatus.NotFound;
}
}
public enum UserStatus {
NotFound,
Offline,
LivePaused,
Live,
}
}

View File

@@ -20,26 +20,16 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.data.dto; package io.github.jwdeveloper.tiktok.data.requests;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
public class TikTokUserInfo public class SignServerResponse
{ {
UserStatus userStatus; private String signedUrl;
String roomId; private String userAgent;
}
long startTime;
public enum UserStatus
{
NotFound,
Offline,
LivePaused,
Live
}
}

View File

@@ -0,0 +1,112 @@
/*
* 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.settings;
import lombok.Getter;
import lombok.Setter;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Consumer;
public class HttpClientSettings {
@Getter
final Map<String, Object> params;
@Getter
final Map<String, String> headers;
@Getter
final Map<String, String> cookies;
@Getter
@Setter
ProxyClientSettings proxyClientSettings;
@Getter
Consumer<HttpClient.Builder> onClientCreating;
@Getter
Consumer<HttpRequest.Builder> onRequestCreating;
@Setter
@Getter
Duration timeout;
public HttpClientSettings() {
this.params = new TreeMap<>();
this.headers = new HashMap<>();
this.cookies = new HashMap<>();
this.timeout = Duration.ofSeconds(2);
this.proxyClientSettings = new ProxyClientSettings();
this.onClientCreating = (x) -> {
};
this.onRequestCreating = (x) -> {
};
}
/**
* @param consumer Use to configure proxy settings for http client
*/
public void configureProxy(Consumer<ProxyClientSettings> consumer) {
proxyClientSettings.setEnabled(true);
consumer.accept(proxyClientSettings);
}
/**
* @param onRequestCreating Every time new Http request in created this method will be triggered
* use to modify request
*/
public void onRequestCreating(Consumer<HttpRequest.Builder> onRequestCreating) {
this.onRequestCreating = onRequestCreating;
}
/**
* @param onClientCreating Every time new instance of Http client request in created this method will be triggered
* use to modify http client
*/
public void onClientCreating(Consumer<HttpClient.Builder> onClientCreating) {
this.onClientCreating = onClientCreating;
}
@Override
public HttpClientSettings clone() {
var newSettings = new HttpClientSettings();
newSettings.setTimeout(this.getTimeout());
newSettings.onRequestCreating(this.onRequestCreating);
newSettings.onClientCreating(this.onClientCreating);
newSettings.getHeaders().putAll(new TreeMap<>(this.headers));
newSettings.getCookies().putAll(new TreeMap<>(this.cookies));
newSettings.getParams().putAll(new TreeMap<>(this.params));
newSettings.proxyClientSettings = this.proxyClientSettings;
return newSettings;
}
}

View File

@@ -20,7 +20,9 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok.data.settings;
import lombok.Data;
import java.time.Duration; import java.time.Duration;
import java.util.HashMap; import java.util.HashMap;
@@ -28,40 +30,81 @@ import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.logging.Level; import java.util.logging.Level;
public class Constants { @Data
public class LiveClientSettings {
/** /**
* Web-URL for TikTok * ISO-Language for Client
*/ */
public static final String TIKTOK_URL_WEB = "https://www.tiktok.com/";
/** private String clientLanguage;
* WebCast-BaseURL for TikTok
*/
public static final String TIKTOK_URL_WEBCAST = "https://webcast.tiktok.com/webcast/";
/**
* Signing API by Isaac Kogan
* https://github-wiki-see.page/m/isaackogan/TikTokLive/wiki/All-About-Signatures
*/
public static final String TIKTOK_SIGN_API = "https://tiktok.eulerstream.com/webcast/sign_url";
/** /**
* Default TimeOut for Connections * Whether to Retry if Connection Fails
*/ */
public static final int DEFAULT_TIMEOUT = 20; private boolean retryOnConnectionFailure;
/** /**
* Default Settings for Client * Before retrying connect, wait for select amount of time
*/ */
public static ClientSettings DefaultClientSettings() { private Duration retryConnectionTimeout;
var clientSettings = new ClientSettings();
clientSettings.setTimeout(Duration.ofSeconds(DEFAULT_TIMEOUT)); /**
* Whether to print Logs to Console
*/
private boolean printToConsole = true;
/**
* LoggingLevel for Logs
*/
private Level logLevel;
/**
* Optional: Use it if you need to change TikTok live hostname in builder
*/
private String hostName;
/**
* Parameters used in requests to TikTok api
*/
private HttpClientSettings httpSettings;
/*
* Optional: Sometimes not every messages 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
*/
private String sessionId;
/*
* Optional: By default roomID is fetched before connect to live, but you can set it manually
*
*/
private String roomId;
public static LiveClientSettings createDefault()
{
var httpSettings = new HttpClientSettings();
httpSettings.getParams().putAll(DefaultClientParams());
httpSettings.getHeaders().putAll(DefaultRequestHeaders());
httpSettings.setTimeout(Duration.ofSeconds(3));
var clientSettings = new LiveClientSettings();
clientSettings.setClientLanguage("en-US"); clientSettings.setClientLanguage("en-US");
clientSettings.setRetryOnConnectionFailure(false); clientSettings.setRetryOnConnectionFailure(false);
clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1)); clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1));
clientSettings.setPrintToConsole(false); clientSettings.setPrintToConsole(false);
clientSettings.setLogLevel(Level.ALL); clientSettings.setLogLevel(Level.ALL);
clientSettings.setClientParameters(Constants.DefaultClientParams());
clientSettings.setHttpSettings(httpSettings);
return clientSettings; return clientSettings;
} }
@@ -115,15 +158,15 @@ public class Constants {
public static Map<String, String> DefaultRequestHeaders() { public static Map<String, String> DefaultRequestHeaders() {
var headers = new HashMap<String, String>(); var headers = new HashMap<String, String>();
headers.put("authority","www.tiktok.com"); headers.put("authority", "www.tiktok.com");
headers.put("Connection", "keep-alive");
headers.put("Cache-Control", "max-age=0"); headers.put("Cache-Control", "max-age=0");
headers.put("Accept", "text/html,application/json,application/protobuf"); headers.put("Accept", "text/html,application/json,application/protobuf");
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36"); headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36");
headers.put("Referer", "https://www.tiktok.com/"); headers.put("Referer", "https://www.tiktok.com/");
headers.put("Origin", "https://www.tiktok.com"); headers.put("Origin", "https://www.tiktok.com");
headers.put("Accept-Language", "en-US,en; q=0.9"); headers.put("Accept-Language", "en-US,en; q=0.9");
headers.put("Accept-Encoding", "gzip, deflate");
return headers; return headers;
} }
} }

View File

@@ -0,0 +1,122 @@
/*
* 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.settings;
import io.github.jwdeveloper.tiktok.data.dto.ProxyData;
import lombok.*;
import java.net.*;
import java.util.*;
import java.util.function.Consumer;
@Getter
@Setter
public class ProxyClientSettings implements Iterator<ProxyData>
{
private boolean enabled, lastSuccess;
private Rotation rotation = Rotation.CONSECUTIVE;
private final List<ProxyData> proxyList = new ArrayList<>();
private int index = 0;
private boolean autoDiscard = true;
private Proxy.Type type = Proxy.Type.DIRECT;
private Consumer<ProxyData> onProxyUpdated = x -> {};
public boolean addProxy(String addressPort) {
return proxyList.add(ProxyData.map(addressPort));
}
public boolean addProxy(String address, int port) {
return addProxy(new InetSocketAddress(address, port));
}
public boolean addProxy(InetSocketAddress inetAddress) {
return proxyList.add(new ProxyData(inetAddress.getHostString(), inetAddress.getPort()));
}
public void addProxies(List<String> list) {
list.forEach(this::addProxy);
}
@Override
public boolean hasNext() {
return !proxyList.isEmpty();
}
@Override
public ProxyData next() {
return lastSuccess ? proxyList.get(index) : rotate();
}
public ProxyData rotate() {
var nextProxy = switch (rotation)
{
case CONSECUTIVE -> {
index = (index+1) % proxyList.size();
yield proxyList.get(index).clone();
}
case RANDOM -> {
index = new Random().nextInt(proxyList.size());
yield proxyList.get(index).clone();
}
case NONE -> proxyList.get(index).clone();
};
onProxyUpdated.accept(nextProxy);
return nextProxy;
}
@Override
public void remove() {
proxyList.remove(index);
}
public void setIndex(int index) {
if (index == 0 && proxyList.isEmpty())
this.index = 0;
else {
if (index < 0 || index >= proxyList.size())
throw new IndexOutOfBoundsException("Index " + index + " exceeds list of size: " + proxyList.size());
this.index = index;
}
}
public ProxyClientSettings clone()
{
ProxyClientSettings settings = new ProxyClientSettings();
settings.setEnabled(enabled);
settings.setRotation(rotation);
settings.setIndex(index);
settings.setType(type);
settings.setOnProxyUpdated(onProxyUpdated);
proxyList.forEach(proxyData -> settings.addProxy(proxyData.getAddress(), proxyData.getPort()));
return settings;
}
public enum Rotation
{
/** Rotate addresses consecutively, from proxy 0 -> 1 -> 2 -> ...etc. */
CONSECUTIVE,
/** Rotate addresses randomly, from proxy 0 -> 69 -> 420 -> 1 -> ...etc. */
RANDOM,
/** Don't rotate addresses at all, pin to the indexed address. */
NONE
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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.exceptions;
/*
* Happens while bad response from http proxy request to TikTok
*/
public class TikTokProxyRequestException extends TikTokLiveException
{
public TikTokProxyRequestException() {
}
public TikTokProxyRequestException(String message) {
super(message);
}
public TikTokProxyRequestException(String message, Throwable cause) {
super(message, cause);
}
public TikTokProxyRequestException(Throwable cause) {
super(cause);
}
public TikTokProxyRequestException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@@ -20,29 +20,26 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.http; package io.github.jwdeveloper.tiktok.exceptions;
import java.util.*; public class TikTokSignServerException extends TikTokLiveRequestException
import java.util.stream.Collectors; {
public TikTokSignServerException() {
public class TikTokCookieJar {
private final Map<String, String> cookies;
public TikTokCookieJar() {
cookies = new HashMap<>();
} }
public String get(String key) { public TikTokSignServerException(String message) {
return cookies.get(key); super(message);
} }
public void set(String key, String value) { public TikTokSignServerException(String message, Throwable cause) {
cookies.put(key, value); super(message, cause);
} }
public String parseCookies() { public TikTokSignServerException(Throwable cause) {
return cookies.entrySet() super(cause);
.stream()
.map(entry -> entry.getKey()+"="+entry.getValue()+";")
.collect(Collectors.joining());
} }
}
public TikTokSignServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@@ -0,0 +1,64 @@
/*
* 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.data.requests.GiftsData;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
public interface LiveHttpClient {
/**
* @return list of gifts that are available in your country
*/
GiftsData.Response fetchGiftsData();
/**
* Returns information about user that is having a livestream
*
* @param userName
* @return
*/
LiveUserData.Response fetchLiveUserData(String userName);
LiveUserData.Response fetchLiveUserData(LiveUserData.Request request);
/**
* @param roomId can be obtained from browsers cookies or by invoked fetchLiveUserData
* @return
*/
LiveData.Response fetchLiveData(String roomId);
LiveData.Response fetchLiveData(LiveData.Request request);
/**
* @param roomId can be obtained from browsers cookies or by invoked fetchLiveUserData
* @return
*/
LiveConnectionData.Response fetchLiveConnectionData(String roomId);
LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request);
}

View File

@@ -22,15 +22,13 @@
*/ */
package io.github.jwdeveloper.tiktok.live.builder; package io.github.jwdeveloper.tiktok.live.builder;
import io.github.jwdeveloper.tiktok.ClientSettings; import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener; import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper; import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> { public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
@@ -48,11 +46,11 @@ public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
/** /**
* Configuration of client settings * Configuration of client settings
* @see ClientSettings * @see LiveClientSettings
* @param onConfigure * @param onConfigure
* @return * @return
*/ */
LiveClientBuilder configure(Consumer<ClientSettings> onConfigure); LiveClientBuilder configure(Consumer<LiveClientSettings> onConfigure);
/** /**
* @see TikTokEventListener * @see TikTokEventListener

View File

@@ -36,6 +36,11 @@ public class ProtoBufferObject {
this.fields = new TreeMap<>(); this.fields = new TreeMap<>();
} }
public Object getField(int index)
{
return fields.get(index);
}
public void addField(int index, String type, Object value) { public void addField(int index, String type, Object value) {
fields.put(index, new ProtoBufferField(type, value)); fields.put(index, new ProtoBufferField(type, value));
} }

View File

@@ -22,11 +22,11 @@
*/ */
package io.github.jwdeveloper.tiktok.websocket; package io.github.jwdeveloper.tiktok.websocket;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
public interface SocketClient { public interface SocketClient {
void start(WebcastResponse webcastResponse, LiveClient tikTokLiveClient); void start(LiveConnectionData.Response webcastResponse, LiveClient tikTokLiveClient);
void stop(); void stop();
} }

View File

@@ -976,131 +976,146 @@ message FanTicketRoomNoticeContent {
} }
message LinkerAcceptNoticeContent { message LinkerAcceptNoticeContent {
int64 FromUserId = 1; int64 fromUserId = 1;
int64 FromRoomId = 2; int64 fromRoomId = 2;
int64 ToUserId = 3; int64 toUserId = 3;
} }
message LinkerCancelContent { message LinkerCancelContent {
int64 FromUserId = 1; int64 fromUserId = 1;
int64 ToUserId = 2; int64 toUserId = 2;
int64 CancelType = 3; int64 cancelType = 3;
int64 ActionId = 4; int64 actionId = 4;
} }
message ListUser {
User user = 1;
int64 linkmicId = 2;
string linkmicIdStr = 3;
int64 linkStatus = 4; // Enum
LinkType linkType = 5; // Enum
int32 userPosition = 6;
int32 silenceStatus = 7; // Enum
int64 modifyTime = 8;
int64 linkerId = 9;
int32 roleType = 10; // Enum
enum LinkType {
LINK_UNKNOWN = 0;
AUDIO = 1;
VIDEO = 2;
}
}
//it is just empty
message LinkerCloseContent { message LinkerCloseContent {
} }
message LinkerCreateContent { message LinkerCreateContent {
int64 OwnerId = 1; int64 ownerId = 1;
int64 OwnerRoomId = 2; int64 ownerRoomId = 2;
int64 LinkType = 3; int64 linkType = 3;
} }
message LinkerEnterContent { message LinkerEnterContent {
repeated User LinkedUsersList = 1; repeated ListUser linkedUsersList = 1;
// LinkmicMultiLiveEnum AnchorMultiLiveEnum = 2; int32 anchorMultiLiveEnum = 2; // Enum
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 3; LinkmicUserSettingInfo anchorSettingInfo = 3;;
} }
message LinkerInviteContent { message LinkerInviteContent {
int64 FromUserId = 1; int64 fromUserId = 1;
int64 FromRoomId = 2; int64 fromRoomId = 2;
string ToRtcExtInfo = 3; string toRtcExtInfo = 3;
bool RtcJoinChannel = 4; bool rtcJoinChannel = 4;
int64 Vendor = 5; int64 vendor = 5;
string SecFromUserId = 6; string secFromUserId = 6;
string ToLinkmicIdStr = 7; string toLinkmicIdStr = 7;
User FromUser = 8; User fromUser = 8;
int64 RequiredMicIdx = 9; 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 { message LinkerKickOutContent {
int64 FromUserId = 1; int64 fromUserId = 1;
//LinkMic.KickoutReason KickoutReason = 2; KickoutReason kickoutReason = 2; // Enum
} }
message LinkerLeaveContent { message LinkerLeaveContent {
int64 UserId = 1; int64 userId = 1;
string LinkmicIdStr = 2; string linkmicIdStr = 2;
int64 SendLeaveUid = 3; int64 sendLeaveUid = 3;
int64 LeaveReason = 4; int64 leaveReason = 4;
} }
//Empty
message LinkerLinkedListChangeContent { message LinkerLinkedListChangeContent {
repeated User LinkedUsersList = 1;
} }
//Empty
message CohostListChangeContent {
}
message LinkerListChangeContent { message LinkerListChangeContent {
repeated LinkLayerListUser LinkedUsersList = 1; repeated ListUser linkedUsersList = 1;
repeated LinkLayerListUser AppliedUsersList = 2; repeated ListUser appliedUsersList = 2;
repeated LinkLayerListUser ConnectingUsersList = 3; repeated ListUser connectingUsersList = 3;
} }
message LinkerMediaChangeContent { message LinkerMediaChangeContent {
// MicIdxOperation Op = 1; int64 op = 1; // Enum
int64 ToUserId = 2; int64 toUserId = 2;
int64 AnchorId = 3; int64 anchorId = 3;
int64 RoomId = 4; int64 roomId = 4;
// LinkerSceneType ChangeScene = 5; int64 changeScene = 5; // Enum
} }
//Empty
message LinkerMicIdxUpdateContent { message LinkerMicIdxUpdateContent {
LinkerMicIdxUpdateInfo MicIdxUpdateInfo = 1;
} }
message LinkerMicIdxUpdateInfo {
// MicIdxOperation Op = 1;
int64 UserId = 2;
int64 MicIdx = 3;
}
message LinkerMuteContent { message LinkerMuteContent {
int64 UserId = 1; int64 userId = 1;
// Data.MuteStatus Status = 2; int64 status = 2; // Enum
} }
message LinkerRandomMatchContent { message LinkerRandomMatchContent {
User User = 1; User user = 1;
int64 RoomId = 2; int64 roomId = 2;
int64 InviteType = 3; int64 inviteType = 3;
string MatchId = 4; string matchId = 4;
int64 InnerChannelId = 5; int64 innerChannelId = 5;
} }
message LinkerReplyContent { message LinkerReplyContent {
int64 FromUserId = 1; int64 fromUserId = 1;
int64 FromRoomId = 2; int64 fromRoomId = 2;
// LinkmicInfo FromUserLinkmicInfo = 3; LinkmicInfo fromUserLinkmicInfo = 3;
int64 ToUserId = 4; int64 toUserId = 4;
// LinkmicInfo ToUserLinkmicInfo = 5; LinkmicInfo toUserLinkmicInfo = 5;
int64 LinkType = 6; int64 linkType = 6;
int64 ReplyStatus = 7; int64 replyStatus = 7;
LinkerSetting LinkerSetting = 8; LinkerSetting linkerSetting = 8;
User FromUser = 9; User fromUser = 9;
User ToUser = 10; User toUser = 10;
map<int64, string> RtcExtInfoMap = 11;
LinkerMicIdxUpdateInfo InviteeMicIdxUpdateInfo = 12; message LinkmicInfo {
map<int64, int64> ApplierMicIdxInfoMap = 13; string accessKey = 1;
// Data.LinkmicMultiLiveEnum AnchorMultiLiveEnum = 14; int64 linkMicId = 2;
// Data.LinkmicUserSettingInfo AnchorSettingInfo = 15; bool joinable = 3;
int64 ActionId = 16; int32 confluenceType = 4;
// repeated LinkmicUserInfo LinkedUsersList = 17; string rtcExtInfo = 5;
int64 SourceType = 18; string rtcAppId = 6;
string rtcAppSign = 7;
string linkmicIdStr = 8;
int64 vendor = 9;
}
} }
message LinkerSetting { message LinkerSetting {
@@ -1113,20 +1128,27 @@ message LinkerSetting {
} }
message LinkerSysKickOutContent { message LinkerSysKickOutContent {
int64 UserId = 1; int64 userId = 1;
string LinkmicIdStr = 2; string linkmicIdStr = 2;
}
message LinkmicUserToastContent {
int64 userId = 1;
int64 roomId = 2;
Text displayText = 3;
} }
message LinkerUpdateUserContent { message LinkerUpdateUserContent {
int64 FromUserId = 1; int64 fromUserId = 1;
int64 ToUserId = 2; int64 toUserId = 2;
map<string, string> UpdateInfoMap = 3;
} }
//Empty
message LinkerUpdateUserSettingContent { message LinkerUpdateUserSettingContent {
// Data.LinkmicUserSettingInfo UpdateUserSettingInfo = 1;
} }
//Empty
message LinkerWaitingListChangeContent { message LinkerWaitingListChangeContent {
} }

View File

@@ -241,6 +241,35 @@ enum CommonContentCase {
} }
enum LinkMessageType {
TPYE_LINKER_UNKNOWN = 0;
TYPE_LINKER_CREATE = 1;
TYPE_LINKER_CLOSE = 2;
TYPE_LINKER_INVITE = 3;
TYPE_LINKER_APPLY = 4;
TYPE_LINKER_REPLY = 5;
TPYE_LINKER_ENTER = 6;
TPYE_LINKER_LEAVE = 7;
TYPE_LINKER_PERMIT = 8;
TPYE_LINKER_CANCEL_INVITE = 9;
TYPE_LINKER_WAITING_LIST_CHANGE = 10;
TYPE_LINKER_LINKED_LIST_CHANGE = 11;
TYPE_LINKER_UPDATE_USER = 12;
TPYE_LINKER_KICK_OUT = 13;
TPYE_LINKER_CANCEL_APPLY = 14;
TYPE_LINKER_MUTE = 15;
TYPE_LINKER_MATCH = 16;
TYPE_LINKER_UPDATE_USER_SETTING = 17;
TYPE_LINKER_MIC_IDX_UPDATE = 18;
TYPE_LINKER_LEAVE_V2 = 19;
TYPE_LINKER_WAITING_LIST_CHANGE_V2 = 20;
TYPE_LINKER_LINKED_LIST_CHANGE_V2 = 21;
TYPE_LINKER_COHOST_LIST_CHANGE = 22;
TYPE_LINKER_MEDIA_CHANGE = 23;
TYPE_LINKER_ACCEPT_NOTICE = 24;
TPYE_LINKER_SYS_KICK_OUT = 101;
TPYE_LINKMIC_USER_TOAST = 102;
}
enum MessageType { enum MessageType {
MESSAGETYPE_SUBSUCCESS = 0; MESSAGETYPE_SUBSUCCESS = 0;

View File

@@ -25,10 +25,6 @@ message WebcastPushFrame {
} }
message WebcastWebsocketAck {
uint64 Id = 1;
string Type = 2;
}
//@WebcastResponse //@WebcastResponse
@@ -733,7 +729,7 @@ message WebcastSystemMessage {
//@WebcastLinkMessage //@WebcastLinkMessage
message WebcastLinkMessage { message WebcastLinkMessage {
Common common = 1; Common common = 1;
MessageType MessageType = 2; LinkMessageType MessageType = 2;
int64 LinkerId = 3; int64 LinkerId = 3;
Scene Scene = 4; Scene Scene = 4;
LinkerInviteContent InviteContent = 5; LinkerInviteContent InviteContent = 5;
@@ -752,14 +748,14 @@ message WebcastLinkMessage {
LinkerUpdateUserSettingContent UpdateUserSettingContent = 18; LinkerUpdateUserSettingContent UpdateUserSettingContent = 18;
LinkerMicIdxUpdateContent MicIdxUpdateContent = 19; LinkerMicIdxUpdateContent MicIdxUpdateContent = 19;
LinkerListChangeContent ListChangeContent = 20; LinkerListChangeContent ListChangeContent = 20;
// CohostListChangeContent CohostListChangeContent = 21; CohostListChangeContent CohostListChangeContent = 21;
LinkerMediaChangeContent MediaChangeContent = 22; LinkerMediaChangeContent MediaChangeContent = 22;
LinkerAcceptNoticeContent ReplyAcceptNoticeContent = 23; LinkerAcceptNoticeContent ReplyAcceptNoticeContent = 23;
LinkerSysKickOutContent SysKickOutContent = 101; LinkerSysKickOutContent SysKickOutContent = 101;
// LinkmicUserToastContent UserToastContent = 102; LinkmicUserToastContent UserToastContent = 102;
string Extra = 200; string extra = 200;
int64 ExpireTimestamp = 201; int64 expireTimestamp = 201;
string TransferExtra = 202; string transferExtra = 202;
} }

View File

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

View File

@@ -23,26 +23,22 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.http.TikTokDataChecker; import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder; import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class TikTokLive public class TikTokLive {
{
/** /**
*
* @param hostName profile name of Tiktok user could be found in profile link * @param hostName profile name of Tiktok user could be found in profile link
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo * example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
* @return LiveClientBuilder * @return LiveClientBuilder
*/ */
public static LiveClientBuilder newClient(String hostName) public static LiveClientBuilder newClient(String hostName) {
{
return new TikTokLiveClientBuilder(hostName); return new TikTokLiveClientBuilder(hostName);
} }
/** /**
* *
* @param hostName profile name of Tiktok user could be found in profile link * @param hostName profile name of Tiktok user could be found in profile link
@@ -51,7 +47,7 @@ public class TikTokLive
*/ */
public static boolean isLiveOnline(String hostName) public static boolean isLiveOnline(String hostName)
{ {
return new TikTokDataChecker().isOnline(hostName); return requests().fetchLiveUserData(hostName).isLiveOnline();
} }
@@ -63,7 +59,7 @@ public class TikTokLive
*/ */
public static CompletableFuture<Boolean> isLiveOnlineAsync(String hostName) public static CompletableFuture<Boolean> isLiveOnlineAsync(String hostName)
{ {
return new TikTokDataChecker().isOnlineAsync(hostName); return CompletableFuture.supplyAsync(()-> isLiveOnline(hostName));
} }
/** /**
@@ -74,7 +70,7 @@ public class TikTokLive
*/ */
public static boolean isHostNameValid(String hostName) public static boolean isHostNameValid(String hostName)
{ {
return new TikTokDataChecker().isHostNameValid(hostName); return requests().fetchLiveUserData(hostName).isHostNameValid();
} }
/** /**
@@ -85,7 +81,15 @@ public class TikTokLive
*/ */
public static CompletableFuture<Boolean> isHostNameValidAsync(String hostName) public static CompletableFuture<Boolean> isHostNameValidAsync(String hostName)
{ {
return new TikTokDataChecker().isHostNameValidAsync(hostName); return CompletableFuture.supplyAsync(()-> isHostNameValid(hostName));
} }
} /**
* Use to get some data from TikTok about users are lives
*
* @return LiveHttpClient
*/
public static LiveHttpClient requests() {
return new TikTokLiveHttpClient();
}
}

View File

@@ -22,24 +22,24 @@
*/ */
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.dto.TikTokUserInfo;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent; import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.data.requests.LiveData;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager; import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.listener.ListenersManager; import io.github.jwdeveloper.tiktok.listener.ListenersManager;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager; import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.live.GiftManager; import io.github.jwdeveloper.tiktok.live.GiftManager;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo; import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
import io.github.jwdeveloper.tiktok.models.ConnectionState; import io.github.jwdeveloper.tiktok.models.ConnectionState;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.websocket.SocketClient; import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -49,24 +49,24 @@ import java.util.logging.Logger;
public class TikTokLiveClient implements LiveClient { public class TikTokLiveClient implements LiveClient {
private final TikTokRoomInfo liveRoomInfo; private final TikTokRoomInfo liveRoomInfo;
private final TikTokGiftManager tikTokGiftManager; private final TikTokGiftManager tikTokGiftManager;
private final TikTokApiService apiService; private final TikTokLiveHttpClient httpClient;
private final SocketClient webSocketClient; private final SocketClient webSocketClient;
private final TikTokEventObserver tikTokEventHandler; private final TikTokLiveEventHandler tikTokEventHandler;
private final ClientSettings clientSettings; private final LiveClientSettings clientSettings;
private final TikTokListenersManager listenersManager; private final TikTokListenersManager listenersManager;
private final Logger logger; private final Logger logger;
public TikTokLiveClient(TikTokRoomInfo tikTokLiveMeta, public TikTokLiveClient(TikTokRoomInfo tikTokLiveMeta,
TikTokApiService tikTokApiService, TikTokLiveHttpClient tiktokHttpClient,
SocketClient webSocketClient, SocketClient webSocketClient,
TikTokGiftManager tikTokGiftManager, TikTokGiftManager tikTokGiftManager,
TikTokEventObserver tikTokEventHandler, TikTokLiveEventHandler tikTokEventHandler,
ClientSettings clientSettings, LiveClientSettings clientSettings,
TikTokListenersManager listenersManager, TikTokListenersManager listenersManager,
Logger logger) { Logger logger) {
this.liveRoomInfo = tikTokLiveMeta; this.liveRoomInfo = tikTokLiveMeta;
this.tikTokGiftManager = tikTokGiftManager; this.tikTokGiftManager = tikTokGiftManager;
this.apiService = tikTokApiService; this.httpClient = tiktokHttpClient;
this.webSocketClient = webSocketClient; this.webSocketClient = webSocketClient;
this.tikTokEventHandler = tikTokEventHandler; this.tikTokEventHandler = tikTokEventHandler;
this.clientSettings = clientSettings; this.clientSettings = clientSettings;
@@ -76,17 +76,15 @@ public class TikTokLiveClient implements LiveClient {
public void connectAsync(Consumer<LiveClient> onConnection) { public void connectAsync(Consumer<LiveClient> onConnection) {
CompletableFuture.supplyAsync(() -> CompletableFuture.runAsync(() -> {
{
connect(); connect();
onConnection.accept(this); onConnection.accept(this);
return this;
}); });
} }
public CompletableFuture<LiveClient> connectAsync() { public CompletableFuture<LiveClient> connectAsync() {
return CompletableFuture.supplyAsync(() -> return CompletableFuture.supplyAsync(() -> {
{
connect(); connect();
return this; return this;
}); });
@@ -103,8 +101,7 @@ public class TikTokLiveClient implements LiveClient {
if (e instanceof TikTokLiveOfflineHostException && clientSettings.isRetryOnConnectionFailure()) { if (e instanceof TikTokLiveOfflineHostException && clientSettings.isRetryOnConnectionFailure()) {
try { try {
Thread.sleep(clientSettings.getRetryConnectionTimeout().toMillis()); Thread.sleep(clientSettings.getRetryConnectionTimeout().toMillis());
} catch (Exception ignored) { } catch (Exception ignored) {}
}
logger.info("Reconnecting"); logger.info("Reconnecting");
tikTokEventHandler.publish(this, new TikTokReconnectingEvent()); tikTokEventHandler.publish(this, new TikTokReconnectingEvent());
this.connect(); this.connect();
@@ -117,6 +114,47 @@ public class TikTokLiveClient implements LiveClient {
} }
} }
public void tryConnect() {
if (!liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
throw new TikTokLiveException("Already connected");
}
setState(ConnectionState.CONNECTING);
var userDataRequest = new LiveUserData.Request(liveRoomInfo.getHostName());
var userData = httpClient.fetchLiveUserData(userDataRequest);
liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp());
liveRoomInfo.setRoomId(userData.getRoomId());
if (userData.getUserStatus() == LiveUserData.UserStatus.Offline) {
throw new TikTokLiveOfflineHostException("User is offline: "+liveRoomInfo.getHostUser());
}
if (userData.getUserStatus() == LiveUserData.UserStatus.NotFound) {
throw new TikTokLiveOfflineHostException("User not found: "+liveRoomInfo.getHostUser());
}
var liveDataRequest = new LiveData.Request(userData.getRoomId());
var liveData = httpClient.fetchLiveData(liveDataRequest);
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostNotFound) {
throw new TikTokLiveOfflineHostException("LiveStream for Host name could not be found.");
}
if (liveData.getLiveStatus() == LiveData.LiveStatus.HostOffline) {
throw new TikTokLiveOfflineHostException("LiveStream for not be found, is the Host offline?");
}
liveRoomInfo.setTitle(liveData.getTitle());
liveRoomInfo.setViewersCount(liveData.getViewers());
liveRoomInfo.setTotalViewersCount(liveData.getTotalViewers());
liveRoomInfo.setAgeRestricted(liveData.isAgeRestricted());
liveRoomInfo.setHost(liveData.getHost());
var liveConnectionRequest =new LiveConnectionData.Request(userData.getRoomId());
var liveConnectionData = httpClient.fetchLiveConnectionData(liveConnectionRequest);
webSocketClient.start(liveConnectionData, this);
setState(ConnectionState.CONNECTED);
tikTokEventHandler.publish(this, new TikTokRoomInfoEvent(liveRoomInfo));
}
public void disconnect() { public void disconnect() {
if (liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) { if (liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
return; return;
@@ -125,48 +163,14 @@ public class TikTokLiveClient implements LiveClient {
setState(ConnectionState.DISCONNECTED); setState(ConnectionState.DISCONNECTED);
} }
public void tryConnect() { private void setState(ConnectionState connectionState) {
if (liveRoomInfo.hasConnectionState(ConnectionState.CONNECTED)) logger.info("TikTokLive client state: " + connectionState.name());
throw new TikTokLiveException("Already connected"); liveRoomInfo.setConnectionState(connectionState);
if (liveRoomInfo.hasConnectionState(ConnectionState.CONNECTING))
throw new TikTokLiveException("Already connecting");
setState(ConnectionState.CONNECTING);
apiService.updateSessionId();
TikTokUserInfo info = apiService.fetchUserInfoFromTikTokApi(liveRoomInfo.getHostName());
liveRoomInfo.setStartTime(info.getStartTime());
if (clientSettings.getRoomId() != null) {
liveRoomInfo.setRoomId(clientSettings.getRoomId());
logger.info("Using roomID from settings: " + clientSettings.getRoomId());
} else {
liveRoomInfo.setRoomId(info.getRoomId());
}
apiService.updateRoomId(liveRoomInfo.getRoomId());
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));
} }
public void publishEvent(TikTokEvent event) {
tikTokEventHandler.publish(this, event);
}
public LiveRoomInfo getRoomInfo() { public LiveRoomInfo getRoomInfo() {
return liveRoomInfo; return liveRoomInfo;
@@ -186,15 +190,4 @@ public class TikTokLiveClient implements LiveClient {
public GiftManager getGiftManager() { public GiftManager getGiftManager() {
return tikTokGiftManager; return tikTokGiftManager;
} }
private void setState(ConnectionState connectionState) {
logger.info("TikTokLive client state: " + connectionState.name());
liveRoomInfo.setConnectionState(connectionState);
}
public void publishEvent(TikTokEvent event)
{
tikTokEventHandler.publish(this, event);
}
} }

View File

@@ -40,12 +40,7 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketRespons
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent; import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandledMessageEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager; import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver; import io.github.jwdeveloper.tiktok.http.HttpClientFactory;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener; import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager; import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.live.GiftManager; import io.github.jwdeveloper.tiktok.live.GiftManager;
@@ -62,10 +57,10 @@ import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokGiftEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokRoomInfoEventHandler; import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokRoomInfoEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokSocialMediaEventHandler; import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokSocialMediaEventHandler;
import io.github.jwdeveloper.tiktok.messages.webcast.*; import io.github.jwdeveloper.tiktok.messages.webcast.*;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.utils.ConsoleColors; import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient; import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -74,17 +69,17 @@ import java.util.logging.*;
public class TikTokLiveClientBuilder implements LiveClientBuilder { public class TikTokLiveClientBuilder implements LiveClientBuilder {
protected final ClientSettings clientSettings; protected final LiveClientSettings clientSettings;
protected final Logger logger; protected final Logger logger;
protected final TikTokEventObserver tikTokEventHandler; protected final TikTokLiveEventHandler tikTokEventHandler;
protected final List<TikTokEventListener> listeners; protected final List<TikTokEventListener> listeners;
protected Consumer<TikTokMapper> onCustomMappings; protected Consumer<TikTokMapper> onCustomMappings;
public TikTokLiveClientBuilder(String userName) { public TikTokLiveClientBuilder(String userName)
this.tikTokEventHandler = new TikTokEventObserver(); {
this.clientSettings = Constants.DefaultClientSettings(); this.clientSettings = LiveClientSettings.createDefault();
this.clientSettings.setHostName(userName); this.clientSettings.setHostName(userName);
this.tikTokEventHandler = new TikTokLiveEventHandler();
this.logger = Logger.getLogger(TikTokLive.class.getSimpleName() + " " + userName); this.logger = Logger.getLogger(TikTokLive.class.getSimpleName() + " " + userName);
this.listeners = new ArrayList<>(); this.listeners = new ArrayList<>();
this.onCustomMappings = (e) -> { this.onCustomMappings = (e) -> {
@@ -97,7 +92,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
} }
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> onConfigure) { public TikTokLiveClientBuilder configure(Consumer<LiveClientSettings> onConfigure) {
onConfigure.accept(clientSettings); onConfigure.accept(clientSettings);
return this; return this;
} }
@@ -108,13 +103,8 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
} }
protected void validate() { protected void validate() {
if (clientSettings.getTimeout() == null) {
clientSettings.setTimeout(Duration.ofSeconds(Constants.DEFAULT_TIMEOUT));
}
if (clientSettings.getClientLanguage() == null || clientSettings.getClientLanguage().isEmpty()) { if (clientSettings.getClientLanguage() == null || clientSettings.getClientLanguage().isEmpty()) {
clientSettings.setClientLanguage(Constants.DefaultClientSettings().getClientLanguage()); clientSettings.setClientLanguage("en");
} }
@@ -127,9 +117,9 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
} }
var params = clientSettings.getClientParameters(); var httpSettings = clientSettings.getHttpSettings();
params.put("app_language", clientSettings.getClientLanguage()); httpSettings.getParams().put("app_language", clientSettings.getClientLanguage());
params.put("webcast_language", clientSettings.getClientLanguage()); httpSettings.getParams().put("webcast_language", clientSettings.getClientLanguage());
var handler = new ConsoleHandler(); var handler = new ConsoleHandler();
@@ -146,9 +136,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
}); });
logger.setUseParentHandlers(false); logger.setUseParentHandlers(false);
logger.addHandler(handler); logger.addHandler(handler);
logger.setLevel(clientSettings.getLogLevel()); logger.setLevel(clientSettings.getLogLevel());
if (!clientSettings.isPrintToConsole()) { if (!clientSettings.isPrintToConsole()) {
logger.setLevel(Level.OFF); logger.setLevel(Level.OFF);
} }
@@ -161,23 +149,22 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
tiktokRoomInfo.setHostName(clientSettings.getHostName()); tiktokRoomInfo.setHostName(clientSettings.getHostName());
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler); var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
var cookieJar = new TikTokCookieJar();
var requestFactory = new TikTokHttpRequestFactory(cookieJar, tikTokEventHandler);
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
var giftManager = new TikTokGiftManager(logger); var giftManager = new TikTokGiftManager(logger);
var eventsMapper = createMapper(giftManager, tiktokRoomInfo); var eventsMapper = createMapper(giftManager, tiktokRoomInfo);
var messageHandler = new TikTokMessageHandler(tikTokEventHandler, eventsMapper); var messageHandler = new TikTokLiveMessageHandler(tikTokEventHandler, eventsMapper);
var httpClientFactory = new HttpClientFactory(clientSettings);
var tikTokLiveHttpClient = new TikTokLiveHttpClient(httpClientFactory, clientSettings);
var webSocketClient = new TikTokWebSocketClient( var webSocketClient = new TikTokWebSocketClient(
cookieJar,
clientSettings, clientSettings,
messageHandler, messageHandler,
tikTokEventHandler); tikTokEventHandler);
return new TikTokLiveClient(tiktokRoomInfo, return new TikTokLiveClient(tiktokRoomInfo,
apiService, tikTokLiveHttpClient,
webSocketClient, webSocketClient,
giftManager, giftManager,
tikTokEventHandler, tikTokEventHandler,
@@ -187,6 +174,11 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
} }
public TikTokLiveMapper createMapper(GiftManager giftManager, TikTokRoomInfo roomInfo) { public TikTokLiveMapper createMapper(GiftManager giftManager, TikTokRoomInfo roomInfo) {
/*
//
*/
var eventMapper = new TikTokGenericEventMapper(); var eventMapper = new TikTokGenericEventMapper();
var mapper = new TikTokLiveMapper(new TikTokLiveMapperHelper(eventMapper)); var mapper = new TikTokLiveMapper(new TikTokLiveMapperHelper(eventMapper));
@@ -248,14 +240,14 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
//LinkMic events //LinkMic events
// mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class); // mapper.webcastObjectToConstructor(WebcastLinkMicBattle.class, TikTokLinkMicBattleEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class); // mapper.webcastObjectToConstructor(WebcastLinkMicArmies.class, TikTokLinkMicArmiesEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class); // mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class); // mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
//Rank events //Rank events
// mapper.webcastObjectToConstructor(WebcastRankTextMessage.class, TikTokRankTextEvent.class); // mapper.webcastObjectToConstructor(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
// mapper.webcastObjectToConstructor(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class); // mapper.webcastObjectToConstructor(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
// mapper.webcastObjectToConstructor(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class); // mapper.webcastObjectToConstructor(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
//Others events //Others events
@@ -263,7 +255,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
// mapper.webcastObjectToConstructor(WebcastMsgDetectMessage.class, TikTokDetectEvent.class); // mapper.webcastObjectToConstructor(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
// mapper.webcastObjectToConstructor(WebcastBarrageMessage.class, TikTokBarrageEvent.class); // mapper.webcastObjectToConstructor(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
// mapper.webcastObjectToConstructor(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class); // mapper.webcastObjectToConstructor(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
// mapper.webcastObjectToConstructor(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class); // mapper.webcastObjectToConstructor(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
// mapper.webcastObjectToConstructor(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class); // mapper.webcastObjectToConstructor(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
// mapper.bytesToEvents(WebcastEnvelopeMessage.class, commonHandler::handleEnvelop); // mapper.bytesToEvents(WebcastEnvelopeMessage.class, commonHandler::handleEnvelop);
@@ -354,7 +346,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
@Override @Override
public LiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) { public TikTokLiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomInfoEvent.class, event); tikTokEventHandler.subscribe(TikTokRoomInfoEvent.class, event);
return this; return this;
} }
@@ -366,7 +358,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
} }
@Override @Override
public LiveClientBuilder onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event) { public TikTokLiveClientBuilder onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event) {
tikTokEventHandler.subscribe(TikTokLiveUnpausedEvent.class, event); tikTokEventHandler.subscribe(TikTokLiveUnpausedEvent.class, event);
return this; return this;
} }

View File

@@ -20,7 +20,7 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.handlers; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer; import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
@@ -31,10 +31,10 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
public class TikTokEventObserver { public class TikTokLiveEventHandler {
private final Map<Class<?>, Set<EventConsumer>> events; private final Map<Class<?>, Set<EventConsumer>> events;
public TikTokEventObserver() { public TikTokLiveEventHandler() {
events = new HashMap<>(); events = new HashMap<>();
} }

View File

@@ -0,0 +1,247 @@
/*
* 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;
import com.google.protobuf.InvalidProtocolBufferException;
import io.github.jwdeveloper.tiktok.data.requests.*;
import io.github.jwdeveloper.tiktok.data.settings.*;
import io.github.jwdeveloper.tiktok.exceptions.*;
import io.github.jwdeveloper.tiktok.http.*;
import io.github.jwdeveloper.tiktok.http.mappers.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.net.http.HttpResponse;
import java.util.Optional;
public class TikTokLiveHttpClient implements LiveHttpClient {
/**
* Signing API by Isaac Kogan
* https://github-wiki-see.page/m/isaackogan/TikTokLive/wiki/All-About-Signatures
*/
private static final String TIKTOK_SIGN_API = "https://tiktok.eulerstream.com/webcast/sign_url";
private static final String TIKTOK_URL_WEB = "https://www.tiktok.com/";
private static final String TIKTOK_URL_WEBCAST = "https://webcast.tiktok.com/webcast/";
private final HttpClientFactory httpFactory;
private final LiveClientSettings clientSettings;
private final LiveUserDataMapper liveUserDataMapper;
private final LiveDataMapper liveDataMapper;
private final SignServerResponseMapper signServerResponseMapper;
private final GiftsDataMapper giftsDataMapper;
public TikTokLiveHttpClient(HttpClientFactory factory, LiveClientSettings settings) {
this.httpFactory = factory;
clientSettings = settings;
liveUserDataMapper = new LiveUserDataMapper();
liveDataMapper = new LiveDataMapper();
signServerResponseMapper = new SignServerResponseMapper();
giftsDataMapper = new GiftsDataMapper();
}
public TikTokLiveHttpClient() {
this(new HttpClientFactory(LiveClientSettings.createDefault()), LiveClientSettings.createDefault());
}
public GiftsData.Response fetchGiftsData() {
var url = TIKTOK_URL_WEBCAST + "gift/list/";
var optional = httpFactory.client(url)
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokLiveRequestException("Unable to fetch gifts information's");
}
var json = optional.get();
return giftsDataMapper.map(json);
}
@Override
public LiveUserData.Response fetchLiveUserData(String userName) {
return fetchLiveUserData(new LiveUserData.Request(userName));
}
@Override
public LiveUserData.Response fetchLiveUserData(LiveUserData.Request request) {
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
if (proxyClientSettings.isEnabled()) {
while (proxyClientSettings.hasNext()) {
try {
var url = TIKTOK_URL_WEB + "api-live/user/room";
var optional = httpFactory.client(url)
.withParam("uniqueId", request.getUserName())
.withParam("sourceType", "54")
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokLiveRequestException("Unable to get information's about user");
}
var json = optional.get();
return liveUserDataMapper.map(json);
} catch (TikTokProxyRequestException ignored) {}
}
}
var url = TIKTOK_URL_WEB + "api-live/user/room";
var optional = httpFactory.client(url)
.withParam("uniqueId", request.getUserName())
.withParam("sourceType", "54")
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokLiveRequestException("Unable to get information's about user");
}
var json = optional.get();
return liveUserDataMapper.map(json);
}
@Override
public LiveData.Response fetchLiveData(String roomId) {
return fetchLiveData(new LiveData.Request(roomId));
}
@Override
public LiveData.Response fetchLiveData(LiveData.Request request) {
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
if (proxyClientSettings.isEnabled()) {
while (proxyClientSettings.hasNext()) {
try {
var url = TIKTOK_URL_WEBCAST + "room/info";
var optional = httpFactory.client(url)
.withParam("room_id", request.getRoomId())
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokLiveRequestException("Unable to get info about live room");
}
var json = optional.get();
return liveDataMapper.map(json);
} catch (TikTokProxyRequestException ignored) {}
}
}
var url = TIKTOK_URL_WEBCAST + "room/info";
var optional = httpFactory.client(url)
.withParam("room_id", request.getRoomId())
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokLiveRequestException("Unable to get info about live room");
}
var json = optional.get();
return liveDataMapper.map(json);
}
@Override
public LiveConnectionData.Response fetchLiveConnectionData(String roomId) {
return fetchLiveConnectionData(new LiveConnectionData.Request(roomId));
}
@Override
public LiveConnectionData.Response fetchLiveConnectionData(LiveConnectionData.Request request) {
HttpResponse<byte[]> credentialsResponse = getOptionalProxyResponse(request).orElseGet(()-> {
SignServerResponse signServerResponse = getSignedUrl(request.getRoomId());
return getWebsocketCredentialsResponse(signServerResponse.getSignedUrl());
});
try {
var optionalHeader = credentialsResponse.headers().firstValue("set-cookie");
if (optionalHeader.isEmpty()) {
throw new TikTokSignServerException("Sign server did not return the set-cookie header");
}
var websocketCookie = optionalHeader.get();
var webcastResponse = WebcastResponse.parseFrom(credentialsResponse.body());
var webSocketUrl = httpFactory
.client(webcastResponse.getPushServer())
.withParam("room_id", request.getRoomId())
.withParam("cursor", webcastResponse.getCursor())
.withParam("resp_content_type", "protobuf")
.withParam("internal_ext", webcastResponse.getInternalExt())
.withParams(webcastResponse.getRouteParamsMapMap())
.build()
.toUrl();
return new LiveConnectionData.Response(websocketCookie, webSocketUrl, webcastResponse);
} catch (InvalidProtocolBufferException e) {
throw new TikTokSignServerException("Unable to parse websocket credentials response to WebcastResponse");
}
}
SignServerResponse getSignedUrl(String roomId) {
var urlToSign = httpFactory
.client(TikTokLiveHttpClient.TIKTOK_URL_WEBCAST + "im/fetch")
.withParam("room_id", roomId)
.build()
.toUrl();
var optional = httpFactory
.client(TikTokLiveHttpClient.TIKTOK_SIGN_API)
.withParam("client", "ttlive-java")
.withParam("uuc", "1")
.withParam("url", urlToSign.toString())
.build()
.toJsonResponse();
if (optional.isEmpty()) {
throw new TikTokSignServerException("Unable to sign url: " + urlToSign);
}
var json = optional.get();
return signServerResponseMapper.map(json);
}
HttpResponse<byte[]> getWebsocketCredentialsResponse(String signedUrl) {
var optionalResponse = httpFactory
.clientEmpty(signedUrl)
.build()
.toResponse();
if (optionalResponse.isEmpty()) {
throw new TikTokSignServerException("Unable to get websocket connection credentials");
}
return optionalResponse.get();
}
Optional<HttpResponse<byte[]>> getOptionalProxyResponse(LiveConnectionData.Request request) {
var proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
if (proxyClientSettings.isEnabled()) {
while (proxyClientSettings.hasNext()) {
try {
SignServerResponse signServerResponse = getSignedUrl(request.getRoomId());
HttpResponse<byte[]> credentialsResponse = getWebsocketCredentialsResponse(signServerResponse.getSignedUrl());
clientSettings.getHttpSettings().getProxyClientSettings().rotate();
return Optional.of(credentialsResponse);
} catch (TikTokProxyRequestException | TikTokSignServerException ignored) {}
}
}
return Optional.empty();
}
}

View File

@@ -20,7 +20,7 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.handlers; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.dto.MessageMetaData; import io.github.jwdeveloper.tiktok.data.dto.MessageMetaData;
@@ -36,18 +36,16 @@ import io.github.jwdeveloper.tiktok.utils.Stopwatch;
import java.time.Duration; import java.time.Duration;
public class TikTokLiveMessageHandler {
public class TikTokMessageHandler { private final TikTokLiveEventHandler tikTokEventHandler;
private final TikTokEventObserver tikTokEventHandler;
private final TikTokLiveMapper mapper; private final TikTokLiveMapper mapper;
public TikTokMessageHandler(TikTokEventObserver tikTokEventHandler, TikTokLiveMapper mapper) { public TikTokLiveMessageHandler(TikTokLiveEventHandler tikTokEventHandler, TikTokLiveMapper mapper) {
this.tikTokEventHandler = tikTokEventHandler; this.tikTokEventHandler = tikTokEventHandler;
this.mapper = mapper; this.mapper = mapper;
} }
public void handle(LiveClient client, WebcastResponse webcastResponse) { public void handle(LiveClient client, WebcastResponse webcastResponse) {
tikTokEventHandler.publish(client, new TikTokWebsocketResponseEvent(webcastResponse)); tikTokEventHandler.publish(client, new TikTokWebsocketResponseEvent(webcastResponse));
for (var message : webcastResponse.getMessagesList()) { for (var message : webcastResponse.getMessagesList()) {
@@ -60,7 +58,8 @@ public class TikTokMessageHandler {
} }
} }
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message) throws Exception { public void handleSingleMessage(LiveClient client, WebcastResponse.Message message)
{
var messageClassName = message.getMethod(); var messageClassName = message.getMethod();
if (!mapper.isRegistered(messageClassName)) { if (!mapper.isRegistered(messageClassName)) {
tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message)); tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message));

View File

@@ -22,14 +22,12 @@
*/ */
package io.github.jwdeveloper.tiktok.gifts; package io.github.jwdeveloper.tiktok.gifts;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.live.GiftManager; import io.github.jwdeveloper.tiktok.live.GiftManager;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*; import java.util.*;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -89,23 +87,17 @@ public class TikTokGiftManager implements GiftManager {
} }
public Gift findById(int giftId) { public Gift findById(int giftId) {
if (!indexById.containsKey(giftId)) { Gift gift = indexById.get(giftId);
return Gift.UNDEFINED; return gift == null ? Gift.UNDEFINED : gift;
}
return indexById.get(giftId);
} }
public Gift findByName(String giftName) { public Gift findByName(String giftName) {
if (!indexByName.containsKey(giftName)) { Gift gift = indexByName.get(giftName);
return Gift.UNDEFINED; return gift == null ? Gift.UNDEFINED : gift;
}
return indexByName.get(giftName);
} }
@Override @Override
public List<Gift> getGifts() public List<Gift> getGifts() {
{
return indexById.values().stream().toList(); return indexById.values().stream().toList();
} }
}
}

View File

@@ -0,0 +1,129 @@
/*
* 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.data.settings.HttpClientSettings;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import lombok.AllArgsConstructor;
import java.net.*;
import java.net.http.*;
import java.nio.charset.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.Collectors;
@AllArgsConstructor
public class HttpClient {
protected final HttpClientSettings httpClientSettings;
protected final String url;
private final Pattern pattern = Pattern.compile("charset=(.*?)(?=&|$)");
public Optional<HttpResponse<byte[]>> toResponse() {
var client = prepareClient();
var request = prepareGetRequest();
try {
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
if (response.statusCode() != 200) {
return Optional.empty();
}
return Optional.of(response);
} catch (Exception e) {
throw new TikTokLiveRequestException(e);
}
}
public Optional<String> toJsonResponse() {
var optional = toResponse();
if (optional.isEmpty()) {
return Optional.empty();
}
var response = optional.get();
var body = response.body();
var charset = charsetFrom(response.headers());
return Optional.of(new String(body,charset));
}
private Charset charsetFrom(HttpHeaders headers) {
String type = headers.firstValue("Content-type").orElse("text/html; charset=utf-8");
int i = type.indexOf(";");
if (i >= 0) type = type.substring(i+1);
try {
Matcher matcher = pattern.matcher(type);
if (!matcher.find())
return StandardCharsets.UTF_8;
return Charset.forName(matcher.group(1));
} catch (Throwable x) {
return StandardCharsets.UTF_8;
}
}
public Optional<byte[]> toBinaryResponse() {
var optional = toResponse();
if (optional.isEmpty()) {
return Optional.empty();
}
var body = optional.get().body();
return Optional.of(body);
}
public URI toUrl() {
var stringUrl = prepareUrlWithParameters(url, httpClientSettings.getParams());
return URI.create(stringUrl);
}
protected HttpRequest prepareGetRequest() {
var requestBuilder = HttpRequest.newBuilder().GET();
requestBuilder.uri(toUrl());
requestBuilder.timeout(httpClientSettings.getTimeout());
httpClientSettings.getHeaders().forEach(requestBuilder::setHeader);
httpClientSettings.getOnRequestCreating().accept(requestBuilder);
return requestBuilder.build();
}
protected java.net.http.HttpClient prepareClient() {
var builder = java.net.http.HttpClient.newBuilder()
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL)
.cookieHandler(new CookieManager())
.connectTimeout(httpClientSettings.getTimeout());
httpClientSettings.getOnClientCreating().accept(builder);
return builder.build();
}
protected String prepareUrlWithParameters(String url, Map<String, Object> parameters) {
if (parameters.isEmpty()) {
return url;
}
return url + "?" + parameters.entrySet().stream().map(entry ->
{
var encodedKey = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8);
var encodedValue = URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8);
return encodedKey + "=" + encodedValue;
}).collect(Collectors.joining("&"));
}
}

View File

@@ -0,0 +1,85 @@
/*
* 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.data.settings.HttpClientSettings;
import java.util.Map;
import java.util.function.Consumer;
public class HttpClientBuilder {
private final HttpClientSettings httpClientSettings;
private String url;
public HttpClientBuilder(String url, HttpClientSettings httpClientSettings) {
this.httpClientSettings = httpClientSettings;
this.url = url;
}
public HttpClientBuilder(String url) {
httpClientSettings = new HttpClientSettings();
this.url = url;
}
public HttpClientBuilder withUrl(String url) {
this.url = url;
return this;
}
public HttpClientBuilder withHttpClientSettings(Consumer<HttpClientSettings> consumer) {
consumer.accept(httpClientSettings);
return this;
}
public HttpClientBuilder withCookie(String name, String value) {
httpClientSettings.getCookies().put(name, value);
return this;
}
public HttpClientBuilder withHeader(String name, String value) {
httpClientSettings.getHeaders().put(name, value);
return this;
}
public HttpClientBuilder withParam(String name, String value) {
httpClientSettings.getParams().put(name, value);
return this;
}
public HttpClientBuilder withParams(Map<String, String> parameters) {
httpClientSettings.getParams().putAll(parameters);
return this;
}
public HttpClientBuilder withHeaders(Map<String, String> headers) {
httpClientSettings.getHeaders().putAll(headers);
return this;
}
public HttpClient build() {
if (httpClientSettings.getProxyClientSettings().isEnabled())
return new HttpProxyClient(httpClientSettings, url);
return new HttpClient(httpClientSettings, url);
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.http;
import io.github.jwdeveloper.tiktok.data.settings.*;
public class HttpClientFactory {
private final LiveClientSettings liveClientSettings;
public HttpClientFactory(LiveClientSettings liveClientSettings) {
this.liveClientSettings = liveClientSettings;
}
public HttpClientBuilder client(String url) {
return new HttpClientBuilder(url, liveClientSettings.getHttpSettings().clone());
}
//Does not contains default httpClientSettings, Params, headers, etd
public HttpClientBuilder clientEmpty(String url) {
var settings = new HttpClientSettings();
settings.setProxyClientSettings(liveClientSettings.getHttpSettings().getProxyClientSettings());
return new HttpClientBuilder(url, settings);
}
}

View File

@@ -0,0 +1,208 @@
/*
* 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.data.settings.*;
import io.github.jwdeveloper.tiktok.exceptions.*;
import javax.net.ssl.*;
import java.io.IOException;
import java.net.*;
import java.net.http.*;
import java.net.http.HttpResponse.ResponseInfo;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;
public class HttpProxyClient extends HttpClient
{
private final ProxyClientSettings proxySettings;
public HttpProxyClient(HttpClientSettings httpClientSettings, String url) {
super(httpClientSettings, url);
this.proxySettings = httpClientSettings.getProxyClientSettings();
}
public Optional<HttpResponse<byte[]>> toResponse() {
return switch (proxySettings.getType()) {
case HTTP, DIRECT -> handleHttpProxyRequest();
default -> handleSocksProxyRequest();
};
}
public Optional<HttpResponse<byte[]>> handleHttpProxyRequest() {
var builder = java.net.http.HttpClient.newBuilder()
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL)
.cookieHandler(new CookieManager())
.connectTimeout(httpClientSettings.getTimeout());
while (proxySettings.hasNext()) {
try {
InetSocketAddress address = proxySettings.next().toSocketAddress();
builder.proxy(ProxySelector.of(address));
httpClientSettings.getOnClientCreating().accept(builder);
var client = builder.build();
var request = prepareGetRequest();
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
if (response.statusCode() != 200) {
proxySettings.setLastSuccess(false);
continue;
}
proxySettings.setLastSuccess(true);
return Optional.of(response);
} catch (HttpConnectTimeoutException | ConnectException e) {
if (proxySettings.isAutoDiscard())
proxySettings.remove();
proxySettings.setLastSuccess(false);
} catch (Exception e) {
throw new TikTokLiveRequestException(e);
}
}
throw new TikTokLiveRequestException("No more proxies available!");
}
private Optional<HttpResponse<byte[]>> handleSocksProxyRequest() {
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{ new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}
public X509Certificate[] getAcceptedIssuers() { return null; }
}}, null);
URL url = toUrl().toURL();
if (proxySettings.hasNext()) {
try {
Proxy proxy = new Proxy(Proxy.Type.SOCKS, proxySettings.next().toSocketAddress());
System.err.println("Connecting to "+ url);
HttpsURLConnection socksConnection = (HttpsURLConnection) url.openConnection(proxy);
socksConnection.setSSLSocketFactory(sc.getSocketFactory());
socksConnection.setConnectTimeout(httpClientSettings.getTimeout().toMillisPart());
socksConnection.setReadTimeout(httpClientSettings.getTimeout().toMillisPart());
byte[] body = socksConnection.getInputStream().readAllBytes();
Map<String, List<String>> headers = socksConnection.getHeaderFields()
.entrySet()
.stream()
.filter(entry -> entry.getKey() != null)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
var responseInfo = createResponseInfo(socksConnection.getResponseCode(), headers);
var response = createHttpResponse(body, toUrl(), responseInfo);
proxySettings.setLastSuccess(true);
return Optional.of(response);
} catch (IOException e) {
if (proxySettings.isAutoDiscard())
proxySettings.remove();
proxySettings.setLastSuccess(false);
throw new TikTokProxyRequestException(e);
} catch (Exception e) {
throw new TikTokLiveRequestException(e);
}
}
throw new TikTokLiveRequestException("No more proxies available!");
} catch (NoSuchAlgorithmException | MalformedURLException | KeyManagementException e) {
// Should never be reached!
System.out.println("handleSocksProxyRequest()! If you see this message, reach us on discord!");
e.printStackTrace();
return Optional.empty();
} catch (TikTokLiveRequestException e) {
e.printStackTrace();
return Optional.empty();
}
}
private ResponseInfo createResponseInfo(int code, Map<String, List<String>> headers) {
return new ResponseInfo() {
@Override
public int statusCode() {
return code;
}
@Override
public HttpHeaders headers() {
return HttpHeaders.of(headers, (s, s1) -> s != null);
}
@Override
public java.net.http.HttpClient.Version version() {
return java.net.http.HttpClient.Version.HTTP_2;
}
};
}
private HttpResponse<byte[]> createHttpResponse(byte[] body,
URI uri,
ResponseInfo info) {
return new HttpResponse<>()
{
@Override
public int statusCode() {
return info.statusCode();
}
@Override
public HttpRequest request() {
throw new UnsupportedOperationException("TODO");
}
@Override
public Optional<HttpResponse<byte[]>> previousResponse() {
return Optional.empty();
}
@Override
public HttpHeaders headers() {
return info.headers();
}
@Override
public byte[] body() {
return body;
}
@Override
public Optional<SSLSession> sslSession() {
throw new UnsupportedOperationException("TODO");
}
@Override
public URI uri() {
return uri;
}
@Override
public java.net.http.HttpClient.Version version() {
return info.version();
}
};
}
}

View File

@@ -1,51 +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.http;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Collectors;
public class HttpUtils
{
public static String parseParameters(String url, Map<String,Object> parameters)
{
if (parameters.isEmpty())
return url;
return url+ "?" + parameters.entrySet().stream().map(entry -> entry.getKey()+"="+entry.getValue()).collect(Collectors.joining("&"));
}
public static String parseParametersEncode(String url, Map<String,Object> parameters)
{
if (parameters.isEmpty())
return url;
return url+ "?" + parameters.entrySet().stream().map(entry -> {
String encodedKey = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8);
String encodedValue = URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8);
return encodedKey+"="+encodedValue;
}).collect(Collectors.joining("&"));
}
}

View File

@@ -1,138 +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.http;
import com.google.gson.*;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.data.dto.TikTokUserInfo;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
import io.github.jwdeveloper.tiktok.mappers.LiveRoomMetaMapper;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.util.HashMap;
import java.util.logging.Logger;
public class TikTokApiService {
private final TikTokHttpClient tiktokHttpClient;
private final Logger logger;
private final ClientSettings clientSettings;
public TikTokApiService(TikTokHttpClient apiClient, Logger logger, ClientSettings clientSettings) {
this.tiktokHttpClient = apiClient;
this.logger = logger;
this.clientSettings = clientSettings;
}
public void updateSessionId() {
if (clientSettings.getSessionId() == null) {
return;
}
if (clientSettings.getSessionId().isEmpty()) {
return;
}
tiktokHttpClient.setSessionId(clientSettings.getSessionId());
}
public void updateRoomId(String roomId)
{
clientSettings.getClientParameters().put("room_id", roomId);
}
public TikTokUserInfo fetchUserInfoFromTikTokApi(String userName) {
var params = new HashMap<>(clientSettings.getClientParameters());
params.put("uniqueId", userName);
params.put("sourceType", 54);
JsonObject roomData;
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 the developer");
}
if (message.equals("user_not_found")) {
return new TikTokUserInfo(TikTokUserInfo.UserStatus.NotFound, "", -1);
}
//live -> status 2
//live paused -> 3
//not live -> status 4
var element = roomData.get("data");
if (element.isJsonNull()) {
return new TikTokUserInfo(TikTokUserInfo.UserStatus.NotFound, "", -1);
}
var data = element.getAsJsonObject();
var user = data.getAsJsonObject("user");
var roomId = user.get("roomId").getAsString();
var status = user.get("status").getAsInt();
var liveRoom = data.getAsJsonObject("liveRoom");
long startTime = liveRoom.get("startTime").getAsLong();
var statusEnum = switch (status) {
case 2 -> TikTokUserInfo.UserStatus.Live;
case 3 -> TikTokUserInfo.UserStatus.LivePaused;
case 4 -> TikTokUserInfo.UserStatus.Offline;
default -> TikTokUserInfo.UserStatus.NotFound;
};
return new TikTokUserInfo(statusEnum, roomId, startTime);
}
public LiveRoomMeta fetchRoomInfo() {
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 server, see stacktrace for more info.", e);
}
}
public WebcastResponse fetchClientData() {
logger.info("Fetching ClientData");
try {
var response = tiktokHttpClient.getSigningServerResponse("im/fetch/", clientSettings.getClientParameters());
clientSettings.getClientParameters().put("cursor", response.getCursor());
clientSettings.getClientParameters().put("internal_ext", response.getInternalExt());
return response;
} catch (Exception e) {
throw new TikTokLiveRequestException("Failed to fetch live websocket connection data", e);
}
}
}

View File

@@ -1,66 +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.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 io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Logger;
import java.util.regex.Pattern;
public class TikTokDataChecker {
public CompletableFuture<Boolean> isOnlineAsync(String hostName) {
return CompletableFuture.supplyAsync(() -> isOnline(hostName));
}
public CompletableFuture<Boolean> isHostNameValidAsync(String hostName) {
return CompletableFuture.supplyAsync(() -> isOnline(hostName));
}
public boolean isOnline(String hostName) {
var data = getApiService().fetchUserInfoFromTikTokApi(hostName);
return data.getUserStatus() == TikTokUserInfo.UserStatus.Live ||
data.getUserStatus() == TikTokUserInfo.UserStatus.LivePaused;
}
public boolean isHostNameValid(String hostName) {
var data = getApiService().fetchUserInfoFromTikTokApi(hostName);
return data.getUserStatus() != TikTokUserInfo.UserStatus.NotFound;
}
public TikTokApiService getApiService() {
var jar = new TikTokCookieJar();
var factory = new TikTokHttpRequestFactory(jar,new TikTokEventObserver());
var client = new TikTokHttpClient(jar, factory);
var settings = new ClientSettings();
settings.setClientParameters(Constants.DefaultClientParams());
var apiService = new TikTokApiService(client, Logger.getGlobal(), settings);
return apiService;
}
}

View File

@@ -1,154 +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.http;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.github.jwdeveloper.tiktok.Constants;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class TikTokHttpClient {
private final TikTokHttpRequestFactory requestFactory;
private final TikTokCookieJar tikTokCookieJar;
public TikTokHttpClient(TikTokCookieJar tikTokCookieJar, TikTokHttpRequestFactory requestFactory) {
this.requestFactory = requestFactory;
this.tikTokCookieJar = tikTokCookieJar;
}
public void setSessionId(String sessionId) {
tikTokCookieJar.set("sessionid", sessionId);
tikTokCookieJar.set("sessionid_ss", sessionId);
tikTokCookieJar.set("sid_tt", sessionId);
}
public String getLivestreamPage(String userName) {
var url = Constants.TIKTOK_URL_WEB + "@" + userName + "/live/";
var get = getRequest(url, null);
return get;
}
public JsonObject getJsonFromTikTokApi(String path, Map<String,Object> params) {
var get = getRequest(Constants.TIKTOK_URL_WEB + path, params);
var json = JsonParser.parseString(get);
var jsonObject = json.getAsJsonObject();
return jsonObject;
}
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;
}
public WebcastResponse getSigningServerResponse(String path, Map<String, Object> parameters) {
var bytes = getSignRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
try {
return WebcastResponse.parseFrom(bytes);
}
catch (Exception e)
{
throw new TikTokLiveRequestException("Unable to deserialize message: "+path,e);
}
}
private String postRequest(String url, Map<String, Object> parameters) {
if (parameters == null) {
parameters = new HashMap<>();
}
var request = requestFactory.setQueries(parameters);
return request.post(url);
}
private String getRequest(String url, Map<String, Object> parameters) {
if (parameters == null) {
parameters = new HashMap<>();
}
var request = requestFactory.setQueries(parameters);
return request.get(url);
}
private byte[] getSignRequest(String url, Map<String, Object> parameters) {
url = getSignedUrl(url, parameters);
try {
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(new URI(url))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
var cookies = response.headers().allValues("Set-Cookie");
for(var cookie : cookies)
{
var split = cookie.split(";")[0].split("=");
var key = split[0];
var value = split[1];
tikTokCookieJar.set(key, value);
}
return response.body();
}
catch (Exception e)
{
throw new TikTokLiveRequestException("Unable to send signature");
}
}
private String getSignedUrl(String url, Map<String, Object> parameters) {
var fullUrl = HttpUtils.parseParameters(url,parameters);
var signParams = new TreeMap<String,Object>();
signParams.put("client", "ttlive-java");
signParams.put("uuc", 1);
signParams.put("url", fullUrl);
var request = requestFactory.setQueries(signParams);
var content = request.get(Constants.TIKTOK_SIGN_API);
try {
var json = JsonParser.parseString(content);
var jsonObject = json.getAsJsonObject();
var signedUrl = jsonObject.get("signedUrl").getAsString();
var userAgent = jsonObject.get("User-Agent").getAsString();
requestFactory.setAgent(userAgent);
return signedUrl;
} catch (Exception e) {
throw new TikTokLiveRequestException("Insufficient values have been supplied for signing. Likely due to an update. Post an issue on GitHub.", e);
}
}
}

View File

@@ -1,167 +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.http;
import io.github.jwdeveloper.tiktok.Constants;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
import io.github.jwdeveloper.tiktok.data.models.http.HttpData;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import lombok.SneakyThrows;
import java.net.CookieManager;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
public class TikTokHttpRequestFactory implements TikTokHttpRequest {
private final CookieManager cookieManager;
private final Map<String, String> defaultHeaders;
private final TikTokCookieJar tikTokCookieJar;
private final HttpClient client;
private final TikTokEventObserver eventHandler;
private String query;
public TikTokHttpRequestFactory(TikTokCookieJar tikTokCookieJar, TikTokEventObserver eventHandler) {
this.tikTokCookieJar = tikTokCookieJar;
this.cookieManager = new CookieManager();
this.eventHandler = eventHandler;
defaultHeaders = Constants.DefaultRequestHeaders();
client = HttpClient.newBuilder()
.cookieHandler(cookieManager)
.connectTimeout(Duration.ofSeconds(2))
.build();
}
@SneakyThrows
public String get(String url) {
var uri = URI.create(url);
var requestBuilder = HttpRequest.newBuilder().GET();
for (var header : defaultHeaders.entrySet()) {
if (header.getKey().equals("Connection") || header.getKey().equals("Accept-Encoding")) {
continue;
}
requestBuilder.setHeader(header.getKey(), header.getValue());
}
if (query != null) {
var baseUri = uri.toString();
var requestUri = URI.create(baseUri + "?" + query);
requestBuilder.uri(requestUri);
} else {
requestBuilder.uri(uri);
}
var result = requestBuilder.build();
return getContent(result);
}
@SneakyThrows
public String post(String url) {
var uri = URI.create(url);
var request = HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(""));
for (var header : defaultHeaders.entrySet()) {
if (header.getKey().equals("Connection")) {
continue;
}
request.setHeader(header.getKey(), header.getValue());
}
request.setHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
request.setHeader("Cookie", tikTokCookieJar.parseCookies());
if (query != null) {
var baseUri = uri.toString();
var requestUri = URI.create(baseUri + "?" + query);
request.uri(requestUri);
}
return getContent(request.build());
}
public TikTokHttpRequest setHeader(String key, String value) {
defaultHeaders.put(key, value);
return this;
}
public TikTokHttpRequest setAgent(String value) {
defaultHeaders.put("User-Agent", value);
return this;
}
public TikTokHttpRequest setQueries(Map<String, Object> queries) {
if (queries == null)
return this;
var testMap = new TreeMap<>(queries);
query = testMap.entrySet().stream().map(x -> {
var key = x.getKey();
try {
return key+"="+URLEncoder.encode(x.getValue().toString(), StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
return key + "=";
}
}).collect(Collectors.joining("&"));
return this;
}
private String getContent(HttpRequest request) throws Exception {
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
var event = new TikTokHttpResponseEvent(response.uri().toString(), HttpData.map(response), HttpData.map(request));
eventHandler.publish(null, event);
if (response.statusCode() == 404) {
throw new TikTokLiveRequestException("Request responded with 404 NOT_FOUND");
}
if (response.statusCode() != 200) {
throw new TikTokLiveRequestException("Request was unsuccessful " + response.statusCode());
}
var cookies = response.headers().allValues("Set-Cookie");
for (var cookie : cookies) {
var split = cookie.split(";")[0].split("=");
var uri = request.uri();
var key = split[0];
var value = split[1];
tikTokCookieJar.set(key, value);
var map = new HashMap<String, List<String>>();
map.put(key, List.of(value));
cookieManager.put(uri, map);
}
return response.body();
}
}

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.http.mappers;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import io.github.jwdeveloper.tiktok.data.requests.GiftsData;
import java.util.ArrayList;
public class GiftsDataMapper {
public GiftsData.Response map(String json) {
var parsedJson = JsonParser.parseString(json);
var jsonObject = parsedJson.getAsJsonObject();
if (!jsonObject.has("data")) {
return new GiftsData.Response(json, new ArrayList<>());
}
var dataElement = jsonObject.getAsJsonObject("data");
if (!dataElement.has("gifts")) {
return new GiftsData.Response(json, new ArrayList<>());
}
var gifts = dataElement.get("gifts").getAsJsonArray()
.asList()
.stream()
.map(this::mapSingleGift)
.toList();
return new GiftsData.Response(json, gifts);
}
private GiftsData.GiftModel mapSingleGift(JsonElement jsonElement) {
var id = jsonElement.getAsJsonObject().get("id").getAsInt();
var name = jsonElement.getAsJsonObject().get("name").getAsString();
var diamondCost = jsonElement.getAsJsonObject().get("diamond_count").getAsInt();
var image = jsonElement.getAsJsonObject()
.get("image").getAsJsonObject()
.get("url_list").getAsJsonArray().get(0).getAsString();
if (image.endsWith(".webp")) {
image = image.replace(".webp", ".jpg");
}
var gift = new GiftsData.GiftModel();
gift.setId(id);
gift.setName(name);
gift.setDiamondCost(diamondCost);
gift.setImage(image);
return gift;
}
}

View File

@@ -20,17 +20,19 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.mappers; package io.github.jwdeveloper.tiktok.http.mappers;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.users.User; import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.data.models.users.UserAttribute; import io.github.jwdeveloper.tiktok.data.models.users.UserAttribute;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta; import io.github.jwdeveloper.tiktok.data.requests.LiveData;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import java.util.ArrayList; import java.util.ArrayList;
public class LiveRoomMetaMapper { public class LiveDataMapper {
/** /**
* 0 - Unknown * 0 - Unknown
* 1 - ? * 1 - ?
@@ -38,38 +40,43 @@ public class LiveRoomMetaMapper {
* 3 - ? * 3 - ?
* 4 - Offline * 4 - Offline
*/ */
public LiveRoomMeta map(JsonObject input) { public LiveData.Response map(String json) {
var liveRoomMeta = new LiveRoomMeta(); var response = new LiveData.Response();
if (!input.has("data")) {
return liveRoomMeta; var parsedJson = JsonParser.parseString(json);
var jsonObject = parsedJson.getAsJsonObject();
if (!jsonObject.has("data")) {
throw new TikTokLiveRequestException("Data section not found in LiveData.Response");
} }
var data = input.getAsJsonObject("data"); var data = jsonObject.getAsJsonObject("data");
if (data.has("status")) { if (data.has("status")) {
var status = data.get("status"); var status = data.get("status");
var statusId = status.getAsInt(); var statusId = status.getAsInt();
var statusValue = switch (statusId) { var statusValue = switch (statusId) {
case 2 -> LiveRoomMeta.LiveRoomStatus.HostOnline; case 2 -> LiveData.LiveStatus.HostOnline;
case 4 -> LiveRoomMeta.LiveRoomStatus.HostOffline; case 4 -> LiveData.LiveStatus.HostOffline;
default -> LiveRoomMeta.LiveRoomStatus.HostNotFound; default -> LiveData.LiveStatus.HostNotFound;
}; };
liveRoomMeta.setStatus(statusValue); response.setLiveStatus(statusValue);
} else { } else {
liveRoomMeta.setStatus(LiveRoomMeta.LiveRoomStatus.HostNotFound); response.setLiveStatus(LiveData.LiveStatus.HostNotFound);
} }
if (data.has("age_restricted")) { if (data.has("age_restricted")) {
var element = data.getAsJsonObject("age_restricted"); var element = data.getAsJsonObject("age_restricted");
var restricted = element.get("restricted").getAsBoolean(); var restricted = element.get("restricted").getAsBoolean();
liveRoomMeta.setAgeRestricted(restricted); response.setAgeRestricted(restricted);
} }
if (data.has("title")) { if (data.has("title")) {
var element = data.get("title"); var element = data.get("title");
var title = element.getAsString(); var title = element.getAsString();
liveRoomMeta.setTitie(title); response.setTitle(title);
} }
if (data.has("stats")) { if (data.has("stats")) {
@@ -81,45 +88,42 @@ public class LiveRoomMetaMapper {
var totalUsers = titalUsersElement.getAsInt(); var totalUsers = titalUsersElement.getAsInt();
liveRoomMeta.setLikeCount(likes); response.setLikes(likes);
liveRoomMeta.setTotalViewers(totalUsers); response.setTotalViewers(totalUsers);
} }
if(data.has("user_count")) if (data.has("user_count")) {
{
var element = data.get("user_count"); var element = data.get("user_count");
var viewers = element.getAsInt(); var viewers = element.getAsInt();
liveRoomMeta.setViewers(viewers); response.setViewers(viewers);
} }
if(data.has("owner")) if (data.has("owner")) {
{
var element = data.getAsJsonObject("owner"); var element = data.getAsJsonObject("owner");
var user = getUser(element); var user = getUser(element);
liveRoomMeta.setHost(user); response.setHost(user);
} }
return liveRoomMeta; return response;
} }
public User getUser(JsonObject jsonElement) public User getUser(JsonObject jsonElement) {
{
var id = jsonElement.get("id").getAsLong(); var id = jsonElement.get("id").getAsLong();
var name = jsonElement.get("display_id").getAsString(); var name = jsonElement.get("display_id").getAsString();
var profileName = jsonElement.get("nickname").getAsString(); var profileName = jsonElement.get("nickname").getAsString();
var followElement =jsonElement.getAsJsonObject("follow_info"); var followElement = jsonElement.getAsJsonObject("follow_info");
var followers = followElement.get("follower_count").getAsInt(); var followers = followElement.get("follower_count").getAsInt();
var followingCount = followElement.get("following_count").getAsInt(); var followingCount = followElement.get("following_count").getAsInt();
var pictureElement =jsonElement.getAsJsonObject("avatar_large"); var pictureElement = jsonElement.getAsJsonObject("avatar_large");
var link = pictureElement.getAsJsonArray("url_list").get(1).getAsString(); var link = pictureElement.getAsJsonArray("url_list").get(1).getAsString();
var picture = new Picture(link); var picture = new Picture(link);
var user = new User(id,name,profileName,picture,followers,followingCount,new ArrayList<>()); var user = new User(id, name, profileName, picture, followers, followingCount, new ArrayList<>());
user.addAttribute(UserAttribute.LiveHost); user.addAttribute(UserAttribute.LiveHost);
return user; return user;
} }
} }

View File

@@ -0,0 +1,66 @@
/*
* 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.mappers;
import com.google.gson.JsonParser;
import io.github.jwdeveloper.tiktok.data.requests.LiveUserData;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
public class LiveUserDataMapper
{
public LiveUserData.Response map(String json) {
var jsonObject = JsonParser.parseString(json).getAsJsonObject();
var message = jsonObject.get("message").getAsString();
if (message.equals("params_error")) {
throw new TikTokLiveRequestException("fetchRoomIdFromTiktokApi -> Unable to fetch roomID, contact the developer");
}
if (message.equals("user_not_found")) {
return new LiveUserData.Response(json, LiveUserData.UserStatus.NotFound, "", -1);
}
//live -> status 2
//live paused -> 3
//not live -> status 4
var element = jsonObject.get("data");
if (element.isJsonNull()) {
return new LiveUserData.Response(json, LiveUserData.UserStatus.NotFound, "", -1);
}
var data = element.getAsJsonObject();
var user = data.getAsJsonObject("user");
var roomId = user.get("roomId").getAsString();
var status = user.get("status").getAsInt();
var liveRoom = data.getAsJsonObject("liveRoom");
long startTime = liveRoom.get("startTime").getAsLong();
var statusEnum = switch (status) {
case 2 -> LiveUserData.UserStatus.Live;
case 3 -> LiveUserData.UserStatus.LivePaused;
case 4 -> LiveUserData.UserStatus.Offline;
default -> LiveUserData.UserStatus.NotFound;
};
return new LiveUserData.Response(json, statusEnum, roomId, startTime);
}
}

View File

@@ -20,17 +20,18 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.live; package io.github.jwdeveloper.tiktok.http.mappers;
import io.github.jwdeveloper.tiktok.data.models.users.User; import com.google.gson.JsonParser;
import io.github.jwdeveloper.tiktok.data.requests.SignServerResponse;
import java.util.List; public class SignServerResponseMapper {
public SignServerResponse map(String json) {
var parsedJson = JsonParser.parseString(json);
var jsonObject = parsedJson.getAsJsonObject();
public interface UserManager var signUrl = jsonObject.get("signedUrl").getAsString();
{ var userAgent = jsonObject.get("User-Agent").getAsString();
TrackedUser observeUser(User user); return new SignServerResponse(signUrl, userAgent);
}
TrackedUser getTrackedUser(Long id);
List<TrackedUser> getTrackedUsers();
} }

View File

@@ -23,6 +23,7 @@
package io.github.jwdeveloper.tiktok.listener; package io.github.jwdeveloper.tiktok.listener;
import io.github.jwdeveloper.tiktok.TikTokLiveEventHandler;
import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver; import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokEventListenerMethodException; import io.github.jwdeveloper.tiktok.exceptions.TikTokEventListenerMethodException;
@@ -36,10 +37,10 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
public class TikTokListenersManager implements ListenersManager { public class TikTokListenersManager implements ListenersManager {
private final io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver eventObserver; private final TikTokLiveEventHandler eventObserver;
private final List<ListenerBindingModel> bindingModels; private final List<ListenerBindingModel> bindingModels;
public TikTokListenersManager(List<TikTokEventListener> listeners, io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver tikTokEventHandler) { public TikTokListenersManager(List<TikTokEventListener> listeners, TikTokLiveEventHandler tikTokEventHandler) {
this.eventObserver = tikTokEventHandler; this.eventObserver = tikTokEventHandler;
this.bindingModels = new ArrayList<>(listeners.size()); this.bindingModels = new ArrayList<>(listeners.size());
for (var listener : listeners) { for (var listener : listeners) {

View File

@@ -23,60 +23,64 @@
package io.github.jwdeveloper.tiktok.websocket; package io.github.jwdeveloper.tiktok.websocket;
import io.github.jwdeveloper.tiktok.ClientSettings; import io.github.jwdeveloper.tiktok.*;
import io.github.jwdeveloper.tiktok.data.dto.ProxyData;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.data.settings.*;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
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; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import org.java_websocket.client.WebSocketClient; import org.java_websocket.client.WebSocketClient;
import java.net.URI; import javax.net.ssl.*;
import java.net.Proxy;
import java.security.cert.X509Certificate;
import java.util.HashMap; import java.util.HashMap;
import java.util.TreeMap;
import java.util.logging.Logger;
public class TikTokWebSocketClient implements SocketClient { public class TikTokWebSocketClient implements SocketClient {
private final ClientSettings clientSettings; private final LiveClientSettings clientSettings;
private final TikTokCookieJar tikTokCookieJar; private final TikTokLiveMessageHandler messageHandler;
private final TikTokMessageHandler messageHandler; private final TikTokLiveEventHandler tikTokEventHandler;
private final TikTokEventObserver tikTokEventHandler;
private WebSocketClient webSocketClient; private WebSocketClient webSocketClient;
private TikTokWebSocketPingingTask pingingTask;
private boolean isConnected; private boolean isConnected;
public TikTokWebSocketClient( public TikTokWebSocketClient(
TikTokCookieJar tikTokCookieJar, LiveClientSettings clientSettings,
ClientSettings clientSettings, TikTokLiveMessageHandler messageHandler,
TikTokMessageHandler messageHandler, TikTokLiveEventHandler tikTokEventHandler) {
TikTokEventObserver tikTokEventHandler) {
this.tikTokCookieJar = tikTokCookieJar;
this.clientSettings = clientSettings; this.clientSettings = clientSettings;
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
this.tikTokEventHandler = tikTokEventHandler; this.tikTokEventHandler = tikTokEventHandler;
isConnected = false; isConnected = false;
} }
public void start(WebcastResponse webcastResponse, LiveClient tikTokLiveClient) { @Override
public void start(LiveConnectionData.Response connectionData, LiveClient liveClient)
{
if (isConnected) { if (isConnected) {
stop(); stop();
} }
if (webcastResponse.getPushServer().isEmpty() || webcastResponse.getRouteParamsMapMap().isEmpty()) messageHandler.handle(liveClient, connectionData.getWebcastResponse());
{
throw new TikTokLiveException("Could not find Room");
}
var headers = new HashMap<String, String>();
headers.put("Cookie", connectionData.getWebsocketCookies());
webSocketClient = new TikTokWebSocketListener(connectionData.getWebsocketUrl(),
headers,
clientSettings.getHttpSettings().getTimeout().toMillisPart(),
messageHandler,
tikTokEventHandler,
liveClient);
// ProxyClientSettings proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
// if (proxyClientSettings.isEnabled())
// connectProxy(proxyClientSettings);
// else
connectDefault();
}
private void connectDefault() {
try { try {
messageHandler.handle(tikTokLiveClient, webcastResponse);
var url = getWebSocketUrl(webcastResponse);
webSocketClient = startWebSocket(url, tikTokLiveClient);
webSocketClient.connect(); webSocketClient.connect();
pingingTask = new TikTokWebSocketPingingTask();
pingingTask.run(webSocketClient);
isConnected = true; isConnected = true;
} catch (Exception e) } catch (Exception e)
{ {
@@ -85,36 +89,46 @@ public class TikTokWebSocketClient implements SocketClient {
} }
} }
private URI getWebSocketUrl(WebcastResponse webcastResponse) { public void connectProxy(ProxyClientSettings proxySettings) {
var tiktokAccessKey = webcastResponse.getRouteParamsMapMap(); while (proxySettings.hasNext()) {
ProxyData proxyData = proxySettings.next();
var parameters = new TreeMap<>(clientSettings.getClientParameters()); if (!tryProxyConnection(proxySettings, proxyData)) {
parameters.putAll(tiktokAccessKey); if (proxySettings.isAutoDiscard())
proxySettings.remove();
var url = webcastResponse.getPushServer(); continue;
var parsed = HttpUtils.parseParametersEncode(url, parameters); }
return URI.create(parsed); isConnected = true;
break;
}
if (!isConnected)
throw new TikTokLiveException("Failed to connect to the websocket");
} }
private WebSocketClient startWebSocket(URI url, LiveClient liveClient) { public boolean tryProxyConnection(ProxyClientSettings proxySettings, ProxyData proxyData) {
var cookie = tikTokCookieJar.parseCookies(); webSocketClient.setProxy(new Proxy(proxySettings.getType(), proxyData.toSocketAddress()));
var headers = new HashMap<String, String>(); try {
headers.put("Cookie", cookie); if (proxySettings.getType() == Proxy.Type.SOCKS) {
return new TikTokWebSocketListener(url, SSLContext sc = SSLContext.getInstance("SSL");
headers, sc.init(null, new TrustManager[]{new X509TrustManager() {
3000, public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}
messageHandler, public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}
tikTokEventHandler, public X509Certificate[] getAcceptedIssuers() { return null; }
liveClient); }}, null);
webSocketClient.setSocketFactory(sc.getSocketFactory());
}
webSocketClient.connect();
return true;
} catch (Exception e)
{
return false;
}
} }
public void stop()
{ public void stop() {
if (isConnected && webSocketClient != null) { if (isConnected && webSocketClient != null && webSocketClient.isOpen()) {
webSocketClient.closeConnection(0, ""); webSocketClient.closeConnection(0, "");
pingingTask.stop();
} }
webSocketClient = null; webSocketClient = null;
pingingTask = null;
isConnected = false; isConnected = false;
} }
} }

View File

@@ -23,103 +23,93 @@
package io.github.jwdeveloper.tiktok.websocket; package io.github.jwdeveloper.tiktok.websocket;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.data.events.TikTokConnectedEvent; import io.github.jwdeveloper.tiktok.*;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent; import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException; import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastPushFrame; import io.github.jwdeveloper.tiktok.messages.webcast.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastWebsocketAck;
import org.java_websocket.client.WebSocketClient; import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455; import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake; import org.java_websocket.handshake.ServerHandshake;
import java.net.URI; import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Map; import java.util.*;
import java.util.Optional;
public class TikTokWebSocketListener extends WebSocketClient { public class TikTokWebSocketListener extends WebSocketClient {
private final TikTokMessageHandler messageHandler; private final TikTokLiveMessageHandler messageHandler;
private final TikTokEventObserver tikTokEventHandler; private final TikTokLiveEventHandler tikTokEventHandler;
private final LiveClient tikTokLiveClient; private final LiveClient tikTokLiveClient;
public TikTokWebSocketListener(URI serverUri, public TikTokWebSocketListener(URI serverUri,
Map<String, String> httpHeaders, Map<String, String> httpHeaders,
int connectTimeout, int connectTimeout,
TikTokMessageHandler messageHandler, TikTokLiveMessageHandler messageHandler,
TikTokEventObserver tikTokEventHandler, TikTokLiveEventHandler tikTokEventHandler,
LiveClient tikTokLiveClient) { LiveClient tikTokLiveClient) {
super(serverUri, new Draft_6455(), httpHeaders,connectTimeout); super(serverUri, new Draft_6455(), httpHeaders, connectTimeout);
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
this.tikTokEventHandler = tikTokEventHandler; this.tikTokEventHandler = tikTokEventHandler;
this.tikTokLiveClient = tikTokLiveClient; this.tikTokLiveClient = tikTokLiveClient;
} }
@Override @Override
public void onMessage(ByteBuffer bytes) public void onMessage(ByteBuffer bytes) {
{
try { try {
handleBinary(bytes.array()); handleBinary(bytes.array());
} catch (Exception e) { } catch (Exception e) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e)); tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e));
} }
if(isNotClosing()) if (isNotClosing()) {
{
sendPing();
}
}
@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());
}
@Override
public void onError(Exception error)
{
tikTokEventHandler.publish(tikTokLiveClient,new TikTokErrorEvent(error));
if(isNotClosing())
{
sendPing(); sendPing();
} }
} }
private void handleBinary(byte[] buffer) { private void handleBinary(byte[] buffer) {
var websocketMessageOptional = getWebcastWebsocketMessage(buffer); var websocketPushFrameOptional = getWebcastPushFrame(buffer);
if (websocketMessageOptional.isEmpty()) { if (websocketPushFrameOptional.isEmpty()) {
return; return;
} }
var websocketMessage = websocketMessageOptional.get(); var websocketPushFrame = websocketPushFrameOptional.get();
var webResponse = getWebResponseMessage(websocketMessage.getPayload()); var webcastResponse = getWebResponseMessage(websocketPushFrame.getPayload());
if(webResponse.getNeedsAck()) if (webcastResponse.getNeedsAck()) {
{ var pushFrameBuilder = WebcastPushFrame.newBuilder();
//For some reason while send ack id, server get disconnected pushFrameBuilder.setPayloadType("ack");
// sendAckId(webResponse.getFetchInterval()); pushFrameBuilder.setLogId(websocketPushFrame.getLogId());
pushFrameBuilder.setPayload(webcastResponse.getInternalExtBytes());
if (isNotClosing())
{
this.send(pushFrameBuilder.build().toByteArray());
}
} }
messageHandler.handle(tikTokLiveClient, webcastResponse);
messageHandler.handle(tikTokLiveClient, webResponse);
} }
private Optional<WebcastPushFrame> getWebcastWebsocketMessage(byte[] buffer) { @Override
public void onOpen(ServerHandshake serverHandshake) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokConnectedEvent());
if (isNotClosing()) {
sendPing();
}
}
@Override
public void onClose(int code, String reason, boolean remote) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokDisconnectedEvent(reason));
tikTokLiveClient.disconnect();
}
@Override
public void onError(Exception error) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(error));
if (isNotClosing()) {
sendPing();
}
}
private Optional<WebcastPushFrame> getWebcastPushFrame(byte[] buffer) {
try { try {
var websocketMessage = WebcastPushFrame.parseFrom(buffer); var websocketMessage = WebcastPushFrame.parseFrom(buffer);
if (websocketMessage.getPayload().isEmpty()) { if (websocketMessage.getPayload().isEmpty()) {
@@ -139,28 +129,12 @@ public class TikTokWebSocketListener extends WebSocketClient {
} }
} }
private boolean isNotClosing() private boolean isNotClosing() {
{
return !isClosed() && !isClosing(); return !isClosed() && !isClosing();
} }
private void sendAckId(long id) {
var serverInfo = WebcastWebsocketAck
.newBuilder()
.setType("ack")
.setId(id)
.build();
if(isNotClosing())
{
System.out.println("SEND ICK ID "+id);
send(serverInfo.toByteArray());
}
}
@Override @Override
public void onMessage(String s) { public void onMessage(String s) {
// System.err.println(s);
} }
} }

View File

@@ -1,81 +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.websocket;
import org.java_websocket.WebSocket;
import java.util.Random;
public class TikTokWebSocketPingingTask
{
private Thread thread;
private boolean isRunning = false;
private final int MIN_TIMEOUT = 5;
private final int MAX_TIMEOUT = 100;
public void run(WebSocket webSocket)
{
stop();
thread = new Thread(() ->
{
pingTask(webSocket);
});
isRunning =true;
thread.start();
}
public void stop()
{
if(thread != null)
{
thread.interrupt();
}
isRunning = false;
}
private void pingTask(WebSocket webSocket)
{
var random = new Random();
while (isRunning)
{
try
{
if(!webSocket.isOpen())
{
Thread.sleep(100);
continue;
}
webSocket.sendPing();
var timeout = random.nextInt(MAX_TIMEOUT)+MIN_TIMEOUT;
Thread.sleep(timeout);
}
catch (Exception e)
{
isRunning = false;
}
}
}
}

View File

@@ -1,47 +0,0 @@
package io.github.jwdeveloper.tiktok.http;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import java.util.*;
public class HttpUtilsTest
{
@Test
public void parseParameters_EmptyParameters_ShouldHaveNoParameters()
{
String parsed = HttpUtils.parseParameters("https://webcast.tiktok.com/webcast/im/fetch/", new HashMap<>());
Assertions.assertEquals("https://webcast.tiktok.com/webcast/im/fetch/", parsed);
}
@Test
public void parseParameters_ValidParameters_ShouldConstructValidURL()
{
LinkedHashMap<String, Object> testMap = new LinkedHashMap<>();
testMap.put("room_id", 1);
testMap.put("uniqueId", "randomName");
String parsed = HttpUtils.parseParameters("https://webcast.tiktok.com/webcast/im/fetch/", testMap);
Assertions.assertEquals("https://webcast.tiktok.com/webcast/im/fetch/?room_id=1&uniqueId=randomName", parsed);
}
@Test
public void parseParametersEncode_EmptyParameters_ShouldHaveNoParameters()
{
String parsed = HttpUtils.parseParametersEncode("https://webcast.tiktok.com/webcast/im/fetch/", new HashMap<>());
Assertions.assertEquals("https://webcast.tiktok.com/webcast/im/fetch/", parsed);
}
@Test
public void parseParametersEncode_ValidParameters_ShouldConstructValidURL()
{
LinkedHashMap<String, Object> testMap = new LinkedHashMap<>();
testMap.put("room_id", 1);
testMap.put("root_referer", "https://www.tiktok.com/");
String parsed = HttpUtils.parseParametersEncode("https://webcast.tiktok.com/webcast/im/fetch/", testMap);
Assertions.assertEquals("https://webcast.tiktok.com/webcast/im/fetch/?room_id=1&root_referer=https%3A%2F%2Fwww.tiktok.com%2F", parsed);
}
}

View File

@@ -1,110 +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.http;
import com.google.gson.JsonObject;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
import io.github.jwdeveloper.tiktok.mappers.LiveRoomMetaMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.HashMap;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
public class TikTokApiServiceTest
{
@Mock
TikTokHttpClient tiktokHttpClient;
@Mock
Logger logger;
@Mock
ClientSettings clientSettings;
@InjectMocks
TikTokApiService tikTokApiService;
@Test
void updateSessionId_NullSessionId_DoesNotSetSessionId() {
when(clientSettings.getSessionId()).thenReturn(null);
tikTokApiService.updateSessionId();
verify(tiktokHttpClient, times(0)).setSessionId(anyString());
}
@Test
void updateSessionId_EmptySessionId_DoesNotSetSessionId() {
when(clientSettings.getSessionId()).thenReturn("");
tikTokApiService.updateSessionId();
verify(tiktokHttpClient, times(0)).setSessionId(anyString());
}
@Test
void updateSessionId_ValidSessionId_SetsSessionId() {
when(clientSettings.getSessionId()).thenReturn("validSessionId");
tikTokApiService.updateSessionId();
verify(tiktokHttpClient, times(1)).setSessionId("validSessionId");
}
//@Test
void fetchRoomInfo_ValidResponse_ReturnsLiveRoomMeta() throws Exception {
HashMap<String, Object> clientParameters = new HashMap<>();
var mockResponse = new JsonObject(); // Assume JsonObject is from the Gson library
var expectedLiveRoomMeta = new LiveRoomMeta(); // Assume LiveRoomMeta is a simple POJO
when(clientSettings.getClientParameters()).thenReturn(clientParameters);
when(tiktokHttpClient.getJsonFromWebcastApi(anyString(), any())).thenReturn(mockResponse);
when(new LiveRoomMetaMapper().map(mockResponse)).thenReturn(expectedLiveRoomMeta); // Assuming LiveRoomMetaMapper is a simple mapper class
LiveRoomMeta liveRoomMeta = tikTokApiService.fetchRoomInfo();
assertEquals(expectedLiveRoomMeta, liveRoomMeta);
}
// @Test
void fetchRoomInfo_ExceptionThrown_ThrowsTikTokLiveRequestException() throws Exception {
when(tiktokHttpClient.getJsonFromWebcastApi(anyString(), any())).thenThrow(new Exception("some exception"));
assertThrows(TikTokLiveRequestException.class, () -> {
tikTokApiService.fetchRoomInfo();
});
}
}

View File

@@ -1,103 +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.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 {
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

@@ -22,6 +22,7 @@
*/ */
package io.github.jwdeveloper.tiktok.listener; package io.github.jwdeveloper.tiktok.listener;
import io.github.jwdeveloper.tiktok.TikTokLiveEventHandler;
import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver; import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent; import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
@@ -41,12 +42,12 @@ import static org.mockito.Mockito.verify;
class TikTokListenersManagerTest { class TikTokListenersManagerTest {
private io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver eventObserver; private TikTokLiveEventHandler eventObserver;
private TikTokListenersManager tikTokListenersManager; private TikTokListenersManager tikTokListenersManager;
@BeforeEach @BeforeEach
void setUp() { void setUp() {
eventObserver = Mockito.mock(io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver.class); eventObserver = Mockito.mock(TikTokLiveEventHandler.class);
List<TikTokEventListener> listeners = new ArrayList<>(); List<TikTokEventListener> listeners = new ArrayList<>();
tikTokListenersManager = new TikTokListenersManager(listeners, eventObserver); tikTokListenersManager = new TikTokListenersManager(listeners, eventObserver);
} }

View File

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

View File

@@ -20,39 +20,36 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.ClientSettings; import java.time.Duration;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.util.logging.Logger; public class ChatMessageExample {
public static void main(String[] args) {
public class ApiServiceMock extends TikTokApiService {
public ApiServiceMock(TikTokHttpClient apiClient, Logger logger, ClientSettings clientSettings) { var roomData = TikTokLive.requests()
super(apiClient, logger, clientSettings); .fetchLiveData("X");
var gifts = TikTokLive.requests().fetchGiftsData();
var user = TikTokLive.requests()
.fetchLiveUserData("mark");
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
.configure(clientSettings ->
{
clientSettings.setPrintToConsole(true);
clientSettings.getHttpSettings().setTimeout(Duration.ofSeconds(21));
})
.onComment((liveClient, event) ->
{
System.out.println("Chat message: " + event.getUser().getName() + " " + event.getText());
})
.onWebsocketUnhandledMessage((liveClient, event) ->
{
liveClient.getLogger().info(event.getMessage().getMethod());
}).buildAndConnect();
} }
@Override
public void updateSessionId() {
}
@Override
public LiveRoomMeta fetchRoomInfo()
{
var meta = new LiveRoomMeta();
meta.setStatus(LiveRoomMeta.LiveRoomStatus.HostOnline);
return meta;
}
@Override
public WebcastResponse fetchClientData() {
return WebcastResponse.newBuilder().build();
}
} }

View File

@@ -42,6 +42,11 @@ public class CustomEventExample {
public static void main(String[] args) { public static void main(String[] args) {
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME) TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
.configure(clientSettings ->
{
clientSettings.setPrintToConsole(true);
})
.onGift((liveClient, event) -> .onGift((liveClient, event) ->
{ {
if (event.getGift().getDiamondCost() > 100) if (event.getGift().getDiamondCost() > 100)
@@ -49,14 +54,14 @@ public class CustomEventExample {
else else
liveClient.publishEvent(new CheapGiftEvent(event.getGift())); liveClient.publishEvent(new CheapGiftEvent(event.getGift()));
}) })
.onEvent(CheapGiftEvent.class,(liveClient, event) -> .onEvent(CheapGiftEvent.class, (liveClient, event) ->
{ {
System.out.println("Thanks for cheap gift"); System.out.println("Thanks for cheap gift");
}) })
.onEvent(ExpensiveGiftEvent.class,(liveClient, event) -> .onEvent(ExpensiveGiftEvent.class, (liveClient, event) ->
{ {
System.out.println("Thanks for expensive gift!"); System.out.println("Thanks for expensive gift!");
}) })
.build(); .buildAndConnect();
} }
} }

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok;
import java.net.Proxy;
public class ProxyExample
{
public static void main(String[] args) throws Exception {
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
.configure(clientSettings -> {
clientSettings.setPrintToConsole(true);
clientSettings.getHttpSettings().configureProxy(proxySettings -> {
proxySettings.setOnProxyUpdated(proxyData -> System.err.println("Next proxy: " + proxyData.toString()));
proxySettings.setType(Proxy.Type.SOCKS);
proxySettings.addProxy("localhost", 8080);
});
})
.onConnected((liveClient, event) ->
liveClient.getLogger().info("Connected "+liveClient.getRoomInfo().getHostName()))
.onDisconnected((liveClient, event) ->
liveClient.getLogger().info("Disconnect reason: "+event.getReason()))
.onLiveEnded((liveClient, event) ->
liveClient.getLogger().info("Live Ended"))
.onError((liveClient, event) ->
event.getException().printStackTrace())
.buildAndConnect();
System.in.read();
}
}

View File

@@ -24,6 +24,7 @@ package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.TikTokSubNotifyEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokSubNotifyEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent; import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
@@ -31,56 +32,20 @@ import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import io.github.jwdeveloper.tiktok.utils.JsonUtil; import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration; import java.time.Duration;
import java.util.HashMap; import java.util.HashMap;
import java.util.logging.Level; import java.util.logging.Level;
public class SimpleExample { public class SimpleExample {
public static String TIKTOK_HOSTNAME = "bangbetmenygy"; public static String TIKTOK_HOSTNAME = "dash4214";
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException, InterruptedException {
showLogo(); showLogo();
// set tiktok username
/*
//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!");
}
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) TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
@@ -88,12 +53,14 @@ public class SimpleExample {
{ {
clientSettings.setHostName(SimpleExample.TIKTOK_HOSTNAME); // This method is useful in case you want change hostname later clientSettings.setHostName(SimpleExample.TIKTOK_HOSTNAME); // This method is useful in case you want change hostname later
clientSettings.setClientLanguage("en"); // Language clientSettings.setClientLanguage("en"); // Language
clientSettings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
clientSettings.setLogLevel(Level.ALL); // Log level clientSettings.setLogLevel(Level.ALL); // Log level
clientSettings.setPrintToConsole(true); // Printing all logs to console even if log level is Level.OFF clientSettings.setPrintToConsole(true); // Printing all logs to console even if log level is Level.OFF
clientSettings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline clientSettings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
clientSettings.getHttpSettings();
//Optional: Sometimes not every message from chat are send to TikTokLiveJava to fix this issue you can set sessionId //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 // documentation how to obtain sessionId https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages
@@ -105,15 +72,6 @@ public class SimpleExample {
//clientSettings.setRoomId("XXXXXXXXXXXXXXXXX"); //clientSettings.setRoomId("XXXXXXXXXXXXXXXXX");
}) })
.onConnected((liveClient, event) ->
{
for (var gift : liveClient.getGiftManager().getGifts()) {
gift.getPicture().downloadImageAsync().thenAccept(image ->
{
});
}
})
.onWebsocketMessage((liveClient, event) -> .onWebsocketMessage((liveClient, event) ->
{ {
@@ -124,9 +82,14 @@ public class SimpleExample {
} }
}) })
.onWebsocketResponse((liveClient, event) -> .onEvent((liveClient, event) ->
{ {
event.getResponse(); if (event instanceof TikTokGiftEvent giftEvent) {
System.out.println("1");
}
if (event instanceof TikTokChestEvent chestEvent) {
System.out.println("2");
}
}) })
.onGift((liveClient, event) -> .onGift((liveClient, event) ->
{ {
@@ -142,7 +105,7 @@ public class SimpleExample {
{ {
print(ConsoleColors.RED, "GIFT COMBO", event.getGift().getName(), event.getCombo()); print(ConsoleColors.RED, "GIFT COMBO", event.getGift().getName(), event.getCombo());
}) })
.onConnected((client, event) -> .onConnected((liveClient, event) ->
{ {
print(ConsoleColors.GREEN, "[Connected]"); print(ConsoleColors.GREEN, "[Connected]");
}) })
@@ -158,19 +121,19 @@ public class SimpleExample {
{ {
print(ConsoleColors.BLUE, "Follow:", ConsoleColors.WHITE_BRIGHT, event.getUser().getName()); print(ConsoleColors.BLUE, "Follow:", ConsoleColors.WHITE_BRIGHT, event.getUser().getName());
}) })
.onJoin((client, event) -> .onJoin((liveClient, event) ->
{ {
print(ConsoleColors.WHITE, "Join:", ConsoleColors.WHITE_BRIGHT, event.getUser().getName()); print(ConsoleColors.WHITE, "Join:", ConsoleColors.WHITE_BRIGHT, event.getUser().getName());
}) })
.onComment((client, event) -> .onComment((liveClient, event) ->
{ {
print(ConsoleColors.GREEN, event.getUser().getName(), ":", ConsoleColors.WHITE_BRIGHT, event.getText()); print(ConsoleColors.GREEN, event.getUser().getName(), ":", ConsoleColors.WHITE_BRIGHT, event.getText());
}) })
.onEvent((client, event) -> .onEvent((liveClient, event) ->
{ {
//System.out.println("Event: " +event.getClass().getSimpleName()); //System.out.println("Event: " +event.getClass().getSimpleName());
}) })
.onError((client, event) -> .onError((liveClient, event) ->
{ {
event.getException().printStackTrace(); event.getException().printStackTrace();
}) })

View File

@@ -40,6 +40,7 @@ Join the support [discord](https://discord.gg/e2XwPNTBBr) and visit the `#java-s
Do you prefer other programming languages? Do you prefer other programming languages?
- **Node** orginal: [TikTok-Live-Connector](https://github.com/isaackogan/TikTok-Live-Connector) by [@zerodytrash](https://github.com/zerodytrash) - **Node** orginal: [TikTok-Live-Connector](https://github.com/isaackogan/TikTok-Live-Connector) by [@zerodytrash](https://github.com/zerodytrash)
- **Rust** rewrite: [TikTokLiveRust](https://github.com/jwdeveloper/TikTokLiveRust)
- **Python** rewrite: [TikTokLive](https://github.com/isaackogan/TikTokLive) by [@isaackogan](https://github.com/isaackogan) - **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) - **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) - **C#** rewrite: [TikTokLiveSharp](https://github.com/frankvHoof93/TikTokLiveSharp) by [@frankvHoof93](https://github.com/frankvHoof93)
@@ -69,7 +70,7 @@ Maven
<dependency> <dependency>
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId> <groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
<artifactId>Client</artifactId> <artifactId>Client</artifactId>
<version>1.0.12-Release</version> <version>1.0.16-Release</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -86,7 +87,7 @@ dependencyResolutionManagement {
} }
dependencies { dependencies {
implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.0.12-Release' implementation 'com.github.jwdeveloper.TikTok-Live-Java:Client:1.0.16-Release'
} }
``` ```

View File

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

View File

@@ -26,14 +26,10 @@ import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo; import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager; import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver; import io.github.jwdeveloper.tiktok.TikTokLiveMessageHandler;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler; import io.github.jwdeveloper.tiktok.TikTokLiveHttpClient;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager; import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.ApiServiceMock;
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.LiveClientMock; import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.LiveClientMock;
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.WebsocketClientMock; import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.WebsocketClientMock;
@@ -87,21 +83,17 @@ public class TikTokMockBuilder extends TikTokLiveClientBuilder {
public LiveClientMock build() { public LiveClientMock build() {
validate(); validate();
var cookie = new TikTokCookieJar();
var tiktokRoomInfo = new TikTokRoomInfo(); var tiktokRoomInfo = new TikTokRoomInfo();
tiktokRoomInfo.setHostName(clientSettings.getHostName()); tiktokRoomInfo.setHostName(clientSettings.getHostName());
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler); var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
var giftManager = new TikTokGiftManager(logger); var giftManager = new TikTokGiftManager(logger);
var requestFactory = new TikTokHttpRequestFactory(cookie, new TikTokEventObserver());
var apiClient = new TikTokHttpClient(cookie, requestFactory);
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
var mapper = createMapper(giftManager, tiktokRoomInfo); var mapper = createMapper(giftManager, tiktokRoomInfo);
var handler = new TikTokMessageHandler(tikTokEventHandler, mapper); var handler = new TikTokLiveMessageHandler(tikTokEventHandler, mapper);
var webSocketClient = new WebsocketClientMock(logger, responses, handler); var webSocketClient = new WebsocketClientMock(logger, responses, handler);
return new LiveClientMock(tiktokRoomInfo, return new LiveClientMock(tiktokRoomInfo,
apiService, new TikTokLiveHttpClient(),
webSocketClient, webSocketClient,
giftManager, giftManager,
tikTokEventHandler, tikTokEventHandler,

View File

@@ -22,12 +22,12 @@
*/ */
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks; package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
import io.github.jwdeveloper.tiktok.ClientSettings; import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.TikTokLiveClient; import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo; import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager; import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver; import io.github.jwdeveloper.tiktok.TikTokLiveEventHandler;
import io.github.jwdeveloper.tiktok.http.TikTokApiService; import io.github.jwdeveloper.tiktok.TikTokLiveHttpClient;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager; import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
@@ -37,16 +37,18 @@ public class LiveClientMock extends TikTokLiveClient {
private final WebsocketClientMock websocketClientMock; private final WebsocketClientMock websocketClientMock;
public LiveClientMock(TikTokRoomInfo tikTokLiveMeta, public LiveClientMock(
TikTokApiService tikTokApiService, TikTokRoomInfo tikTokLiveMeta,
WebsocketClientMock webSocketClient, TikTokLiveHttpClient httpClient,
TikTokGiftManager tikTokGiftManager, WebsocketClientMock webSocketClient,
TikTokEventObserver tikTokEventHandler, TikTokGiftManager tikTokGiftManager,
ClientSettings clientSettings, TikTokLiveEventHandler tikTokEventHandler,
TikTokListenersManager listenersManager, LiveClientSettings clientSettings,
Logger logger) { TikTokListenersManager listenersManager,
super(tikTokLiveMeta, Logger logger) {
tikTokApiService, super(
tikTokLiveMeta,
httpClient,
webSocketClient, webSocketClient,
tikTokGiftManager, tikTokGiftManager,
tikTokEventHandler, tikTokEventHandler,
@@ -58,7 +60,6 @@ public class LiveClientMock extends TikTokLiveClient {
} }
public void publishMessage(String type, String base64) { public void publishMessage(String type, String base64) {
websocketClientMock.addMessage(type, base64); websocketClientMock.addMessage(type, base64);
} }

View File

@@ -22,10 +22,8 @@
*/ */
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks; package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
import com.google.protobuf.ByteString; import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; import io.github.jwdeveloper.tiktok.TikTokLiveMessageHandler;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.websocket.SocketClient; import io.github.jwdeveloper.tiktok.websocket.SocketClient;
@@ -40,7 +38,7 @@ public class WebsocketClientMock implements SocketClient {
Logger logger; Logger logger;
Stack<WebcastResponse> responses; Stack<WebcastResponse> responses;
Stack<MsgStruct> messages; Stack<MsgStruct> messages;
TikTokMessageHandler messageHandler; TikTokLiveMessageHandler messageHandler;
LiveClient client; LiveClient client;
@@ -58,7 +56,7 @@ public class WebsocketClientMock implements SocketClient {
byte[] messageValue; byte[] messageValue;
} }
public WebsocketClientMock(Logger logger, Stack<WebcastResponse> responses, TikTokMessageHandler messageHandler) { public WebsocketClientMock(Logger logger, Stack<WebcastResponse> responses, TikTokLiveMessageHandler messageHandler) {
this.logger = logger; this.logger = logger;
this.responses = responses; this.responses = responses;
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
@@ -91,8 +89,9 @@ public class WebsocketClientMock implements SocketClient {
} }
@Override @Override
public void start(WebcastResponse webcastResponse, LiveClient tikTokLiveClient) { public void start(LiveConnectionData.Response webcastResponse, LiveClient tikTokLiveClient) {
logger.info("Running message: " + responses.size()); logger.info("Running message: " + responses.size());
@@ -110,7 +109,6 @@ public class WebsocketClientMock implements SocketClient {
}); });
isRunning = true; isRunning = true;
thread.start(); thread.start();
} }
@Override @Override

View File

@@ -23,6 +23,7 @@
package io.github.jwdeveloper.tiktok.tools.util; package io.github.jwdeveloper.tiktok.tools.util;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.ConsoleColors; import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import io.github.jwdeveloper.tiktok.utils.JsonUtil; import io.github.jwdeveloper.tiktok.utils.JsonUtil;
@@ -34,8 +35,8 @@ public class MessageUtil {
var methodName = message.getMethod(); var methodName = message.getMethod();
var inputClazz = Class.forName("io.github.jwdeveloper.tiktok.messages.webcast." + methodName); var inputClazz = Class.forName("io.github.jwdeveloper.tiktok.messages.webcast." + methodName);
var parseMethod = inputClazz.getDeclaredMethod("parseFrom", ByteString.class); var parseMethod = inputClazz.getDeclaredMethod("parseFrom", ByteString.class);
var deserialized = parseMethod.invoke(null, message.getPayload()); var webcastObject = parseMethod.invoke(null, message.getPayload());
return JsonUtil.messageToJson(deserialized); return JsonUtil.messageToJson(webcastObject);
} catch (Exception ex) { } catch (Exception ex) {
return ConsoleColors.RED + "Can not find mapper for " + message.getMethod(); return ConsoleColors.RED + "Can not find mapper for " + message.getMethod();
@@ -48,6 +49,7 @@ public class MessageUtil {
var inputClazz = Class.forName("io.github.jwdeveloper.tiktok.messages.webcast." + messageName); var inputClazz = Class.forName("io.github.jwdeveloper.tiktok.messages.webcast." + messageName);
var parseMethod = inputClazz.getDeclaredMethod("parseFrom", byte[].class); var parseMethod = inputClazz.getDeclaredMethod("parseFrom", byte[].class);
var deserialized = parseMethod.invoke(null, bytes); var deserialized = parseMethod.invoke(null, bytes);
return JsonUtil.messageToJson(deserialized); return JsonUtil.messageToJson(deserialized);
} catch (Exception ex) { } catch (Exception ex) {
var sb = new StringBuilder(); var sb = new StringBuilder();

View File

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

View File

@@ -37,7 +37,8 @@ import java.sql.SQLException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
public class Main { public class Main {
public static void main(String[] args) throws SQLException, ExecutionException, InterruptedException, IOException { public static void main(String[] args) throws SQLException
{
var settings = new Settings(); var settings = new Settings();
settings.setUserName("szalonamoniaxx"); settings.setUserName("szalonamoniaxx");
settings.setSessionTag("battle"); settings.setSessionTag("battle");

View File

@@ -23,6 +23,7 @@
package io.github.jwdeveloper.tiktok.webviewer; package io.github.jwdeveloper.tiktok.webviewer;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkLayerMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkLayerMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
@@ -32,11 +33,11 @@ import java.io.IOException;
public class ToolsExamples { public class ToolsExamples {
private static final String tiktokUser = "debb.cl"; private static final String tiktokUser = "k.peaks";
private static final String db = "db-battle"; private static final String db = "a";
private static final String sessionTag = "gifts"; private static final String sessionTag = "a";
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
// runCollector(); // runCollector();
@@ -53,6 +54,7 @@ public class ToolsExamples {
//WebcastLinkMicBattlePunishFinish end of battle? //WebcastLinkMicBattlePunishFinish end of battle?
//WebcastLinkLayerMessage send after end of battle //WebcastLinkLayerMessage send after end of battle
// send after LinkLayer -> WebcastLinkMessage // send after LinkLayer -> WebcastLinkMessage
private static void runCollector() { private static void runCollector() {
TikTokLiveTools.createCollector(db) TikTokLiveTools.createCollector(db)
.addUser(tiktokUser) .addUser(tiktokUser)
@@ -60,15 +62,17 @@ public class ToolsExamples {
.configureLiveClient(liveClientBuilder -> .configureLiveClient(liveClientBuilder ->
{ {
liveClientBuilder.configure(clientSettings -> liveClientBuilder.configure(clientSettings ->
{ {
clientSettings.setPrintToConsole(true); clientSettings.setPrintToConsole(true);
}); })
liveClientBuilder.onWebsocketResponse((liveClient, event) -> .onComment((liveClient, event) ->
{ {
for (var msg : event.getResponse().getMessagesList()) { System.out.println("Chat message: " + event.getUser().getName() + " " + event.getText());
System.out.println(msg.getMethod()); })
} .onWebsocketUnhandledMessage((liveClient, event) ->
}); {
liveClient.getLogger().info(event.getMessage().getMethod());
});
liveClientBuilder.onConnected((liveClient, event) -> liveClientBuilder.onConnected((liveClient, event) ->
{ {
liveClient.getLogger().info("Connected"); liveClient.getLogger().info("Connected");

View File

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

View File

@@ -84,7 +84,6 @@ public class CodeExample {
{ {
settings.setHostName("bangbetmenygy"); // This method is useful in case you want change hostname later settings.setHostName("bangbetmenygy"); // This method is useful in case you want change hostname later
settings.setClientLanguage("en"); // Language settings.setClientLanguage("en"); // Language
settings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
settings.setLogLevel(Level.ALL); // Log level settings.setLogLevel(Level.ALL); // Log level
settings.setPrintToConsole(true); // Printing all logs to console even if log level is Level.OFF 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.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline

View File

@@ -83,6 +83,17 @@ Do you prefer other programming languages?
{{events-content}} {{events-content}}
{{for item of data }}
{{if item is 2}}
my name is {{item.name}}
{{else}}
{{end}}
{{end}}
<br> <br>
## Listeners ## Listeners

View File

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

View File

@@ -25,6 +25,7 @@ package io.github.jwdeveloper.tiktok.gifts;
import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeSpec;
import io.github.jwdeveloper.tiktok.TikTokLive;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.gifts.downloader.GiftDto; import io.github.jwdeveloper.tiktok.gifts.downloader.GiftDto;
import lombok.Getter; import lombok.Getter;
@@ -32,6 +33,7 @@ import lombok.Getter;
import javax.lang.model.element.Modifier; import javax.lang.model.element.Modifier;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.time.Duration;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -42,10 +44,17 @@ public class GenerateGiftsEnum {
public static void main(String args[]) throws IOException { public static void main(String args[]) throws IOException {
TikTokLive.newClient("X")
.configure(liveClientSettings ->
{
var httpSetting = liveClientSettings.getHttpSettings();
httpSetting.setTimeout(Duration.ofSeconds(12));
});
var downloader = new GiftsDownloader(); var downloader = new GiftsDownloader();
var gifts = downloader.getGiftsFromFile(); var gifts = downloader.getGiftsFromFile();
for(var link : gifts) for (var link : gifts) {
{
System.out.println(link.getImage()); System.out.println(link.getImage());
} }
var groupedByName = gifts.stream().collect(Collectors.groupingBy(GiftDto::getName)); var groupedByName = gifts.stream().collect(Collectors.groupingBy(GiftDto::getName));
@@ -105,9 +114,16 @@ public class GenerateGiftsEnum {
.replace("'", "_") .replace("'", "_")
.replace(".", "_") .replace(".", "_")
.replace("-", "_") .replace("-", "_")
.replace("!","_") .replace("&", "_")
.replace("!", "_")
.toUpperCase(); .toUpperCase();
boolean startsWithNumber = name.matches("^[0-9].*");
if (startsWithNumber) {
name = "_" + name;
}
if (isNumeric(name)) { if (isNumeric(name)) {
name = "_" + name; name = "_" + name;
} }
@@ -141,8 +157,7 @@ public class GenerateGiftsEnum {
} }
} }
public static TypeSpec addGift(int id, String name, int diamond, String picture) public static TypeSpec addGift(int id, String name, int diamond, String picture) {
{
return TypeSpec.anonymousClassBuilder( return TypeSpec.anonymousClassBuilder(
"$L, $S, $L, $S", "$L, $S, $L, $S",
id, id,

View File

@@ -68,10 +68,10 @@ public class GiftsDownloader {
var officialGifts = officalGift.run(); var officialGifts = officalGift.run();
System.out.println("Official Gifts: " + officialGifts.size()); System.out.println("Official Gifts: " + officialGifts.size());
System.out.println("Downlooading Official Gifts"); System.out.println("Downlooading GiftExtraJson Gifts");
var extraGiftsJson = new GiftExtraJson(); var extraGiftsJson = new GiftExtraJson();
var extraGifts = extraGiftsJson.run(); var extraGifts = extraGiftsJson.run();
System.out.println("Official Gifts: " + extraGifts.size()); System.out.println("GiftExtraJson Gifts: " + extraGifts.size());
var outputHashMap = new TreeMap<Integer, GiftDto>(); var outputHashMap = new TreeMap<Integer, GiftDto>();
for (var gift : scraperGifts) { for (var gift : scraperGifts) {
@@ -86,7 +86,7 @@ public class GiftsDownloader {
var gson = new GsonBuilder().setPrettyPrinting() var gson = new GsonBuilder().setPrettyPrinting()
.create(); .create();
var json = gson.toJson(outputHashMap); var json = gson.toJson(outputHashMap);
FilesUtility.saveFile("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\output.json", json); FilesUtility.saveFile("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\output_1_0_15.json", json);
System.out.println("Gifts saved to file!"); System.out.println("Gifts saved to file!");
return outputHashMap.values().stream().toList(); return outputHashMap.values().stream().toList();
} }

View File

@@ -23,15 +23,8 @@
package io.github.jwdeveloper.tiktok.gifts.downloader; package io.github.jwdeveloper.tiktok.gifts.downloader;
import com.google.gson.*; import com.google.gson.*;
import io.github.jwdeveloper.tiktok.Constants;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
import io.github.jwdeveloper.tiktok.utils.FilesUtility; import io.github.jwdeveloper.tiktok.utils.FilesUtility;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@@ -22,21 +22,14 @@
*/ */
package io.github.jwdeveloper.tiktok.gifts.downloader; package io.github.jwdeveloper.tiktok.gifts.downloader;
import com.google.gson.GsonBuilder; import io.github.jwdeveloper.tiktok.TikTokLive;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import io.github.jwdeveloper.tiktok.Constants;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
import io.github.jwdeveloper.tiktok.utils.FilesUtility; import io.github.jwdeveloper.tiktok.utils.FilesUtility;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
public class GiftOfficialJson { public class GiftOfficialJson {
@@ -45,63 +38,30 @@ public class GiftOfficialJson {
} }
public List<GiftDto> run() { public List<GiftDto> run() {
var output = new ArrayList<GiftDto>();
var jsonGifts = getJsonGifts();
for (var jsonElement : jsonGifts) {
var gift = getGift(jsonElement);
output.add(gift);
}
return output;
}
private GiftDto getGift(JsonElement jsonElement) {
var id = jsonElement.getAsJsonObject().get("id").getAsInt();
var name = jsonElement.getAsJsonObject().get("name").getAsString();
var diamondCost = jsonElement.getAsJsonObject().get("diamond_count").getAsInt();
var image = jsonElement.getAsJsonObject()
.get("image").getAsJsonObject()
.get("url_list").getAsJsonArray().get(0).getAsString();
if(image.endsWith(".webp"))
{
image = image.replace(".webp",".jpg");
}
var gift = new GiftDto();
gift.setId(id);
gift.setName(name);
gift.setDiamondCost(diamondCost);
gift.setImage(image);
return gift;
}
public static JsonArray getJsonGifts() {
var jar = new TikTokCookieJar();
var tiktokHttpClient = new TikTokHttpClient(jar, new TikTokHttpRequestFactory(jar, new TikTokEventObserver()));
var settings = Constants.DefaultClientSettings();
var dtf = DateTimeFormatter.ofPattern("dd/MM/yyyy");
var now = LocalDateTime.now();
var date = now.format(dtf).replace("/", "_");
var fileName = "official_" + date + ".json";
try { try {
var response = tiktokHttpClient.getJsonFromWebcastApi("gift/list/", settings.getClientParameters()); var dtf = DateTimeFormatter.ofPattern("dd/MM/yyyy");
var gson = new GsonBuilder().setPrettyPrinting().create(); var now = LocalDateTime.now();
FilesUtility.saveFile("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\official\\" + fileName, gson.toJson(response)); var date = now.format(dtf).replace("/", "_");
if (!response.has("data")) { var fileName = "official_" + date + ".json";
return new JsonArray();
} var httpClient = TikTokLive.requests();
var dataJson = response.getAsJsonObject("data"); var giftsInfo = httpClient.fetchGiftsData();
if (!dataJson.has("gifts")) { FilesUtility.saveFile("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\official\\" + fileName, giftsInfo.getJson());
return new JsonArray();
}
return dataJson.get("gifts").getAsJsonArray(); return giftsInfo.getGifts().stream().map(e ->
{
var gift = new GiftDto();
gift.setId(e.getId());
gift.setImage(e.getImage());
gift.setName(e.getName());
gift.setDiamondCost(e.getDiamondCost());
return gift;
}).collect(Collectors.toList());
} catch (Exception e) { } catch (Exception e) {
throw new TikTokLiveRequestException("Failed to fetch giftTokens from WebCast, see stacktrace for more info.", e); throw new TikTokLiveRequestException("Failed to fetch giftTokens from WebCast, see stacktrace for more info.", e);
} }
} }
} }

View File

@@ -298,5 +298,509 @@
"name": "Team Bracelet", "name": "Team Bracelet",
"diamondCost": 2, "diamondCost": 2,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/54cb1eeca369e5bea1b97707ca05d189.png~tplv-obj.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/54cb1eeca369e5bea1b97707ca05d189.png~tplv-obj.png"
},
{
"id": 5514,
"name": "Birds",
"diamondCost": 600,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0911b5726d912dabbf6ee4b0383352ea.png~tplv-obj.png"
},
{
"id": 5524,
"name": "Tsar",
"diamondCost": 100,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/cb1c3e6263d4b6c08301f8798dcb5a9b.png~tplv-obj.png"
},
{
"id": 5549,
"name": "Ballet Dancer",
"diamondCost": 500,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c09cc8ce49476d2c46e9c8af6189d5f4.png~tplv-obj.png"
},
{
"id": 5559,
"name": "Crystal Heart",
"diamondCost": 499,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ae46ac6582a606009643440fe4138eb4.png~tplv-obj.png"
},
{
"id": 5680,
"name": "Disco ball",
"diamondCost": 1000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8d0cb854bbe8eeea654f3f9c353c5cf0~tplv-obj.png"
},
{
"id": 6112,
"name": "King Cake ",
"diamondCost": 9,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/aa99da9f6b499ff879c3860e888a53ae~tplv-obj.png"
},
{
"id": 6393,
"name": "Magic Hat",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b156ffd21bb3849a52144ab1688bbc43~tplv-obj.png"
},
{
"id": 6426,
"name": "Dombra",
"diamondCost": 20,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ccd9fea1988521d1e81051a916800d6c~tplv-obj.png"
},
{
"id": 6452,
"name": "Jakarta Roundabout",
"diamondCost": 16999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/31f67910fc5858cf087da65746f1f9f3~tplv-obj.png"
},
{
"id": 6633,
"name": "Independence Day",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b967993872a6e40f3477d30545f8d2eb~tplv-obj.png"
},
{
"id": 6655,
"name": "Summer Iris ",
"diamondCost": 30,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/cb591f5b5729fa6e64cac57c78724981~tplv-obj.png"
},
{
"id": 6741,
"name": "Gorgeous Trophy",
"diamondCost": 7000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/279c9495c2150e333bc4bc13761d177e~tplv-obj.png"
},
{
"id": 6756,
"name": "Hot",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ec679890070187b61620b9662afb814e~tplv-obj.png"
},
{
"id": 6800,
"name": "Pinata",
"diamondCost": 699,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c8a18d43dc9fb4598d7e991ebeb958ae~tplv-obj.png"
},
{
"id": 6967,
"name": "Autumn Leaves",
"diamondCost": 500,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/30adcaf443df63e3bfd2751ad251f87d~tplv-obj.png"
},
{
"id": 7032,
"name": "Maracas",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/00204efcf0573192ad5d872c7beeaf5b~tplv-obj.png"
},
{
"id": 7084,
"name": "Witchy Kitty",
"diamondCost": 30,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/dfce46f99a1206cca84f9092603e4783~tplv-obj.png"
},
{
"id": 7105,
"name": "Magic Potion",
"diamondCost": 499,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e055625e9239df7e833702c768e033d2~tplv-obj.png"
},
{
"id": 7377,
"name": "Christmas Market G",
"diamondCost": 2000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/f498f29ef628c8318006a9ff2f49bf08~tplv-obj.png"
},
{
"id": 7458,
"name": "Wooly Hat",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a234d0187047fa48805c8ea2e1f1f756~tplv-obj.png"
},
{
"id": 7475,
"name": "Mistletoe GDM 23",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/3527969b8c27e3194e61ff0787a9c3c2~tplv-obj.png"
},
{
"id": 7477,
"name": "Panettone GDM 23",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/64ce2413a362442819b4551703b7b26c~tplv-obj.png"
},
{
"id": 7498,
"name": "Candy Cane Gun",
"diamondCost": 799,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/58ef7964e32adc5fc47c5706a02e4ff0~tplv-obj.png"
},
{
"id": 7504,
"name": "Holiday Stocking",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e05de50999ebb446e15c4947b30d3140~tplv-obj.png"
},
{
"id": 7523,
"name": "Hot Choco GDM 23",
"diamondCost": 30,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/f62f5912077d9af84256de288399125a~tplv-obj.png"
},
{
"id": 7525,
"name": "Christmas CarouseG",
"diamondCost": 2000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b5ba3941f7389da7495b659e888ea61a~tplv-obj.png"
},
{
"id": 7527,
"name": "Christmas Wreath G",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7842b50135e089334fc40d9705bb53c7~tplv-obj.png"
},
{
"id": 7551,
"name": "Snowman",
"diamondCost": 99,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e094e0fafc14aaf127fa0d0a7926619a~tplv-obj.png"
},
{
"id": 7697,
"name": "LOVE U",
"diamondCost": 899,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/79d45877691333e2ba69a9098406e95c~tplv-obj.png"
},
{
"id": 7707,
"name": "I'm blue",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c560ec76d5599198aaea9377c5ffab6e~tplv-obj.png"
},
{
"id": 7846,
"name": "Grumpy Glasses",
"diamondCost": 99,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/6f38f8ed7442f69a105788b5c0c74a38~tplv-obj.png"
},
{
"id": 7920,
"name": "Husky",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a2f5d595e9d96aec19a7c0ed5fa9b017~tplv-obj.png"
},
{
"id": 7921,
"name": "Golden",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b97f58dcb0250489ae98529bcb0542ca~tplv-obj.png"
},
{
"id": 8005,
"name": "Falling For You",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a198bd39d2511dbba6a68867740e3ff9~tplv-obj.png"
},
{
"id": 8207,
"name": "The Crown",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5bf798f92fe96ba53c0f4d28f052f9bb~tplv-obj.png"
},
{
"id": 8250,
"name": "Disco ball",
"diamondCost": 1000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a53d3ef956eb2f1aa7a7db46024c70bb~tplv-obj.png"
},
{
"id": 8253,
"name": "Spring Train",
"diamondCost": 3999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b859c413a241fec75bc78668aeb0f581~tplv-obj.png"
},
{
"id": 8264,
"name": "Happy Weekend",
"diamondCost": 599,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b04f104e717798235cd3edaa6703e6a3~tplv-obj.png"
},
{
"id": 8265,
"name": "Happy Friday",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/65e8fcb76825b9ec36a24faf9a3e9495~tplv-obj.png"
},
{
"id": 8266,
"name": "Good Afternoon",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/bff3b908c4dd9cf19ab431cc99dc7940~tplv-obj.png"
},
{
"id": 8269,
"name": "Good Morning",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5c1a28f3aa7eefc27491f3020748ce54~tplv-obj.png"
},
{
"id": 8442,
"name": "Flower Festival",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9bfe63e39b581a69ff944758c3eae5a0~tplv-obj.png"
},
{
"id": 8754,
"name": "Aurora",
"diamondCost": 12000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1f59f5593ce135325c1a034825cec18c.png~tplv-obj.png"
},
{
"id": 8803,
"name": "Miss You",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/3c53396b922691a7520698f47105a753.png~tplv-obj.png"
},
{
"id": 8804,
"name": "Vacation",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/8f46e8eef9cbd5304fb802104c2b4ef4.png~tplv-obj.png"
},
{
"id": 8890,
"name": "Pink Shoes",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/cba8a7c718988bd51c7b6055e9ab1ec4.png~tplv-obj.png"
},
{
"id": 9111,
"name": "Popcorn",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/676d2d4c31a8979f1fd06cdf5ecd922f~tplv-obj.png"
},
{
"id": 9152,
"name": "Spin with me GDM",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/149ac2e87d05490d7d251149cefe27a2.png~tplv-obj.png"
},
{
"id": 9242,
"name": "Pumpkin Spice Latte",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0636d91615f7417ddd5f29438bf5debe~tplv-obj.png"
},
{
"id": 9303,
"name": "Rabbit and Mochi",
"diamondCost": 999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/213ef2549fbb10ec783c95a41d28cf0a.png~tplv-obj.png"
},
{
"id": 9304,
"name": "Boo the Ghost",
"diamondCost": 88,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/cb909c78f2412e4927ea68d6af8e048f.png~tplv-obj.png"
},
{
"id": 9354,
"name": "I'm here",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/7006392a82d57452d5ef08dd90e169c1.png~tplv-obj.png"
},
{
"id": 9355,
"name": "So cute",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/d40d31241efcf57c630e894bb3007b8a.png~tplv-obj.png"
},
{
"id": 9363,
"name": "Elf GDM 23",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/60e5289b379660cc562742cf987a2d35.png~tplv-obj.png"
},
{
"id": 9535,
"name": "Play for you",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/182659e90a3432aa155e61c9c0d89df0.png~tplv-obj.png"
},
{
"id": 9536,
"name": "Fake smile",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/35ce62173962e33834703212d0b845a7.png~tplv-obj.png"
},
{
"id": 9576,
"name": "Yeah Nah",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4b20c5aab3841657a343be3769307805.png~tplv-obj.png"
},
{
"id": 9581,
"name": "Turkey Face GDDec",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/65349d1ef783fc207c1d2b54a8d521a7.png~tplv-obj.png"
},
{
"id": 9583,
"name": "Cool!",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/424c61f16c16919f169fd0352bd24661.png~tplv-obj.png"
},
{
"id": 9587,
"name": "Christmas Potato",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/5448f1f5157d3a4a88e0f57acf3dbfe0.png~tplv-obj.png"
},
{
"id": 9604,
"name": "Gobble Gobble",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/ada9babc0b55cf005e8c8d13dfc30b42.png~tplv-obj.png"
},
{
"id": 9615,
"name": "Festive Tiny Diny",
"diamondCost": 15,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f2a8c2967c7153e9077bb469f2e42317.png~tplv-obj.png"
},
{
"id": 9617,
"name": "Xmas Mishka Bear",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/700c1c8817847317407cc2b8c6c9da42.png~tplv-obj.png"
},
{
"id": 9625,
"name": "Elf's Hat ",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9857a040c92b34d6a261201a93c185f.png~tplv-obj.png"
},
{
"id": 9647,
"name": "Kitten Paw",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/332520d7b5085ce591396c8d2bb9d352.png~tplv-obj.png"
},
{
"id": 9650,
"name": "The Van Cat",
"diamondCost": 799,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6973dd1b6d3dee3ca3f0ebac3c1d2977.png~tplv-obj.png"
},
{
"id": 9656,
"name": "Gingerbread man",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/af01db3e3cb9f54ea2cb421fab6062bc.png~tplv-obj.png"
},
{
"id": 9657,
"name": "GB North Pole",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/79715a53c41619e7b205eb26e57926d4.png~tplv-obj.png"
},
{
"id": 9658,
"name": "DE North Pole",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/130e17b5b561a93cefbd236586881477.png~tplv-obj.png"
},
{
"id": 9667,
"name": "Kiwi Bird",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/b73cb4aaa76a33efd881192589d65351.png~tplv-obj.png"
},
{
"id": 9668,
"name": "Gingerman Party",
"diamondCost": 1200,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/008a9554e736642f1b2dca9f198bb710.png~tplv-obj.png"
},
{
"id": 9670,
"name": "Reindeer",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4565fa0cd1dbf76463144b0d4cc50bf1.png~tplv-obj.png"
},
{
"id": 9671,
"name": "Gingebread Man",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/2399f65414f77419ec7d5e9274dc8e0e.png~tplv-obj.png"
},
{
"id": 9672,
"name": "Mimi & Fifi",
"diamondCost": 5000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/0a72d0084695d03586fea7d854dc3a47.png~tplv-obj.png"
},
{
"id": 9678,
"name": "Holiday Carousel",
"diamondCost": 2000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/b5ba3941f7389da7495b659e888ea61a.png~tplv-obj.png"
},
{
"id": 9680,
"name": "Xmas in London",
"diamondCost": 20000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/876204a6ad0b1b0e4675d9be42439183.png~tplv-obj.png"
},
{
"id": 9682,
"name": "Stay Warm",
"diamondCost": 450,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/abd104eb08ce0c351292036d8897fb8d.png~tplv-obj.png"
},
{
"id": 9688,
"name": "Snowglobe",
"diamondCost": 499,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/ea5ac5f8e186897456bed2e78fc78ca5.png~tplv-obj.png"
},
{
"id": 9698,
"name": "Candy Cane",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1fa0a4ed666304c78a46de200b85c84b.png~tplv-obj.png"
},
{
"id": 9703,
"name": "Really Curious",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/793ba68723567b695b12f2ef08dc1484.png~tplv-obj.png"
},
{
"id": 9704,
"name": "Nemo",
"diamondCost": 15,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/68fcf30cb3fb07e9546f5e7fbc2b0ac0.png~tplv-obj.png"
},
{
"id": 9706,
"name": "Elfs Hat ",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9857a040c92b34d6a261201a93c185f.png~tplv-obj.png"
},
{
"id": 9770,
"name": "Shiba Cookie",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4ea5282e7f61cbeee1214422d40ad407.png~tplv-obj.png"
},
{
"id": 9771,
"name": "KFC Chicken",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9d59ccd2328b8a46841b3b1c87d9e55.png~tplv-obj.png"
} }
] ]

File diff suppressed because one or more lines are too long

View File

@@ -349,9 +349,9 @@
}, },
"5514": { "5514": {
"id": 5514, "id": 5514,
"name": "", "name": "Birds",
"diamondCost": 600, "diamondCost": 600,
"image": "https://storage.streamdps.com/iblock/77b/77b29c9978438cbed17bfa7fcfd82a7c/805806ca07c5ed0b4315652ce3952c53.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0911b5726d912dabbf6ee4b0383352ea.png~tplv-obj.png"
}, },
"5518": { "5518": {
"id": 5518, "id": 5518,
@@ -365,6 +365,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/0f1/0f100548d20594a29c36938ceaea1a62/9e8ba4ba863ec74182826cd0ec1204f9.webp" "image": "https://storage.streamdps.com/iblock/0f1/0f100548d20594a29c36938ceaea1a62/9e8ba4ba863ec74182826cd0ec1204f9.webp"
}, },
"5524": {
"id": 5524,
"name": "Tsar",
"diamondCost": 100,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/cb1c3e6263d4b6c08301f8798dcb5a9b.png~tplv-obj.png"
},
"5525": { "5525": {
"id": 5525, "id": 5525,
"name": "", "name": "",
@@ -395,6 +401,12 @@
"diamondCost": 5, "diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8525a07c6bf16a74eee66e9ad119b3b8.png~tplv-obj.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8525a07c6bf16a74eee66e9ad119b3b8.png~tplv-obj.png"
}, },
"5549": {
"id": 5549,
"name": "Ballet Dancer",
"diamondCost": 500,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c09cc8ce49476d2c46e9c8af6189d5f4.png~tplv-obj.png"
},
"5556": { "5556": {
"id": 5556, "id": 5556,
"name": "", "name": "",
@@ -409,9 +421,9 @@
}, },
"5559": { "5559": {
"id": 5559, "id": 5559,
"name": "", "name": "Crystal Heart",
"diamondCost": 499, "diamondCost": 499,
"image": "https://storage.streamdps.com/iblock/7ee/7eed736538e3381d1060959a4a6265cc/a0688e0e9dbbf0a18129a01a5787eb05.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ae46ac6582a606009643440fe4138eb4.png~tplv-obj.png"
}, },
"5560": { "5560": {
"id": 5560, "id": 5560,
@@ -669,7 +681,7 @@
"id": 5680, "id": 5680,
"name": "Disco ball", "name": "Disco ball",
"diamondCost": 1000, "diamondCost": 1000,
"image": "https://storage.streamdps.com/iblock/cdd/cdd759a0d8715e70c1d888c785259620/864a0df77a777eb522157c4d8eb393a3.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8d0cb854bbe8eeea654f3f9c353c5cf0~tplv-obj.png"
}, },
"5685": { "5685": {
"id": 5685, "id": 5685,
@@ -1679,6 +1691,12 @@
"diamondCost": 99, "diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/755/7554b4a059474294a01241f9065b0b12/3c499a6504236ff8ec6d072747ce0230.png" "image": "https://storage.streamdps.com/iblock/755/7554b4a059474294a01241f9065b0b12/3c499a6504236ff8ec6d072747ce0230.png"
}, },
"6112": {
"id": 6112,
"name": "King Cake ",
"diamondCost": 9,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/aa99da9f6b499ff879c3860e888a53ae~tplv-obj.png"
},
"6113": { "6113": {
"id": 6113, "id": 6113,
"name": "Taco ", "name": "Taco ",
@@ -2071,9 +2089,9 @@
}, },
"6393": { "6393": {
"id": 6393, "id": 6393,
"name": "", "name": "Magic Hat",
"diamondCost": 299, "diamondCost": 299,
"image": "https://storage.streamdps.com/iblock/9ac/9ac682d8a906e071def06929fca8ac7a/36982973f4f0f8ef9ebb4bb67494f72a.webp" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b156ffd21bb3849a52144ab1688bbc43~tplv-obj.png"
}, },
"6398": { "6398": {
"id": 6398, "id": 6398,
@@ -2123,6 +2141,12 @@
"diamondCost": 2000, "diamondCost": 2000,
"image": "https://storage.streamdps.com/iblock/49b/49be18ae5914346ffcaf15a519ba9c1c/41326cb23d22010f0c4a8edf5bd27615.webp" "image": "https://storage.streamdps.com/iblock/49b/49be18ae5914346ffcaf15a519ba9c1c/41326cb23d22010f0c4a8edf5bd27615.webp"
}, },
"6426": {
"id": 6426,
"name": "Dombra",
"diamondCost": 20,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ccd9fea1988521d1e81051a916800d6c~tplv-obj.png"
},
"6427": { "6427": {
"id": 6427, "id": 6427,
"name": "Hat and Mustache", "name": "Hat and Mustache",
@@ -2189,6 +2213,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/e11/e110e47562d77ab5fa26cc31e840f801/a4a1823ef2c1bc65c4dc2a4e82ec446b.png" "image": "https://storage.streamdps.com/iblock/e11/e110e47562d77ab5fa26cc31e840f801/a4a1823ef2c1bc65c4dc2a4e82ec446b.png"
}, },
"6452": {
"id": 6452,
"name": "Jakarta Roundabout",
"diamondCost": 16999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/31f67910fc5858cf087da65746f1f9f3~tplv-obj.png"
},
"6454": { "6454": {
"id": 6454, "id": 6454,
"name": "", "name": "",
@@ -2561,6 +2591,12 @@
"diamondCost": 99, "diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/b17/b171f313a2ba4af15e8645f02d24d4e7/a58831515ce8102cb72841e8ed45ed08.webp" "image": "https://storage.streamdps.com/iblock/b17/b171f313a2ba4af15e8645f02d24d4e7/a58831515ce8102cb72841e8ed45ed08.webp"
}, },
"6633": {
"id": 6633,
"name": "Independence Day",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b967993872a6e40f3477d30545f8d2eb~tplv-obj.png"
},
"6634": { "6634": {
"id": 6634, "id": 6634,
"name": "Sunday Roast", "name": "Sunday Roast",
@@ -2597,6 +2633,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/c1e/c1e1683273f5505462f45358cd773806/ba5afaec3f62e18672bd1b25a4e8a4d2.webp" "image": "https://storage.streamdps.com/iblock/c1e/c1e1683273f5505462f45358cd773806/ba5afaec3f62e18672bd1b25a4e8a4d2.webp"
}, },
"6655": {
"id": 6655,
"name": "Summer Iris ",
"diamondCost": 30,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/cb591f5b5729fa6e64cac57c78724981~tplv-obj.png"
},
"6661": { "6661": {
"id": 6661, "id": 6661,
"name": "Kiss your Heart", "name": "Kiss your Heart",
@@ -2705,6 +2747,12 @@
"diamondCost": 100, "diamondCost": 100,
"image": "https://storage.streamdps.com/iblock/cc8/cc8133c73d5ca2cb5fde306f5b4e2a11/fb273956755fe6fbf7263023a9c36ebe.webp" "image": "https://storage.streamdps.com/iblock/cc8/cc8133c73d5ca2cb5fde306f5b4e2a11/fb273956755fe6fbf7263023a9c36ebe.webp"
}, },
"6741": {
"id": 6741,
"name": "Gorgeous Trophy",
"diamondCost": 7000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/279c9495c2150e333bc4bc13761d177e~tplv-obj.png"
},
"6743": { "6743": {
"id": 6743, "id": 6743,
"name": "", "name": "",
@@ -2735,6 +2783,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/457/457a95d19f48aa254b10a30ee8e2c791/b3e217a47d1b38fe06ef11e149aae0e0.webp" "image": "https://storage.streamdps.com/iblock/457/457a95d19f48aa254b10a30ee8e2c791/b3e217a47d1b38fe06ef11e149aae0e0.webp"
}, },
"6756": {
"id": 6756,
"name": "Hot",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ec679890070187b61620b9662afb814e~tplv-obj.png"
},
"6757": { "6757": {
"id": 6757, "id": 6757,
"name": "Dash", "name": "Dash",
@@ -2837,6 +2891,12 @@
"diamondCost": 199, "diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/53b/53ba63daed395b1c8eda6cd5fa51b912/2ddcbdeeebee2a97780b4e846aace552.webp" "image": "https://storage.streamdps.com/iblock/53b/53ba63daed395b1c8eda6cd5fa51b912/2ddcbdeeebee2a97780b4e846aace552.webp"
}, },
"6800": {
"id": 6800,
"name": "Pinata",
"diamondCost": 699,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c8a18d43dc9fb4598d7e991ebeb958ae~tplv-obj.png"
},
"6813": { "6813": {
"id": 6813, "id": 6813,
"name": "Fantastic", "name": "Fantastic",
@@ -3129,7 +3189,7 @@
"id": 6967, "id": 6967,
"name": "Autumn Leaves", "name": "Autumn Leaves",
"diamondCost": 500, "diamondCost": 500,
"image": "https://storage.streamdps.com/iblock/f04/f042339687e8abaa2fc0e1976d9b11f4/251a0624bc3a23ba39d75467868dcbf8.webp" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/30adcaf443df63e3bfd2751ad251f87d~tplv-obj.png"
}, },
"6968": { "6968": {
"id": 6968, "id": 6968,
@@ -3275,6 +3335,12 @@
"diamondCost": 10, "diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/eeb/eeb4c2ae379b89120c8ae69bbbea8642/ea6d73fcf39771c592560120d2c9b577.webp" "image": "https://storage.streamdps.com/iblock/eeb/eeb4c2ae379b89120c8ae69bbbea8642/ea6d73fcf39771c592560120d2c9b577.webp"
}, },
"7032": {
"id": 7032,
"name": "Maracas",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/00204efcf0573192ad5d872c7beeaf5b~tplv-obj.png"
},
"7037": { "7037": {
"id": 7037, "id": 7037,
"name": "", "name": "",
@@ -3385,9 +3451,9 @@
}, },
"7084": { "7084": {
"id": 7084, "id": 7084,
"name": "", "name": "Witchy Kitty",
"diamondCost": 30, "diamondCost": 30,
"image": "https://storage.streamdps.com/iblock/1c6/1c64bc1b780d8a987986694a699e0585/0d6afd7934d363dba4a747f8c0bec66b.webp" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/dfce46f99a1206cca84f9092603e4783~tplv-obj.png"
}, },
"7086": { "7086": {
"id": 7086, "id": 7086,
@@ -3443,6 +3509,12 @@
"diamondCost": 5, "diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/5f2/5f2f2f673c116c46372ee874bfb66685/759b52ad2866ed2f5a78ccd558f4457e.webp" "image": "https://storage.streamdps.com/iblock/5f2/5f2f2f673c116c46372ee874bfb66685/759b52ad2866ed2f5a78ccd558f4457e.webp"
}, },
"7105": {
"id": 7105,
"name": "Magic Potion",
"diamondCost": 499,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e055625e9239df7e833702c768e033d2~tplv-obj.png"
},
"7106": { "7106": {
"id": 7106, "id": 7106,
"name": "", "name": "",
@@ -3737,6 +3809,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/bf8/bf8e32bd0bf5a916195b5848db571f4f/a9241b01b970aa44c2d5cea5e8ba69d6.webp" "image": "https://storage.streamdps.com/iblock/bf8/bf8e32bd0bf5a916195b5848db571f4f/a9241b01b970aa44c2d5cea5e8ba69d6.webp"
}, },
"7377": {
"id": 7377,
"name": "Christmas Market G",
"diamondCost": 2000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/f498f29ef628c8318006a9ff2f49bf08~tplv-obj.png"
},
"7391": { "7391": {
"id": 7391, "id": 7391,
"name": "I\u0027m shy", "name": "I\u0027m shy",
@@ -3773,6 +3851,12 @@
"diamondCost": 10, "diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/8f7/8f7fcac557fb70fa0bbd69809c112c0e/978e0bcdcd8cbf4cbdfdb53d9fc39eaa.webp" "image": "https://storage.streamdps.com/iblock/8f7/8f7fcac557fb70fa0bbd69809c112c0e/978e0bcdcd8cbf4cbdfdb53d9fc39eaa.webp"
}, },
"7458": {
"id": 7458,
"name": "Wooly Hat",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a234d0187047fa48805c8ea2e1f1f756~tplv-obj.png"
},
"7467": { "7467": {
"id": 7467, "id": 7467,
"name": "Chasing the Dream", "name": "Chasing the Dream",
@@ -3785,12 +3869,30 @@
"diamondCost": 5000, "diamondCost": 5000,
"image": "https://storage.streamdps.com/iblock/f5c/f5cda80a1f9853c49226a450faf26e8f/6318d17d7a2526f521123402d19a4c3e.webp" "image": "https://storage.streamdps.com/iblock/f5c/f5cda80a1f9853c49226a450faf26e8f/6318d17d7a2526f521123402d19a4c3e.webp"
}, },
"7475": {
"id": 7475,
"name": "Mistletoe GDM 23",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/3527969b8c27e3194e61ff0787a9c3c2~tplv-obj.png"
},
"7477": {
"id": 7477,
"name": "Panettone GDM 23",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/64ce2413a362442819b4551703b7b26c~tplv-obj.png"
},
"7482": { "7482": {
"id": 7482, "id": 7482,
"name": "Flying Jets", "name": "Flying Jets",
"diamondCost": 5000, "diamondCost": 5000,
"image": "https://storage.streamdps.com/iblock/5a4/5a4f3c7adc31f60326e3adf1a3a20bf9/bc96de02ceba4b91c1f9c996293974b4.webp" "image": "https://storage.streamdps.com/iblock/5a4/5a4f3c7adc31f60326e3adf1a3a20bf9/bc96de02ceba4b91c1f9c996293974b4.webp"
}, },
"7498": {
"id": 7498,
"name": "Candy Cane Gun",
"diamondCost": 799,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/58ef7964e32adc5fc47c5706a02e4ff0~tplv-obj.png"
},
"7501": { "7501": {
"id": 7501, "id": 7501,
"name": "Hello Traveler", "name": "Hello Traveler",
@@ -3803,6 +3905,30 @@
"diamondCost": 299, "diamondCost": 299,
"image": "https://storage.streamdps.com/iblock/679/679e9e38e38f8a4ce707328aa92b8997/9fedb22710af980bbf7b3092b08ecb94.webp" "image": "https://storage.streamdps.com/iblock/679/679e9e38e38f8a4ce707328aa92b8997/9fedb22710af980bbf7b3092b08ecb94.webp"
}, },
"7504": {
"id": 7504,
"name": "Holiday Stocking",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e05de50999ebb446e15c4947b30d3140~tplv-obj.png"
},
"7523": {
"id": 7523,
"name": "Hot Choco GDM 23",
"diamondCost": 30,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/f62f5912077d9af84256de288399125a~tplv-obj.png"
},
"7525": {
"id": 7525,
"name": "Christmas CarouseG",
"diamondCost": 2000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b5ba3941f7389da7495b659e888ea61a~tplv-obj.png"
},
"7527": {
"id": 7527,
"name": "Christmas Wreath G",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7842b50135e089334fc40d9705bb53c7~tplv-obj.png"
},
"7529": { "7529": {
"id": 7529, "id": 7529,
"name": "Mystery Firework", "name": "Mystery Firework",
@@ -3845,6 +3971,12 @@
"diamondCost": 199, "diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/e36/e36cb42edac42a0636f8785b80c274dc/bbd87fef7b269564a4ca32009879c0ab.webp" "image": "https://storage.streamdps.com/iblock/e36/e36cb42edac42a0636f8785b80c274dc/bbd87fef7b269564a4ca32009879c0ab.webp"
}, },
"7551": {
"id": 7551,
"name": "Snowman",
"diamondCost": 99,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e094e0fafc14aaf127fa0d0a7926619a~tplv-obj.png"
},
"7591": { "7591": {
"id": 7591, "id": 7591,
"name": "Tiny Diny", "name": "Tiny Diny",
@@ -3899,6 +4031,18 @@
"diamondCost": 500, "diamondCost": 500,
"image": "https://storage.streamdps.com/iblock/dca/dcac97e4190d46d113f4bdf2918ee173/4fae166b3f3273b9dbbc2a86bea0ec18.webp" "image": "https://storage.streamdps.com/iblock/dca/dcac97e4190d46d113f4bdf2918ee173/4fae166b3f3273b9dbbc2a86bea0ec18.webp"
}, },
"7697": {
"id": 7697,
"name": "LOVE U",
"diamondCost": 899,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/79d45877691333e2ba69a9098406e95c~tplv-obj.png"
},
"7707": {
"id": 7707,
"name": "I\u0027m blue",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c560ec76d5599198aaea9377c5ffab6e~tplv-obj.png"
},
"7720": { "7720": {
"id": 7720, "id": 7720,
"name": "Flying Jets", "name": "Flying Jets",
@@ -4013,6 +4157,12 @@
"diamondCost": 199, "diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/3c4/3c40e306064bb00719cb77dec261891a/bc24ae9f8a52d13475897170332d546f.webp" "image": "https://storage.streamdps.com/iblock/3c4/3c40e306064bb00719cb77dec261891a/bc24ae9f8a52d13475897170332d546f.webp"
}, },
"7846": {
"id": 7846,
"name": "Grumpy Glasses",
"diamondCost": 99,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/6f38f8ed7442f69a105788b5c0c74a38~tplv-obj.png"
},
"7851": { "7851": {
"id": 7851, "id": 7851,
"name": "Football Helmet", "name": "Football Helmet",
@@ -4073,6 +4223,18 @@
"diamondCost": 15000, "diamondCost": 15000,
"image": "https://storage.streamdps.com/iblock/a12/a12a1b23f1f6a19d728de84e1f43e21d/ff288346e9855a9bb6deb4450491028f.webp" "image": "https://storage.streamdps.com/iblock/a12/a12a1b23f1f6a19d728de84e1f43e21d/ff288346e9855a9bb6deb4450491028f.webp"
}, },
"7920": {
"id": 7920,
"name": "Husky",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a2f5d595e9d96aec19a7c0ed5fa9b017~tplv-obj.png"
},
"7921": {
"id": 7921,
"name": "Golden",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b97f58dcb0250489ae98529bcb0542ca~tplv-obj.png"
},
"7927": { "7927": {
"id": 7927, "id": 7927,
"name": "Puppy Love", "name": "Puppy Love",
@@ -4157,6 +4319,12 @@
"diamondCost": 10, "diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/486/486a2490c987c2bb97b6068fd5aac5ab/49d9045fcfe94bbfbd08c3363bb4512a.webp" "image": "https://storage.streamdps.com/iblock/486/486a2490c987c2bb97b6068fd5aac5ab/49d9045fcfe94bbfbd08c3363bb4512a.webp"
}, },
"8005": {
"id": 8005,
"name": "Falling For You",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a198bd39d2511dbba6a68867740e3ff9~tplv-obj.png"
},
"8017": { "8017": {
"id": 8017, "id": 8017,
"name": "Headphone", "name": "Headphone",
@@ -4289,6 +4457,12 @@
"diamondCost": 5, "diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/27f/27fe97cb0f1b8056fa0aedc918ea560e/966df61a39e36fe0f7237e55c3298117.webp" "image": "https://storage.streamdps.com/iblock/27f/27fe97cb0f1b8056fa0aedc918ea560e/966df61a39e36fe0f7237e55c3298117.webp"
}, },
"8207": {
"id": 8207,
"name": "The Crown",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5bf798f92fe96ba53c0f4d28f052f9bb~tplv-obj.png"
},
"8217": { "8217": {
"id": 8217, "id": 8217,
"name": "Capybara", "name": "Capybara",
@@ -4355,6 +4529,18 @@
"diamondCost": 19999, "diamondCost": 19999,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/a598ba4c7024f4d46c1268be4d82f901~tplv-obj.jpg" "image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/a598ba4c7024f4d46c1268be4d82f901~tplv-obj.jpg"
}, },
"8250": {
"id": 8250,
"name": "Disco ball",
"diamondCost": 1000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a53d3ef956eb2f1aa7a7db46024c70bb~tplv-obj.png"
},
"8253": {
"id": 8253,
"name": "Spring Train",
"diamondCost": 3999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b859c413a241fec75bc78668aeb0f581~tplv-obj.png"
},
"8259": { "8259": {
"id": 8259, "id": 8259,
"name": "I love you", "name": "I love you",
@@ -4373,6 +4559,24 @@
"diamondCost": 6000, "diamondCost": 6000,
"image": "https://storage.streamdps.com/iblock/88d/88df4387d65bcc77b691098fd649bd59/ad401a92ddba9aae15bb777f9f38638d.webp" "image": "https://storage.streamdps.com/iblock/88d/88df4387d65bcc77b691098fd649bd59/ad401a92ddba9aae15bb777f9f38638d.webp"
}, },
"8264": {
"id": 8264,
"name": "Happy Weekend",
"diamondCost": 599,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b04f104e717798235cd3edaa6703e6a3~tplv-obj.png"
},
"8265": {
"id": 8265,
"name": "Happy Friday",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/65e8fcb76825b9ec36a24faf9a3e9495~tplv-obj.png"
},
"8266": {
"id": 8266,
"name": "Good Afternoon",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/bff3b908c4dd9cf19ab431cc99dc7940~tplv-obj.png"
},
"8267": { "8267": {
"id": 8267, "id": 8267,
"name": "Good Evening", "name": "Good Evening",
@@ -4385,6 +4589,12 @@
"diamondCost": 399, "diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b7b55087141bd5f965eb31a99a5f157b~tplv-obj.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b7b55087141bd5f965eb31a99a5f157b~tplv-obj.png"
}, },
"8269": {
"id": 8269,
"name": "Good Morning",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5c1a28f3aa7eefc27491f3020748ce54~tplv-obj.png"
},
"8277": { "8277": {
"id": 8277, "id": 8277,
"name": "Love Drop", "name": "Love Drop",
@@ -4529,6 +4739,12 @@
"diamondCost": 15000, "diamondCost": 15000,
"image": "https://storage.streamdps.com/iblock/bfc/bfcf491b940e478b6410047bc047af1b/abbbdd13015a9f31be1b905268873d73.webp" "image": "https://storage.streamdps.com/iblock/bfc/bfcf491b940e478b6410047bc047af1b/abbbdd13015a9f31be1b905268873d73.webp"
}, },
"8442": {
"id": 8442,
"name": "Flower Festival",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9bfe63e39b581a69ff944758c3eae5a0~tplv-obj.png"
},
"8448": { "8448": {
"id": 8448, "id": 8448,
"name": "Raccoon", "name": "Raccoon",
@@ -4667,6 +4883,12 @@
"diamondCost": 199, "diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/282/28210d38f8625d7c3f39bb85e1fd59c4/61f609f602fc0f3cc2bff6cf94d32fbe.webp" "image": "https://storage.streamdps.com/iblock/282/28210d38f8625d7c3f39bb85e1fd59c4/61f609f602fc0f3cc2bff6cf94d32fbe.webp"
}, },
"8754": {
"id": 8754,
"name": "Aurora",
"diamondCost": 12000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1f59f5593ce135325c1a034825cec18c.png~tplv-obj.png"
},
"8767": { "8767": {
"id": 8767, "id": 8767,
"name": "Golden Trumpet", "name": "Golden Trumpet",
@@ -4691,6 +4913,18 @@
"diamondCost": 450, "diamondCost": 450,
"image": "https://storage.streamdps.com/iblock/285/285070af9d4f72b74e7d74c22157f2d9/67d9fa3239a7f9a09ef78c832a66e624.webp" "image": "https://storage.streamdps.com/iblock/285/285070af9d4f72b74e7d74c22157f2d9/67d9fa3239a7f9a09ef78c832a66e624.webp"
}, },
"8803": {
"id": 8803,
"name": "Miss You",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/3c53396b922691a7520698f47105a753.png~tplv-obj.png"
},
"8804": {
"id": 8804,
"name": "Vacation",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/8f46e8eef9cbd5304fb802104c2b4ef4.png~tplv-obj.png"
},
"8806": { "8806": {
"id": 8806, "id": 8806,
"name": "Dancing Capybaras", "name": "Dancing Capybaras",
@@ -4757,6 +4991,12 @@
"diamondCost": 1200, "diamondCost": 1200,
"image": "https://storage.streamdps.com/iblock/07d/07d678346c7eb588bc3cbddf343ab791/8f8f50f5350e4b1c0b151aff333e43a4.webp" "image": "https://storage.streamdps.com/iblock/07d/07d678346c7eb588bc3cbddf343ab791/8f8f50f5350e4b1c0b151aff333e43a4.webp"
}, },
"8890": {
"id": 8890,
"name": "Pink Shoes",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/cba8a7c718988bd51c7b6055e9ab1ec4.png~tplv-obj.png"
},
"8892": { "8892": {
"id": 8892, "id": 8892,
"name": "Dream Team", "name": "Dream Team",
@@ -4859,6 +5099,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp" "image": "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"
}, },
"9111": {
"id": 9111,
"name": "Popcorn",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/676d2d4c31a8979f1fd06cdf5ecd922f~tplv-obj.png"
},
"9135": { "9135": {
"id": 9135, "id": 9135,
"name": "Magic Forest", "name": "Magic Forest",
@@ -4895,6 +5141,12 @@
"diamondCost": 3999, "diamondCost": 3999,
"image": "https://storage.streamdps.com/iblock/990/99093308d3ad2c3833d230f9aae7f702/36f073ad050bd79d7d1ba6d781e7ef11.webp" "image": "https://storage.streamdps.com/iblock/990/99093308d3ad2c3833d230f9aae7f702/36f073ad050bd79d7d1ba6d781e7ef11.webp"
}, },
"9152": {
"id": 9152,
"name": "Spin with me GDM",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/149ac2e87d05490d7d251149cefe27a2.png~tplv-obj.png"
},
"9175": { "9175": {
"id": 9175, "id": 9175,
"name": "Pretzel", "name": "Pretzel",
@@ -4913,12 +5165,30 @@
"diamondCost": 20000, "diamondCost": 20000,
"image": "https://storage.streamdps.com/iblock/c79/c793af446369ecef5238e73312c84ccd/464a76f3e6eaee9afc771f45a4bba9df.webp" "image": "https://storage.streamdps.com/iblock/c79/c793af446369ecef5238e73312c84ccd/464a76f3e6eaee9afc771f45a4bba9df.webp"
}, },
"9242": {
"id": 9242,
"name": "Pumpkin Spice Latte",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0636d91615f7417ddd5f29438bf5debe~tplv-obj.png"
},
"9255": { "9255": {
"id": 9255, "id": 9255,
"name": "Aerobic headband", "name": "Aerobic headband",
"diamondCost": 99, "diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/3d9/3d98c2fbc96922da37a9d22881bb06b9/0a99af132ab8e3fe9806d2412abc6bf0.webp" "image": "https://storage.streamdps.com/iblock/3d9/3d98c2fbc96922da37a9d22881bb06b9/0a99af132ab8e3fe9806d2412abc6bf0.webp"
}, },
"9303": {
"id": 9303,
"name": "Rabbit and Mochi",
"diamondCost": 999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/213ef2549fbb10ec783c95a41d28cf0a.png~tplv-obj.png"
},
"9304": {
"id": 9304,
"name": "Boo the Ghost",
"diamondCost": 88,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/cb909c78f2412e4927ea68d6af8e048f.png~tplv-obj.png"
},
"9333": { "9333": {
"id": 9333, "id": 9333,
"name": "LIVE Fest Clappers", "name": "LIVE Fest Clappers",
@@ -4931,6 +5201,30 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1e98afffef90ed4b2cc9c9ebb88e3608.png~tplv-obj.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1e98afffef90ed4b2cc9c9ebb88e3608.png~tplv-obj.png"
}, },
"9354": {
"id": 9354,
"name": "I\u0027m here",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/7006392a82d57452d5ef08dd90e169c1.png~tplv-obj.png"
},
"9355": {
"id": 9355,
"name": "So cute",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/d40d31241efcf57c630e894bb3007b8a.png~tplv-obj.png"
},
"9363": {
"id": 9363,
"name": "Elf GDM 23",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/60e5289b379660cc562742cf987a2d35.png~tplv-obj.png"
},
"9427": {
"id": 9427,
"name": "Pegasus",
"diamondCost": 42999,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f600a2495ab5d250e7da2066484a9383.png~tplv-obj.jpg"
},
"9463": { "9463": {
"id": 9463, "id": 9463,
"name": "Fairy Wings", "name": "Fairy Wings",
@@ -5003,22 +5297,232 @@
"diamondCost": 12000, "diamondCost": 12000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/51a7d74bcb4a6417be59f0ffc0b77e96.png~tplv-obj.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/51a7d74bcb4a6417be59f0ffc0b77e96.png~tplv-obj.png"
}, },
"9522": { "9535": {
"id": 9522, "id": 9535,
"name": "Exclusive Spark", "name": "Play for you",
"diamondCost": 1000, "diamondCost": 299,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f0bda1eb6856e2feea9cfcb6c575c8a0.png~tplv-obj.jpg" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/182659e90a3432aa155e61c9c0d89df0.png~tplv-obj.png"
}, },
"9523": { "9536": {
"id": 9523, "id": 9536,
"name": "Exclusive Jet", "name": "Fake smile",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/35ce62173962e33834703212d0b845a7.png~tplv-obj.png"
},
"9576": {
"id": 9576,
"name": "Yeah Nah",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4b20c5aab3841657a343be3769307805.png~tplv-obj.png"
},
"9581": {
"id": 9581,
"name": "Turkey Face GDDec",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/65349d1ef783fc207c1d2b54a8d521a7.png~tplv-obj.png"
},
"9583": {
"id": 9583,
"name": "Cool!",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/424c61f16c16919f169fd0352bd24661.png~tplv-obj.png"
},
"9587": {
"id": 9587,
"name": "Christmas Potato",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/5448f1f5157d3a4a88e0f57acf3dbfe0.png~tplv-obj.png"
},
"9604": {
"id": 9604,
"name": "Gobble Gobble",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/ada9babc0b55cf005e8c8d13dfc30b42.png~tplv-obj.png"
},
"9615": {
"id": 9615,
"name": "Festive Tiny Diny",
"diamondCost": 15,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f2a8c2967c7153e9077bb469f2e42317.png~tplv-obj.png"
},
"9617": {
"id": 9617,
"name": "Xmas Mishka Bear",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/700c1c8817847317407cc2b8c6c9da42.png~tplv-obj.png"
},
"9625": {
"id": 9625,
"name": "Elf\u0027s Hat ",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9857a040c92b34d6a261201a93c185f.png~tplv-obj.png"
},
"9639": {
"id": 9639,
"name": "2024",
"diamondCost": 1,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/484a44bbe62ce47687d1da31a6602bbd.png~tplv-obj.jpg"
},
"9640": {
"id": 9640,
"name": "2024 Glasses",
"diamondCost": 224,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/512d2e9934cbae8d1019a391814edbd2.png~tplv-obj.jpg"
},
"9641": {
"id": 9641,
"name": "2024 Countdown",
"diamondCost": 2024,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/a358a3ce18241dcc6e7d0b02d091d563.png~tplv-obj.jpg"
},
"9642": {
"id": 9642,
"name": "Train to 2024",
"diamondCost": 12024,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/0cb12913e0a96bbcc45f97b450e74cd3.png~tplv-obj.jpg"
},
"9643": {
"id": 9643,
"name": "2024 JoyLens",
"diamondCost": 224,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/36d82bbcd87c1914df84262d9bdd9b95.png~tplv-obj.jpg"
},
"9644": {
"id": 9644,
"name": "Sparkling Countdown",
"diamondCost": 2024,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/d6b4539ed9683707bdefe268f6575e74.png~tplv-obj.jpg"
},
"9645": {
"id": 9645,
"name": "New Year Journey",
"diamondCost": 12024,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/0ef9654d92354172fb9b3b364827940c.png~tplv-obj.jpg"
},
"9647": {
"id": 9647,
"name": "Kitten Paw",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/332520d7b5085ce591396c8d2bb9d352.png~tplv-obj.png"
},
"9650": {
"id": 9650,
"name": "The Van Cat",
"diamondCost": 799,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6973dd1b6d3dee3ca3f0ebac3c1d2977.png~tplv-obj.png"
},
"9656": {
"id": 9656,
"name": "Gingerbread man",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/af01db3e3cb9f54ea2cb421fab6062bc.png~tplv-obj.png"
},
"9657": {
"id": 9657,
"name": "GB North Pole",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/79715a53c41619e7b205eb26e57926d4.png~tplv-obj.png"
},
"9658": {
"id": 9658,
"name": "DE North Pole",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/130e17b5b561a93cefbd236586881477.png~tplv-obj.png"
},
"9667": {
"id": 9667,
"name": "Kiwi Bird",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/b73cb4aaa76a33efd881192589d65351.png~tplv-obj.png"
},
"9668": {
"id": 9668,
"name": "Gingerman Party",
"diamondCost": 1200,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/008a9554e736642f1b2dca9f198bb710.png~tplv-obj.png"
},
"9670": {
"id": 9670,
"name": "Reindeer",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4565fa0cd1dbf76463144b0d4cc50bf1.png~tplv-obj.png"
},
"9671": {
"id": 9671,
"name": "Gingebread Man",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/2399f65414f77419ec7d5e9274dc8e0e.png~tplv-obj.png"
},
"9672": {
"id": 9672,
"name": "Mimi \u0026 Fifi",
"diamondCost": 5000, "diamondCost": 5000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1cc167a00aa4d5dfe48018afb38c3daa.png~tplv-obj.jpg" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/0a72d0084695d03586fea7d854dc3a47.png~tplv-obj.png"
}, },
"9524": { "9678": {
"id": 9524, "id": 9678,
"name": "Exclusive Yacht", "name": "Holiday Carousel",
"diamondCost": 2000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/b5ba3941f7389da7495b659e888ea61a.png~tplv-obj.png"
},
"9680": {
"id": 9680,
"name": "Xmas in London",
"diamondCost": 20000, "diamondCost": 20000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/da8c85d5ae09ebf320216202e8fa015d.png~tplv-obj.jpg" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/876204a6ad0b1b0e4675d9be42439183.png~tplv-obj.png"
},
"9682": {
"id": 9682,
"name": "Stay Warm",
"diamondCost": 450,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/abd104eb08ce0c351292036d8897fb8d.png~tplv-obj.png"
},
"9688": {
"id": 9688,
"name": "Snowglobe",
"diamondCost": 499,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/ea5ac5f8e186897456bed2e78fc78ca5.png~tplv-obj.png"
},
"9698": {
"id": 9698,
"name": "Candy Cane",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1fa0a4ed666304c78a46de200b85c84b.png~tplv-obj.png"
},
"9703": {
"id": 9703,
"name": "Really Curious",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/793ba68723567b695b12f2ef08dc1484.png~tplv-obj.png"
},
"9704": {
"id": 9704,
"name": "Nemo",
"diamondCost": 15,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/68fcf30cb3fb07e9546f5e7fbc2b0ac0.png~tplv-obj.png"
},
"9706": {
"id": 9706,
"name": "Elfs Hat ",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9857a040c92b34d6a261201a93c185f.png~tplv-obj.png"
},
"9717": {
"id": 9717,
"name": "Lucky Airdrop Box",
"diamondCost": 999,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6ae56f08ae3ee57ea2dda0025bfd39d3.png~tplv-obj.jpg"
},
"9770": {
"id": 9770,
"name": "Shiba Cookie",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4ea5282e7f61cbeee1214422d40ad407.png~tplv-obj.png"
},
"9771": {
"id": 9771,
"name": "KFC Chicken",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9d59ccd2328b8a46841b3b1c87d9e55.png~tplv-obj.png"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -349,9 +349,9 @@
}, },
"5514": { "5514": {
"id": 5514, "id": 5514,
"name": "", "name": "Birds",
"diamondCost": 600, "diamondCost": 600,
"image": "https://storage.streamdps.com/iblock/77b/77b29c9978438cbed17bfa7fcfd82a7c/805806ca07c5ed0b4315652ce3952c53.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0911b5726d912dabbf6ee4b0383352ea.png~tplv-obj.png"
}, },
"5518": { "5518": {
"id": 5518, "id": 5518,
@@ -365,6 +365,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/0f1/0f100548d20594a29c36938ceaea1a62/9e8ba4ba863ec74182826cd0ec1204f9.webp" "image": "https://storage.streamdps.com/iblock/0f1/0f100548d20594a29c36938ceaea1a62/9e8ba4ba863ec74182826cd0ec1204f9.webp"
}, },
"5524": {
"id": 5524,
"name": "Tsar",
"diamondCost": 100,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/cb1c3e6263d4b6c08301f8798dcb5a9b.png~tplv-obj.png"
},
"5525": { "5525": {
"id": 5525, "id": 5525,
"name": "", "name": "",
@@ -395,6 +401,12 @@
"diamondCost": 5, "diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8525a07c6bf16a74eee66e9ad119b3b8.png~tplv-obj.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8525a07c6bf16a74eee66e9ad119b3b8.png~tplv-obj.png"
}, },
"5549": {
"id": 5549,
"name": "Ballet Dancer",
"diamondCost": 500,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c09cc8ce49476d2c46e9c8af6189d5f4.png~tplv-obj.png"
},
"5556": { "5556": {
"id": 5556, "id": 5556,
"name": "", "name": "",
@@ -409,9 +421,9 @@
}, },
"5559": { "5559": {
"id": 5559, "id": 5559,
"name": "", "name": "Crystal Heart",
"diamondCost": 499, "diamondCost": 499,
"image": "https://storage.streamdps.com/iblock/7ee/7eed736538e3381d1060959a4a6265cc/a0688e0e9dbbf0a18129a01a5787eb05.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ae46ac6582a606009643440fe4138eb4.png~tplv-obj.png"
}, },
"5560": { "5560": {
"id": 5560, "id": 5560,
@@ -669,7 +681,7 @@
"id": 5680, "id": 5680,
"name": "Disco ball", "name": "Disco ball",
"diamondCost": 1000, "diamondCost": 1000,
"image": "https://storage.streamdps.com/iblock/cdd/cdd759a0d8715e70c1d888c785259620/864a0df77a777eb522157c4d8eb393a3.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/8d0cb854bbe8eeea654f3f9c353c5cf0~tplv-obj.png"
}, },
"5685": { "5685": {
"id": 5685, "id": 5685,
@@ -1679,6 +1691,12 @@
"diamondCost": 99, "diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/755/7554b4a059474294a01241f9065b0b12/3c499a6504236ff8ec6d072747ce0230.png" "image": "https://storage.streamdps.com/iblock/755/7554b4a059474294a01241f9065b0b12/3c499a6504236ff8ec6d072747ce0230.png"
}, },
"6112": {
"id": 6112,
"name": "King Cake ",
"diamondCost": 9,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/aa99da9f6b499ff879c3860e888a53ae~tplv-obj.png"
},
"6113": { "6113": {
"id": 6113, "id": 6113,
"name": "Taco ", "name": "Taco ",
@@ -2071,9 +2089,9 @@
}, },
"6393": { "6393": {
"id": 6393, "id": 6393,
"name": "", "name": "Magic Hat",
"diamondCost": 299, "diamondCost": 299,
"image": "https://storage.streamdps.com/iblock/9ac/9ac682d8a906e071def06929fca8ac7a/36982973f4f0f8ef9ebb4bb67494f72a.webp" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b156ffd21bb3849a52144ab1688bbc43~tplv-obj.png"
}, },
"6398": { "6398": {
"id": 6398, "id": 6398,
@@ -2123,6 +2141,12 @@
"diamondCost": 2000, "diamondCost": 2000,
"image": "https://storage.streamdps.com/iblock/49b/49be18ae5914346ffcaf15a519ba9c1c/41326cb23d22010f0c4a8edf5bd27615.webp" "image": "https://storage.streamdps.com/iblock/49b/49be18ae5914346ffcaf15a519ba9c1c/41326cb23d22010f0c4a8edf5bd27615.webp"
}, },
"6426": {
"id": 6426,
"name": "Dombra",
"diamondCost": 20,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ccd9fea1988521d1e81051a916800d6c~tplv-obj.png"
},
"6427": { "6427": {
"id": 6427, "id": 6427,
"name": "Hat and Mustache", "name": "Hat and Mustache",
@@ -2189,6 +2213,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/e11/e110e47562d77ab5fa26cc31e840f801/a4a1823ef2c1bc65c4dc2a4e82ec446b.png" "image": "https://storage.streamdps.com/iblock/e11/e110e47562d77ab5fa26cc31e840f801/a4a1823ef2c1bc65c4dc2a4e82ec446b.png"
}, },
"6452": {
"id": 6452,
"name": "Jakarta Roundabout",
"diamondCost": 16999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/31f67910fc5858cf087da65746f1f9f3~tplv-obj.png"
},
"6454": { "6454": {
"id": 6454, "id": 6454,
"name": "", "name": "",
@@ -2561,6 +2591,12 @@
"diamondCost": 99, "diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/b17/b171f313a2ba4af15e8645f02d24d4e7/a58831515ce8102cb72841e8ed45ed08.webp" "image": "https://storage.streamdps.com/iblock/b17/b171f313a2ba4af15e8645f02d24d4e7/a58831515ce8102cb72841e8ed45ed08.webp"
}, },
"6633": {
"id": 6633,
"name": "Independence Day",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b967993872a6e40f3477d30545f8d2eb~tplv-obj.png"
},
"6634": { "6634": {
"id": 6634, "id": 6634,
"name": "Sunday Roast", "name": "Sunday Roast",
@@ -2597,6 +2633,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/c1e/c1e1683273f5505462f45358cd773806/ba5afaec3f62e18672bd1b25a4e8a4d2.webp" "image": "https://storage.streamdps.com/iblock/c1e/c1e1683273f5505462f45358cd773806/ba5afaec3f62e18672bd1b25a4e8a4d2.webp"
}, },
"6655": {
"id": 6655,
"name": "Summer Iris ",
"diamondCost": 30,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/cb591f5b5729fa6e64cac57c78724981~tplv-obj.png"
},
"6661": { "6661": {
"id": 6661, "id": 6661,
"name": "Kiss your Heart", "name": "Kiss your Heart",
@@ -2705,6 +2747,12 @@
"diamondCost": 100, "diamondCost": 100,
"image": "https://storage.streamdps.com/iblock/cc8/cc8133c73d5ca2cb5fde306f5b4e2a11/fb273956755fe6fbf7263023a9c36ebe.webp" "image": "https://storage.streamdps.com/iblock/cc8/cc8133c73d5ca2cb5fde306f5b4e2a11/fb273956755fe6fbf7263023a9c36ebe.webp"
}, },
"6741": {
"id": 6741,
"name": "Gorgeous Trophy",
"diamondCost": 7000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/279c9495c2150e333bc4bc13761d177e~tplv-obj.png"
},
"6743": { "6743": {
"id": 6743, "id": 6743,
"name": "", "name": "",
@@ -2735,6 +2783,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/457/457a95d19f48aa254b10a30ee8e2c791/b3e217a47d1b38fe06ef11e149aae0e0.webp" "image": "https://storage.streamdps.com/iblock/457/457a95d19f48aa254b10a30ee8e2c791/b3e217a47d1b38fe06ef11e149aae0e0.webp"
}, },
"6756": {
"id": 6756,
"name": "Hot",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/ec679890070187b61620b9662afb814e~tplv-obj.png"
},
"6757": { "6757": {
"id": 6757, "id": 6757,
"name": "Dash", "name": "Dash",
@@ -2837,6 +2891,12 @@
"diamondCost": 199, "diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/53b/53ba63daed395b1c8eda6cd5fa51b912/2ddcbdeeebee2a97780b4e846aace552.webp" "image": "https://storage.streamdps.com/iblock/53b/53ba63daed395b1c8eda6cd5fa51b912/2ddcbdeeebee2a97780b4e846aace552.webp"
}, },
"6800": {
"id": 6800,
"name": "Pinata",
"diamondCost": 699,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c8a18d43dc9fb4598d7e991ebeb958ae~tplv-obj.png"
},
"6813": { "6813": {
"id": 6813, "id": 6813,
"name": "Fantastic", "name": "Fantastic",
@@ -3129,7 +3189,7 @@
"id": 6967, "id": 6967,
"name": "Autumn Leaves", "name": "Autumn Leaves",
"diamondCost": 500, "diamondCost": 500,
"image": "https://storage.streamdps.com/iblock/f04/f042339687e8abaa2fc0e1976d9b11f4/251a0624bc3a23ba39d75467868dcbf8.webp" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/30adcaf443df63e3bfd2751ad251f87d~tplv-obj.png"
}, },
"6968": { "6968": {
"id": 6968, "id": 6968,
@@ -3275,6 +3335,12 @@
"diamondCost": 10, "diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/eeb/eeb4c2ae379b89120c8ae69bbbea8642/ea6d73fcf39771c592560120d2c9b577.webp" "image": "https://storage.streamdps.com/iblock/eeb/eeb4c2ae379b89120c8ae69bbbea8642/ea6d73fcf39771c592560120d2c9b577.webp"
}, },
"7032": {
"id": 7032,
"name": "Maracas",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/00204efcf0573192ad5d872c7beeaf5b~tplv-obj.png"
},
"7037": { "7037": {
"id": 7037, "id": 7037,
"name": "", "name": "",
@@ -3385,9 +3451,9 @@
}, },
"7084": { "7084": {
"id": 7084, "id": 7084,
"name": "", "name": "Witchy Kitty",
"diamondCost": 30, "diamondCost": 30,
"image": "https://storage.streamdps.com/iblock/1c6/1c64bc1b780d8a987986694a699e0585/0d6afd7934d363dba4a747f8c0bec66b.webp" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/dfce46f99a1206cca84f9092603e4783~tplv-obj.png"
}, },
"7086": { "7086": {
"id": 7086, "id": 7086,
@@ -3443,6 +3509,12 @@
"diamondCost": 5, "diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/5f2/5f2f2f673c116c46372ee874bfb66685/759b52ad2866ed2f5a78ccd558f4457e.webp" "image": "https://storage.streamdps.com/iblock/5f2/5f2f2f673c116c46372ee874bfb66685/759b52ad2866ed2f5a78ccd558f4457e.webp"
}, },
"7105": {
"id": 7105,
"name": "Magic Potion",
"diamondCost": 499,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e055625e9239df7e833702c768e033d2~tplv-obj.png"
},
"7106": { "7106": {
"id": 7106, "id": 7106,
"name": "", "name": "",
@@ -3737,6 +3809,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/bf8/bf8e32bd0bf5a916195b5848db571f4f/a9241b01b970aa44c2d5cea5e8ba69d6.webp" "image": "https://storage.streamdps.com/iblock/bf8/bf8e32bd0bf5a916195b5848db571f4f/a9241b01b970aa44c2d5cea5e8ba69d6.webp"
}, },
"7377": {
"id": 7377,
"name": "Christmas Market G",
"diamondCost": 2000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/f498f29ef628c8318006a9ff2f49bf08~tplv-obj.png"
},
"7391": { "7391": {
"id": 7391, "id": 7391,
"name": "I\u0027m shy", "name": "I\u0027m shy",
@@ -3773,6 +3851,12 @@
"diamondCost": 10, "diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/8f7/8f7fcac557fb70fa0bbd69809c112c0e/978e0bcdcd8cbf4cbdfdb53d9fc39eaa.webp" "image": "https://storage.streamdps.com/iblock/8f7/8f7fcac557fb70fa0bbd69809c112c0e/978e0bcdcd8cbf4cbdfdb53d9fc39eaa.webp"
}, },
"7458": {
"id": 7458,
"name": "Wooly Hat",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a234d0187047fa48805c8ea2e1f1f756~tplv-obj.png"
},
"7467": { "7467": {
"id": 7467, "id": 7467,
"name": "Chasing the Dream", "name": "Chasing the Dream",
@@ -3785,12 +3869,30 @@
"diamondCost": 5000, "diamondCost": 5000,
"image": "https://storage.streamdps.com/iblock/f5c/f5cda80a1f9853c49226a450faf26e8f/6318d17d7a2526f521123402d19a4c3e.webp" "image": "https://storage.streamdps.com/iblock/f5c/f5cda80a1f9853c49226a450faf26e8f/6318d17d7a2526f521123402d19a4c3e.webp"
}, },
"7475": {
"id": 7475,
"name": "Mistletoe GDM 23",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/3527969b8c27e3194e61ff0787a9c3c2~tplv-obj.png"
},
"7477": {
"id": 7477,
"name": "Panettone GDM 23",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/64ce2413a362442819b4551703b7b26c~tplv-obj.png"
},
"7482": { "7482": {
"id": 7482, "id": 7482,
"name": "Flying Jets", "name": "Flying Jets",
"diamondCost": 5000, "diamondCost": 5000,
"image": "https://storage.streamdps.com/iblock/5a4/5a4f3c7adc31f60326e3adf1a3a20bf9/bc96de02ceba4b91c1f9c996293974b4.webp" "image": "https://storage.streamdps.com/iblock/5a4/5a4f3c7adc31f60326e3adf1a3a20bf9/bc96de02ceba4b91c1f9c996293974b4.webp"
}, },
"7498": {
"id": 7498,
"name": "Candy Cane Gun",
"diamondCost": 799,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/58ef7964e32adc5fc47c5706a02e4ff0~tplv-obj.png"
},
"7501": { "7501": {
"id": 7501, "id": 7501,
"name": "Hello Traveler", "name": "Hello Traveler",
@@ -3803,6 +3905,30 @@
"diamondCost": 299, "diamondCost": 299,
"image": "https://storage.streamdps.com/iblock/679/679e9e38e38f8a4ce707328aa92b8997/9fedb22710af980bbf7b3092b08ecb94.webp" "image": "https://storage.streamdps.com/iblock/679/679e9e38e38f8a4ce707328aa92b8997/9fedb22710af980bbf7b3092b08ecb94.webp"
}, },
"7504": {
"id": 7504,
"name": "Holiday Stocking",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e05de50999ebb446e15c4947b30d3140~tplv-obj.png"
},
"7523": {
"id": 7523,
"name": "Hot Choco GDM 23",
"diamondCost": 30,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/f62f5912077d9af84256de288399125a~tplv-obj.png"
},
"7525": {
"id": 7525,
"name": "Christmas CarouseG",
"diamondCost": 2000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b5ba3941f7389da7495b659e888ea61a~tplv-obj.png"
},
"7527": {
"id": 7527,
"name": "Christmas Wreath G",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/7842b50135e089334fc40d9705bb53c7~tplv-obj.png"
},
"7529": { "7529": {
"id": 7529, "id": 7529,
"name": "Mystery Firework", "name": "Mystery Firework",
@@ -3845,6 +3971,12 @@
"diamondCost": 199, "diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/e36/e36cb42edac42a0636f8785b80c274dc/bbd87fef7b269564a4ca32009879c0ab.webp" "image": "https://storage.streamdps.com/iblock/e36/e36cb42edac42a0636f8785b80c274dc/bbd87fef7b269564a4ca32009879c0ab.webp"
}, },
"7551": {
"id": 7551,
"name": "Snowman",
"diamondCost": 99,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/e094e0fafc14aaf127fa0d0a7926619a~tplv-obj.png"
},
"7591": { "7591": {
"id": 7591, "id": 7591,
"name": "Tiny Diny", "name": "Tiny Diny",
@@ -3899,6 +4031,18 @@
"diamondCost": 500, "diamondCost": 500,
"image": "https://storage.streamdps.com/iblock/dca/dcac97e4190d46d113f4bdf2918ee173/4fae166b3f3273b9dbbc2a86bea0ec18.webp" "image": "https://storage.streamdps.com/iblock/dca/dcac97e4190d46d113f4bdf2918ee173/4fae166b3f3273b9dbbc2a86bea0ec18.webp"
}, },
"7697": {
"id": 7697,
"name": "LOVE U",
"diamondCost": 899,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/79d45877691333e2ba69a9098406e95c~tplv-obj.png"
},
"7707": {
"id": 7707,
"name": "I\u0027m blue",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/c560ec76d5599198aaea9377c5ffab6e~tplv-obj.png"
},
"7720": { "7720": {
"id": 7720, "id": 7720,
"name": "Flying Jets", "name": "Flying Jets",
@@ -4013,6 +4157,12 @@
"diamondCost": 199, "diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/3c4/3c40e306064bb00719cb77dec261891a/bc24ae9f8a52d13475897170332d546f.webp" "image": "https://storage.streamdps.com/iblock/3c4/3c40e306064bb00719cb77dec261891a/bc24ae9f8a52d13475897170332d546f.webp"
}, },
"7846": {
"id": 7846,
"name": "Grumpy Glasses",
"diamondCost": 99,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/6f38f8ed7442f69a105788b5c0c74a38~tplv-obj.png"
},
"7851": { "7851": {
"id": 7851, "id": 7851,
"name": "Football Helmet", "name": "Football Helmet",
@@ -4073,6 +4223,18 @@
"diamondCost": 15000, "diamondCost": 15000,
"image": "https://storage.streamdps.com/iblock/a12/a12a1b23f1f6a19d728de84e1f43e21d/ff288346e9855a9bb6deb4450491028f.webp" "image": "https://storage.streamdps.com/iblock/a12/a12a1b23f1f6a19d728de84e1f43e21d/ff288346e9855a9bb6deb4450491028f.webp"
}, },
"7920": {
"id": 7920,
"name": "Husky",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a2f5d595e9d96aec19a7c0ed5fa9b017~tplv-obj.png"
},
"7921": {
"id": 7921,
"name": "Golden",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b97f58dcb0250489ae98529bcb0542ca~tplv-obj.png"
},
"7927": { "7927": {
"id": 7927, "id": 7927,
"name": "Puppy Love", "name": "Puppy Love",
@@ -4157,6 +4319,12 @@
"diamondCost": 10, "diamondCost": 10,
"image": "https://storage.streamdps.com/iblock/486/486a2490c987c2bb97b6068fd5aac5ab/49d9045fcfe94bbfbd08c3363bb4512a.webp" "image": "https://storage.streamdps.com/iblock/486/486a2490c987c2bb97b6068fd5aac5ab/49d9045fcfe94bbfbd08c3363bb4512a.webp"
}, },
"8005": {
"id": 8005,
"name": "Falling For You",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a198bd39d2511dbba6a68867740e3ff9~tplv-obj.png"
},
"8017": { "8017": {
"id": 8017, "id": 8017,
"name": "Headphone", "name": "Headphone",
@@ -4289,6 +4457,12 @@
"diamondCost": 5, "diamondCost": 5,
"image": "https://storage.streamdps.com/iblock/27f/27fe97cb0f1b8056fa0aedc918ea560e/966df61a39e36fe0f7237e55c3298117.webp" "image": "https://storage.streamdps.com/iblock/27f/27fe97cb0f1b8056fa0aedc918ea560e/966df61a39e36fe0f7237e55c3298117.webp"
}, },
"8207": {
"id": 8207,
"name": "The Crown",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5bf798f92fe96ba53c0f4d28f052f9bb~tplv-obj.png"
},
"8217": { "8217": {
"id": 8217, "id": 8217,
"name": "Capybara", "name": "Capybara",
@@ -4355,6 +4529,18 @@
"diamondCost": 19999, "diamondCost": 19999,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/a598ba4c7024f4d46c1268be4d82f901~tplv-obj.jpg" "image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/a598ba4c7024f4d46c1268be4d82f901~tplv-obj.jpg"
}, },
"8250": {
"id": 8250,
"name": "Disco ball",
"diamondCost": 1000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a53d3ef956eb2f1aa7a7db46024c70bb~tplv-obj.png"
},
"8253": {
"id": 8253,
"name": "Spring Train",
"diamondCost": 3999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b859c413a241fec75bc78668aeb0f581~tplv-obj.png"
},
"8259": { "8259": {
"id": 8259, "id": 8259,
"name": "I love you", "name": "I love you",
@@ -4373,6 +4559,24 @@
"diamondCost": 6000, "diamondCost": 6000,
"image": "https://storage.streamdps.com/iblock/88d/88df4387d65bcc77b691098fd649bd59/ad401a92ddba9aae15bb777f9f38638d.webp" "image": "https://storage.streamdps.com/iblock/88d/88df4387d65bcc77b691098fd649bd59/ad401a92ddba9aae15bb777f9f38638d.webp"
}, },
"8264": {
"id": 8264,
"name": "Happy Weekend",
"diamondCost": 599,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b04f104e717798235cd3edaa6703e6a3~tplv-obj.png"
},
"8265": {
"id": 8265,
"name": "Happy Friday",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/65e8fcb76825b9ec36a24faf9a3e9495~tplv-obj.png"
},
"8266": {
"id": 8266,
"name": "Good Afternoon",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/bff3b908c4dd9cf19ab431cc99dc7940~tplv-obj.png"
},
"8267": { "8267": {
"id": 8267, "id": 8267,
"name": "Good Evening", "name": "Good Evening",
@@ -4385,6 +4589,12 @@
"diamondCost": 399, "diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b7b55087141bd5f965eb31a99a5f157b~tplv-obj.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b7b55087141bd5f965eb31a99a5f157b~tplv-obj.png"
}, },
"8269": {
"id": 8269,
"name": "Good Morning",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/5c1a28f3aa7eefc27491f3020748ce54~tplv-obj.png"
},
"8277": { "8277": {
"id": 8277, "id": 8277,
"name": "Love Drop", "name": "Love Drop",
@@ -4529,6 +4739,12 @@
"diamondCost": 15000, "diamondCost": 15000,
"image": "https://storage.streamdps.com/iblock/bfc/bfcf491b940e478b6410047bc047af1b/abbbdd13015a9f31be1b905268873d73.webp" "image": "https://storage.streamdps.com/iblock/bfc/bfcf491b940e478b6410047bc047af1b/abbbdd13015a9f31be1b905268873d73.webp"
}, },
"8442": {
"id": 8442,
"name": "Flower Festival",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9bfe63e39b581a69ff944758c3eae5a0~tplv-obj.png"
},
"8448": { "8448": {
"id": 8448, "id": 8448,
"name": "Raccoon", "name": "Raccoon",
@@ -4667,6 +4883,12 @@
"diamondCost": 199, "diamondCost": 199,
"image": "https://storage.streamdps.com/iblock/282/28210d38f8625d7c3f39bb85e1fd59c4/61f609f602fc0f3cc2bff6cf94d32fbe.webp" "image": "https://storage.streamdps.com/iblock/282/28210d38f8625d7c3f39bb85e1fd59c4/61f609f602fc0f3cc2bff6cf94d32fbe.webp"
}, },
"8754": {
"id": 8754,
"name": "Aurora",
"diamondCost": 12000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1f59f5593ce135325c1a034825cec18c.png~tplv-obj.png"
},
"8767": { "8767": {
"id": 8767, "id": 8767,
"name": "Golden Trumpet", "name": "Golden Trumpet",
@@ -4691,6 +4913,18 @@
"diamondCost": 450, "diamondCost": 450,
"image": "https://storage.streamdps.com/iblock/285/285070af9d4f72b74e7d74c22157f2d9/67d9fa3239a7f9a09ef78c832a66e624.webp" "image": "https://storage.streamdps.com/iblock/285/285070af9d4f72b74e7d74c22157f2d9/67d9fa3239a7f9a09ef78c832a66e624.webp"
}, },
"8803": {
"id": 8803,
"name": "Miss You",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/3c53396b922691a7520698f47105a753.png~tplv-obj.png"
},
"8804": {
"id": 8804,
"name": "Vacation",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/8f46e8eef9cbd5304fb802104c2b4ef4.png~tplv-obj.png"
},
"8806": { "8806": {
"id": 8806, "id": 8806,
"name": "Dancing Capybaras", "name": "Dancing Capybaras",
@@ -4757,6 +4991,12 @@
"diamondCost": 1200, "diamondCost": 1200,
"image": "https://storage.streamdps.com/iblock/07d/07d678346c7eb588bc3cbddf343ab791/8f8f50f5350e4b1c0b151aff333e43a4.webp" "image": "https://storage.streamdps.com/iblock/07d/07d678346c7eb588bc3cbddf343ab791/8f8f50f5350e4b1c0b151aff333e43a4.webp"
}, },
"8890": {
"id": 8890,
"name": "Pink Shoes",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/cba8a7c718988bd51c7b6055e9ab1ec4.png~tplv-obj.png"
},
"8892": { "8892": {
"id": 8892, "id": 8892,
"name": "Dream Team", "name": "Dream Team",
@@ -4859,6 +5099,12 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp" "image": "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"
}, },
"9111": {
"id": 9111,
"name": "Popcorn",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/676d2d4c31a8979f1fd06cdf5ecd922f~tplv-obj.png"
},
"9135": { "9135": {
"id": 9135, "id": 9135,
"name": "Magic Forest", "name": "Magic Forest",
@@ -4895,6 +5141,12 @@
"diamondCost": 3999, "diamondCost": 3999,
"image": "https://storage.streamdps.com/iblock/990/99093308d3ad2c3833d230f9aae7f702/36f073ad050bd79d7d1ba6d781e7ef11.webp" "image": "https://storage.streamdps.com/iblock/990/99093308d3ad2c3833d230f9aae7f702/36f073ad050bd79d7d1ba6d781e7ef11.webp"
}, },
"9152": {
"id": 9152,
"name": "Spin with me GDM",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/149ac2e87d05490d7d251149cefe27a2.png~tplv-obj.png"
},
"9175": { "9175": {
"id": 9175, "id": 9175,
"name": "Pretzel", "name": "Pretzel",
@@ -4913,12 +5165,30 @@
"diamondCost": 20000, "diamondCost": 20000,
"image": "https://storage.streamdps.com/iblock/c79/c793af446369ecef5238e73312c84ccd/464a76f3e6eaee9afc771f45a4bba9df.webp" "image": "https://storage.streamdps.com/iblock/c79/c793af446369ecef5238e73312c84ccd/464a76f3e6eaee9afc771f45a4bba9df.webp"
}, },
"9242": {
"id": 9242,
"name": "Pumpkin Spice Latte",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/0636d91615f7417ddd5f29438bf5debe~tplv-obj.png"
},
"9255": { "9255": {
"id": 9255, "id": 9255,
"name": "Aerobic headband", "name": "Aerobic headband",
"diamondCost": 99, "diamondCost": 99,
"image": "https://storage.streamdps.com/iblock/3d9/3d98c2fbc96922da37a9d22881bb06b9/0a99af132ab8e3fe9806d2412abc6bf0.webp" "image": "https://storage.streamdps.com/iblock/3d9/3d98c2fbc96922da37a9d22881bb06b9/0a99af132ab8e3fe9806d2412abc6bf0.webp"
}, },
"9303": {
"id": 9303,
"name": "Rabbit and Mochi",
"diamondCost": 999,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/213ef2549fbb10ec783c95a41d28cf0a.png~tplv-obj.png"
},
"9304": {
"id": 9304,
"name": "Boo the Ghost",
"diamondCost": 88,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/cb909c78f2412e4927ea68d6af8e048f.png~tplv-obj.png"
},
"9333": { "9333": {
"id": 9333, "id": 9333,
"name": "LIVE Fest Clappers", "name": "LIVE Fest Clappers",
@@ -4931,6 +5201,30 @@
"diamondCost": 1, "diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1e98afffef90ed4b2cc9c9ebb88e3608.png~tplv-obj.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1e98afffef90ed4b2cc9c9ebb88e3608.png~tplv-obj.png"
}, },
"9354": {
"id": 9354,
"name": "I\u0027m here",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/7006392a82d57452d5ef08dd90e169c1.png~tplv-obj.png"
},
"9355": {
"id": 9355,
"name": "So cute",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/d40d31241efcf57c630e894bb3007b8a.png~tplv-obj.png"
},
"9363": {
"id": 9363,
"name": "Elf GDM 23",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/60e5289b379660cc562742cf987a2d35.png~tplv-obj.png"
},
"9427": {
"id": 9427,
"name": "Pegasus",
"diamondCost": 42999,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f600a2495ab5d250e7da2066484a9383.png~tplv-obj.jpg"
},
"9463": { "9463": {
"id": 9463, "id": 9463,
"name": "Fairy Wings", "name": "Fairy Wings",
@@ -5003,22 +5297,232 @@
"diamondCost": 12000, "diamondCost": 12000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/51a7d74bcb4a6417be59f0ffc0b77e96.png~tplv-obj.png" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/51a7d74bcb4a6417be59f0ffc0b77e96.png~tplv-obj.png"
}, },
"9522": { "9535": {
"id": 9522, "id": 9535,
"name": "Exclusive Spark", "name": "Play for you",
"diamondCost": 1000, "diamondCost": 299,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f0bda1eb6856e2feea9cfcb6c575c8a0.png~tplv-obj.jpg" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/182659e90a3432aa155e61c9c0d89df0.png~tplv-obj.png"
}, },
"9523": { "9536": {
"id": 9523, "id": 9536,
"name": "Exclusive Jet", "name": "Fake smile",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/35ce62173962e33834703212d0b845a7.png~tplv-obj.png"
},
"9576": {
"id": 9576,
"name": "Yeah Nah",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4b20c5aab3841657a343be3769307805.png~tplv-obj.png"
},
"9581": {
"id": 9581,
"name": "Turkey Face GDDec",
"diamondCost": 399,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/65349d1ef783fc207c1d2b54a8d521a7.png~tplv-obj.png"
},
"9583": {
"id": 9583,
"name": "Cool!",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/424c61f16c16919f169fd0352bd24661.png~tplv-obj.png"
},
"9587": {
"id": 9587,
"name": "Christmas Potato",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/5448f1f5157d3a4a88e0f57acf3dbfe0.png~tplv-obj.png"
},
"9604": {
"id": 9604,
"name": "Gobble Gobble",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/ada9babc0b55cf005e8c8d13dfc30b42.png~tplv-obj.png"
},
"9615": {
"id": 9615,
"name": "Festive Tiny Diny",
"diamondCost": 15,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f2a8c2967c7153e9077bb469f2e42317.png~tplv-obj.png"
},
"9617": {
"id": 9617,
"name": "Xmas Mishka Bear",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/700c1c8817847317407cc2b8c6c9da42.png~tplv-obj.png"
},
"9625": {
"id": 9625,
"name": "Elf\u0027s Hat ",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9857a040c92b34d6a261201a93c185f.png~tplv-obj.png"
},
"9639": {
"id": 9639,
"name": "2024",
"diamondCost": 1,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/484a44bbe62ce47687d1da31a6602bbd.png~tplv-obj.jpg"
},
"9640": {
"id": 9640,
"name": "2024 Glasses",
"diamondCost": 224,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/512d2e9934cbae8d1019a391814edbd2.png~tplv-obj.jpg"
},
"9641": {
"id": 9641,
"name": "2024 Countdown",
"diamondCost": 2024,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/a358a3ce18241dcc6e7d0b02d091d563.png~tplv-obj.jpg"
},
"9642": {
"id": 9642,
"name": "Train to 2024",
"diamondCost": 12024,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/0cb12913e0a96bbcc45f97b450e74cd3.png~tplv-obj.jpg"
},
"9643": {
"id": 9643,
"name": "2024 JoyLens",
"diamondCost": 224,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/36d82bbcd87c1914df84262d9bdd9b95.png~tplv-obj.jpg"
},
"9644": {
"id": 9644,
"name": "Sparkling Countdown",
"diamondCost": 2024,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/d6b4539ed9683707bdefe268f6575e74.png~tplv-obj.jpg"
},
"9645": {
"id": 9645,
"name": "New Year Journey",
"diamondCost": 12024,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/0ef9654d92354172fb9b3b364827940c.png~tplv-obj.jpg"
},
"9647": {
"id": 9647,
"name": "Kitten Paw",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/332520d7b5085ce591396c8d2bb9d352.png~tplv-obj.png"
},
"9650": {
"id": 9650,
"name": "The Van Cat",
"diamondCost": 799,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6973dd1b6d3dee3ca3f0ebac3c1d2977.png~tplv-obj.png"
},
"9656": {
"id": 9656,
"name": "Gingerbread man",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/af01db3e3cb9f54ea2cb421fab6062bc.png~tplv-obj.png"
},
"9657": {
"id": 9657,
"name": "GB North Pole",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/79715a53c41619e7b205eb26e57926d4.png~tplv-obj.png"
},
"9658": {
"id": 9658,
"name": "DE North Pole",
"diamondCost": 199,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/130e17b5b561a93cefbd236586881477.png~tplv-obj.png"
},
"9667": {
"id": 9667,
"name": "Kiwi Bird",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/b73cb4aaa76a33efd881192589d65351.png~tplv-obj.png"
},
"9668": {
"id": 9668,
"name": "Gingerman Party",
"diamondCost": 1200,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/008a9554e736642f1b2dca9f198bb710.png~tplv-obj.png"
},
"9670": {
"id": 9670,
"name": "Reindeer",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4565fa0cd1dbf76463144b0d4cc50bf1.png~tplv-obj.png"
},
"9671": {
"id": 9671,
"name": "Gingebread Man",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/2399f65414f77419ec7d5e9274dc8e0e.png~tplv-obj.png"
},
"9672": {
"id": 9672,
"name": "Mimi \u0026 Fifi",
"diamondCost": 5000, "diamondCost": 5000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1cc167a00aa4d5dfe48018afb38c3daa.png~tplv-obj.jpg" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/0a72d0084695d03586fea7d854dc3a47.png~tplv-obj.png"
}, },
"9524": { "9678": {
"id": 9524, "id": 9678,
"name": "Exclusive Yacht", "name": "Holiday Carousel",
"diamondCost": 2000,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/b5ba3941f7389da7495b659e888ea61a.png~tplv-obj.png"
},
"9680": {
"id": 9680,
"name": "Xmas in London",
"diamondCost": 20000, "diamondCost": 20000,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/da8c85d5ae09ebf320216202e8fa015d.png~tplv-obj.jpg" "image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/876204a6ad0b1b0e4675d9be42439183.png~tplv-obj.png"
},
"9682": {
"id": 9682,
"name": "Stay Warm",
"diamondCost": 450,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/abd104eb08ce0c351292036d8897fb8d.png~tplv-obj.png"
},
"9688": {
"id": 9688,
"name": "Snowglobe",
"diamondCost": 499,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/ea5ac5f8e186897456bed2e78fc78ca5.png~tplv-obj.png"
},
"9698": {
"id": 9698,
"name": "Candy Cane",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1fa0a4ed666304c78a46de200b85c84b.png~tplv-obj.png"
},
"9703": {
"id": 9703,
"name": "Really Curious",
"diamondCost": 1,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/793ba68723567b695b12f2ef08dc1484.png~tplv-obj.png"
},
"9704": {
"id": 9704,
"name": "Nemo",
"diamondCost": 15,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/68fcf30cb3fb07e9546f5e7fbc2b0ac0.png~tplv-obj.png"
},
"9706": {
"id": 9706,
"name": "Elfs Hat ",
"diamondCost": 299,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9857a040c92b34d6a261201a93c185f.png~tplv-obj.png"
},
"9717": {
"id": 9717,
"name": "Lucky Airdrop Box",
"diamondCost": 999,
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/6ae56f08ae3ee57ea2dda0025bfd39d3.png~tplv-obj.jpg"
},
"9770": {
"id": 9770,
"name": "Shiba Cookie",
"diamondCost": 10,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/4ea5282e7f61cbeee1214422d40ad407.png~tplv-obj.png"
},
"9771": {
"id": 9771,
"name": "KFC Chicken",
"diamondCost": 5,
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/f9d59ccd2328b8a46841b3b1c87d9e55.png~tplv-obj.png"
} }
} }

Binary file not shown.

View File

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