mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-28 09:19:40 -05:00
Compare commits
25 Commits
1.0.0-Rele
...
1.0.5-Rele
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea8c740faa | ||
|
|
1977cbe8dc | ||
|
|
c3a48c4d70 | ||
|
|
2c51844fd9 | ||
|
|
8ff4236452 | ||
|
|
7817aeb652 | ||
|
|
4c122ab754 | ||
|
|
519c22de8e | ||
|
|
6d268c42f1 | ||
|
|
788653484f | ||
|
|
6cebbf891d | ||
|
|
cc32648988 | ||
|
|
4c797724d3 | ||
|
|
6941107db8 | ||
|
|
ed70799cd9 | ||
|
|
e12b0901f7 | ||
|
|
563e9618e2 | ||
|
|
82112f0140 | ||
|
|
77e30de5e1 | ||
|
|
a2b10ba7f6 | ||
|
|
957e38a5d2 | ||
|
|
5e77b3f57f | ||
|
|
690b9eb272 | ||
|
|
fc91991c2c | ||
|
|
0f735a7876 |
309
.gitignore
vendored
309
.gitignore
vendored
@@ -1,61 +1,85 @@
|
|||||||
# Project exclude paths
|
backend-infrastructure/.aws-sam
|
||||||
/API/target/
|
|
||||||
/Client/target/
|
|
||||||
*.db
|
|
||||||
|
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
# Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode
|
||||||
|
|
||||||
|
### Linux ###
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
### OSX ###
|
||||||
|
*.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
### PyCharm ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
# User-specific stuff
|
# User-specific stuff:
|
||||||
.idea/**/workspace.xml
|
.idea/**/workspace.xml
|
||||||
.idea/**/tasks.xml
|
.idea/**/tasks.xml
|
||||||
.idea/**/usage.statistics.xml
|
.idea/dictionaries
|
||||||
.idea/**/dictionaries
|
.idea/
|
||||||
.idea/**/shelf
|
|
||||||
|
|
||||||
# AWS User-specific
|
# Sensitive or high-churn files:
|
||||||
.idea/**/aws.xml
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
.idea/**/contentModel.xml
|
|
||||||
|
|
||||||
# Sensitive or high-churn files
|
|
||||||
.idea/**/dataSources/
|
.idea/**/dataSources/
|
||||||
.idea/**/dataSources.ids
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.xml
|
||||||
.idea/**/dataSources.local.xml
|
.idea/**/dataSources.local.xml
|
||||||
.idea/**/sqlDataSources.xml
|
.idea/**/sqlDataSources.xml
|
||||||
.idea/**/dynamic.xml
|
.idea/**/dynamic.xml
|
||||||
.idea/**/uiDesigner.xml
|
.idea/**/uiDesigner.xml
|
||||||
.idea/**/dbnavigator.xml
|
|
||||||
|
|
||||||
# Gradle
|
# Gradle:
|
||||||
.idea/**/gradle.xml
|
.idea/**/gradle.xml
|
||||||
.idea/**/libraries
|
.idea/**/libraries
|
||||||
|
|
||||||
# Gradle and Maven with auto-import
|
|
||||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
|
||||||
# since they will be recreated, and may cause churn. Uncomment if using
|
|
||||||
# auto-import.
|
|
||||||
# .idea/artifacts
|
|
||||||
# .idea/compiler.xml
|
|
||||||
# .idea/jarRepositories.xml
|
|
||||||
# .idea/modules.xml
|
|
||||||
# .idea/*.iml
|
|
||||||
# .idea/modules
|
|
||||||
# *.iml
|
|
||||||
# *.ipr
|
|
||||||
|
|
||||||
# CMake
|
# CMake
|
||||||
cmake-build-*/
|
cmake-build-debug/
|
||||||
|
|
||||||
# Mongo Explorer plugin
|
# Mongo Explorer plugin:
|
||||||
.idea/**/mongoSettings.xml
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
# File-based project format
|
## File-based project format:
|
||||||
*.iws
|
*.iws
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
# IntelliJ
|
# IntelliJ
|
||||||
out/
|
/out/
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
# mpeltonen/sbt-idea plugin
|
||||||
.idea_modules/
|
.idea_modules/
|
||||||
@@ -66,8 +90,8 @@ atlassian-ide-plugin.xml
|
|||||||
# Cursive Clojure plugin
|
# Cursive Clojure plugin
|
||||||
.idea/replstate.xml
|
.idea/replstate.xml
|
||||||
|
|
||||||
# SonarLint plugin
|
# Ruby plugin and RubyMine
|
||||||
.idea/sonarlint/
|
/.rakeTasks
|
||||||
|
|
||||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
com_crashlytics_export_strings.xml
|
com_crashlytics_export_strings.xml
|
||||||
@@ -75,69 +99,150 @@ crashlytics.properties
|
|||||||
crashlytics-build.properties
|
crashlytics-build.properties
|
||||||
fabric.properties
|
fabric.properties
|
||||||
|
|
||||||
# Editor-based Rest Client
|
### PyCharm Patch ###
|
||||||
.idea/httpRequests
|
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||||
|
|
||||||
# Android studio 3.1+ serialized cache file
|
*.iml
|
||||||
.idea/caches/build_file_checksums.ser
|
modules.xml
|
||||||
/.idea/.gitignore
|
.idea/misc.xml
|
||||||
/.idea/.name
|
*.ipr
|
||||||
/.idea/compiler.xml
|
|
||||||
/TestApplication/target/classes/io/github/jwdeveloper/tiktok/ConfigurationExample.class
|
# Sonarlint plugin
|
||||||
/TestApplication/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
|
.idea/sonarlint
|
||||||
/TestApplication/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
|
|
||||||
/Tools/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
|
### Python ###
|
||||||
/Tools/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
|
# Byte-compiled / optimized / DLL files
|
||||||
/Tools-EventsCollector/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
|
__pycache__/
|
||||||
/Tools-ReadmeGenerator/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
|
*.py[cod]
|
||||||
/Tools-ReadmeGenerator/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
|
*$py.class
|
||||||
/.idea/encodings.xml
|
|
||||||
/Tools-ReadmeGenerator/target/classes/io/github/jwdeveloper/tiktok/EventsListGenerator$EventTypeComparator.class
|
# C extensions
|
||||||
/Tools-ReadmeGenerator/target/classes/io/github/jwdeveloper/tiktok/EventsListGenerator.class
|
*.so
|
||||||
/Tools-EventsCollector/target/classes/io/github/jwdeveloper/tiktok/tools/collector/tables/ExceptionInfoModel.class
|
|
||||||
/Tools/target/classes/io/github/jwdeveloper/tiktok/utils/FilesUtility.class
|
# Distribution / packaging
|
||||||
/TestApplication/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
|
.Python
|
||||||
/TestApplication/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
|
build/
|
||||||
/Tools/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
|
develop-eggs/
|
||||||
/Tools/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
|
dist/
|
||||||
/Tools-EventsCollector/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
|
downloads/
|
||||||
/Tools-ReadmeGenerator/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
|
eggs/
|
||||||
/Tools-ReadmeGenerator/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
|
.eggs/
|
||||||
/.idea/jarRepositories.xml
|
lib/
|
||||||
/TestApplication/target/classes/io/github/jwdeveloper/tiktok/ListenerExample$CustomListener.class
|
lib64/
|
||||||
/TestApplication/target/classes/io/github/jwdeveloper/tiktok/ListenerExample.class
|
parts/
|
||||||
/Tools-ReadmeGenerator/target/classes/io/github/jwdeveloper/tiktok/LiveClientMethodsGenerator.class
|
sdist/
|
||||||
/TestApplication/target/classes/io/github/jwdeveloper/tiktok/Main.class
|
var/
|
||||||
/Tools-EventsCollector/target/classes/io/github/jwdeveloper/tiktok/tools/collector/Main.class
|
wheels/
|
||||||
/Tools-ReadmeGenerator/target/classes/io/github/jwdeveloper/tiktok/Main.class
|
*.egg-info/
|
||||||
/.idea/misc.xml
|
.installed.cfg
|
||||||
/Tools-ReadmeGenerator/src/main/resources/output.md
|
*.egg
|
||||||
/Tools-ReadmeGenerator/target/classes/output.md
|
|
||||||
/TestApplication/target/maven-archiver/pom.properties
|
# PyInstaller
|
||||||
/Tools/target/maven-archiver/pom.properties
|
# Usually these files are written by a python script from a template
|
||||||
/Tools-EventsCollector/target/maven-archiver/pom.properties
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
/Tools-ReadmeGenerator/target/maven-archiver/pom.properties
|
*.manifest
|
||||||
/.idea/inspectionProfiles/Project_Default.xml
|
*.spec
|
||||||
/Tools/target/classes/io/github/jwdeveloper/tiktok/protocol/ProtocolGenerator.class
|
|
||||||
/Tools-ReadmeGenerator/target/classes/io/github/jwdeveloper/tiktok/ReadmeGenerator.class
|
# Installer logs
|
||||||
/TestApplication/target/classes/io/github/jwdeveloper/tiktok/SimpleExample.class
|
pip-log.txt
|
||||||
/Tools-EventsCollector/target/classes/io/github/jwdeveloper/tiktok/tools/collector/db/SqlConsts.class
|
pip-delete-this-directory.txt
|
||||||
/Tools-ReadmeGenerator/target/classes/template.md
|
|
||||||
/Tools/target/classes/io/github/jwdeveloper/tiktok/utils/TemplateUtility.class
|
# Unit test / coverage reports
|
||||||
/TestApplication/target/TestApplication-0.0.18-Release.jar
|
htmlcov/
|
||||||
/TestApplication/target/TestApplication-0.0.18-Release-all.jar
|
.tox/
|
||||||
/Tools-EventsCollector/target/classes/io/github/jwdeveloper/tiktok/tools/collector/db/TikTokDatabase.class
|
.coverage
|
||||||
/Tools-EventsCollector/target/classes/io/github/jwdeveloper/tiktok/tools/collector/tables/TikTokErrorModel$TikTokErrorModelBuilder.class
|
.coverage.*
|
||||||
/Tools-EventsCollector/target/classes/io/github/jwdeveloper/tiktok/tools/collector/tables/TikTokErrorModel.class
|
.cache
|
||||||
/Tools-EventsCollector/target/classes/io/github/jwdeveloper/tiktok/tools/collector/db/TikTokErrorModelDAO.class
|
.pytest_cache/
|
||||||
/target/TikTokLiveJava-0.0.18-Release-all.pom
|
nosetests.xml
|
||||||
/Tools-EventsCollector/target/classes/io/github/jwdeveloper/tiktok/tools/collector/tables/TikTokMessageModel$TikTokMessageModelBuilder.class
|
coverage.xml
|
||||||
/Tools-EventsCollector/target/classes/io/github/jwdeveloper/tiktok/tools/collector/tables/TikTokMessageModel.class
|
*.cover
|
||||||
/Tools-EventsCollector/target/classes/io/github/jwdeveloper/tiktok/tools/collector/db/TikTokMessageModelDAO.class
|
.hypothesis/
|
||||||
/Tools/target/Tools-0.0.18-Release.jar
|
|
||||||
/Tools/target/Tools-0.0.18-Release-all.jar
|
# Translations
|
||||||
/Tools-EventsCollector/target/Tools-EventsCollector-0.0.18-Release.jar
|
*.mo
|
||||||
/Tools-EventsCollector/target/Tools-EventsCollector-0.0.18-Release-all.jar
|
*.pot
|
||||||
/Tools-ReadmeGenerator/target/Tools-ReadmeGenerator-0.0.18-Release.jar
|
|
||||||
/Tools-ReadmeGenerator/target/Tools-ReadmeGenerator-0.0.18-Release-all.jar
|
# Flask stuff:
|
||||||
/.idea/vcs.xml
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule.*
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
**/target/
|
||||||
|
# Build folder
|
||||||
|
|
||||||
|
*/build/*
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode
|
||||||
|
/python-app-backend/samconfig.toml
|
||||||
|
/java-app-backend/BackendFunction/dependency-reduced-pom.xml
|
||||||
3
.idea/protoeditor.xml
generated
3
.idea/protoeditor.xml
generated
@@ -64,6 +64,9 @@
|
|||||||
<ImportPathEntry>
|
<ImportPathEntry>
|
||||||
<option name="location" value="file://$PROJECT_DIR$/API/src/main/proto" />
|
<option name="location" value="file://$PROJECT_DIR$/API/src/main/proto" />
|
||||||
</ImportPathEntry>
|
</ImportPathEntry>
|
||||||
|
<ImportPathEntry>
|
||||||
|
<option name="location" value="file://$USER_HOME$/AppData/Local/JetBrains/IntelliJIdea2022.3/protoeditor" />
|
||||||
|
</ImportPathEntry>
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
<option name="descriptorPath" value="google/protobuf/descriptor.proto" />
|
<option name="descriptorPath" value="google/protobuf/descriptor.proto" />
|
||||||
|
|||||||
@@ -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>0.0.25-Release</version>
|
<version>1.0.4-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>API</artifactId>
|
<artifactId>API</artifactId>
|
||||||
|
|||||||
@@ -52,11 +52,6 @@ public class ClientSettings {
|
|||||||
*/
|
*/
|
||||||
private Duration retryConnectionTimeout;
|
private Duration retryConnectionTimeout;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to handle Events received from Room when Connecting
|
|
||||||
*/
|
|
||||||
private boolean handleExistingEvents;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to print Logs to Console
|
* Whether to print Logs to Console
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ public class Constants {
|
|||||||
var clientSettings = new ClientSettings();
|
var clientSettings = new ClientSettings();
|
||||||
clientSettings.setTimeout(Duration.ofSeconds(DEFAULT_TIMEOUT));
|
clientSettings.setTimeout(Duration.ofSeconds(DEFAULT_TIMEOUT));
|
||||||
clientSettings.setClientLanguage("en-US");
|
clientSettings.setClientLanguage("en-US");
|
||||||
clientSettings.setHandleExistingEvents(true);
|
|
||||||
clientSettings.setRetryOnConnectionFailure(false);
|
clientSettings.setRetryOnConnectionFailure(false);
|
||||||
clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1));
|
clientSettings.setRetryConnectionTimeout(Duration.ofSeconds(1));
|
||||||
clientSettings.setPrintToConsole(false);
|
clientSettings.setPrintToConsole(false);
|
||||||
|
|||||||
@@ -30,3 +30,6 @@ public @interface EventMeta
|
|||||||
{
|
{
|
||||||
EventType eventType();
|
EventType eventType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.data.events;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
|
||||||
|
import io.github.jwdeveloper.tiktok.annotations.EventType;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
|
||||||
|
|
||||||
|
@EventMeta(eventType = EventType.Message)
|
||||||
|
public class TikTokLiveUnpausedEvent extends TikTokEvent {
|
||||||
|
}
|
||||||
@@ -20,36 +20,52 @@
|
|||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.data.events.room;
|
package io.github.jwdeveloper.tiktok.data.events.envelop;
|
||||||
|
|
||||||
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.TikTokHeaderEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.RankingUser;
|
import io.github.jwdeveloper.tiktok.data.models.Text;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomUserSeqMessage;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.util.List;
|
import io.github.jwdeveloper.tiktok.data.models.chest.Chest;
|
||||||
import java.util.stream.Collectors;
|
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastEnvelopeMessage;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@EventMeta(eventType = EventType.Message)
|
@EventMeta(eventType = EventType.Message)
|
||||||
public class TikTokRoomUserInfoEvent extends TikTokHeaderEvent {
|
@Value
|
||||||
private final int totalUsers;
|
public class TikTokChestEvent extends TikTokHeaderEvent {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only top 5 users in ranking has detailed data
|
* Chest target
|
||||||
* rest has only ID
|
|
||||||
*/
|
*/
|
||||||
private final List<RankingUser> usersRanking;
|
Chest chest;
|
||||||
public TikTokRoomUserInfoEvent(WebcastRoomUserSeqMessage msg) {
|
|
||||||
super(msg.getCommon());
|
|
||||||
totalUsers = msg.getTotalUser();
|
|
||||||
usersRanking = msg.getRanksListList().stream().map(RankingUser::new)
|
|
||||||
.sorted((ru1, ru2) -> Integer.compare(ru2.getScore(), ru1.getScore()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User that send a chest
|
||||||
|
*/
|
||||||
|
User user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time when chest has been open
|
||||||
|
*/
|
||||||
|
Date openedAt;
|
||||||
|
|
||||||
|
public TikTokChestEvent(Chest chest, WebcastEnvelopeMessage msg) {
|
||||||
|
super(msg.getCommon());
|
||||||
|
this.chest = chest;
|
||||||
|
|
||||||
|
var text = Text.map(msg.getCommon().getDisplayText());
|
||||||
|
var userPiece = (Text.UserTextPiece) text.getTextPieces().get(0);
|
||||||
|
user = userPiece.getUser();
|
||||||
|
|
||||||
|
|
||||||
|
var envelopInfo = msg.getEnvelopeInfo();
|
||||||
|
|
||||||
|
openedAt = new Date(envelopInfo.getUnpackAt());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,67 +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.data.events.room;
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
|
|
||||||
import io.github.jwdeveloper.tiktok.annotations.EventType;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokHeaderEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.models.users.UserAttribute;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.RoomMessage;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomMessage;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSystemMessage;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@EventMeta(eventType = EventType.Message)
|
|
||||||
public class TikTokRoomEvent extends TikTokHeaderEvent
|
|
||||||
{
|
|
||||||
private User hostUser;
|
|
||||||
private String hostLanguage;
|
|
||||||
private final String welcomeMessage;
|
|
||||||
|
|
||||||
public TikTokRoomEvent(WebcastRoomMessage msg) {
|
|
||||||
super(msg.getCommon());
|
|
||||||
welcomeMessage = msg.getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokRoomEvent(RoomMessage msg) {
|
|
||||||
super(msg.getCommon());
|
|
||||||
welcomeMessage = msg.getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokRoomEvent(WebcastSystemMessage msg) {
|
|
||||||
super(msg.getCommon());
|
|
||||||
welcomeMessage = msg.getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TikTokRoomEvent(WebcastLiveIntroMessage msg) {
|
|
||||||
super(msg.getCommon());
|
|
||||||
hostUser = User.map(msg.getHost());
|
|
||||||
hostUser.addAttribute(UserAttribute.LiveHost);
|
|
||||||
welcomeMessage = msg.getContent();
|
|
||||||
hostLanguage = msg.getLanguage();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.data.events.room;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.annotations.EventMeta;
|
||||||
|
import io.github.jwdeveloper.tiktok.annotations.EventType;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Triggered when LiveRoomInfo got updated such as likes, viewers, ranking ....
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
@EventMeta(eventType = EventType.Message)
|
||||||
|
public class TikTokRoomInfoEvent extends TikTokEvent
|
||||||
|
{
|
||||||
|
LiveRoomInfo roomInfo;
|
||||||
|
}
|
||||||
@@ -51,7 +51,7 @@ 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("");
|
||||||
}
|
}
|
||||||
var url = profilePicture.getUrlList(index);
|
var url = profilePicture.getUrlList(index);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import lombok.Value;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@@ -45,6 +46,12 @@ public class Text {
|
|||||||
this.value = computeValue();
|
this.value = computeValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public <T extends TextPiece> Optional<TextPiece> getTextPiece(Class<T> type)
|
||||||
|
{
|
||||||
|
return textPieces.stream().filter(e -> e.getClass().equals(type)).findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
public static Text map(io.github.jwdeveloper.tiktok.messages.data.Text input) {
|
public static Text map(io.github.jwdeveloper.tiktok.messages.data.Text input) {
|
||||||
var pieces = input.getPiecesListList().stream().map(Text::mapTextPiece).toList();
|
var pieces = input.getPiecesListList().stream().map(Text::mapTextPiece).toList();
|
||||||
return new Text(input.getKey(), input.getDefaultPattern(), pieces);
|
return new Text(input.getKey(), input.getDefaultPattern(), pieces);
|
||||||
@@ -98,6 +105,7 @@ public class Text {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Value
|
||||||
public static class UserTextPiece extends TextPiece {
|
public static class UserTextPiece extends TextPiece {
|
||||||
User user;
|
User user;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.data.models.chest;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Chest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total diamonds inside the chest
|
||||||
|
*/
|
||||||
|
int totalDiamonds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total users participated in chest
|
||||||
|
*/
|
||||||
|
int totalUsers;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,8 @@ public class User {
|
|||||||
@Getter(AccessLevel.NONE)
|
@Getter(AccessLevel.NONE)
|
||||||
private Set<UserAttribute> attributes;
|
private Set<UserAttribute> attributes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public List<UserAttribute> getAttributes() {
|
public List<UserAttribute> getAttributes() {
|
||||||
return attributes.stream().toList();
|
return attributes.stream().toList();
|
||||||
}
|
}
|
||||||
@@ -107,6 +109,23 @@ public class User {
|
|||||||
this.attributes = new HashSet<>();
|
this.attributes = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public User(Long id,
|
||||||
|
String name,
|
||||||
|
String profileName,
|
||||||
|
Picture picture,
|
||||||
|
long following,
|
||||||
|
long followers,
|
||||||
|
List<Badge> badges) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.profileName = profileName;
|
||||||
|
this.picture = picture;
|
||||||
|
this.following = following;
|
||||||
|
this.followers = followers;
|
||||||
|
this.badges = badges;
|
||||||
|
this.attributes = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
public User(Long userId,
|
public User(Long userId,
|
||||||
String nickName) {
|
String nickName) {
|
||||||
this.id = userId;
|
this.id = userId;
|
||||||
|
|||||||
@@ -31,4 +31,5 @@ public interface TikTokHttpRequest {
|
|||||||
String get(String url);
|
String get(String url);
|
||||||
|
|
||||||
String post(String url);
|
String post(String url);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,14 +22,31 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.live;
|
package io.github.jwdeveloper.tiktok.live;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.RankingUser;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||||
import io.github.jwdeveloper.tiktok.models.ConnectionState;
|
import io.github.jwdeveloper.tiktok.models.ConnectionState;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface LiveRoomInfo
|
public interface LiveRoomInfo
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return get current count of viewers of live
|
||||||
|
*/
|
||||||
int getViewersCount();
|
int getViewersCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return get total current count of viewers since beginning of live
|
||||||
|
*/
|
||||||
|
int getTotalViewersCount();
|
||||||
int getLikesCount();
|
int getLikesCount();
|
||||||
boolean isAgeRestricted();
|
boolean isAgeRestricted();
|
||||||
String getRoomId();
|
String getRoomId();
|
||||||
String getHostName();
|
String getHostName();
|
||||||
|
String getTitle();
|
||||||
|
User getHostUser();
|
||||||
|
List<RankingUser> getUsersRanking();
|
||||||
ConnectionState getConnectionState();
|
ConnectionState getConnectionState();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,16 +22,19 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.live;
|
package io.github.jwdeveloper.tiktok.live;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class LiveRoomMeta {
|
public class LiveRoomMeta {
|
||||||
|
|
||||||
private LiveRoomStatus status;
|
private LiveRoomStatus status;
|
||||||
|
|
||||||
private boolean ageRestricted;
|
private boolean ageRestricted;
|
||||||
|
private String titie;
|
||||||
|
private int likeCount;
|
||||||
|
private int totalViewers;
|
||||||
|
private int viewers;
|
||||||
|
private User host;
|
||||||
|
|
||||||
public enum LiveRoomStatus
|
public enum LiveRoomStatus
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
|||||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomEvent;
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomUserInfoEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
|
||||||
@@ -39,9 +38,7 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandl
|
|||||||
|
|
||||||
public interface EventsBuilder<T> {
|
public interface EventsBuilder<T> {
|
||||||
|
|
||||||
T onRoom(EventConsumer<TikTokRoomEvent> event);
|
T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event);
|
||||||
|
|
||||||
T onRoomUserInfo(EventConsumer<TikTokRoomUserInfoEvent> event);
|
|
||||||
|
|
||||||
T onComment(EventConsumer<TikTokCommentEvent> event);
|
T onComment(EventConsumer<TikTokCommentEvent> event);
|
||||||
|
|
||||||
@@ -51,6 +48,7 @@ public interface EventsBuilder<T> {
|
|||||||
|
|
||||||
T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> event);
|
T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> event);
|
||||||
|
|
||||||
|
|
||||||
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> event);
|
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> event);
|
||||||
T onGift(EventConsumer<TikTokGiftEvent> event);
|
T onGift(EventConsumer<TikTokGiftEvent> event);
|
||||||
|
|
||||||
@@ -67,10 +65,13 @@ public interface EventsBuilder<T> {
|
|||||||
T onJoin(EventConsumer<TikTokJoinEvent> event);
|
T onJoin(EventConsumer<TikTokJoinEvent> event);
|
||||||
|
|
||||||
T onShare(EventConsumer<TikTokShareEvent> event);
|
T onShare(EventConsumer<TikTokShareEvent> event);
|
||||||
T onUnhandledSocial(EventConsumer<TikTokUnhandledSocialEvent> event);
|
|
||||||
|
// T onChest(EventConsumer<TikTokChestEvent> event);
|
||||||
|
|
||||||
T onLivePaused(EventConsumer<TikTokLivePausedEvent> event);
|
T onLivePaused(EventConsumer<TikTokLivePausedEvent> event);
|
||||||
|
|
||||||
|
T onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event);
|
||||||
|
|
||||||
T onLiveEnded(EventConsumer<TikTokLiveEndedEvent> event);
|
T onLiveEnded(EventConsumer<TikTokLiveEndedEvent> event);
|
||||||
|
|
||||||
T onConnected(EventConsumer<TikTokConnectedEvent> event);
|
T onConnected(EventConsumer<TikTokConnectedEvent> event);
|
||||||
@@ -80,10 +81,11 @@ public interface EventsBuilder<T> {
|
|||||||
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> event);
|
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> event);
|
||||||
|
|
||||||
T onError(EventConsumer<TikTokErrorEvent> event);
|
T onError(EventConsumer<TikTokErrorEvent> event);
|
||||||
|
|
||||||
T onEvent(EventConsumer<TikTokEvent> event);
|
T onEvent(EventConsumer<TikTokEvent> event);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO Figure out how those events works
|
// TODO Figure out how those events works
|
||||||
//T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);
|
//T onLinkMicFanTicket(TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event);
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ enum MemberMessageAction {
|
|||||||
enum ControlAction {
|
enum ControlAction {
|
||||||
ControlActionUNKNOWN = 0;
|
ControlActionUNKNOWN = 0;
|
||||||
STREAM_PAUSED = 1; // Stream Paused by Host
|
STREAM_PAUSED = 1; // Stream Paused by Host
|
||||||
|
STREAM_UNPAUSED = 2;
|
||||||
STREAM_ENDED = 3; // Stream Ended by Host
|
STREAM_ENDED = 3; // Stream Ended by Host
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,3 +112,28 @@ enum BarrageType
|
|||||||
FansLevelEntrance = 11;
|
FansLevelEntrance = 11;
|
||||||
GamePartnership = 12;
|
GamePartnership = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum EnvelopeBusinessType
|
||||||
|
{
|
||||||
|
BusinessTypeUnknown = 0;
|
||||||
|
BusinessTypeUserDiamond = 1;
|
||||||
|
BusinessTypePlatformDiamond = 2;
|
||||||
|
BusinessTypePlatformShell = 3;
|
||||||
|
BusinessTypePortal = 4;
|
||||||
|
BusinessTypePlatformMerch = 5;
|
||||||
|
BusinessTypeEoYDiamond = 6;
|
||||||
|
BusinessTypeFanClubGtM = 7;
|
||||||
|
}
|
||||||
|
enum EnvelopeFollowShowStatus
|
||||||
|
{
|
||||||
|
EnvelopeFollowShowUnknown = 0;
|
||||||
|
EnvelopeFollowShow = 1;
|
||||||
|
EnvelopeFollowNotShow = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EnvelopeDisplay
|
||||||
|
{
|
||||||
|
EnvelopeDisplayUnknown = 0;
|
||||||
|
EnvelopeDisplayNew = 1;
|
||||||
|
EnvelopeDisplayHide = 2;
|
||||||
|
}
|
||||||
@@ -246,13 +246,13 @@ message WebcastEmoteChatMessage {
|
|||||||
message WebcastEnvelopeMessage {
|
message WebcastEnvelopeMessage {
|
||||||
Common common = 1;
|
Common common = 1;
|
||||||
EnvelopeInfo envelopeInfo = 2;
|
EnvelopeInfo envelopeInfo = 2;
|
||||||
int64 display = 3; // @warning Enum not found, should be Display
|
EnvelopeDisplay display = 3; // @warning Enum not found, should be Display
|
||||||
|
|
||||||
// @EnvelopeInfo
|
// @EnvelopeInfo
|
||||||
// proto.webcast.im.EnvelopeMessage
|
// proto.webcast.im.EnvelopeMessage
|
||||||
message EnvelopeInfo {
|
message EnvelopeInfo {
|
||||||
string envelopeId = 1;
|
string envelopeId = 1;
|
||||||
int64 businessType = 2; // @warning Enum not found, should be BusinessType
|
EnvelopeBusinessType businessType = 2;
|
||||||
string envelopeIdc = 3;
|
string envelopeIdc = 3;
|
||||||
string sendUserName = 4;
|
string sendUserName = 4;
|
||||||
int32 diamondCount = 5;
|
int32 diamondCount = 5;
|
||||||
@@ -262,7 +262,7 @@ message WebcastEnvelopeMessage {
|
|||||||
Image sendUserAvatar = 9;
|
Image sendUserAvatar = 9;
|
||||||
string createAt = 10;
|
string createAt = 10;
|
||||||
string roomId = 11;
|
string roomId = 11;
|
||||||
int64 followShowStatus = 12; // @warning Enum not found, should be FollowShowStatus
|
EnvelopeFollowShowStatus followShowStatus = 12; // @warning Enum not found, should be FollowShowStatus
|
||||||
int32 skinId = 13;
|
int32 skinId = 13;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>0.0.25-Release</version>
|
<version>1.0.4-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@@ -41,12 +41,28 @@
|
|||||||
<artifactId>Java-WebSocket</artifactId>
|
<artifactId>Java-WebSocket</artifactId>
|
||||||
<version>1.5.4</version>
|
<version>1.5.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testng</groupId>
|
||||||
|
<artifactId>testng</artifactId>
|
||||||
|
<version>7.4.0</version> <!-- Use the desired TestNG version -->
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>3.0.0-M5</version>
|
||||||
|
<configuration>
|
||||||
|
<argLine>-Xmx512m</argLine>
|
||||||
|
<suiteXmlFiles>
|
||||||
|
<suiteXmlFile>testng.xml</suiteXmlFile>
|
||||||
|
</suiteXmlFiles>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
|||||||
@@ -23,12 +23,68 @@
|
|||||||
package io.github.jwdeveloper.tiktok;
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.http.TikTokDataChecker;
|
||||||
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class TikTokLive
|
public class TikTokLive
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param hostName profile name of Tiktok user could be found in profile link
|
||||||
|
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
|
||||||
|
* @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
|
||||||
|
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
|
||||||
|
* @return true if live is Online, false if is offline
|
||||||
|
*/
|
||||||
|
public static boolean isLiveOnline(String hostName)
|
||||||
|
{
|
||||||
|
return new TikTokDataChecker().isOnline(hostName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param hostName profile name of Tiktok user could be found in profile link
|
||||||
|
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
|
||||||
|
* @return true if live is Online, false if is offline
|
||||||
|
*/
|
||||||
|
public static CompletableFuture<Boolean> isLiveOnlineAsync(String hostName)
|
||||||
|
{
|
||||||
|
return new TikTokDataChecker().isOnlineAsync(hostName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param hostName profile name of Tiktok user could be found in profile link
|
||||||
|
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
|
||||||
|
* @return true is hostName name is valid and exists, false if not
|
||||||
|
*/
|
||||||
|
public static boolean isHostNameValid(String hostName)
|
||||||
|
{
|
||||||
|
return new TikTokDataChecker().isHostNameValid(hostName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param hostName profile name of Tiktok user could be found in profile link
|
||||||
|
* example: https://www.tiktok.com/@dostawcavideo hostName would be dostawcavideo
|
||||||
|
* @return true is hostName name is valid and exists, false if not
|
||||||
|
*/
|
||||||
|
public static CompletableFuture<Boolean> isHostNameValidAsync(String hostName)
|
||||||
|
{
|
||||||
|
return new TikTokDataChecker().isHostNameValidAsync(hostName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ package io.github.jwdeveloper.tiktok;
|
|||||||
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.room.TikTokRoomInfoEvent;
|
||||||
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;
|
||||||
@@ -112,7 +113,7 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
if (!liveRoomInfo.hasConnectionState(ConnectionState.CONNECTED)) {
|
if (liveRoomInfo.hasConnectionState(ConnectionState.DISCONNECTED)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
webSocketClient.stop();
|
webSocketClient.stop();
|
||||||
@@ -138,14 +139,24 @@ public class TikTokLiveClient implements LiveClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var roomData = apiService.fetchRoomInfo();
|
var liveRoomMeta = apiService.fetchRoomInfo();
|
||||||
if (roomData.getStatus() != LiveRoomMeta.LiveRoomStatus.HostOnline) {
|
if (liveRoomMeta.getStatus() == LiveRoomMeta.LiveRoomStatus.HostNotFound) {
|
||||||
throw new TikTokLiveOfflineHostException("LiveStream for Host name could not be found. Is the Host online?");
|
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();
|
var clientData = apiService.fetchClientData();
|
||||||
webSocketClient.start(clientData, this);
|
webSocketClient.start(clientData, this);
|
||||||
setState(ConnectionState.CONNECTED);
|
setState(ConnectionState.CONNECTED);
|
||||||
|
tikTokEventHandler.publish(this,new TikTokRoomInfoEvent(liveRoomInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ package io.github.jwdeveloper.tiktok;
|
|||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.envelop.TikTokChestEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
|
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomEvent;
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomUserInfoEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
|
||||||
@@ -42,6 +42,8 @@ import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
|||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
|
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.events.TikTokRoomInfoEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.events.TikTokSocialMediaEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
||||||
@@ -130,11 +132,12 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
|
|
||||||
logger.setLevel(clientSettings.getLogLevel());
|
logger.setLevel(clientSettings.getLogLevel());
|
||||||
|
|
||||||
if (clientSettings.isPrintToConsole() && clientSettings.getLogLevel() == Level.OFF) {
|
if (!clientSettings.isPrintToConsole()) {
|
||||||
logger.setLevel(Level.ALL);
|
logger.setLevel(Level.OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveClient build() {
|
public LiveClient build() {
|
||||||
@@ -148,14 +151,18 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
|
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
|
||||||
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
|
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
|
||||||
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
|
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
|
||||||
var giftManager = new TikTokGiftManager();
|
var giftManager = new TikTokGiftManager(logger);
|
||||||
var eventMapper = new TikTokGenericEventMapper();
|
var eventMapper = new TikTokGenericEventMapper();
|
||||||
|
|
||||||
var giftHandler = new TikTokGiftEventHandler(giftManager);
|
var giftHandler = new TikTokGiftEventHandler(giftManager);
|
||||||
|
var roomInfoHandler = new TikTokRoomInfoEventHandler(tiktokRoomInfo);
|
||||||
|
var socialHandler = new TikTokSocialMediaEventHandler(tiktokRoomInfo);
|
||||||
|
|
||||||
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler,
|
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler,
|
||||||
tiktokRoomInfo,
|
roomInfoHandler,
|
||||||
eventMapper,
|
eventMapper,
|
||||||
giftHandler
|
giftHandler,
|
||||||
|
socialHandler
|
||||||
);
|
);
|
||||||
|
|
||||||
var webSocketClient = new TikTokWebSocketClient(logger,
|
var webSocketClient = new TikTokWebSocketClient(logger,
|
||||||
@@ -190,6 +197,12 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
public LiveClientBuilder onChest(EventConsumer<TikTokChestEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokChestEvent.class, event);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLinkMicFanTicket(
|
public TikTokLiveClientBuilder onLinkMicFanTicket(
|
||||||
EventConsumer<TikTokLinkMicFanTicketEvent> event) {
|
EventConsumer<TikTokLinkMicFanTicketEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
|
||||||
@@ -239,16 +252,25 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onRoom(EventConsumer<TikTokRoomEvent> event) {
|
@Override
|
||||||
tikTokEventHandler.subscribe(TikTokRoomEvent.class, event);
|
public LiveClientBuilder onRoomInfo(EventConsumer<TikTokRoomInfoEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokRoomInfoEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLivePaused(EventConsumer<TikTokLivePausedEvent> event) {
|
public TikTokLiveClientBuilder onLivePaused(EventConsumer<TikTokLivePausedEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokLivePausedEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokLivePausedEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LiveClientBuilder onLiveUnpaused(EventConsumer<TikTokLiveUnpausedEvent> event) {
|
||||||
|
tikTokEventHandler.subscribe(TikTokLiveUnpausedEvent.class, event);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onLike(EventConsumer<TikTokLikeEvent> event) {
|
public TikTokLiveClientBuilder onLike(EventConsumer<TikTokLikeEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokLikeEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokLikeEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
@@ -321,13 +343,6 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onRoomUserInfo(
|
|
||||||
EventConsumer<TikTokRoomUserInfoEvent> event) {
|
|
||||||
tikTokEventHandler.subscribe(TikTokRoomUserInfoEvent.class, event);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TikTokLiveClientBuilder onComment(EventConsumer<TikTokCommentEvent> event) {
|
public TikTokLiveClientBuilder onComment(EventConsumer<TikTokCommentEvent> event) {
|
||||||
tikTokEventHandler.subscribe(TikTokCommentEvent.class, event);
|
tikTokEventHandler.subscribe(TikTokCommentEvent.class, event);
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -22,28 +22,52 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok;
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.RankingUser;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||||
import io.github.jwdeveloper.tiktok.models.ConnectionState;
|
import io.github.jwdeveloper.tiktok.models.ConnectionState;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
|
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TikTokRoomInfo implements LiveRoomInfo
|
public class TikTokRoomInfo implements LiveRoomInfo {
|
||||||
{
|
private String roomId;
|
||||||
|
|
||||||
private int likesCount;
|
private int likesCount;
|
||||||
|
|
||||||
private int viewersCount;
|
private int viewersCount;
|
||||||
|
|
||||||
private String roomId;
|
private int totalViewersCount;
|
||||||
|
|
||||||
private boolean ageRestricted;
|
private boolean ageRestricted;
|
||||||
|
|
||||||
|
private User host;
|
||||||
|
|
||||||
|
private List<RankingUser> usersRanking = new LinkedList<>();
|
||||||
|
|
||||||
private String hostName;
|
private String hostName;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String language = "en";
|
||||||
|
|
||||||
private ConnectionState connectionState = ConnectionState.DISCONNECTED;
|
private ConnectionState connectionState = ConnectionState.DISCONNECTED;
|
||||||
|
|
||||||
public boolean hasConnectionState(ConnectionState state)
|
public boolean hasConnectionState(ConnectionState state) {
|
||||||
{
|
|
||||||
return connectionState == state;
|
return connectionState == state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getHostUser() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateRanking(List<RankingUser> rankingUsers) {
|
||||||
|
usersRanking.clear();
|
||||||
|
usersRanking.addAll(rankingUsers);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,18 +28,22 @@ 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.util.HashMap;
|
import java.lang.reflect.Field;
|
||||||
import java.util.List;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Map;
|
import java.util.*;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class TikTokGiftManager implements GiftManager {
|
public class TikTokGiftManager implements GiftManager {
|
||||||
|
|
||||||
private final Map<Integer, Gift> indexById;
|
private final Map<Integer, Gift> indexById;
|
||||||
private final Map<String, Gift> indexByName;
|
private final Map<String, Gift> indexByName;
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
public TikTokGiftManager() {
|
public TikTokGiftManager(Logger logger)
|
||||||
|
{
|
||||||
indexById = new HashMap<>();
|
indexById = new HashMap<>();
|
||||||
indexByName = new HashMap<>();
|
indexByName = new HashMap<>();
|
||||||
|
this.logger = logger;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +70,7 @@ public class TikTokGiftManager implements GiftManager {
|
|||||||
field.set(enumInstance, name);
|
field.set(enumInstance, name);
|
||||||
|
|
||||||
|
|
||||||
|
// EnumSet
|
||||||
field = Gift.class.getDeclaredField("diamondCost");
|
field = Gift.class.getDeclaredField("diamondCost");
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(enumInstance, diamondCost);
|
field.set(enumInstance, diamondCost);
|
||||||
|
|||||||
@@ -22,42 +22,43 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.handlers;
|
package io.github.jwdeveloper.tiktok.handlers;
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.*;
|
import io.github.jwdeveloper.tiktok.data.events.*;
|
||||||
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.envelop.TikTokChestEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEndEvent;
|
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEndEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
|
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollStartEvent;
|
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollStartEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollUpdateEvent;
|
import io.github.jwdeveloper.tiktok.data.events.poll.TikTokPollUpdateEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomPinEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomUserInfoEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
|
||||||
import io.github.jwdeveloper.tiktok.data.events.social.TikTokShareEvent;
|
import io.github.jwdeveloper.tiktok.data.models.chest.Chest;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.Text;
|
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
|
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.events.TikTokRoomInfoEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.events.TikTokSocialMediaEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
|
import io.github.jwdeveloper.tiktok.mappers.TikTokGenericEventMapper;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.enums.EnvelopeDisplay;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.*;
|
import io.github.jwdeveloper.tiktok.messages.webcast.*;
|
||||||
import io.github.jwdeveloper.tiktok.models.SocialTypes;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
||||||
|
|
||||||
private final TikTokRoomInfo roomInfo;
|
|
||||||
private final TikTokGiftEventHandler giftHandler;
|
private final TikTokGiftEventHandler giftHandler;
|
||||||
private final Pattern socialMediaPattern = Pattern.compile("pm_mt_guidance_viewer_([0-9]+)_share");
|
private final TikTokRoomInfoEventHandler roomInfoHandler;
|
||||||
|
private final TikTokSocialMediaEventHandler socialHandler;
|
||||||
|
|
||||||
public TikTokMessageHandlerRegistration(TikTokEventObserver tikTokEventHandler,
|
public TikTokMessageHandlerRegistration(TikTokEventObserver tikTokEventHandler,
|
||||||
TikTokRoomInfo roomInfo,
|
TikTokRoomInfoEventHandler roomInfoHandler,
|
||||||
TikTokGenericEventMapper genericTikTokEventMapper,
|
TikTokGenericEventMapper genericTikTokEventMapper,
|
||||||
TikTokGiftEventHandler tikTokGiftEventHandler) {
|
TikTokGiftEventHandler tikTokGiftEventHandler,
|
||||||
|
TikTokSocialMediaEventHandler tikTokSocialMediaEventHandler) {
|
||||||
super(tikTokEventHandler, genericTikTokEventMapper);
|
super(tikTokEventHandler, genericTikTokEventMapper);
|
||||||
this.giftHandler = tikTokGiftEventHandler;
|
this.giftHandler = tikTokGiftEventHandler;
|
||||||
this.roomInfo = roomInfo;
|
this.roomInfoHandler = roomInfoHandler;
|
||||||
|
this.socialHandler = tikTokSocialMediaEventHandler;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,22 +66,19 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
|||||||
|
|
||||||
//ConnectionEvents events
|
//ConnectionEvents events
|
||||||
registerMapping(WebcastControlMessage.class, this::handleWebcastControlMessage);
|
registerMapping(WebcastControlMessage.class, this::handleWebcastControlMessage);
|
||||||
registerMapping(WebcastSystemMessage.class, TikTokRoomEvent.class);
|
|
||||||
|
|
||||||
|
|
||||||
//Room status events
|
//Room status events
|
||||||
registerMapping(WebcastLiveIntroMessage.class, TikTokRoomEvent.class);
|
registerMapping(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
|
||||||
registerMapping(WebcastRoomUserSeqMessage.class, this::handleRoomUserSeqMessage);
|
registerMapping(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
|
||||||
registerMapping(RoomMessage.class, TikTokRoomEvent.class);
|
|
||||||
registerMapping(WebcastRoomMessage.class, TikTokRoomEvent.class);
|
|
||||||
registerMapping(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
|
registerMapping(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
|
||||||
|
|
||||||
//User Interactions events
|
//User Interactions events
|
||||||
registerMapping(WebcastChatMessage.class, TikTokCommentEvent.class);
|
registerMapping(WebcastChatMessage.class, TikTokCommentEvent.class);
|
||||||
registerMapping(WebcastLikeMessage.class, this::handleLike);
|
registerMappings(WebcastLikeMessage.class, this::handleLike);
|
||||||
registerMappings(WebcastGiftMessage.class, giftHandler::handleGift);
|
registerMappings(WebcastGiftMessage.class, giftHandler::handleGift);
|
||||||
registerMapping(WebcastSocialMessage.class, this::handleSocialMedia);
|
registerMapping(WebcastSocialMessage.class, socialHandler::handle);
|
||||||
registerMapping(WebcastMemberMessage.class, this::handleMemberMessage);
|
registerMappings(WebcastMemberMessage.class, this::handleMemberMessage);
|
||||||
|
|
||||||
//Host Interaction events
|
//Host Interaction events
|
||||||
registerMapping(WebcastPollMessage.class, this::handlePollEvent);
|
registerMapping(WebcastPollMessage.class, this::handlePollEvent);
|
||||||
@@ -106,7 +104,7 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
|||||||
registerMapping(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
|
registerMapping(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
|
||||||
registerMapping(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
|
registerMapping(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
|
||||||
registerMapping(WebcastQuestionNewMessage.class, TikTokQuestionEvent.class);
|
registerMapping(WebcastQuestionNewMessage.class, TikTokQuestionEvent.class);
|
||||||
registerMapping(WebcastEnvelopeMessage.class, TikTokEnvelopeEvent.class);
|
registerMappings(WebcastEnvelopeMessage.class, this::handleEnvelop);
|
||||||
registerMapping(WebcastSubNotifyMessage.class, TikTokSubNotifyEvent.class);
|
registerMapping(WebcastSubNotifyMessage.class, TikTokSubNotifyEvent.class);
|
||||||
registerMapping(WebcastEmoteChatMessage.class, TikTokEmoteEvent.class);
|
registerMapping(WebcastEmoteChatMessage.class, TikTokEmoteEvent.class);
|
||||||
}
|
}
|
||||||
@@ -118,53 +116,37 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
|||||||
return switch (message.getAction()) {
|
return switch (message.getAction()) {
|
||||||
case STREAM_PAUSED -> new TikTokLivePausedEvent();
|
case STREAM_PAUSED -> new TikTokLivePausedEvent();
|
||||||
case STREAM_ENDED -> new TikTokLiveEndedEvent();
|
case STREAM_ENDED -> new TikTokLiveEndedEvent();
|
||||||
|
case STREAM_UNPAUSED -> new TikTokLiveUnpausedEvent();
|
||||||
default -> new TikTokUnhandledControlEvent(message);
|
default -> new TikTokUnhandledControlEvent(message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private TikTokEvent handleSocialMedia(byte[] msg) {
|
private List<TikTokEvent> handleMemberMessage(byte[] msg) {
|
||||||
var message = WebcastSocialMessage.parseFrom(msg);
|
|
||||||
|
|
||||||
var socialType = Text.map(message.getCommon().getDisplayText()).getKey();
|
|
||||||
var matcher = socialMediaPattern.matcher(socialType);
|
|
||||||
|
|
||||||
if (matcher.find()) {
|
|
||||||
var value = matcher.group(1);
|
|
||||||
var number = Integer.parseInt(value);
|
|
||||||
return new TikTokShareEvent(message, number);
|
|
||||||
}
|
|
||||||
|
|
||||||
return switch (socialType) {
|
|
||||||
case SocialTypes.LikeType -> new TikTokLikeEvent(message, roomInfo.getLikesCount());
|
|
||||||
case SocialTypes.FollowType -> new TikTokFollowEvent(message);
|
|
||||||
case SocialTypes.ShareType -> new TikTokShareEvent(message);
|
|
||||||
case SocialTypes.JoinType -> new TikTokJoinEvent(message, roomInfo.getViewersCount());
|
|
||||||
default -> new TikTokUnhandledSocialEvent(message);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private TikTokEvent handleMemberMessage(byte[] msg) {
|
|
||||||
var message = WebcastMemberMessage.parseFrom(msg);
|
var message = WebcastMemberMessage.parseFrom(msg);
|
||||||
return switch (message.getAction()) {
|
|
||||||
|
var event = switch (message.getAction()) {
|
||||||
case JOINED -> new TikTokJoinEvent(message);
|
case JOINED -> new TikTokJoinEvent(message);
|
||||||
case SUBSCRIBED -> new TikTokSubscribeEvent(message);
|
case SUBSCRIBED -> new TikTokSubscribeEvent(message);
|
||||||
default -> new TikTokUnhandledMemberEvent(message);
|
default -> new TikTokUnhandledMemberEvent(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var roomInfoEvent = roomInfoHandler.handleRoomInfo(tikTokRoomInfo ->
|
||||||
|
{
|
||||||
|
tikTokRoomInfo.setViewersCount(message.getMemberCount());
|
||||||
|
});
|
||||||
|
|
||||||
|
return List.of(event, roomInfoEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TikTokEvent handleRoomUserSeqMessage(byte[] msg) {
|
private List<TikTokEvent> handleLike(byte[] msg) {
|
||||||
var event = (TikTokRoomUserInfoEvent) mapper.mapToEvent(WebcastRoomUserSeqMessage.class, TikTokRoomUserInfoEvent.class, msg);
|
|
||||||
roomInfo.setViewersCount(event.getTotalUsers());
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TikTokEvent handleLike(byte[] msg) {
|
|
||||||
var event = (TikTokLikeEvent) mapper.mapToEvent(WebcastLikeMessage.class, TikTokLikeEvent.class, msg);
|
var event = (TikTokLikeEvent) mapper.mapToEvent(WebcastLikeMessage.class, TikTokLikeEvent.class, msg);
|
||||||
roomInfo.setLikesCount(event.getTotalLikes());
|
var roomInfoEvent = roomInfoHandler.handleRoomInfo(tikTokRoomInfo ->
|
||||||
return event;
|
{
|
||||||
|
tikTokRoomInfo.setLikesCount(event.getTotalLikes());
|
||||||
|
});
|
||||||
|
return List.of(event, roomInfoEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@@ -187,5 +169,18 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private List<TikTokEvent> handleEnvelop(byte[] data) {
|
||||||
|
var msg = WebcastEnvelopeMessage.parseFrom(data);
|
||||||
|
if (msg.getDisplay() != EnvelopeDisplay.EnvelopeDisplayNew) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
var totalDiamonds = msg.getEnvelopeInfo().getDiamondCount();
|
||||||
|
var totalUsers = msg.getEnvelopeInfo().getPeopleCount();
|
||||||
|
var chest = new Chest(totalDiamonds, totalUsers);
|
||||||
|
|
||||||
|
return List.of(new TikTokChestEvent(chest, msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.handlers.events;
|
||||||
|
|
||||||
|
public class TikTokChestEventHandler {
|
||||||
|
}
|
||||||
@@ -28,9 +28,11 @@ import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
|||||||
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
|
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
|
||||||
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
import sun.misc.Unsafe;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -48,10 +50,22 @@ public class TikTokGiftEventHandler {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public List<TikTokEvent> handleGift(byte[] msg) {
|
public List<TikTokEvent> handleGift(byte[] msg) {
|
||||||
var currentMessage = WebcastGiftMessage.parseFrom(msg);
|
var currentMessage = WebcastGiftMessage.parseFrom(msg);
|
||||||
|
return handleGift(currentMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TikTokEvent> handleGift(WebcastGiftMessage currentMessage) {
|
||||||
var userId = currentMessage.getUser().getId();
|
var userId = currentMessage.getUser().getId();
|
||||||
var currentType = GiftSendType.fromNumber(currentMessage.getSendType());
|
var currentType = GiftSendType.fromNumber(currentMessage.getSendType());
|
||||||
var containsPreviousMessage = giftsMessages.containsKey(userId);
|
var containsPreviousMessage = giftsMessages.containsKey(userId);
|
||||||
|
|
||||||
|
|
||||||
|
//If gift is not streakable just return onGift event
|
||||||
|
if (currentMessage.getGift().getType() != 1) {
|
||||||
|
var comboEvent = getGiftComboEvent(currentMessage, GiftSendType.Finished);
|
||||||
|
var giftEvent = getGiftEvent(currentMessage);
|
||||||
|
return List.of(comboEvent, giftEvent);
|
||||||
|
}
|
||||||
|
|
||||||
if (!containsPreviousMessage) {
|
if (!containsPreviousMessage) {
|
||||||
if (currentType == GiftSendType.Finished) {
|
if (currentType == GiftSendType.Finished) {
|
||||||
return List.of(getGiftEvent(currentMessage));
|
return List.of(getGiftEvent(currentMessage));
|
||||||
@@ -81,6 +95,7 @@ public class TikTokGiftEventHandler {
|
|||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private TikTokGiftEvent getGiftEvent(WebcastGiftMessage message) {
|
private TikTokGiftEvent getGiftEvent(WebcastGiftMessage message) {
|
||||||
var gift = getGiftObject(message);
|
var gift = getGiftObject(message);
|
||||||
return new TikTokGiftEvent(gift, message);
|
return new TikTokGiftEvent(gift, message);
|
||||||
@@ -92,17 +107,36 @@ public class TikTokGiftEventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Gift getGiftObject(WebcastGiftMessage giftMessage) {
|
private Gift getGiftObject(WebcastGiftMessage giftMessage) {
|
||||||
var gift = giftManager.findById((int) giftMessage.getGiftId());
|
var giftId = (int) giftMessage.getGiftId();
|
||||||
|
var gift = giftManager.findById(giftId);
|
||||||
if (gift == Gift.UNDEFINED) {
|
if (gift == Gift.UNDEFINED) {
|
||||||
gift = giftManager.findByName(giftMessage.getGift().getName());
|
gift = giftManager.findByName(giftMessage.getGift().getName());
|
||||||
}
|
}
|
||||||
if (gift == Gift.UNDEFINED) {
|
if (gift == Gift.UNDEFINED) {
|
||||||
gift = giftManager.registerGift(
|
gift = giftManager.registerGift(
|
||||||
(int) giftMessage.getGift().getId(),
|
giftId,
|
||||||
giftMessage.getGift().getName(),
|
giftMessage.getGift().getName(),
|
||||||
giftMessage.getGift().getDiamondCount(),
|
giftMessage.getGift().getDiamondCount(),
|
||||||
Picture.map(giftMessage.getGift().getImage()));
|
Picture.map(giftMessage.getGift().getImage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gift.getPicture().getLink().endsWith(".webp")) {
|
||||||
|
updatePicture(gift, giftMessage);
|
||||||
|
}
|
||||||
return gift;
|
return gift;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void updatePicture(Gift gift, WebcastGiftMessage webcastGiftMessage) {
|
||||||
|
try {
|
||||||
|
var picture = Picture.map(webcastGiftMessage.getGift().getImage());
|
||||||
|
var constructor = Unsafe.class.getDeclaredConstructors()[0];
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
var field = Gift.class.getDeclaredField("picture");
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(gift, picture);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new TikTokLiveException("Unable to update picture in gift: " + gift.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.handlers.events;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.RankingUser;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLiveIntroMessage;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastRoomUserSeqMessage;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class TikTokRoomInfoEventHandler {
|
||||||
|
private final TikTokRoomInfo roomInfo;
|
||||||
|
|
||||||
|
public TikTokRoomInfoEventHandler(TikTokRoomInfo roomInfo) {
|
||||||
|
this.roomInfo = roomInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TikTokEvent handleRoomInfo(Consumer<TikTokRoomInfo> consumer) {
|
||||||
|
consumer.accept(roomInfo);
|
||||||
|
return new TikTokRoomInfoEvent(roomInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public TikTokEvent handleUserRanking(byte[] msg) {
|
||||||
|
var message = WebcastRoomUserSeqMessage.parseFrom(msg);
|
||||||
|
var totalUsers = message.getTotalUser();
|
||||||
|
var userRanking = message.getRanksListList().stream().map(RankingUser::new)
|
||||||
|
.sorted((ru1, ru2) -> Integer.compare(ru2.getScore(), ru1.getScore()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return handleRoomInfo(tikTokRoomInfo ->
|
||||||
|
{
|
||||||
|
tikTokRoomInfo.setTotalViewersCount(totalUsers);
|
||||||
|
tikTokRoomInfo.updateRanking(userRanking);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public TikTokEvent handleIntro(byte[] msg) {
|
||||||
|
var message = WebcastLiveIntroMessage.parseFrom(msg);
|
||||||
|
var hostUser = User.map(message.getHost());
|
||||||
|
var language = message.getLanguage();
|
||||||
|
|
||||||
|
return handleRoomInfo(tikTokRoomInfo ->
|
||||||
|
{
|
||||||
|
if(tikTokRoomInfo.getHost() == null)
|
||||||
|
{
|
||||||
|
tikTokRoomInfo.setHost(hostUser);
|
||||||
|
}
|
||||||
|
tikTokRoomInfo.setLanguage(language);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.handlers.events;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.TikTokUnhandledSocialEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokFollowEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokJoinEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.social.TikTokShareEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.Text;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastSocialMessage;
|
||||||
|
import io.github.jwdeveloper.tiktok.models.SocialTypes;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class TikTokSocialMediaEventHandler
|
||||||
|
{
|
||||||
|
private final TikTokRoomInfo roomInfo;
|
||||||
|
private final Pattern socialMediaPattern = Pattern.compile("pm_mt_guidance_viewer_([0-9]+)_share");
|
||||||
|
|
||||||
|
public TikTokSocialMediaEventHandler(TikTokRoomInfo roomInfo) {
|
||||||
|
this.roomInfo = roomInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public TikTokEvent handle(byte[] msg)
|
||||||
|
{
|
||||||
|
var message = WebcastSocialMessage.parseFrom(msg);
|
||||||
|
|
||||||
|
var socialType = Text.map(message.getCommon().getDisplayText()).getKey();
|
||||||
|
var matcher = socialMediaPattern.matcher(socialType);
|
||||||
|
|
||||||
|
if (matcher.find()) {
|
||||||
|
var value = matcher.group(1);
|
||||||
|
var number = Integer.parseInt(value);
|
||||||
|
return new TikTokShareEvent(message, number);
|
||||||
|
}
|
||||||
|
|
||||||
|
return switch (socialType) {
|
||||||
|
case SocialTypes.LikeType -> new TikTokLikeEvent(message, roomInfo.getLikesCount());
|
||||||
|
case SocialTypes.FollowType -> new TikTokFollowEvent(message);
|
||||||
|
case SocialTypes.ShareType -> new TikTokShareEvent(message);
|
||||||
|
case SocialTypes.JoinType -> new TikTokJoinEvent(message, roomInfo.getViewersCount());
|
||||||
|
default -> new TikTokUnhandledSocialEvent(message);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -30,7 +30,6 @@ import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
|
|||||||
import io.github.jwdeveloper.tiktok.mappers.LiveRoomMetaMapper;
|
import io.github.jwdeveloper.tiktok.mappers.LiveRoomMetaMapper;
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
|
|
||||||
import javax.script.ScriptEngineManager;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -47,49 +46,34 @@ public class TikTokApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void updateSessionId()
|
public void updateSessionId() {
|
||||||
{
|
if (clientSettings.getSessionId() == null) {
|
||||||
if(clientSettings.getSessionId() == null)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(clientSettings.getSessionId().isEmpty())
|
if (clientSettings.getSessionId().isEmpty()) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tiktokHttpClient.setSessionId(clientSettings.getSessionId());
|
tiktokHttpClient.setSessionId(clientSettings.getSessionId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean sendMessage(String message, String sessionId) {
|
public String fetchRoomId(String userName) {
|
||||||
if (sessionId.isEmpty()) {
|
var roomId = fetchRoomIdFromTiktokApi(userName);
|
||||||
throw new TikTokLiveException("Session ID must not be Empty");
|
clientSettings.getClientParameters().put("room_id", roomId);
|
||||||
}
|
logger.info("RoomID -> " + roomId);
|
||||||
var roomId = clientSettings.getClientParameters().get("room_id");
|
return roomId;
|
||||||
if (roomId == null) {
|
|
||||||
throw new TikTokLiveException("Room ID must not be Empty");
|
|
||||||
}
|
|
||||||
logger.info("Sending message to chat");
|
|
||||||
try {
|
|
||||||
var params = new HashMap<String, Object>(clientSettings.getClientParameters());
|
|
||||||
params.put("content", message);
|
|
||||||
params.put("channel", "tiktok_web");
|
|
||||||
params.remove("cursor");
|
|
||||||
tiktokHttpClient.setSessionId(sessionId);
|
|
||||||
tiktokHttpClient.postMessageToChat(params);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new TikTokLiveRequestException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String fetchRoomId(String userName) {
|
private String fetchRoomIdFromTikTokPage(String userName)
|
||||||
|
{
|
||||||
|
/* var roomId = RequestChain.<String>create()
|
||||||
|
.then(() -> fetchRoomIdFromTikTokPage(userName))
|
||||||
|
.then(() -> fetchRoomIdFromTiktokApi(userName))
|
||||||
|
.run();*/
|
||||||
logger.info("Fetching room ID");
|
logger.info("Fetching room ID");
|
||||||
String html;
|
String html;
|
||||||
try {
|
try {
|
||||||
html = tiktokHttpClient.getLivestreamPage(userName);
|
html = tiktokHttpClient.getLivestreamPage(userName);
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new TikTokLiveRequestException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
|
throw new TikTokLiveRequestException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,22 +96,35 @@ public class TikTokApiService {
|
|||||||
throw new TikTokLiveOfflineHostException("Unable to fetch room ID, live host could be offline or name is misspelled");
|
throw new TikTokLiveOfflineHostException("Unable to fetch room ID, live host could be offline or name is misspelled");
|
||||||
}
|
}
|
||||||
|
|
||||||
clientSettings.getClientParameters().put("room_id", id);
|
|
||||||
logger.info("RoomID -> " + id);
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String fetchRoomIdFromTiktokApi(String userName) {
|
||||||
|
|
||||||
|
var params = new HashMap<>(clientSettings.getClientParameters());
|
||||||
|
params.put("uniqueId", userName);
|
||||||
|
params.put("sourceType", 54);
|
||||||
|
var roomData = tiktokHttpClient.getJsonFromTikTokApi("api-live/user/room/", params);
|
||||||
|
|
||||||
|
var data = roomData.getAsJsonObject("data");
|
||||||
|
var user =data.getAsJsonObject("user");
|
||||||
|
var roomId = user.get("roomId").getAsString();
|
||||||
|
|
||||||
|
|
||||||
|
return roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public LiveRoomMeta fetchRoomInfo() {
|
public LiveRoomMeta fetchRoomInfo() {
|
||||||
logger.info("Fetching RoomInfo");
|
logger.info("Fetching RoomInfo");
|
||||||
try {
|
try {
|
||||||
var response = tiktokHttpClient.getJObjectFromWebcastAPI("room/info/", clientSettings.getClientParameters());
|
var response = tiktokHttpClient.getJsonFromWebcastApi("room/info/", clientSettings.getClientParameters());
|
||||||
var mapper = new LiveRoomMetaMapper();
|
var mapper = new LiveRoomMetaMapper();
|
||||||
var liveRoomMeta = mapper.map(response);
|
var liveRoomMeta = mapper.map(response);
|
||||||
logger.info("RoomInfo status -> " + liveRoomMeta.getStatus());
|
logger.info("RoomInfo status -> " + liveRoomMeta.getStatus());
|
||||||
return liveRoomMeta;
|
return liveRoomMeta;
|
||||||
} catch (Exception e)
|
} catch (Exception e) {
|
||||||
{
|
|
||||||
throw new TikTokLiveRequestException("Failed to fetch room info from WebCast, see stacktrace for more info.", e);
|
throw new TikTokLiveRequestException("Failed to fetch room info from WebCast, see stacktrace for more info.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +133,7 @@ public class TikTokApiService {
|
|||||||
|
|
||||||
logger.info("Fetching ClientData");
|
logger.info("Fetching ClientData");
|
||||||
try {
|
try {
|
||||||
var response = tiktokHttpClient.getSigningServerMessage("im/fetch/", clientSettings.getClientParameters());
|
var response = tiktokHttpClient.getSigningServerResponse("im/fetch/", clientSettings.getClientParameters());
|
||||||
clientSettings.getClientParameters().put("cursor", response.getCursor());
|
clientSettings.getClientParameters().put("cursor", response.getCursor());
|
||||||
clientSettings.getClientParameters().put("internal_ext", response.getInternalExt());
|
clientSettings.getClientParameters().put("internal_ext", response.getInternalExt());
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.http;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
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 factory = new TikTokHttpRequestFactory(new TikTokCookieJar());
|
||||||
|
var url = getLiveUrl(hostName);
|
||||||
|
try {
|
||||||
|
var response = factory.get(url);
|
||||||
|
var titleContent = extractTitleContent(response);
|
||||||
|
return isTitleLiveOnline(titleContent);
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new TikTokLiveRequestException("Unable to make check live online request",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHostNameValid(String hostName) {
|
||||||
|
var factory = new TikTokHttpRequestFactory(new TikTokCookieJar());
|
||||||
|
var url = getProfileUrl(hostName);
|
||||||
|
try {
|
||||||
|
var response = factory.get(url);
|
||||||
|
var titleContent = extractTitleContent(response);
|
||||||
|
return isTitleHostNameValid(titleContent, hostName);
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new TikTokLiveRequestException("Unable to make check host name valid request",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTitleLiveOnline(String title) {
|
||||||
|
return title.contains("is LIVE");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTitleHostNameValid(String title, String hostName)
|
||||||
|
{
|
||||||
|
return title.contains(hostName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractTitleContent(String html) {
|
||||||
|
var regex = "<title\\b[^>]*>(.*?)<\\/title>";
|
||||||
|
var pattern = Pattern.compile(regex);
|
||||||
|
var matcher = pattern.matcher(html);
|
||||||
|
if (matcher.find()) {
|
||||||
|
return matcher.group(1);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getLiveUrl(String hostName) {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.append("https://www.tiktok.com/@");
|
||||||
|
sb.append(hostName);
|
||||||
|
sb.append("/live");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getProfileUrl(String hostName) {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.append("https://www.tiktok.com/@");
|
||||||
|
sb.append(hostName);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,20 +60,23 @@ public class TikTokHttpClient {
|
|||||||
return get;
|
return get;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String postMessageToChat(Map<String,Object> parameters)
|
public JsonObject getJsonFromTikTokApi(String path, Map<String,Object> params)
|
||||||
{
|
{
|
||||||
var get = postRequest(Constants.TIKTOK_URL_WEBCAST + "room/chat/", parameters);
|
var get = getRequest(Constants.TIKTOK_URL_WEB + path, params);
|
||||||
return get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonObject getJObjectFromWebcastAPI(String path, Map<String, Object> parameters) {
|
|
||||||
var get = getRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
|
|
||||||
var json = JsonParser.parseString(get);
|
var json = JsonParser.parseString(get);
|
||||||
var jsonObject = json.getAsJsonObject();
|
var jsonObject = json.getAsJsonObject();
|
||||||
return jsonObject;
|
return jsonObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebcastResponse getSigningServerMessage(String path, Map<String, Object> parameters) {
|
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);
|
var bytes = getSignRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
|
||||||
try {
|
try {
|
||||||
return WebcastResponse.parseFrom(bytes);
|
return WebcastResponse.parseFrom(bytes);
|
||||||
|
|||||||
@@ -59,22 +59,29 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String get(String url) {
|
public String get(String url) {
|
||||||
var uri = URI.create(url);
|
var uri = URI.create(url);
|
||||||
var request = HttpRequest.newBuilder().GET();
|
var requestBuilder = HttpRequest.newBuilder().GET();
|
||||||
|
|
||||||
for (var header : defaultHeaders.entrySet())
|
for (var header : defaultHeaders.entrySet())
|
||||||
{
|
{
|
||||||
if(header.getKey().equals("Connection") || header.getKey().equals("Accept-Encoding"))
|
if(header.getKey().equals("Connection") || header.getKey().equals("Accept-Encoding"))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
request.setHeader(header.getKey(), header.getValue());
|
requestBuilder.setHeader(header.getKey(), header.getValue());
|
||||||
}
|
}
|
||||||
if (query != null) {
|
if (query != null) {
|
||||||
var baseUri = uri.toString();
|
var baseUri = uri.toString();
|
||||||
var requestUri = URI.create(baseUri + "?" + query);
|
var requestUri = URI.create(baseUri + "?" + query);
|
||||||
request.uri(requestUri);
|
requestBuilder.uri(requestUri);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
requestBuilder.uri(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getContent(request.build());
|
var result = requestBuilder.build();
|
||||||
|
|
||||||
|
return getContent(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
|
|||||||
@@ -22,9 +22,15 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.mappers;
|
package io.github.jwdeveloper.tiktok.mappers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.users.User;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.users.UserAttribute;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
|
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class LiveRoomMetaMapper {
|
public class LiveRoomMetaMapper {
|
||||||
/**
|
/**
|
||||||
* 0 - Unknown
|
* 0 - Unknown
|
||||||
@@ -46,15 +52,12 @@ public class LiveRoomMetaMapper {
|
|||||||
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 0 -> LiveRoomMeta.LiveRoomStatus.HostNotFound;
|
|
||||||
case 2 -> LiveRoomMeta.LiveRoomStatus.HostOnline;
|
case 2 -> LiveRoomMeta.LiveRoomStatus.HostOnline;
|
||||||
case 4 -> LiveRoomMeta.LiveRoomStatus.HostOffline;
|
case 4 -> LiveRoomMeta.LiveRoomStatus.HostOffline;
|
||||||
default-> LiveRoomMeta.LiveRoomStatus.HostNotFound;
|
default -> LiveRoomMeta.LiveRoomStatus.HostNotFound;
|
||||||
};
|
};
|
||||||
liveRoomMeta.setStatus(statusValue);
|
liveRoomMeta.setStatus(statusValue);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
liveRoomMeta.setStatus(LiveRoomMeta.LiveRoomStatus.HostNotFound);
|
liveRoomMeta.setStatus(LiveRoomMeta.LiveRoomStatus.HostNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +66,61 @@ public class LiveRoomMetaMapper {
|
|||||||
var restricted = element.get("restricted").getAsBoolean();
|
var restricted = element.get("restricted").getAsBoolean();
|
||||||
liveRoomMeta.setAgeRestricted(restricted);
|
liveRoomMeta.setAgeRestricted(restricted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.has("title")) {
|
||||||
|
var element = data.get("title");
|
||||||
|
var title = element.getAsString();
|
||||||
|
liveRoomMeta.setTitie(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.has("stats")) {
|
||||||
|
var statsElement = data.getAsJsonObject("stats");
|
||||||
|
var likeElement = statsElement.get("like_count");
|
||||||
|
var likes = likeElement.getAsInt();
|
||||||
|
|
||||||
|
var titalUsersElement = statsElement.get("total_user");
|
||||||
|
var totalUsers = titalUsersElement.getAsInt();
|
||||||
|
|
||||||
|
|
||||||
|
liveRoomMeta.setLikeCount(likes);
|
||||||
|
liveRoomMeta.setTotalViewers(totalUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.has("user_count"))
|
||||||
|
{
|
||||||
|
var element = data.get("user_count");
|
||||||
|
var viewers = element.getAsInt();
|
||||||
|
liveRoomMeta.setViewers(viewers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.has("owner"))
|
||||||
|
{
|
||||||
|
var element = data.getAsJsonObject("owner");
|
||||||
|
var user = getUser(element);
|
||||||
|
liveRoomMeta.setHost(user);
|
||||||
|
}
|
||||||
|
|
||||||
return liveRoomMeta;
|
return liveRoomMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public User getUser(JsonObject jsonElement)
|
||||||
|
{
|
||||||
|
var id = jsonElement.get("id").getAsLong();
|
||||||
|
var name = jsonElement.get("display_id").getAsString();
|
||||||
|
var profileName = jsonElement.get("nickname").getAsString();
|
||||||
|
|
||||||
|
|
||||||
|
var followElement =jsonElement.getAsJsonObject("follow_info");
|
||||||
|
var followers = followElement.get("follower_count").getAsInt();
|
||||||
|
var followingCount = followElement.get("following_count").getAsInt();
|
||||||
|
|
||||||
|
|
||||||
|
var pictureElement =jsonElement.getAsJsonObject("avatar_large");
|
||||||
|
var link = pictureElement.getAsJsonArray("url_list").get(1).getAsString();
|
||||||
|
var picture = new Picture(link);
|
||||||
|
|
||||||
|
var user = new User(id,name,profileName,picture,followers,followingCount,new ArrayList<>());
|
||||||
|
user.addAttribute(UserAttribute.LiveHost);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,10 +74,7 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (clientSettings.isHandleExistingEvents()) {
|
|
||||||
logger.info("Handling existing events");
|
|
||||||
webResponseHandler.handle(tikTokLiveClient, webcastResponse);
|
webResponseHandler.handle(tikTokLiveClient, webcastResponse);
|
||||||
}
|
|
||||||
var url = getWebSocketUrl(webcastResponse);
|
var url = getWebSocketUrl(webcastResponse);
|
||||||
webSocketClient = startWebSocket(url, tikTokLiveClient);
|
webSocketClient = startWebSocket(url, tikTokLiveClient);
|
||||||
webSocketClient.connect();
|
webSocketClient.connect();
|
||||||
@@ -85,7 +82,8 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
pingingTask = new TikTokWebSocketPingingTask();
|
pingingTask = new TikTokWebSocketPingingTask();
|
||||||
pingingTask.run(webSocketClient);
|
pingingTask.run(webSocketClient);
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e)
|
||||||
|
{
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
throw new TikTokLiveException("Failed to connect to the websocket", e);
|
throw new TikTokLiveException("Failed to connect to the websocket", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public class TikTokGiftManagerTest {
|
|||||||
var gifts = giftManager.getGifts();
|
var gifts = giftManager.getGifts();
|
||||||
var optional = gifts.stream().filter(r -> r == fakeGift).findFirst();
|
var optional = gifts.stream().filter(r -> r == fakeGift).findFirst();
|
||||||
Assertions.assertTrue(optional.isPresent());
|
Assertions.assertTrue(optional.isPresent());
|
||||||
|
// Assertions.assertNotNull(optional.get().name());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.github.jwdeveloper.tiktok.handlers.events;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftSendType;
|
||||||
|
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.data.GiftStruct;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.data.Image;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.data.User;
|
||||||
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.TestInstance;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
class TikTokGiftEventHandlerTest {
|
||||||
|
|
||||||
|
public static TikTokGiftEventHandler handler;
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public void before() {
|
||||||
|
var manager = new TikTokGiftManager(Logger.getLogger("x"));
|
||||||
|
manager.registerGift(123, "example", 123, new Picture("image.webp"));
|
||||||
|
handler = new TikTokGiftEventHandler(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldHandleGifts() {
|
||||||
|
var message = getGiftMessage("example-new-name", 123, "image-new.png", 0, 1,false);
|
||||||
|
var result = handler.handleGift(message);
|
||||||
|
|
||||||
|
Assertions.assertEquals(2, result.size());
|
||||||
|
|
||||||
|
var event = (TikTokGiftEvent) result.get(0);
|
||||||
|
var gift = event.getGift();
|
||||||
|
Assertions.assertEquals("image-new.png",gift.getPicture().getLink());
|
||||||
|
Assertions.assertEquals(123,gift.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldHandleStrakableGift() {
|
||||||
|
var message = getGiftMessage("example-new-name", 123, "image-new.png", 0, 1,true);
|
||||||
|
var result = handler.handleGift(message);
|
||||||
|
|
||||||
|
Assertions.assertEquals(1, result.size());
|
||||||
|
|
||||||
|
var event = (TikTokGiftEvent) result.get(0);
|
||||||
|
var gift = event.getGift();
|
||||||
|
Assertions.assertEquals("image-new.png",gift.getPicture().getLink());
|
||||||
|
Assertions.assertEquals(123,gift.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldHandleStrike()
|
||||||
|
{
|
||||||
|
var message1 = getGiftMessage("example-new-name", 123, "image-new.png", 1, 1,true);
|
||||||
|
var message2 = getGiftMessage("example-new-name", 123, "image-new.png", 2, 1,true);
|
||||||
|
var message3 = getGiftMessage("example-new-name", 123, "image-new.png", 0, 1,true);
|
||||||
|
|
||||||
|
var result1 = handler.handleGift(message1);
|
||||||
|
var result2 = handler.handleGift(message2);
|
||||||
|
var result3 = handler.handleGift(message3);
|
||||||
|
|
||||||
|
var event1 = (TikTokGiftComboEvent) result1.get(0);
|
||||||
|
var event2 = (TikTokGiftComboEvent) result2.get(0);
|
||||||
|
|
||||||
|
Assertions.assertEquals(2, result3.size());
|
||||||
|
var event3 = (TikTokGiftComboEvent) result3.get(0);
|
||||||
|
|
||||||
|
Assertions.assertEquals(GiftSendType.Begin,event1.getComboState());
|
||||||
|
Assertions.assertEquals(GiftSendType.Active,event2.getComboState());
|
||||||
|
Assertions.assertEquals(GiftSendType.Finished,event3.getComboState());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public WebcastGiftMessage getGiftMessage(String giftName,
|
||||||
|
int giftId,
|
||||||
|
String giftImage,
|
||||||
|
int sendType,
|
||||||
|
int userId,
|
||||||
|
boolean streakable) {
|
||||||
|
var builder = WebcastGiftMessage.newBuilder();
|
||||||
|
var giftBuilder = GiftStruct.newBuilder();
|
||||||
|
var userBuilder = User.newBuilder();
|
||||||
|
|
||||||
|
|
||||||
|
giftBuilder.setId(giftId);
|
||||||
|
giftBuilder.setName(giftName);
|
||||||
|
giftBuilder.setImage(Image.newBuilder().addUrlList(giftImage).build());
|
||||||
|
giftBuilder.setType(streakable?1:0);
|
||||||
|
userBuilder.setId(userId);
|
||||||
|
|
||||||
|
builder.setGiftId(giftId);
|
||||||
|
builder.setUser(userBuilder);
|
||||||
|
builder.setSendType(sendType);
|
||||||
|
builder.setGift(giftBuilder);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -84,23 +84,8 @@ public class TikTokApiServiceTest
|
|||||||
verify(tiktokHttpClient, times(1)).setSessionId("validSessionId");
|
verify(tiktokHttpClient, times(1)).setSessionId("validSessionId");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void sendMessage_EmptySessionId_ThrowsException() {
|
|
||||||
assertThrows(TikTokLiveException.class, () -> {
|
|
||||||
tikTokApiService.sendMessage("some message", "");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
// @Test
|
||||||
void sendMessage_NullRoomId_ThrowsException() {
|
|
||||||
when(clientSettings.getClientParameters()).thenReturn(new HashMap<>());
|
|
||||||
|
|
||||||
assertThrows(TikTokLiveException.class, () -> {
|
|
||||||
tikTokApiService.sendMessage("some message", "someSessionId");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void fetchRoomId_ValidResponse_ReturnsRoomId() throws Exception {
|
void fetchRoomId_ValidResponse_ReturnsRoomId() throws Exception {
|
||||||
String expectedRoomId = "123456";
|
String expectedRoomId = "123456";
|
||||||
String htmlResponse = "room_id=" + expectedRoomId ;
|
String htmlResponse = "room_id=" + expectedRoomId ;
|
||||||
@@ -112,7 +97,7 @@ public class TikTokApiServiceTest
|
|||||||
verify(clientSettings.getClientParameters()).put("room_id", expectedRoomId);
|
verify(clientSettings.getClientParameters()).put("room_id", expectedRoomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
// @Test
|
||||||
void fetchRoomId_ExceptionThrown_ThrowsTikTokLiveRequestException() throws Exception {
|
void fetchRoomId_ExceptionThrown_ThrowsTikTokLiveRequestException() throws Exception {
|
||||||
when(tiktokHttpClient.getLivestreamPage(anyString())).thenThrow(new Exception("some exception"));
|
when(tiktokHttpClient.getLivestreamPage(anyString())).thenThrow(new Exception("some exception"));
|
||||||
|
|
||||||
@@ -121,14 +106,14 @@ public class TikTokApiServiceTest
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
//@Test
|
||||||
void fetchRoomInfo_ValidResponse_ReturnsLiveRoomMeta() throws Exception {
|
void fetchRoomInfo_ValidResponse_ReturnsLiveRoomMeta() throws Exception {
|
||||||
HashMap<String, Object> clientParameters = new HashMap<>();
|
HashMap<String, Object> clientParameters = new HashMap<>();
|
||||||
var mockResponse = new JsonObject(); // Assume JsonObject is from the Gson library
|
var mockResponse = new JsonObject(); // Assume JsonObject is from the Gson library
|
||||||
var expectedLiveRoomMeta = new LiveRoomMeta(); // Assume LiveRoomMeta is a simple POJO
|
var expectedLiveRoomMeta = new LiveRoomMeta(); // Assume LiveRoomMeta is a simple POJO
|
||||||
|
|
||||||
when(clientSettings.getClientParameters()).thenReturn(clientParameters);
|
when(clientSettings.getClientParameters()).thenReturn(clientParameters);
|
||||||
when(tiktokHttpClient.getJObjectFromWebcastAPI(anyString(), any())).thenReturn(mockResponse);
|
when(tiktokHttpClient.getJsonFromWebcastApi(anyString(), any())).thenReturn(mockResponse);
|
||||||
when(new LiveRoomMetaMapper().map(mockResponse)).thenReturn(expectedLiveRoomMeta); // Assuming LiveRoomMetaMapper is a simple mapper class
|
when(new LiveRoomMetaMapper().map(mockResponse)).thenReturn(expectedLiveRoomMeta); // Assuming LiveRoomMetaMapper is a simple mapper class
|
||||||
|
|
||||||
LiveRoomMeta liveRoomMeta = tikTokApiService.fetchRoomInfo();
|
LiveRoomMeta liveRoomMeta = tikTokApiService.fetchRoomInfo();
|
||||||
@@ -136,9 +121,9 @@ public class TikTokApiServiceTest
|
|||||||
assertEquals(expectedLiveRoomMeta, liveRoomMeta);
|
assertEquals(expectedLiveRoomMeta, liveRoomMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
// @Test
|
||||||
void fetchRoomInfo_ExceptionThrown_ThrowsTikTokLiveRequestException() throws Exception {
|
void fetchRoomInfo_ExceptionThrown_ThrowsTikTokLiveRequestException() throws Exception {
|
||||||
when(tiktokHttpClient.getJObjectFromWebcastAPI(anyString(), any())).thenThrow(new Exception("some exception"));
|
when(tiktokHttpClient.getJsonFromWebcastApi(anyString(), any())).thenThrow(new Exception("some exception"));
|
||||||
|
|
||||||
assertThrows(TikTokLiveRequestException.class, () -> {
|
assertThrows(TikTokLiveRequestException.class, () -> {
|
||||||
tikTokApiService.fetchRoomInfo();
|
tikTokApiService.fetchRoomInfo();
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.http;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class TikTokLiveOnlineCheckerTest {
|
||||||
|
|
||||||
|
private final String TARGET_USER = "bangbetmenygy";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldTestOnline() {
|
||||||
|
var sut = new TikTokDataChecker();
|
||||||
|
var result = sut.isOnline(TARGET_USER);
|
||||||
|
|
||||||
|
Assertions.assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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>0.0.25-Release</version>
|
<version>1.0.4-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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 io.github.jwdeveloper.tiktok.data.models.Picture;
|
||||||
|
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
||||||
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
|
|
||||||
|
public class CustomGiftExample {
|
||||||
|
/**
|
||||||
|
* If you can't find your wanted Gift inside Gift enum register it manually
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
LiveClient client = TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
|
||||||
|
.onConnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
liveClient.disconnect();
|
||||||
|
})
|
||||||
|
|
||||||
|
.onGift((liveClient, event) ->
|
||||||
|
{
|
||||||
|
liveClient.getLogger().info(event.getGift().getName());
|
||||||
|
}).build();
|
||||||
|
|
||||||
|
GiftManager giftManager = client.getGiftManager();
|
||||||
|
|
||||||
|
//If you can't find your wanted Gift inside Gift enum register it manually
|
||||||
|
giftManager.registerGift(123, "my custom gift", 69, new Picture("https://as2.ftcdn.net/v2/jpg/03/03/62/45/1000_F_303624505_u0bFT1Rnoj8CMUSs8wMCwoKlnWlh5Jiq.jpg"));
|
||||||
|
|
||||||
|
|
||||||
|
//You can also override existing gift, for example Rose has Id 5655
|
||||||
|
//We can make our custom gift appear in the event instead of rose
|
||||||
|
giftManager.registerGift(5655, "custom-rose", 999, new Picture("https://as2.ftcdn.net/v2/jpg/03/03/62/45/1000_F_303624505_u0bFT1Rnoj8CMUSs8wMCwoKlnWlh5Jiq.jpg"));
|
||||||
|
|
||||||
|
client.connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok;
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
|
||||||
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -30,11 +31,26 @@ import java.util.logging.Level;
|
|||||||
|
|
||||||
public class SimpleExample
|
public class SimpleExample
|
||||||
{
|
{
|
||||||
public static String TIKTOK_HOSTNAME = "szwagierkaqueen";
|
public static String TIKTOK_HOSTNAME = "bangbetmenygy";
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
|
|
||||||
showLogo();
|
showLogo();
|
||||||
// set tiktok username
|
// set tiktok username
|
||||||
|
|
||||||
|
/*
|
||||||
|
Optional checking if host name is correct
|
||||||
|
if(TikTokLive.isHostNameValid(TIKTOK_HOSTNAME))
|
||||||
|
{
|
||||||
|
System.out.println("Live is online!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional checking if live is online
|
||||||
|
if(TikTokLive.isLiveOnline(TIKTOK_HOSTNAME))
|
||||||
|
{
|
||||||
|
System.out.println("Live is online!");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
|
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
|
||||||
.configure(clientSettings ->
|
.configure(clientSettings ->
|
||||||
{
|
{
|
||||||
@@ -43,7 +59,6 @@ public class SimpleExample
|
|||||||
clientSettings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
|
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.setHandleExistingEvents(true); // Invokes all TikTok events that had occurred before connection
|
|
||||||
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
|
||||||
|
|
||||||
@@ -79,6 +94,10 @@ public class SimpleExample
|
|||||||
{
|
{
|
||||||
print(ConsoleColors.RED,"[Disconnected]");
|
print(ConsoleColors.RED,"[Disconnected]");
|
||||||
})
|
})
|
||||||
|
.onRoomInfo((liveClient, event) ->
|
||||||
|
{
|
||||||
|
var info = event.getRoomInfo();
|
||||||
|
})
|
||||||
.onFollow((liveClient, event) ->
|
.onFollow((liveClient, event) ->
|
||||||
{
|
{
|
||||||
print(ConsoleColors.BLUE, "Follow:", ConsoleColors.WHITE_BRIGHT, event.getUser().getName());
|
print(ConsoleColors.BLUE, "Follow:", ConsoleColors.WHITE_BRIGHT, event.getUser().getName());
|
||||||
|
|||||||
Binary file not shown.
583
README.md
583
README.md
@@ -29,10 +29,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
A Java library inspired by [TikTokLive](https://github.com/isaackogan/TikTokLive) and [TikTokLiveSharp](https://github.com/sebheron/TikTokLiveSharp). Use it to receive live stream events such as comments and gifts in realtime from [TikTok LIVE](https://www.tiktok.com/live) by connecting to TikTok's internal WebCast push service.
|
A Java library inspired by [TikTokLive](https://github.com/isaackogan/TikTokLive) and [TikTokLiveSharp](https://github.com/frankvHoof93/TikTokLiveSharp). Use it to receive live stream events such as comments and gifts in realtime from [TikTok LIVE](https://www.tiktok.com/live) by connecting to TikTok's internal WebCast push service.
|
||||||
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
|
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
|
||||||
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
|
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.youtube.com/watch?v=eerWGgUKc6c" align="right" target="blank"><img src="https://img.youtube.com/vi/eerWGgUKc6c/hqdefault.jpg" alt="IMAGE ALT TEXT" width="38%" align="right"></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
Join the support [discord](https://discord.gg/e2XwPNTBBr) and visit the `#java-support` channel for questions, contributions and ideas. Feel free to make pull requests with missing/new features, fixes, etc
|
Join the support [discord](https://discord.gg/e2XwPNTBBr) and visit the `#java-support` channel for questions, contributions and ideas. Feel free to make pull requests with missing/new features, fixes, etc
|
||||||
|
|
||||||
Do you prefer other programming languages?
|
Do you prefer other programming languages?
|
||||||
@@ -65,7 +69,7 @@ Do you prefer other programming languages?
|
|||||||
<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.0</version>
|
<version>1.0.5-Release</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -91,6 +95,13 @@ TikTokLive.newClient("bangbetmenygy")
|
|||||||
{
|
{
|
||||||
System.out.println(event.getComboState()+ " " + event.getCombo() + " " + event.getGift().getName());
|
System.out.println(event.getComboState()+ " " + event.getCombo() + " " + event.getGift().getName());
|
||||||
})
|
})
|
||||||
|
.onRoomInfo((liveClient, event) ->
|
||||||
|
{
|
||||||
|
var roomInfo = event.getRoomInfo();
|
||||||
|
System.out.println("Room Id: "+roomInfo.getRoomId());
|
||||||
|
System.out.println("Likes: "+roomInfo.getLikesCount());
|
||||||
|
System.out.println("Viewers: "+roomInfo.getViewersCount());
|
||||||
|
})
|
||||||
.onJoin((liveClient, event) ->
|
.onJoin((liveClient, event) ->
|
||||||
{
|
{
|
||||||
System.out.println(event.getUser().getProfileName() + "Hello on my stream! ");
|
System.out.println(event.getUser().getProfileName() + "Hello on my stream! ");
|
||||||
@@ -118,7 +129,6 @@ TikTokLive.newClient("bangbetmenygy")
|
|||||||
settings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
|
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.setHandleExistingEvents(true); // Invokes all TikTok events that had occurred before connection
|
|
||||||
settings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
|
settings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
|
||||||
settings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
|
settings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
|
||||||
|
|
||||||
@@ -140,36 +150,35 @@ TikTokLive.newClient("bangbetmenygy")
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Control**:
|
**Control**:
|
||||||
|
|
||||||
- [onConnected](#onconnected-tiktokconnectedevent)
|
- [onConnected](#onconnected-tiktokconnectedevent)
|
||||||
- [onReconnecting](#onreconnecting-tiktokreconnectingevent)
|
|
||||||
- [onDisconnected](#ondisconnected-tiktokdisconnectedevent)
|
- [onDisconnected](#ondisconnected-tiktokdisconnectedevent)
|
||||||
|
- [onReconnecting](#onreconnecting-tiktokreconnectingevent)
|
||||||
- [onError](#onerror-tiktokerrorevent)
|
- [onError](#onerror-tiktokerrorevent)
|
||||||
|
|
||||||
**Message**:
|
**Message**:
|
||||||
|
|
||||||
- [onEvent](#onevent-tiktokevent)
|
- [onEvent](#onevent-tiktokevent)
|
||||||
- [onShare](#onshare-tiktokshareevent)
|
|
||||||
- [onLivePaused](#onlivepaused-tiktoklivepausedevent)
|
|
||||||
- [onRoom](#onroom-tiktokroomevent)
|
|
||||||
- [onGiftCombo](#ongiftcombo-tiktokgiftcomboevent)
|
|
||||||
- [onJoin](#onjoin-tiktokjoinevent)
|
|
||||||
- [onRoomUserInfo](#onroomuserinfo-tiktokroomuserinfoevent)
|
|
||||||
- [onComment](#oncomment-tiktokcommentevent)
|
|
||||||
- [onGift](#ongift-tiktokgiftevent)
|
|
||||||
- [onLike](#onlike-tiktoklikeevent)
|
|
||||||
- [onSubscribe](#onsubscribe-tiktoksubscribeevent)
|
- [onSubscribe](#onsubscribe-tiktoksubscribeevent)
|
||||||
- [onQuestion](#onquestion-tiktokquestionevent)
|
- [onQuestion](#onquestion-tiktokquestionevent)
|
||||||
- [onEmote](#onemote-tiktokemoteevent)
|
|
||||||
- [onLiveEnded](#onliveended-tiktokliveendedevent)
|
|
||||||
- [onFollow](#onfollow-tiktokfollowevent)
|
- [onFollow](#onfollow-tiktokfollowevent)
|
||||||
- [onUnhandledSocial](#onunhandledsocial-tiktokunhandledsocialevent)
|
- [onLike](#onlike-tiktoklikeevent)
|
||||||
|
- [onLiveEnded](#onliveended-tiktokliveendedevent)
|
||||||
|
- [onRoomInfo](#onroominfo-tiktokroominfoevent)
|
||||||
|
- [onShare](#onshare-tiktokshareevent)
|
||||||
|
- [onGiftCombo](#ongiftcombo-tiktokgiftcomboevent)
|
||||||
|
- [onEmote](#onemote-tiktokemoteevent)
|
||||||
|
- [onGift](#ongift-tiktokgiftevent)
|
||||||
|
- [onComment](#oncomment-tiktokcommentevent)
|
||||||
|
- [onLivePaused](#onlivepaused-tiktoklivepausedevent)
|
||||||
|
- [onLiveUnpaused](#onliveunpaused-tiktokliveunpausedevent)
|
||||||
|
- [onJoin](#onjoin-tiktokjoinevent)
|
||||||
|
|
||||||
**Debug**:
|
**Debug**:
|
||||||
|
|
||||||
- [onWebsocketResponse](#onwebsocketresponse-tiktokwebsocketresponseevent)
|
|
||||||
- [onWebsocketUnhandledMessage](#onwebsocketunhandledmessage-tiktokwebsocketunhandledmessageevent)
|
- [onWebsocketUnhandledMessage](#onwebsocketunhandledmessage-tiktokwebsocketunhandledmessageevent)
|
||||||
|
- [onWebsocketResponse](#onwebsocketresponse-tiktokwebsocketresponseevent)
|
||||||
- [onWebsocketMessage](#onwebsocketmessage-tiktokwebsocketmessageevent)
|
- [onWebsocketMessage](#onwebsocketmessage-tiktokwebsocketmessageevent)
|
||||||
# Examples
|
# Examples
|
||||||
<br>
|
<br>
|
||||||
@@ -177,7 +186,7 @@ TikTokLive.newClient("bangbetmenygy")
|
|||||||
## onConnected [TikTokConnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokConnectedEvent.java)
|
## onConnected [TikTokConnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokConnectedEvent.java)
|
||||||
|
|
||||||
|
|
||||||
Triggered when the connection is successfully established.
|
Triggered when the connection is successfully established.
|
||||||
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@@ -191,6 +200,26 @@ TikTokLive.newClient("host-name")
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onDisconnected [TikTokDisconnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokDisconnectedEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic.
|
||||||
|
Note that you should wait a little bit before attempting a reconnect to to avoid being rate-limited.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onDisconnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## onReconnecting [TikTokReconnectingEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokReconnectingEvent.java)
|
## onReconnecting [TikTokReconnectingEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokReconnectingEvent.java)
|
||||||
@@ -208,32 +237,12 @@ TikTokLive.newClient("host-name")
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onDisconnected [TikTokDisconnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokDisconnectedEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic.
|
|
||||||
Note that you should wait a little bit before attempting a reconnect to to avoid being rate-limited.
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onDisconnected((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## onError [TikTokErrorEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokErrorEvent.java)
|
## onError [TikTokErrorEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokErrorEvent.java)
|
||||||
|
|
||||||
|
|
||||||
General error event. You should handle this.
|
General error event. You should handle this.
|
||||||
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@@ -252,7 +261,7 @@ TikTokLive.newClient("host-name")
|
|||||||
## onEvent [TikTokEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/common/TikTokEvent.java)
|
## onEvent [TikTokEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/common/TikTokEvent.java)
|
||||||
|
|
||||||
|
|
||||||
Base class for all events
|
Base class for all events
|
||||||
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@@ -266,190 +275,12 @@ TikTokLive.newClient("host-name")
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onShare [TikTokShareEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokShareEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
Triggers when a user shares the stream. Based on social event.
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onShare((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onLivePaused [TikTokLivePausedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLivePausedEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onLivePaused((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onRoom [TikTokRoomEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/room/TikTokRoomEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onRoom((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onGiftCombo [TikTokGiftComboEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftComboEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
Triggered every time gift is sent
|
|
||||||
|
|
||||||
@see GiftSendType it has 3 states
|
|
||||||
|
|
||||||
<p>Example when user sends gift with combo</p>
|
|
||||||
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
|
|
||||||
<p>Combo: 4 -> comboState = GiftSendType.Active</p>
|
|
||||||
<p>Combo: 8 -> comboState = GiftSendType.Active</p>
|
|
||||||
<p>Combo: 12 -> comboState = GiftSendType.Finsihed</p>
|
|
||||||
|
|
||||||
Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onGiftCombo((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onJoin [TikTokJoinEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokJoinEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onJoin((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onRoomUserInfo [TikTokRoomUserInfoEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/room/TikTokRoomUserInfoEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
Only top 5 users in ranking has detailed data
|
|
||||||
rest has only ID
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onRoomUserInfo((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onComment [TikTokCommentEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokCommentEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
Triggered every time a new chat comment arrives.
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onComment((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onGift [TikTokGiftEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
Triggered when user sends gifts that has
|
|
||||||
no combo (most of expensive gifts)
|
|
||||||
or if combo has finished
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onGift((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onLike [TikTokLikeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokLikeEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onLike((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## onSubscribe [TikTokSubscribeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokSubscribeEvent.java)
|
## onSubscribe [TikTokSubscribeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokSubscribeEvent.java)
|
||||||
|
|
||||||
|
|
||||||
Triggers when a user creates a subscription.
|
Triggers when a user creates a subscription.
|
||||||
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@@ -482,50 +313,12 @@ TikTokLive.newClient("host-name")
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onEmote [TikTokEmoteEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokEmoteEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
Triggered every time a subscriber sends an emote (sticker).
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onEmote((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onLiveEnded [TikTokLiveEndedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLiveEndedEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
Triggered when the live stream gets terminated by the host. Will also trigger the TikTokDisconnectedEvent event.
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onLiveEnded((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## onFollow [TikTokFollowEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokFollowEvent.java)
|
## onFollow [TikTokFollowEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokFollowEvent.java)
|
||||||
|
|
||||||
|
|
||||||
Triggers when a user follows the streamer. Based on social event.
|
Triggers when a user follows the streamer. Based on social event.
|
||||||
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@@ -541,13 +334,228 @@ TikTokLive.newClient("host-name")
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## onUnhandledSocial [TikTokUnhandledSocialEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokUnhandledSocialEvent.java)
|
## onLike [TikTokLikeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokLikeEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onLike((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onLiveEnded [TikTokLiveEndedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLiveEndedEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered when the live stream gets terminated by the host. Will also trigger the TikTokDisconnectedEvent event.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onLiveEnded((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onRoomInfo [TikTokRoomInfoEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/room/TikTokRoomInfoEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
TikTokLive.newClient("host-name")
|
TikTokLive.newClient("host-name")
|
||||||
.onUnhandledSocial((liveClient, event) ->
|
.onRoomInfo((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onShare [TikTokShareEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokShareEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggers when a user shares the stream. Based on social event.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onShare((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onGiftCombo [TikTokGiftComboEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftComboEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered every time gift is sent
|
||||||
|
|
||||||
|
@see GiftSendType it has 3 states
|
||||||
|
|
||||||
|
<p>Example when user sends gift with combo</p>
|
||||||
|
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
|
||||||
|
<p>Combo: 4 -> comboState = GiftSendType.Active</p>
|
||||||
|
<p>Combo: 8 -> comboState = GiftSendType.Active</p>
|
||||||
|
<p>Combo: 12 -> comboState = GiftSendType.Finsihed</p>
|
||||||
|
|
||||||
|
Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onGiftCombo((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onEmote [TikTokEmoteEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokEmoteEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered every time a subscriber sends an emote (sticker).
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onEmote((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onGift [TikTokGiftEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered when user sends gifts that has
|
||||||
|
no combo (most of expensive gifts)
|
||||||
|
or if combo has finished
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onGift((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onComment [TikTokCommentEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokCommentEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered every time a new chat comment arrives.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onComment((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onLivePaused [TikTokLivePausedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLivePausedEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onLivePaused((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onLiveUnpaused [TikTokLiveUnpausedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLiveUnpausedEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onLiveUnpaused((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onJoin [TikTokJoinEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokJoinEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onJoin((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onWebsocketUnhandledMessage [TikTokWebsocketUnhandledMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketUnhandledMessageEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onWebsocketUnhandledMessage((liveClient, event) ->
|
||||||
{
|
{
|
||||||
|
|
||||||
})
|
})
|
||||||
@@ -564,30 +572,11 @@ TikTokLive.newClient("host-name")
|
|||||||
|
|
||||||
```java
|
```java
|
||||||
TikTokLive.newClient("host-name")
|
TikTokLive.newClient("host-name")
|
||||||
.onWebsocketResponse((liveClient, event) ->
|
.onWebsocketResponse((liveClient, event) ->
|
||||||
{
|
{
|
||||||
|
|
||||||
})
|
})
|
||||||
.buildAndConnect();
|
.buildAndConnect();
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## onWebsocketUnhandledMessage [TikTokWebsocketUnhandledMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketUnhandledMessageEvent.java)
|
|
||||||
|
|
||||||
|
|
||||||
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
|
|
||||||
|
|
||||||
|
|
||||||
```java
|
|
||||||
TikTokLive.newClient("host-name")
|
|
||||||
.onWebsocketUnhandledMessage((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
.buildAndConnect();
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -597,16 +586,16 @@ TikTokLive.newClient("host-name")
|
|||||||
## onWebsocketMessage [TikTokWebsocketMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketMessageEvent.java)
|
## onWebsocketMessage [TikTokWebsocketMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketMessageEvent.java)
|
||||||
|
|
||||||
|
|
||||||
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
|
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
|
||||||
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
TikTokLive.newClient("host-name")
|
TikTokLive.newClient("host-name")
|
||||||
.onWebsocketMessage((liveClient, event) ->
|
.onWebsocketMessage((liveClient, event) ->
|
||||||
{
|
{
|
||||||
|
|
||||||
})
|
})
|
||||||
.buildAndConnect();
|
.buildAndConnect();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -619,14 +608,14 @@ TikTokLive.newClient("host-name")
|
|||||||
|
|
||||||
```java
|
```java
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Listeners are an alternative way of handling events.
|
* Listeners are an alternative way of handling events.
|
||||||
* I would to suggest to use then when logic of handing event
|
* I would to suggest to use then when logic of handing event
|
||||||
* is more complex
|
* is more complex
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
showLogo();
|
showLogo();
|
||||||
CustomListener customListener = new CustomListener();
|
CustomListener customListener = new CustomListener();
|
||||||
|
|
||||||
@@ -636,7 +625,7 @@ TikTokLive.newClient("host-name")
|
|||||||
System.in.read();
|
System.in.read();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Method in TikTokEventListener should meet 4 requirements to be detected
|
* Method in TikTokEventListener should meet 4 requirements to be detected
|
||||||
* - must have @TikTokEventHandler annotation
|
* - must have @TikTokEventHandler annotation
|
||||||
@@ -645,7 +634,7 @@ TikTokLive.newClient("host-name")
|
|||||||
* - second must be class that extending TikTokEvent
|
* - second must be class that extending TikTokEvent
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static class CustomListener implements TikTokEventListener {
|
public static class CustomListener implements TikTokEventListener {
|
||||||
|
|
||||||
@TikTokEventHandler
|
@TikTokEventHandler
|
||||||
public void onLike(LiveClient liveClient, TikTokLikeEvent event) {
|
public void onLike(LiveClient liveClient, TikTokLikeEvent event) {
|
||||||
@@ -682,9 +671,9 @@ TikTokLive.newClient("host-name")
|
|||||||
liveClient.getLogger().info(event.getClass().getSimpleName());
|
liveClient.getLogger().info(event.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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>0.0.25-Release</version>
|
<version>1.0.4-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@@ -29,6 +29,11 @@
|
|||||||
<artifactId>jdbi3-core</artifactId>
|
<artifactId>jdbi3-core</artifactId>
|
||||||
<version>3.23.0</version>
|
<version>3.23.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.protobuf-java-format</groupId>
|
||||||
|
<artifactId>protobuf-java-format</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jdbi</groupId>
|
<groupId>org.jdbi</groupId>
|
||||||
<artifactId>jdbi3-sqlobject</artifactId>
|
<artifactId>jdbi3-sqlobject</artifactId>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import io.github.jwdeveloper.tiktok.tools.collector.client.TikTokMessageCollecto
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class RunCollector {
|
public class RunCollector {
|
||||||
|
|
||||||
@@ -38,39 +39,39 @@ public class RunCollector {
|
|||||||
public static void main(String[] args) throws SQLException, IOException {
|
public static void main(String[] args) throws SQLException, IOException {
|
||||||
|
|
||||||
TikTokMessageCollectorClient.create("giftsCollector")
|
TikTokMessageCollectorClient.create("giftsCollector")
|
||||||
.addUser("cbcgod")
|
//.addUser("crece.sara")
|
||||||
// .addUser("mr_cios")
|
//.addUser("moniczkka")
|
||||||
|
.addUser("valeria.viral")
|
||||||
// .addUser("cbcgod")
|
// .addUser("cbcgod")
|
||||||
// .addUser("psychotropnazywo")
|
// .addUser("psychotropnazywo")
|
||||||
// .addUser("accordionistka")
|
// .addUser("accordionistka")
|
||||||
.addEventFilter(WebcastGiftMessage.class)
|
//.addEventFilter(WebcastGiftMessage.class)
|
||||||
.addOnBuilder(liveClientBuilder ->
|
.addOnBuilder(liveClientBuilder ->
|
||||||
{
|
{
|
||||||
liveClientBuilder.onGift((liveClient, event) ->
|
|
||||||
{
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
liveClientBuilder.onGiftCombo((liveClient, event) ->
|
liveClientBuilder.onGiftCombo((liveClient, event) ->
|
||||||
{
|
{
|
||||||
|
liveClient.getLogger().setLevel(Level.OFF);
|
||||||
|
var gifts = liveClient.getGiftManager().getGifts();
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
liveClientBuilder.onGift((liveClient, event) ->
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.append("GIFT User: " + event.getUser().getProfileName()+" ");
|
sb.append("GIFT COMBO User: " + event.getUser().getProfileName()+" ");
|
||||||
sb.append("Name: " + event.getGift().name() + " ");
|
sb.append("Name: " + event.getGift().getName() + " ");
|
||||||
sb.append("Combo: " + event.getCombo() + " ");
|
sb.append("Combo: " + event.getCombo() + " ");
|
||||||
|
sb.append("COST: " + event.getGift().getDiamondCost() + " ");
|
||||||
|
sb.append("STATE: " + event.getComboState() + " ");
|
||||||
System.out.println(sb.toString());
|
System.out.println(sb.toString());
|
||||||
});
|
});
|
||||||
liveClientBuilder.onGiftCombo((liveClient, event) ->
|
|
||||||
|
liveClientBuilder.onGift((liveClient, event) ->
|
||||||
{
|
{
|
||||||
|
liveClient.getLogger().setLevel(Level.OFF);
|
||||||
|
var gifts = liveClient.getGiftManager().getGifts();
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.append("COMBO User: " + event.getUser().getProfileName()+" ");
|
sb.append("GIFT User: " + event.getUser().getProfileName()+" ");
|
||||||
sb.append("Name: " + event.getGift().name() + " ");
|
sb.append("Name: " + event.getGift().getName() + " ");
|
||||||
|
sb.append("COST: " + event.getGift().getDiamondCost() + " ");
|
||||||
sb.append("Combo: " + event.getCombo() + " ");
|
sb.append("Combo: " + event.getCombo() + " ");
|
||||||
sb.append("Type: " + event.getComboState().name());
|
|
||||||
System.out.println(sb.toString());
|
System.out.println(sb.toString());
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -78,6 +79,7 @@ public class RunCollector {
|
|||||||
|
|
||||||
System.in.read();
|
System.in.read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public class MessageUtil
|
|||||||
var deserialized = parseMethod.invoke(null, message.getPayload());
|
var deserialized = parseMethod.invoke(null, message.getPayload());
|
||||||
return JsonUtil.messageToJson(deserialized);
|
return JsonUtil.messageToJson(deserialized);
|
||||||
} 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,8 +49,13 @@ public class MessageUtil
|
|||||||
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)
|
||||||
return ConsoleColors.RED+ "Can not find mapper for "+methodName;
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.append("Can not find mapper for "+methodName);
|
||||||
|
sb.append("\n");
|
||||||
|
//String jsonString = JsonFormat.printToString(protobufData);
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1247
Tools-EventsCollector/src/main/resources/web.json
Normal file
1247
Tools-EventsCollector/src/main/resources/web.json
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -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>0.0.25-Release</version>
|
<version>1.0.4-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>Tools-EventsWebViewer</artifactId>
|
<artifactId>Tools-EventsWebViewer</artifactId>
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
<artifactId>slf4j-simple</artifactId>
|
<artifactId>slf4j-simple</artifactId>
|
||||||
<version>2.0.7</version>
|
<version>2.0.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
<groupId>io.github.jwdeveloper.tiktok</groupId>
|
||||||
<artifactId>Tools-EventsCollector</artifactId>
|
<artifactId>Tools-EventsCollector</artifactId>
|
||||||
|
|||||||
@@ -39,17 +39,21 @@ public class TikTokManager {
|
|||||||
TikTokMessagessCollectorBuilder client;
|
TikTokMessagessCollectorBuilder client;
|
||||||
MessageCollector msgCollector;
|
MessageCollector msgCollector;
|
||||||
|
|
||||||
|
public static String dbName= "ab";
|
||||||
|
|
||||||
public TikTokManager() {
|
public TikTokManager() {
|
||||||
msgCollector = new MessageCollector("web");
|
msgCollector = new MessageCollector(dbName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(String name) throws SQLException {
|
public void connect(String name) throws SQLException {
|
||||||
disconnect();
|
disconnect();
|
||||||
client = TikTokMessageCollectorClient.create(msgCollector, "web")
|
client = TikTokMessageCollectorClient.create(msgCollector, dbName)
|
||||||
.addOnBuilder(liveClientBuilder ->
|
.addOnBuilder(liveClientBuilder ->
|
||||||
|
{
|
||||||
|
liveClientBuilder.onRoomInfo((liveClient, event) ->
|
||||||
{
|
{
|
||||||
|
|
||||||
|
});
|
||||||
liveClientBuilder.onGift((liveClient, event) ->
|
liveClientBuilder.onGift((liveClient, event) ->
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -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>0.0.25-Release</version>
|
<version>1.0.4-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ public class CodeExample {
|
|||||||
{
|
{
|
||||||
System.out.println(event.getComboState()+ " " + event.getCombo() + " " + event.getGift().getName());
|
System.out.println(event.getComboState()+ " " + event.getCombo() + " " + event.getGift().getName());
|
||||||
})
|
})
|
||||||
|
.onRoomInfo((liveClient, event) ->
|
||||||
|
{
|
||||||
|
var roomInfo = event.getRoomInfo();
|
||||||
|
System.out.println("Room Id: "+roomInfo.getRoomId());
|
||||||
|
System.out.println("Likes: "+roomInfo.getLikesCount());
|
||||||
|
System.out.println("Viewers: "+roomInfo.getViewersCount());
|
||||||
|
})
|
||||||
.onJoin((liveClient, event) ->
|
.onJoin((liveClient, event) ->
|
||||||
{
|
{
|
||||||
System.out.println(event.getUser().getProfileName() + "Hello on my stream! ");
|
System.out.println(event.getUser().getProfileName() + "Hello on my stream! ");
|
||||||
@@ -80,7 +87,6 @@ public class CodeExample {
|
|||||||
settings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
|
settings.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.setHandleExistingEvents(true); // Invokes all TikTok events that had occurred before connection
|
|
||||||
settings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
|
settings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
|
||||||
settings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
|
settings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
|
||||||
|
|
||||||
|
|||||||
681
Tools-ReadmeGenerator/src/main/resources/output.md
Normal file
681
Tools-ReadmeGenerator/src/main/resources/output.md
Normal file
@@ -0,0 +1,681 @@
|
|||||||
|
<div align="center" >
|
||||||
|
<a target="blank" >
|
||||||
|
<img src="https://raw.githubusercontent.com/jwdeveloper/TikTokLiveJava/develop-1_0_0/Tools-ReadmeGenerator/src/main/resources/logo.svg" width="15%" >
|
||||||
|
</img>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div align="center" >
|
||||||
|
<h1>TikTok Live Java</h1>
|
||||||
|
|
||||||
|
❤️❤️🎁 *Connect to TikTok live in 3 lines* 🎁❤️❤️
|
||||||
|
|
||||||
|
<div align="center" >
|
||||||
|
<a href="https://jitpack.io/#jwdeveloper/TikTok-Live-Java" target="blank" >
|
||||||
|
<img src="https://jitpack.io/v/jwdeveloper/TikTok-Live-Java.svg" width="20%" >
|
||||||
|
</img>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<a href="https://discord.gg/e2XwPNTBBr" target="blank" >
|
||||||
|
<img src="https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white" >
|
||||||
|
</img>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a target="blank" >
|
||||||
|
<img src="https://img.shields.io/badge/java-%23ED8B00.svg?style=for-the-badge&logo=openjdk&logoColor=white" >
|
||||||
|
</img>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
A Java library inspired by [TikTokLive](https://github.com/isaackogan/TikTokLive) and [TikTokLiveSharp](https://github.com/frankvHoof93/TikTokLiveSharp). Use it to receive live stream events such as comments and gifts in realtime from [TikTok LIVE](https://www.tiktok.com/live) by connecting to TikTok's internal WebCast push service.
|
||||||
|
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
|
||||||
|
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.youtube.com/watch?v=eerWGgUKc6c" align="right" target="blank"><img src="https://img.youtube.com/vi/eerWGgUKc6c/hqdefault.jpg" alt="IMAGE ALT TEXT" width="38%" align="right"></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Join the support [discord](https://discord.gg/e2XwPNTBBr) and visit the `#java-support` channel for questions, contributions and ideas. Feel free to make pull requests with missing/new features, fixes, etc
|
||||||
|
|
||||||
|
Do you prefer other programming languages?
|
||||||
|
- **Node** orginal: [TikTok-Live-Connector](https://github.com/isaackogan/TikTok-Live-Connector) by [@zerodytrash](https://github.com/zerodytrash)
|
||||||
|
- **Python** rewrite: [TikTokLive](https://github.com/isaackogan/TikTokLive) by [@isaackogan](https://github.com/isaackogan)
|
||||||
|
- **Go** rewrite: [GoTikTokLive](https://github.com/Davincible/gotiktoklive) by [@Davincible](https://github.com/Davincible)
|
||||||
|
- **C#** rewrite: [TikTokLiveSharp](https://github.com/frankvHoof93/TikTokLiveSharp) by [@frankvHoof93](https://github.com/frankvHoof93)
|
||||||
|
|
||||||
|
**NOTE:** This is not an official API. It's a reverse engineering project.
|
||||||
|
|
||||||
|
#### Overview
|
||||||
|
- [Getting started](#getting-started)
|
||||||
|
- [Events](#events)
|
||||||
|
- [Listeners](#listeners)
|
||||||
|
- [Contributing](#contributing)
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
1. Install the package via Maven
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jitpack.io</id>
|
||||||
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
|
||||||
|
<artifactId>Client</artifactId>
|
||||||
|
<version>NOT_FOUND</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create your first chat connection
|
||||||
|
|
||||||
|
```java
|
||||||
|
|
||||||
|
TikTokLive.newClient("bangbetmenygy")
|
||||||
|
.onGift((liveClient, event) ->
|
||||||
|
{
|
||||||
|
String message = switch (event.getGift()) {
|
||||||
|
case ROSE -> "ROSE!";
|
||||||
|
case GG -> "GOOD GAME";
|
||||||
|
case TIKTOK -> "Ye";
|
||||||
|
case CORGI -> "Nice gift";
|
||||||
|
default -> "Thank you for " + event.getGift().getName();
|
||||||
|
};
|
||||||
|
System.out.println(event.getUser().getProfileName() + " sends " + message);
|
||||||
|
})
|
||||||
|
.onGiftCombo((liveClient, event) ->
|
||||||
|
{
|
||||||
|
System.out.println(event.getComboState()+ " " + event.getCombo() + " " + event.getGift().getName());
|
||||||
|
})
|
||||||
|
.onRoomInfo((liveClient, event) ->
|
||||||
|
{
|
||||||
|
var roomInfo = event.getRoomInfo();
|
||||||
|
System.out.println("Room Id: "+roomInfo.getRoomId());
|
||||||
|
System.out.println("Likes: "+roomInfo.getLikesCount());
|
||||||
|
System.out.println("Viewers: "+roomInfo.getViewersCount());
|
||||||
|
})
|
||||||
|
.onJoin((liveClient, event) ->
|
||||||
|
{
|
||||||
|
System.out.println(event.getUser().getProfileName() + "Hello on my stream! ");
|
||||||
|
})
|
||||||
|
.onConnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
System.out.println("Connected to live ");
|
||||||
|
})
|
||||||
|
.onError((liveClient, event) ->
|
||||||
|
{
|
||||||
|
System.out.println("Error! " + event.getException().getMessage());
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
|
||||||
|
```
|
||||||
|
3. Configure (optional)
|
||||||
|
|
||||||
|
```java
|
||||||
|
|
||||||
|
TikTokLive.newClient("bangbetmenygy")
|
||||||
|
.configure((settings) ->
|
||||||
|
{
|
||||||
|
settings.setHostName("bangbetmenygy"); // This method is useful in case you want change hostname later
|
||||||
|
settings.setClientLanguage("en"); // Language
|
||||||
|
settings.setTimeout(Duration.ofSeconds(2)); // Connection timeout
|
||||||
|
settings.setLogLevel(Level.ALL); // Log level
|
||||||
|
settings.setPrintToConsole(true); // Printing all logs to console even if log level is Level.OFF
|
||||||
|
settings.setRetryOnConnectionFailure(true); // Reconnecting if TikTok user is offline
|
||||||
|
settings.setRetryConnectionTimeout(Duration.ofSeconds(1)); // Timeout before next reconnection
|
||||||
|
|
||||||
|
//Optional: Sometimes not every message from chat are send to TikTokLiveJava to fix this issue you can set sessionId
|
||||||
|
// documentation how to obtain sessionId https://github.com/isaackogan/TikTok-Live-Connector#send-chat-messages
|
||||||
|
settings.setSessionId("86c3c8bf4b17ebb2d74bb7fa66fd0000");
|
||||||
|
|
||||||
|
//Optional:
|
||||||
|
//RoomId can be used as an override if you're having issues with HostId.
|
||||||
|
//You can find it in the HTML for the livestream-page
|
||||||
|
settings.setRoomId("XXXXXXXXXXXXXXXXX");
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
//
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Control**:
|
||||||
|
|
||||||
|
- [onConnected](#onconnected-tiktokconnectedevent)
|
||||||
|
- [onDisconnected](#ondisconnected-tiktokdisconnectedevent)
|
||||||
|
- [onReconnecting](#onreconnecting-tiktokreconnectingevent)
|
||||||
|
- [onError](#onerror-tiktokerrorevent)
|
||||||
|
|
||||||
|
**Message**:
|
||||||
|
|
||||||
|
- [onEvent](#onevent-tiktokevent)
|
||||||
|
- [onSubscribe](#onsubscribe-tiktoksubscribeevent)
|
||||||
|
- [onQuestion](#onquestion-tiktokquestionevent)
|
||||||
|
- [onFollow](#onfollow-tiktokfollowevent)
|
||||||
|
- [onLike](#onlike-tiktoklikeevent)
|
||||||
|
- [onLiveEnded](#onliveended-tiktokliveendedevent)
|
||||||
|
- [onRoomInfo](#onroominfo-tiktokroominfoevent)
|
||||||
|
- [onShare](#onshare-tiktokshareevent)
|
||||||
|
- [onGiftCombo](#ongiftcombo-tiktokgiftcomboevent)
|
||||||
|
- [onEmote](#onemote-tiktokemoteevent)
|
||||||
|
- [onGift](#ongift-tiktokgiftevent)
|
||||||
|
- [onComment](#oncomment-tiktokcommentevent)
|
||||||
|
- [onLivePaused](#onlivepaused-tiktoklivepausedevent)
|
||||||
|
- [onLiveUnpaused](#onliveunpaused-tiktokliveunpausedevent)
|
||||||
|
- [onJoin](#onjoin-tiktokjoinevent)
|
||||||
|
|
||||||
|
**Debug**:
|
||||||
|
|
||||||
|
- [onWebsocketUnhandledMessage](#onwebsocketunhandledmessage-tiktokwebsocketunhandledmessageevent)
|
||||||
|
- [onWebsocketResponse](#onwebsocketresponse-tiktokwebsocketresponseevent)
|
||||||
|
- [onWebsocketMessage](#onwebsocketmessage-tiktokwebsocketmessageevent)
|
||||||
|
# Examples
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onConnected [TikTokConnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokConnectedEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered when the connection is successfully established.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onConnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onDisconnected [TikTokDisconnectedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokDisconnectedEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered when the connection gets disconnected. In that case you can call connect() again to have a reconnect logic.
|
||||||
|
Note that you should wait a little bit before attempting a reconnect to to avoid being rate-limited.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onDisconnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onReconnecting [TikTokReconnectingEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokReconnectingEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onReconnecting((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onError [TikTokErrorEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokErrorEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
General error event. You should handle this.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onError((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onEvent [TikTokEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/common/TikTokEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Base class for all events
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onEvent((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onSubscribe [TikTokSubscribeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokSubscribeEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggers when a user creates a subscription.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onSubscribe((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onQuestion [TikTokQuestionEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokQuestionEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered every time someone asks a new question via the question feature.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onQuestion((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onFollow [TikTokFollowEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokFollowEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggers when a user follows the streamer. Based on social event.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onFollow((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onLike [TikTokLikeEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokLikeEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onLike((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onLiveEnded [TikTokLiveEndedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLiveEndedEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered when the live stream gets terminated by the host. Will also trigger the TikTokDisconnectedEvent event.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onLiveEnded((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onRoomInfo [TikTokRoomInfoEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/room/TikTokRoomInfoEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onRoomInfo((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onShare [TikTokShareEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokShareEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggers when a user shares the stream. Based on social event.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onShare((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onGiftCombo [TikTokGiftComboEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftComboEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered every time gift is sent
|
||||||
|
|
||||||
|
@see GiftSendType it has 3 states
|
||||||
|
|
||||||
|
<p>Example when user sends gift with combo</p>
|
||||||
|
<p>>Combo: 1 -> comboState = GiftSendType.Begin</p>
|
||||||
|
<p>Combo: 4 -> comboState = GiftSendType.Active</p>
|
||||||
|
<p>Combo: 8 -> comboState = GiftSendType.Active</p>
|
||||||
|
<p>Combo: 12 -> comboState = GiftSendType.Finsihed</p>
|
||||||
|
|
||||||
|
Remember if comboState is Finsihed both TikTokGiftComboEvent and TikTokGiftEvent event gets triggered
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onGiftCombo((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onEmote [TikTokEmoteEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokEmoteEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered every time a subscriber sends an emote (sticker).
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onEmote((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onGift [TikTokGiftEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/gift/TikTokGiftEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered when user sends gifts that has
|
||||||
|
no combo (most of expensive gifts)
|
||||||
|
or if combo has finished
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onGift((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onComment [TikTokCommentEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokCommentEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered every time a new chat comment arrives.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onComment((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onLivePaused [TikTokLivePausedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLivePausedEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onLivePaused((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onLiveUnpaused [TikTokLiveUnpausedEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/TikTokLiveUnpausedEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onLiveUnpaused((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onJoin [TikTokJoinEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/social/TikTokJoinEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onJoin((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onWebsocketUnhandledMessage [TikTokWebsocketUnhandledMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketUnhandledMessageEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onWebsocketUnhandledMessage((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onWebsocketResponse [TikTokWebsocketResponseEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketResponseEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onWebsocketResponse((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## onWebsocketMessage [TikTokWebsocketMessageEvent](https://github.com/jwdeveloper/TikTokLiveJava/blob/master/API/src/main/java/io/github/jwdeveloper/tiktok/data/events/websocket/TikTokWebsocketMessageEvent.java)
|
||||||
|
|
||||||
|
|
||||||
|
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case.
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
TikTokLive.newClient("host-name")
|
||||||
|
.onWebsocketMessage((liveClient, event) ->
|
||||||
|
{
|
||||||
|
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## Listeners
|
||||||
|
|
||||||
|
```java
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Listeners are an alternative way of handling events.
|
||||||
|
* I would to suggest to use then when logic of handing event
|
||||||
|
* is more complex
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
showLogo();
|
||||||
|
CustomListener customListener = new CustomListener();
|
||||||
|
|
||||||
|
TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
|
||||||
|
.addListener(customListener)
|
||||||
|
.buildAndConnect();
|
||||||
|
System.in.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Method in TikTokEventListener should meet 4 requirements to be detected
|
||||||
|
* - must have @TikTokEventHandler annotation
|
||||||
|
* - must have 2 parameters
|
||||||
|
* - first parameter must be LiveClient
|
||||||
|
* - second must be class that extending TikTokEvent
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static class CustomListener implements TikTokEventListener {
|
||||||
|
|
||||||
|
@TikTokEventHandler
|
||||||
|
public void onLike(LiveClient liveClient, TikTokLikeEvent event) {
|
||||||
|
System.out.println(event.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@TikTokEventHandler
|
||||||
|
public void onError(LiveClient liveClient, TikTokErrorEvent event) {
|
||||||
|
// event.getException().printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@TikTokEventHandler
|
||||||
|
public void onComment(LiveClient liveClient, TikTokCommentEvent event) {
|
||||||
|
var userName = event.getUser().getName();
|
||||||
|
var text = event.getText();
|
||||||
|
liveClient.getLogger().info(userName + ": " + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TikTokEventHandler
|
||||||
|
public void onGift(LiveClient liveClient, TikTokGiftEvent event) {
|
||||||
|
var message = switch (event.getGift()) {
|
||||||
|
case ROSE -> "Thanks :)";
|
||||||
|
case APPETIZERS -> ":OO";
|
||||||
|
case APRIL -> ":D";
|
||||||
|
case TIKTOK -> ":P";
|
||||||
|
case CAP -> ":F";
|
||||||
|
default -> ":I";
|
||||||
|
};
|
||||||
|
liveClient.getLogger().info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TikTokEventHandler
|
||||||
|
public void onAnyEvent(LiveClient liveClient, TikTokEvent event) {
|
||||||
|
liveClient.getLogger().info(event.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
Your improvements are welcome! Feel free to open an <a href="https://github.com/jwdeveloper/TikTok-Live-Java/issues">issue</a> or <a href="https://github.com/jwdeveloper/TikTok-Live-Java/pulls">pull request</a>.
|
||||||
@@ -33,6 +33,10 @@ A Java library inspired by [TikTokLive](https://github.com/isaackogan/TikTokLive
|
|||||||
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
|
The library includes a wrapper that connects to the WebCast service using just the username (`uniqueId`). This allows you to connect to your own live chat as well as the live chat of other streamers.
|
||||||
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
|
No credentials are required. Events such as [Members Joining](#member), [Gifts](#gift), [Subscriptions](#subscribe), [Viewers](#roomuser), [Follows](#social), [Shares](#social), [Questions](#questionnew), [Likes](#like) and [Battles](#linkmicbattle) can be tracked.
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.youtube.com/watch?v=eerWGgUKc6c" align="right" target="blank"><img src="https://img.youtube.com/vi/eerWGgUKc6c/hqdefault.jpg" alt="IMAGE ALT TEXT" width="38%" align="right"></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
Join the support [discord](https://discord.gg/e2XwPNTBBr) and visit the `#java-support` channel for questions, contributions and ideas. Feel free to make pull requests with missing/new features, fixes, etc
|
Join the support [discord](https://discord.gg/e2XwPNTBBr) and visit the `#java-support` channel for questions, contributions and ideas. Feel free to make pull requests with missing/new features, fixes, etc
|
||||||
|
|
||||||
Do you prefer other programming languages?
|
Do you prefer other programming languages?
|
||||||
|
|||||||
@@ -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>0.0.25-Release</version>
|
<version>1.0.4-Release</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
<artifactId>javapoet</artifactId>
|
<artifactId>javapoet</artifactId>
|
||||||
<version>1.13.0</version>
|
<version>1.13.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.reflections</groupId>
|
<groupId>org.reflections</groupId>
|
||||||
<artifactId>reflections</artifactId>
|
<artifactId>reflections</artifactId>
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ public class GenerateGiftsEnum {
|
|||||||
|
|
||||||
var downloader = new GiftsDownloader();
|
var downloader = new GiftsDownloader();
|
||||||
var gifts = downloader.getGiftsFromFile();
|
var gifts = downloader.getGiftsFromFile();
|
||||||
|
for(var link : gifts)
|
||||||
|
{
|
||||||
|
System.out.println(link.getImage());
|
||||||
|
}
|
||||||
var groupedByName = gifts.stream().collect(Collectors.groupingBy(GiftDto::getName));
|
var groupedByName = gifts.stream().collect(Collectors.groupingBy(GiftDto::getName));
|
||||||
System.out.println("Total gifts" + gifts.size());
|
System.out.println("Total gifts" + gifts.size());
|
||||||
var result = generate(groupedByName);
|
var result = generate(groupedByName);
|
||||||
@@ -66,11 +70,11 @@ public class GenerateGiftsEnum {
|
|||||||
.addParameter(int.class, "id")
|
.addParameter(int.class, "id")
|
||||||
.addParameter(String.class, "name")
|
.addParameter(String.class, "name")
|
||||||
.addParameter(int.class, "diamondCost")
|
.addParameter(int.class, "diamondCost")
|
||||||
.addParameter(Picture.class, "picture")
|
.addParameter(String.class, "pictureLink")
|
||||||
.addStatement("this.id = id")
|
.addStatement("this.id = id")
|
||||||
.addStatement("this.name = name")
|
.addStatement("this.name = name")
|
||||||
.addStatement("this.diamondCost = diamondCost")
|
.addStatement("this.diamondCost = diamondCost")
|
||||||
.addStatement("this.picture = picture")
|
.addStatement("this.picture = new Picture(pictureLink)")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
var inRangeMethod = MethodSpec.methodBuilder("hasDiamondCostRange")
|
var inRangeMethod = MethodSpec.methodBuilder("hasDiamondCostRange")
|
||||||
@@ -91,7 +95,7 @@ public class GenerateGiftsEnum {
|
|||||||
enumBuilder.addMethod(constructor);
|
enumBuilder.addMethod(constructor);
|
||||||
|
|
||||||
|
|
||||||
enumBuilder.addEnumConstant("UNDEFINED", addGift(-1, "undefined", -1, new Picture("")));
|
enumBuilder.addEnumConstant("UNDEFINED", addGift(-1, "undefined", -1, ""));
|
||||||
for (var giftInfo : giftInfoMap.entrySet()) {
|
for (var giftInfo : giftInfoMap.entrySet()) {
|
||||||
|
|
||||||
|
|
||||||
@@ -117,16 +121,13 @@ public class GenerateGiftsEnum {
|
|||||||
if (contier > 1) {
|
if (contier > 1) {
|
||||||
enumName += "_" + value.getId();
|
enumName += "_" + value.getId();
|
||||||
}
|
}
|
||||||
enumBuilder.addEnumConstant(enumName, addGift(value.getId(), value.getName(), value.getDiamondCost(), new Picture(value.getImage())));
|
enumBuilder.addEnumConstant(enumName, addGift(value.getId(), value.getName(), value.getDiamondCost(), value.getImage()));
|
||||||
contier++;
|
contier++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
onEnums(enumBuilder);
|
var output = JavaFile.builder("io.github.jwdeveloper.tiktok.data.models.gifts", enumBuilder.build());
|
||||||
|
|
||||||
|
|
||||||
var output = JavaFile.builder("io.github.jwdeveloper.tiktok.events.objects", enumBuilder.build());
|
|
||||||
output.addFileComment("This enum is generated");
|
output.addFileComment("This enum is generated");
|
||||||
return output.build();
|
return output.build();
|
||||||
}
|
}
|
||||||
@@ -140,22 +141,14 @@ public class GenerateGiftsEnum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onEnums(TypeSpec.Builder builder) {
|
public static TypeSpec addGift(int id, String name, int diamond, String picture)
|
||||||
// builder.addEnumConstant("RUGBY_BALL", addGift(6249, "Rugby Ball", 10));
|
|
||||||
// builder.addEnumConstant("I_LOVE_YOU", addGift(5779, "I Love you", 10));
|
|
||||||
// builder.addEnumConstant("BOUQUET_FLOWER", addGift(5780, "Bouquet Flower", 30));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static TypeSpec addGift(int id, String name, int diamont, Picture picture)
|
|
||||||
{
|
{
|
||||||
var pictureValue = "new Picture(\""+picture.getLink()+"\")";
|
|
||||||
return TypeSpec.anonymousClassBuilder(
|
return TypeSpec.anonymousClassBuilder(
|
||||||
"$L, $S, $L, $S",
|
"$L, $S, $L, $S",
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
diamont,
|
diamond,
|
||||||
pictureValue)
|
picture)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import com.google.gson.Gson;
|
|||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import io.github.jwdeveloper.tiktok.gifts.downloader.GiftDto;
|
import io.github.jwdeveloper.tiktok.gifts.downloader.GiftDto;
|
||||||
|
import io.github.jwdeveloper.tiktok.gifts.downloader.GiftExtraJson;
|
||||||
import io.github.jwdeveloper.tiktok.gifts.downloader.GiftOfficialJson;
|
import io.github.jwdeveloper.tiktok.gifts.downloader.GiftOfficialJson;
|
||||||
import io.github.jwdeveloper.tiktok.gifts.downloader.GiftScraperJson;
|
import io.github.jwdeveloper.tiktok.gifts.downloader.GiftScraperJson;
|
||||||
import io.github.jwdeveloper.tiktok.utils.FilesUtility;
|
import io.github.jwdeveloper.tiktok.utils.FilesUtility;
|
||||||
@@ -38,11 +39,15 @@ import java.util.TreeMap;
|
|||||||
public class GiftsDownloader {
|
public class GiftsDownloader {
|
||||||
|
|
||||||
public static void main(String[] run) {
|
public static void main(String[] run) {
|
||||||
new GiftsDownloader().getGifts();
|
var gifts = new GiftsDownloader().getGifts();
|
||||||
|
for(var gift : gifts)
|
||||||
|
{
|
||||||
|
System.out.println(gift.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GiftDto> getGiftsFromFile() {
|
public List<GiftDto> getGiftsFromFile() {
|
||||||
var content = FilesUtility.loadFileContent("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\output.json");
|
var content = FilesUtility.loadFileContent("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\output_1_0_4.json");
|
||||||
Type mapType = new TypeToken<Map<Integer, GiftDto>>() {
|
Type mapType = new TypeToken<Map<Integer, GiftDto>>() {
|
||||||
}.getType();
|
}.getType();
|
||||||
var mapper = new Gson().fromJson(content, mapType);
|
var mapper = new Gson().fromJson(content, mapType);
|
||||||
@@ -62,6 +67,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");
|
||||||
|
var extraGiftsJson = new GiftExtraJson();
|
||||||
|
var extraGifts = extraGiftsJson.run();
|
||||||
|
System.out.println("Official Gifts: " + extraGifts.size());
|
||||||
|
|
||||||
var outputHashMap = new TreeMap<Integer, GiftDto>();
|
var outputHashMap = new TreeMap<Integer, GiftDto>();
|
||||||
for (var gift : scraperGifts) {
|
for (var gift : scraperGifts) {
|
||||||
@@ -70,10 +79,13 @@ public class GiftsDownloader {
|
|||||||
for (var gift : officialGifts) {
|
for (var gift : officialGifts) {
|
||||||
outputHashMap.put(gift.getId(), gift);
|
outputHashMap.put(gift.getId(), gift);
|
||||||
}
|
}
|
||||||
|
for (var gift : extraGifts) {
|
||||||
|
outputHashMap.put(gift.getId(), gift);
|
||||||
|
}
|
||||||
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_4.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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package io.github.jwdeveloper.tiktok.gifts.downloader;
|
||||||
|
|
||||||
|
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 java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GiftExtraJson
|
||||||
|
{
|
||||||
|
public static void main(String[] args) {
|
||||||
|
var reuslt = new GiftExtraJson().run();
|
||||||
|
|
||||||
|
System.out.println(reuslt.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
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("diamondCost").getAsInt();
|
||||||
|
var image = jsonElement.getAsJsonObject().get("image").getAsString();
|
||||||
|
var gift = new GiftDto();
|
||||||
|
gift.setId(id);
|
||||||
|
gift.setName(name);
|
||||||
|
gift.setDiamondCost(diamondCost);
|
||||||
|
gift.setImage(image);
|
||||||
|
return gift;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonArray getJsonGifts() {
|
||||||
|
|
||||||
|
var extraGifts =FilesUtility.loadFileContent("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\extra_gifts.json");
|
||||||
|
JsonElement jsonElement = JsonParser.parseString(extraGifts);
|
||||||
|
return jsonElement.getAsJsonArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,7 +88,7 @@ public class GiftOfficialJson {
|
|||||||
var fileName = "official_" + date + ".json";
|
var fileName = "official_" + date + ".json";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var response = tiktokHttpClient.getJObjectFromWebcastAPI("gift/list/", settings.getClientParameters());
|
var response = tiktokHttpClient.getJsonFromWebcastApi("gift/list/", settings.getClientParameters());
|
||||||
var gson = new GsonBuilder().setPrettyPrinting().create();
|
var gson = new GsonBuilder().setPrettyPrinting().create();
|
||||||
FilesUtility.saveFile("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\official\\" + fileName, gson.toJson(response));
|
FilesUtility.saveFile("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\Tools\\src\\main\\resources\\gifts\\official\\" + fileName, gson.toJson(response));
|
||||||
if (!response.has("data")) {
|
if (!response.has("data")) {
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ 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.TikTokMessageHandlerRegistration;
|
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
||||||
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
|
import io.github.jwdeveloper.tiktok.handlers.events.TikTokGiftEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.events.TikTokRoomInfoEventHandler;
|
||||||
|
import io.github.jwdeveloper.tiktok.handlers.events.TikTokSocialMediaEventHandler;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
|
||||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||||
@@ -93,14 +95,15 @@ public class TikTokMockBuilder extends TikTokLiveClientBuilder {
|
|||||||
tiktokRoomInfo.setHostName(clientSettings.getHostName());
|
tiktokRoomInfo.setHostName(clientSettings.getHostName());
|
||||||
|
|
||||||
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
|
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
|
||||||
var giftManager = new TikTokGiftManager();
|
var giftManager = new TikTokGiftManager(logger);
|
||||||
var requestFactory = new TikTokHttpRequestFactory(cookie);
|
var requestFactory = new TikTokHttpRequestFactory(cookie);
|
||||||
var apiClient = new TikTokHttpClient(cookie, requestFactory);
|
var apiClient = new TikTokHttpClient(cookie, requestFactory);
|
||||||
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
|
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
|
||||||
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler,
|
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler,
|
||||||
tiktokRoomInfo,
|
new TikTokRoomInfoEventHandler(tiktokRoomInfo),
|
||||||
new TikTokGenericEventMapper(),
|
new TikTokGenericEventMapper(),
|
||||||
new TikTokGiftEventHandler(giftManager));
|
new TikTokGiftEventHandler(giftManager),
|
||||||
|
new TikTokSocialMediaEventHandler(tiktokRoomInfo));
|
||||||
var webSocketClient = new WebsocketClientMock(logger, responses, webResponseHandler);
|
var webSocketClient = new WebsocketClientMock(logger, responses, webResponseHandler);
|
||||||
|
|
||||||
return new LiveClientMock(tiktokRoomInfo,
|
return new LiveClientMock(tiktokRoomInfo,
|
||||||
|
|||||||
44
Tools/src/main/resources/gifts/extra_gifts.json
Normal file
44
Tools/src/main/resources/gifts/extra_gifts.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 7812,
|
||||||
|
"name": "Bravo",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b25e72d59e9771b09da8c8c70f395f82~tplv-obj.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8239,
|
||||||
|
"name": "White Rose",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a2d81f3847457be9083a9c76a59b08cb~tplv-obj.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7813,
|
||||||
|
"name": "Health Potion",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/13f6a46b763c496306ff541daf3021a4~tplv-obj.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7814,
|
||||||
|
"name": "Panettone",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/64ce2413a362442819b4551703b7b26c~tplv-obj.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5631,
|
||||||
|
"name": "Power hug",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9578adce6e3da2d211583212bdfd1b0e~tplv-obj.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9463,
|
||||||
|
"name": "Fairy Wings",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/e504dc2f313b8c6df9e99a848e1b3a99.png~tplv-obj.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9139,
|
||||||
|
"name": "Team Bracelet",
|
||||||
|
"diamondCost": 2,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/54cb1eeca369e5bea1b97707ca05d189.png~tplv-obj.png"
|
||||||
|
}
|
||||||
|
]
|
||||||
17129
Tools/src/main/resources/gifts/official/official_10_11_2023.json
Normal file
17129
Tools/src/main/resources/gifts/official/official_10_11_2023.json
Normal file
File diff suppressed because it is too large
Load Diff
15950
Tools/src/main/resources/gifts/official/official_12_10_2023.json
Normal file
15950
Tools/src/main/resources/gifts/official/official_12_10_2023.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -553,9 +553,9 @@
|
|||||||
},
|
},
|
||||||
"5631": {
|
"5631": {
|
||||||
"id": 5631,
|
"id": 5631,
|
||||||
"name": "",
|
"name": "Power hug",
|
||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/ecf/ecf0b721b1b346a31fba8b0a17fe6287/5412c67a1cacdfbfc4c01407b8b4263c.png"
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9578adce6e3da2d211583212bdfd1b0e~tplv-obj.png"
|
||||||
},
|
},
|
||||||
"5632": {
|
"5632": {
|
||||||
"id": 5632,
|
"id": 5632,
|
||||||
@@ -2021,6 +2021,12 @@
|
|||||||
"diamondCost": 500,
|
"diamondCost": 500,
|
||||||
"image": "https://storage.streamdps.com/iblock/25f/25f030f47cfc60d296bb1041ddb91f6e/ca3357a76a2be178c581530009ce215a.png"
|
"image": "https://storage.streamdps.com/iblock/25f/25f030f47cfc60d296bb1041ddb91f6e/ca3357a76a2be178c581530009ce215a.png"
|
||||||
},
|
},
|
||||||
|
"6367": {
|
||||||
|
"id": 6367,
|
||||||
|
"name": "Falcon",
|
||||||
|
"diamondCost": 10999,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/f88/f886e7678bef35f8c762a323386e6d23/7249e0af64c78d1d569a8d7a86ab58cd.png"
|
||||||
|
},
|
||||||
"6369": {
|
"6369": {
|
||||||
"id": 6369,
|
"id": 6369,
|
||||||
"name": "Lion",
|
"name": "Lion",
|
||||||
@@ -2099,6 +2105,12 @@
|
|||||||
"diamondCost": 5,
|
"diamondCost": 5,
|
||||||
"image": "https://storage.streamdps.com/iblock/ce5/ce57f012363358333397b6c72704b466/aa71c1c351b698c09a151a434bfd2652.png"
|
"image": "https://storage.streamdps.com/iblock/ce5/ce57f012363358333397b6c72704b466/aa71c1c351b698c09a151a434bfd2652.png"
|
||||||
},
|
},
|
||||||
|
"6417": {
|
||||||
|
"id": 6417,
|
||||||
|
"name": "Club",
|
||||||
|
"diamondCost": 2000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/49b/49be18ae5914346ffcaf15a519ba9c1c/41326cb23d22010f0c4a8edf5bd27615.webp"
|
||||||
|
},
|
||||||
"6427": {
|
"6427": {
|
||||||
"id": 6427,
|
"id": 6427,
|
||||||
"name": "Hat and Mustache",
|
"name": "Hat and Mustache",
|
||||||
@@ -2819,6 +2831,12 @@
|
|||||||
"diamondCost": 2150,
|
"diamondCost": 2150,
|
||||||
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/46fa70966d8e931497f5289060f9a794~tplv-obj.jpg"
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/46fa70966d8e931497f5289060f9a794~tplv-obj.jpg"
|
||||||
},
|
},
|
||||||
|
"6833": {
|
||||||
|
"id": 6833,
|
||||||
|
"name": "Castle Fantasy",
|
||||||
|
"diamondCost": 20000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/a08/a088a2975c7d4a68b8146a4c6b5c97c1/2729c82ccd54828bd950675e7491d71c.webp"
|
||||||
|
},
|
||||||
"6834": {
|
"6834": {
|
||||||
"id": 6834,
|
"id": 6834,
|
||||||
"name": "Gift Box",
|
"name": "Gift Box",
|
||||||
@@ -3251,6 +3269,12 @@
|
|||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/341/341ed57767654fa7df9660988af5aa8c/b8ef51ac15bd2af523d9010fc0259d7f.webp"
|
"image": "https://storage.streamdps.com/iblock/341/341ed57767654fa7df9660988af5aa8c/b8ef51ac15bd2af523d9010fc0259d7f.webp"
|
||||||
},
|
},
|
||||||
|
"7041": {
|
||||||
|
"id": 7041,
|
||||||
|
"name": "Arcade Game",
|
||||||
|
"diamondCost": 1200,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/fd0/fd0785612b024900444a0a69083400ff/3181d6af50b05dd65a7ba75902bb5b94.webp"
|
||||||
|
},
|
||||||
"7048": {
|
"7048": {
|
||||||
"id": 7048,
|
"id": 7048,
|
||||||
"name": "I LOVE KR",
|
"name": "I LOVE KR",
|
||||||
@@ -3803,6 +3827,12 @@
|
|||||||
"diamondCost": 10,
|
"diamondCost": 10,
|
||||||
"image": "https://storage.streamdps.com/iblock/b24/b24309d4ea6722875678e492ae12fb3f/864ac7928a78b43be2d1ee93915a53f5.webp"
|
"image": "https://storage.streamdps.com/iblock/b24/b24309d4ea6722875678e492ae12fb3f/864ac7928a78b43be2d1ee93915a53f5.webp"
|
||||||
},
|
},
|
||||||
|
"7598": {
|
||||||
|
"id": 7598,
|
||||||
|
"name": "Pirate’s Ship",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/475/4753e54cae562b34edbf1a157cd60b21/722409ec69cfaf707d611b0987799296.webp"
|
||||||
|
},
|
||||||
"7604": {
|
"7604": {
|
||||||
"id": 7604,
|
"id": 7604,
|
||||||
"name": "2023",
|
"name": "2023",
|
||||||
@@ -3905,6 +3935,24 @@
|
|||||||
"diamondCost": 100,
|
"diamondCost": 100,
|
||||||
"image": "https://storage.streamdps.com/iblock/841/841037f168f5e2757ead3d4989d40850/cac3e62b0c75d0914fe2e588832e14ee.webp"
|
"image": "https://storage.streamdps.com/iblock/841/841037f168f5e2757ead3d4989d40850/cac3e62b0c75d0914fe2e588832e14ee.webp"
|
||||||
},
|
},
|
||||||
|
"7812": {
|
||||||
|
"id": 7812,
|
||||||
|
"name": "Bravo",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b25e72d59e9771b09da8c8c70f395f82~tplv-obj.png"
|
||||||
|
},
|
||||||
|
"7813": {
|
||||||
|
"id": 7813,
|
||||||
|
"name": "Health Potion",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/13f6a46b763c496306ff541daf3021a4~tplv-obj.png"
|
||||||
|
},
|
||||||
|
"7814": {
|
||||||
|
"id": 7814,
|
||||||
|
"name": "Panettone",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/64ce2413a362442819b4551703b7b26c~tplv-obj.png"
|
||||||
|
},
|
||||||
"7823": {
|
"7823": {
|
||||||
"id": 7823,
|
"id": 7823,
|
||||||
"name": "Leon and Lion",
|
"name": "Leon and Lion",
|
||||||
@@ -3995,6 +4043,12 @@
|
|||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/923/92341a47e85be94fb6a6699a6c430a93/d60527955f9597a43d339357fed6a5fc.webp"
|
"image": "https://storage.streamdps.com/iblock/923/92341a47e85be94fb6a6699a6c430a93/d60527955f9597a43d339357fed6a5fc.webp"
|
||||||
},
|
},
|
||||||
|
"7911": {
|
||||||
|
"id": 7911,
|
||||||
|
"name": "Maggie",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/a12/a12a1b23f1f6a19d728de84e1f43e21d/ff288346e9855a9bb6deb4450491028f.webp"
|
||||||
|
},
|
||||||
"7927": {
|
"7927": {
|
||||||
"id": 7927,
|
"id": 7927,
|
||||||
"name": "Puppy Love",
|
"name": "Puppy Love",
|
||||||
@@ -4043,6 +4097,12 @@
|
|||||||
"diamondCost": 88,
|
"diamondCost": 88,
|
||||||
"image": "https://storage.streamdps.com/iblock/e22/e2266686271c7a90ff04517f248c6f73/0459d679c01a5bfa5a4be1d61ec81ec8.webp"
|
"image": "https://storage.streamdps.com/iblock/e22/e2266686271c7a90ff04517f248c6f73/0459d679c01a5bfa5a4be1d61ec81ec8.webp"
|
||||||
},
|
},
|
||||||
|
"7978": {
|
||||||
|
"id": 7978,
|
||||||
|
"name": "Leopard",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/eb4/eb4d116b15c03c2974b86fa400fa6a07/9a34b020e29f2d25f434387ae01b6386.webp"
|
||||||
|
},
|
||||||
"7984": {
|
"7984": {
|
||||||
"id": 7984,
|
"id": 7984,
|
||||||
"name": "Counting Sheep",
|
"name": "Counting Sheep",
|
||||||
@@ -4229,6 +4289,12 @@
|
|||||||
"diamondCost": 88,
|
"diamondCost": 88,
|
||||||
"image": "https://storage.streamdps.com/iblock/88e/88e25becb6f23daa0e97669a3b2905fb/d7b74b5b1e20c22e9baa4f1f02f1c6f5.webp"
|
"image": "https://storage.streamdps.com/iblock/88e/88e25becb6f23daa0e97669a3b2905fb/d7b74b5b1e20c22e9baa4f1f02f1c6f5.webp"
|
||||||
},
|
},
|
||||||
|
"8239": {
|
||||||
|
"id": 8239,
|
||||||
|
"name": "White Rose",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a2d81f3847457be9083a9c76a59b08cb~tplv-obj.png"
|
||||||
|
},
|
||||||
"8243": {
|
"8243": {
|
||||||
"id": 8243,
|
"id": 8243,
|
||||||
"name": "Cheer You Up",
|
"name": "Cheer You Up",
|
||||||
@@ -4349,6 +4415,12 @@
|
|||||||
"diamondCost": 34500,
|
"diamondCost": 34500,
|
||||||
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/3781e9159ff09272826d3f2216ba36ef.png~tplv-obj.jpg"
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/3781e9159ff09272826d3f2216ba36ef.png~tplv-obj.jpg"
|
||||||
},
|
},
|
||||||
|
"8387": {
|
||||||
|
"id": 8387,
|
||||||
|
"name": "peacock",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/f9f/f9f23f00af57e8fb8a421a2a7f24aacc/a5eb745418085f1be7692f577ff04b9c.webp"
|
||||||
|
},
|
||||||
"8391": {
|
"8391": {
|
||||||
"id": 8391,
|
"id": 8391,
|
||||||
"name": "Sam the Whale",
|
"name": "Sam the Whale",
|
||||||
@@ -4409,6 +4481,12 @@
|
|||||||
"diamondCost": 88,
|
"diamondCost": 88,
|
||||||
"image": "https://storage.streamdps.com/iblock/405/405fcf52a1de3d14ab9834c1f30cc330/0deed9ee2c79ba6bf2005b0ce667bf60.webp"
|
"image": "https://storage.streamdps.com/iblock/405/405fcf52a1de3d14ab9834c1f30cc330/0deed9ee2c79ba6bf2005b0ce667bf60.webp"
|
||||||
},
|
},
|
||||||
|
"8435": {
|
||||||
|
"id": 8435,
|
||||||
|
"name": "Pyramids",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/bfc/bfcf491b940e478b6410047bc047af1b/abbbdd13015a9f31be1b905268873d73.webp"
|
||||||
|
},
|
||||||
"8448": {
|
"8448": {
|
||||||
"id": 8448,
|
"id": 8448,
|
||||||
"name": "Raccoon",
|
"name": "Raccoon",
|
||||||
@@ -4421,6 +4499,12 @@
|
|||||||
"diamondCost": 99,
|
"diamondCost": 99,
|
||||||
"image": "https://storage.streamdps.com/iblock/a0f/a0ff283ce42ad27a03d6b8b98e81463b/9e5a49a9bae80f0afa30257d562cec8e.webp"
|
"image": "https://storage.streamdps.com/iblock/a0f/a0ff283ce42ad27a03d6b8b98e81463b/9e5a49a9bae80f0afa30257d562cec8e.webp"
|
||||||
},
|
},
|
||||||
|
"8456": {
|
||||||
|
"id": 8456,
|
||||||
|
"name": "Zeus",
|
||||||
|
"diamondCost": 34000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/f4e/f4e74e07fff3d3b48143a5c56af7fec4/8b15ef2f342dcd2066bcdcf82e5f07e9.webp"
|
||||||
|
},
|
||||||
"8457": {
|
"8457": {
|
||||||
"id": 8457,
|
"id": 8457,
|
||||||
"name": "Zeus",
|
"name": "Zeus",
|
||||||
@@ -4457,12 +4541,24 @@
|
|||||||
"diamondCost": 199,
|
"diamondCost": 199,
|
||||||
"image": "https://storage.streamdps.com/iblock/50f/50f04937063753d6de255d2b5a080c1c/4f101c7c50ddbe8bd26a2ce5f8c16896.webp"
|
"image": "https://storage.streamdps.com/iblock/50f/50f04937063753d6de255d2b5a080c1c/4f101c7c50ddbe8bd26a2ce5f8c16896.webp"
|
||||||
},
|
},
|
||||||
|
"8599": {
|
||||||
|
"id": 8599,
|
||||||
|
"name": "Convertible Car",
|
||||||
|
"diamondCost": 12000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/2cf/2cfc5af50894de318b81438a7e137710/060001e901992f5462c841b987876eeb.webp"
|
||||||
|
},
|
||||||
"8600": {
|
"8600": {
|
||||||
"id": 8600,
|
"id": 8600,
|
||||||
"name": "Sending positivity",
|
"name": "Sending positivity",
|
||||||
"diamondCost": 199,
|
"diamondCost": 199,
|
||||||
"image": "https://storage.streamdps.com/iblock/29b/29b0e9cb18e3479d17188235f8fdf480/58c6e916f44dcdda9d2f68dbdae77ddb.webp"
|
"image": "https://storage.streamdps.com/iblock/29b/29b0e9cb18e3479d17188235f8fdf480/58c6e916f44dcdda9d2f68dbdae77ddb.webp"
|
||||||
},
|
},
|
||||||
|
"8602": {
|
||||||
|
"id": 8602,
|
||||||
|
"name": "Gorilla",
|
||||||
|
"diamondCost": 30000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/1e2/1e29b9d1a0263f1487498dc556cdcbc1/bec227242f8c9b258855071aa050ac17.webp"
|
||||||
|
},
|
||||||
"8604": {
|
"8604": {
|
||||||
"id": 8604,
|
"id": 8604,
|
||||||
"name": "Starfish Bay",
|
"name": "Starfish Bay",
|
||||||
@@ -4553,6 +4649,12 @@
|
|||||||
"diamondCost": 2000,
|
"diamondCost": 2000,
|
||||||
"image": "https://storage.streamdps.com/iblock/a29/a29903a975ce45f7b9939b510412fcee/051afc0510a7349a9ebfcde9e0fdec24.webp"
|
"image": "https://storage.streamdps.com/iblock/a29/a29903a975ce45f7b9939b510412fcee/051afc0510a7349a9ebfcde9e0fdec24.webp"
|
||||||
},
|
},
|
||||||
|
"8814": {
|
||||||
|
"id": 8814,
|
||||||
|
"name": "Superhero fight",
|
||||||
|
"diamondCost": 30000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/d6b/d6b1c955153c8f8c5048d6c8f0d1b418/97d04b889e64328e9ab07224f6072b5f.webp"
|
||||||
|
},
|
||||||
"8815": {
|
"8815": {
|
||||||
"id": 8815,
|
"id": 8815,
|
||||||
"name": "Pink shoes",
|
"name": "Pink shoes",
|
||||||
@@ -4661,6 +4763,12 @@
|
|||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/ff9/ff906a964a6ad9c4504438302d9354b8/3ee4796c239930c395afb3d7ef10295a.webp"
|
"image": "https://storage.streamdps.com/iblock/ff9/ff906a964a6ad9c4504438302d9354b8/3ee4796c239930c395afb3d7ef10295a.webp"
|
||||||
},
|
},
|
||||||
|
"9086": {
|
||||||
|
"id": 9086,
|
||||||
|
"name": "Man V Seagull",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/e5d/e5d95d519ee0ed7922de14f224a9504d/e80d8e840dd44cdf20de4c572c25e0f4.webp"
|
||||||
|
},
|
||||||
"9087": {
|
"9087": {
|
||||||
"id": 9087,
|
"id": 9087,
|
||||||
"name": "Flame heart",
|
"name": "Flame heart",
|
||||||
@@ -4673,6 +4781,12 @@
|
|||||||
"diamondCost": 41999,
|
"diamondCost": 41999,
|
||||||
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/bfb8425a7e8fa03f9fec05a973a4a506.png~tplv-obj.jpg"
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/bfb8425a7e8fa03f9fec05a973a4a506.png~tplv-obj.jpg"
|
||||||
},
|
},
|
||||||
|
"9095": {
|
||||||
|
"id": 9095,
|
||||||
|
"name": "Birthday Party",
|
||||||
|
"diamondCost": 6999,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/d0d/d0d1164a9ed81239b70cb25b93927023/d0dba293643c67dc33c1f4dda04e5b50.webp"
|
||||||
|
},
|
||||||
"9096": {
|
"9096": {
|
||||||
"id": 9096,
|
"id": 9096,
|
||||||
"name": "Birthday Crown",
|
"name": "Birthday Crown",
|
||||||
@@ -4685,6 +4799,18 @@
|
|||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"
|
"image": "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"
|
||||||
},
|
},
|
||||||
|
"9138": {
|
||||||
|
"id": 9138,
|
||||||
|
"name": "Trending Figure",
|
||||||
|
"diamondCost": 999,
|
||||||
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/df7b556ccf369bf9a42fe83ec8a77acf.png~tplv-obj.jpg"
|
||||||
|
},
|
||||||
|
"9139": {
|
||||||
|
"id": 9139,
|
||||||
|
"name": "Team Bracelet",
|
||||||
|
"diamondCost": 2,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/54cb1eeca369e5bea1b97707ca05d189.png~tplv-obj.png"
|
||||||
|
},
|
||||||
"9147": {
|
"9147": {
|
||||||
"id": 9147,
|
"id": 9147,
|
||||||
"name": "Bigfoot",
|
"name": "Bigfoot",
|
||||||
@@ -4708,5 +4834,53 @@
|
|||||||
"name": "Pretzel",
|
"name": "Pretzel",
|
||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/a67/a6797793eb382a99d38b2a0c37ec9b58/04ea1042707a361ad0f4668d0d759daa.webp"
|
"image": "https://storage.streamdps.com/iblock/a67/a6797793eb382a99d38b2a0c37ec9b58/04ea1042707a361ad0f4668d0d759daa.webp"
|
||||||
|
},
|
||||||
|
"9184": {
|
||||||
|
"id": 9184,
|
||||||
|
"name": "Cube",
|
||||||
|
"diamondCost": 10,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/69d/69dab4e352882c0bd29c3864e24d80de/258857221189c76260b6af5eeb43e93b.webp"
|
||||||
|
},
|
||||||
|
"9240": {
|
||||||
|
"id": 9240,
|
||||||
|
"name": "Dancing queens",
|
||||||
|
"diamondCost": 20000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/c79/c793af446369ecef5238e73312c84ccd/464a76f3e6eaee9afc771f45a4bba9df.webp"
|
||||||
|
},
|
||||||
|
"9255": {
|
||||||
|
"id": 9255,
|
||||||
|
"name": "Aerobic headband",
|
||||||
|
"diamondCost": 99,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/3d9/3d98c2fbc96922da37a9d22881bb06b9/0a99af132ab8e3fe9806d2412abc6bf0.webp"
|
||||||
|
},
|
||||||
|
"9463": {
|
||||||
|
"id": 9463,
|
||||||
|
"name": "Fairy Wings",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/e504dc2f313b8c6df9e99a848e1b3a99.png~tplv-obj.png"
|
||||||
|
},
|
||||||
|
"9465": {
|
||||||
|
"id": 9465,
|
||||||
|
"name": "Fruit Friends",
|
||||||
|
"diamondCost": 299,
|
||||||
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1153dd51308c556cb4fcc48c7d62209f.png~tplv-obj.jpg"
|
||||||
|
},
|
||||||
|
"9466": {
|
||||||
|
"id": 9466,
|
||||||
|
"name": "Amusement Park",
|
||||||
|
"diamondCost": 17000,
|
||||||
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/12ecc01c2984c5d85bb508e80103a3cb.png~tplv-obj.jpg"
|
||||||
|
},
|
||||||
|
"9467": {
|
||||||
|
"id": 9467,
|
||||||
|
"name": "Lili the Leopard",
|
||||||
|
"diamondCost": 6599,
|
||||||
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/7be03e1af477d1dbc6eb742d0c969372.png~tplv-obj.jpg"
|
||||||
|
},
|
||||||
|
"9468": {
|
||||||
|
"id": 9468,
|
||||||
|
"name": "Rhythmic Bear",
|
||||||
|
"diamondCost": 2999,
|
||||||
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/16eacf541e4bd6816e88139d079519f5.png~tplv-obj.jpg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
4820
Tools/src/main/resources/gifts/used_outputs/output_1_0_0.json
Normal file
4820
Tools/src/main/resources/gifts/used_outputs/output_1_0_0.json
Normal file
File diff suppressed because it is too large
Load Diff
4886
Tools/src/main/resources/gifts/used_outputs/output_1_0_4.json
Normal file
4886
Tools/src/main/resources/gifts/used_outputs/output_1_0_4.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -553,9 +553,9 @@
|
|||||||
},
|
},
|
||||||
"5631": {
|
"5631": {
|
||||||
"id": 5631,
|
"id": 5631,
|
||||||
"name": "",
|
"name": "Power hug",
|
||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/ecf/ecf0b721b1b346a31fba8b0a17fe6287/5412c67a1cacdfbfc4c01407b8b4263c.png"
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/9578adce6e3da2d211583212bdfd1b0e~tplv-obj.png"
|
||||||
},
|
},
|
||||||
"5632": {
|
"5632": {
|
||||||
"id": 5632,
|
"id": 5632,
|
||||||
@@ -2021,6 +2021,12 @@
|
|||||||
"diamondCost": 500,
|
"diamondCost": 500,
|
||||||
"image": "https://storage.streamdps.com/iblock/25f/25f030f47cfc60d296bb1041ddb91f6e/ca3357a76a2be178c581530009ce215a.png"
|
"image": "https://storage.streamdps.com/iblock/25f/25f030f47cfc60d296bb1041ddb91f6e/ca3357a76a2be178c581530009ce215a.png"
|
||||||
},
|
},
|
||||||
|
"6367": {
|
||||||
|
"id": 6367,
|
||||||
|
"name": "Falcon",
|
||||||
|
"diamondCost": 10999,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/f88/f886e7678bef35f8c762a323386e6d23/7249e0af64c78d1d569a8d7a86ab58cd.png"
|
||||||
|
},
|
||||||
"6369": {
|
"6369": {
|
||||||
"id": 6369,
|
"id": 6369,
|
||||||
"name": "Lion",
|
"name": "Lion",
|
||||||
@@ -2099,6 +2105,12 @@
|
|||||||
"diamondCost": 5,
|
"diamondCost": 5,
|
||||||
"image": "https://storage.streamdps.com/iblock/ce5/ce57f012363358333397b6c72704b466/aa71c1c351b698c09a151a434bfd2652.png"
|
"image": "https://storage.streamdps.com/iblock/ce5/ce57f012363358333397b6c72704b466/aa71c1c351b698c09a151a434bfd2652.png"
|
||||||
},
|
},
|
||||||
|
"6417": {
|
||||||
|
"id": 6417,
|
||||||
|
"name": "Club",
|
||||||
|
"diamondCost": 2000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/49b/49be18ae5914346ffcaf15a519ba9c1c/41326cb23d22010f0c4a8edf5bd27615.webp"
|
||||||
|
},
|
||||||
"6427": {
|
"6427": {
|
||||||
"id": 6427,
|
"id": 6427,
|
||||||
"name": "Hat and Mustache",
|
"name": "Hat and Mustache",
|
||||||
@@ -2819,6 +2831,12 @@
|
|||||||
"diamondCost": 2150,
|
"diamondCost": 2150,
|
||||||
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/46fa70966d8e931497f5289060f9a794~tplv-obj.jpg"
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/46fa70966d8e931497f5289060f9a794~tplv-obj.jpg"
|
||||||
},
|
},
|
||||||
|
"6833": {
|
||||||
|
"id": 6833,
|
||||||
|
"name": "Castle Fantasy",
|
||||||
|
"diamondCost": 20000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/a08/a088a2975c7d4a68b8146a4c6b5c97c1/2729c82ccd54828bd950675e7491d71c.webp"
|
||||||
|
},
|
||||||
"6834": {
|
"6834": {
|
||||||
"id": 6834,
|
"id": 6834,
|
||||||
"name": "Gift Box",
|
"name": "Gift Box",
|
||||||
@@ -3251,6 +3269,12 @@
|
|||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/341/341ed57767654fa7df9660988af5aa8c/b8ef51ac15bd2af523d9010fc0259d7f.webp"
|
"image": "https://storage.streamdps.com/iblock/341/341ed57767654fa7df9660988af5aa8c/b8ef51ac15bd2af523d9010fc0259d7f.webp"
|
||||||
},
|
},
|
||||||
|
"7041": {
|
||||||
|
"id": 7041,
|
||||||
|
"name": "Arcade Game",
|
||||||
|
"diamondCost": 1200,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/fd0/fd0785612b024900444a0a69083400ff/3181d6af50b05dd65a7ba75902bb5b94.webp"
|
||||||
|
},
|
||||||
"7048": {
|
"7048": {
|
||||||
"id": 7048,
|
"id": 7048,
|
||||||
"name": "I LOVE KR",
|
"name": "I LOVE KR",
|
||||||
@@ -3803,6 +3827,12 @@
|
|||||||
"diamondCost": 10,
|
"diamondCost": 10,
|
||||||
"image": "https://storage.streamdps.com/iblock/b24/b24309d4ea6722875678e492ae12fb3f/864ac7928a78b43be2d1ee93915a53f5.webp"
|
"image": "https://storage.streamdps.com/iblock/b24/b24309d4ea6722875678e492ae12fb3f/864ac7928a78b43be2d1ee93915a53f5.webp"
|
||||||
},
|
},
|
||||||
|
"7598": {
|
||||||
|
"id": 7598,
|
||||||
|
"name": "Pirate’s Ship",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/475/4753e54cae562b34edbf1a157cd60b21/722409ec69cfaf707d611b0987799296.webp"
|
||||||
|
},
|
||||||
"7604": {
|
"7604": {
|
||||||
"id": 7604,
|
"id": 7604,
|
||||||
"name": "2023",
|
"name": "2023",
|
||||||
@@ -3905,6 +3935,24 @@
|
|||||||
"diamondCost": 100,
|
"diamondCost": 100,
|
||||||
"image": "https://storage.streamdps.com/iblock/841/841037f168f5e2757ead3d4989d40850/cac3e62b0c75d0914fe2e588832e14ee.webp"
|
"image": "https://storage.streamdps.com/iblock/841/841037f168f5e2757ead3d4989d40850/cac3e62b0c75d0914fe2e588832e14ee.webp"
|
||||||
},
|
},
|
||||||
|
"7812": {
|
||||||
|
"id": 7812,
|
||||||
|
"name": "Bravo",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/b25e72d59e9771b09da8c8c70f395f82~tplv-obj.png"
|
||||||
|
},
|
||||||
|
"7813": {
|
||||||
|
"id": 7813,
|
||||||
|
"name": "Health Potion",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/13f6a46b763c496306ff541daf3021a4~tplv-obj.png"
|
||||||
|
},
|
||||||
|
"7814": {
|
||||||
|
"id": 7814,
|
||||||
|
"name": "Panettone",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/64ce2413a362442819b4551703b7b26c~tplv-obj.png"
|
||||||
|
},
|
||||||
"7823": {
|
"7823": {
|
||||||
"id": 7823,
|
"id": 7823,
|
||||||
"name": "Leon and Lion",
|
"name": "Leon and Lion",
|
||||||
@@ -3995,6 +4043,12 @@
|
|||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/923/92341a47e85be94fb6a6699a6c430a93/d60527955f9597a43d339357fed6a5fc.webp"
|
"image": "https://storage.streamdps.com/iblock/923/92341a47e85be94fb6a6699a6c430a93/d60527955f9597a43d339357fed6a5fc.webp"
|
||||||
},
|
},
|
||||||
|
"7911": {
|
||||||
|
"id": 7911,
|
||||||
|
"name": "Maggie",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/a12/a12a1b23f1f6a19d728de84e1f43e21d/ff288346e9855a9bb6deb4450491028f.webp"
|
||||||
|
},
|
||||||
"7927": {
|
"7927": {
|
||||||
"id": 7927,
|
"id": 7927,
|
||||||
"name": "Puppy Love",
|
"name": "Puppy Love",
|
||||||
@@ -4043,6 +4097,12 @@
|
|||||||
"diamondCost": 88,
|
"diamondCost": 88,
|
||||||
"image": "https://storage.streamdps.com/iblock/e22/e2266686271c7a90ff04517f248c6f73/0459d679c01a5bfa5a4be1d61ec81ec8.webp"
|
"image": "https://storage.streamdps.com/iblock/e22/e2266686271c7a90ff04517f248c6f73/0459d679c01a5bfa5a4be1d61ec81ec8.webp"
|
||||||
},
|
},
|
||||||
|
"7978": {
|
||||||
|
"id": 7978,
|
||||||
|
"name": "Leopard",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/eb4/eb4d116b15c03c2974b86fa400fa6a07/9a34b020e29f2d25f434387ae01b6386.webp"
|
||||||
|
},
|
||||||
"7984": {
|
"7984": {
|
||||||
"id": 7984,
|
"id": 7984,
|
||||||
"name": "Counting Sheep",
|
"name": "Counting Sheep",
|
||||||
@@ -4229,6 +4289,12 @@
|
|||||||
"diamondCost": 88,
|
"diamondCost": 88,
|
||||||
"image": "https://storage.streamdps.com/iblock/88e/88e25becb6f23daa0e97669a3b2905fb/d7b74b5b1e20c22e9baa4f1f02f1c6f5.webp"
|
"image": "https://storage.streamdps.com/iblock/88e/88e25becb6f23daa0e97669a3b2905fb/d7b74b5b1e20c22e9baa4f1f02f1c6f5.webp"
|
||||||
},
|
},
|
||||||
|
"8239": {
|
||||||
|
"id": 8239,
|
||||||
|
"name": "White Rose",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/a2d81f3847457be9083a9c76a59b08cb~tplv-obj.png"
|
||||||
|
},
|
||||||
"8243": {
|
"8243": {
|
||||||
"id": 8243,
|
"id": 8243,
|
||||||
"name": "Cheer You Up",
|
"name": "Cheer You Up",
|
||||||
@@ -4349,6 +4415,12 @@
|
|||||||
"diamondCost": 34500,
|
"diamondCost": 34500,
|
||||||
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/3781e9159ff09272826d3f2216ba36ef.png~tplv-obj.jpg"
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/3781e9159ff09272826d3f2216ba36ef.png~tplv-obj.jpg"
|
||||||
},
|
},
|
||||||
|
"8387": {
|
||||||
|
"id": 8387,
|
||||||
|
"name": "peacock",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/f9f/f9f23f00af57e8fb8a421a2a7f24aacc/a5eb745418085f1be7692f577ff04b9c.webp"
|
||||||
|
},
|
||||||
"8391": {
|
"8391": {
|
||||||
"id": 8391,
|
"id": 8391,
|
||||||
"name": "Sam the Whale",
|
"name": "Sam the Whale",
|
||||||
@@ -4409,6 +4481,12 @@
|
|||||||
"diamondCost": 88,
|
"diamondCost": 88,
|
||||||
"image": "https://storage.streamdps.com/iblock/405/405fcf52a1de3d14ab9834c1f30cc330/0deed9ee2c79ba6bf2005b0ce667bf60.webp"
|
"image": "https://storage.streamdps.com/iblock/405/405fcf52a1de3d14ab9834c1f30cc330/0deed9ee2c79ba6bf2005b0ce667bf60.webp"
|
||||||
},
|
},
|
||||||
|
"8435": {
|
||||||
|
"id": 8435,
|
||||||
|
"name": "Pyramids",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/bfc/bfcf491b940e478b6410047bc047af1b/abbbdd13015a9f31be1b905268873d73.webp"
|
||||||
|
},
|
||||||
"8448": {
|
"8448": {
|
||||||
"id": 8448,
|
"id": 8448,
|
||||||
"name": "Raccoon",
|
"name": "Raccoon",
|
||||||
@@ -4421,6 +4499,12 @@
|
|||||||
"diamondCost": 99,
|
"diamondCost": 99,
|
||||||
"image": "https://storage.streamdps.com/iblock/a0f/a0ff283ce42ad27a03d6b8b98e81463b/9e5a49a9bae80f0afa30257d562cec8e.webp"
|
"image": "https://storage.streamdps.com/iblock/a0f/a0ff283ce42ad27a03d6b8b98e81463b/9e5a49a9bae80f0afa30257d562cec8e.webp"
|
||||||
},
|
},
|
||||||
|
"8456": {
|
||||||
|
"id": 8456,
|
||||||
|
"name": "Zeus",
|
||||||
|
"diamondCost": 34000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/f4e/f4e74e07fff3d3b48143a5c56af7fec4/8b15ef2f342dcd2066bcdcf82e5f07e9.webp"
|
||||||
|
},
|
||||||
"8457": {
|
"8457": {
|
||||||
"id": 8457,
|
"id": 8457,
|
||||||
"name": "Zeus",
|
"name": "Zeus",
|
||||||
@@ -4457,12 +4541,24 @@
|
|||||||
"diamondCost": 199,
|
"diamondCost": 199,
|
||||||
"image": "https://storage.streamdps.com/iblock/50f/50f04937063753d6de255d2b5a080c1c/4f101c7c50ddbe8bd26a2ce5f8c16896.webp"
|
"image": "https://storage.streamdps.com/iblock/50f/50f04937063753d6de255d2b5a080c1c/4f101c7c50ddbe8bd26a2ce5f8c16896.webp"
|
||||||
},
|
},
|
||||||
|
"8599": {
|
||||||
|
"id": 8599,
|
||||||
|
"name": "Convertible Car",
|
||||||
|
"diamondCost": 12000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/2cf/2cfc5af50894de318b81438a7e137710/060001e901992f5462c841b987876eeb.webp"
|
||||||
|
},
|
||||||
"8600": {
|
"8600": {
|
||||||
"id": 8600,
|
"id": 8600,
|
||||||
"name": "Sending positivity",
|
"name": "Sending positivity",
|
||||||
"diamondCost": 199,
|
"diamondCost": 199,
|
||||||
"image": "https://storage.streamdps.com/iblock/29b/29b0e9cb18e3479d17188235f8fdf480/58c6e916f44dcdda9d2f68dbdae77ddb.webp"
|
"image": "https://storage.streamdps.com/iblock/29b/29b0e9cb18e3479d17188235f8fdf480/58c6e916f44dcdda9d2f68dbdae77ddb.webp"
|
||||||
},
|
},
|
||||||
|
"8602": {
|
||||||
|
"id": 8602,
|
||||||
|
"name": "Gorilla",
|
||||||
|
"diamondCost": 30000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/1e2/1e29b9d1a0263f1487498dc556cdcbc1/bec227242f8c9b258855071aa050ac17.webp"
|
||||||
|
},
|
||||||
"8604": {
|
"8604": {
|
||||||
"id": 8604,
|
"id": 8604,
|
||||||
"name": "Starfish Bay",
|
"name": "Starfish Bay",
|
||||||
@@ -4553,6 +4649,12 @@
|
|||||||
"diamondCost": 2000,
|
"diamondCost": 2000,
|
||||||
"image": "https://storage.streamdps.com/iblock/a29/a29903a975ce45f7b9939b510412fcee/051afc0510a7349a9ebfcde9e0fdec24.webp"
|
"image": "https://storage.streamdps.com/iblock/a29/a29903a975ce45f7b9939b510412fcee/051afc0510a7349a9ebfcde9e0fdec24.webp"
|
||||||
},
|
},
|
||||||
|
"8814": {
|
||||||
|
"id": 8814,
|
||||||
|
"name": "Superhero fight",
|
||||||
|
"diamondCost": 30000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/d6b/d6b1c955153c8f8c5048d6c8f0d1b418/97d04b889e64328e9ab07224f6072b5f.webp"
|
||||||
|
},
|
||||||
"8815": {
|
"8815": {
|
||||||
"id": 8815,
|
"id": 8815,
|
||||||
"name": "Pink shoes",
|
"name": "Pink shoes",
|
||||||
@@ -4661,6 +4763,12 @@
|
|||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/ff9/ff906a964a6ad9c4504438302d9354b8/3ee4796c239930c395afb3d7ef10295a.webp"
|
"image": "https://storage.streamdps.com/iblock/ff9/ff906a964a6ad9c4504438302d9354b8/3ee4796c239930c395afb3d7ef10295a.webp"
|
||||||
},
|
},
|
||||||
|
"9086": {
|
||||||
|
"id": 9086,
|
||||||
|
"name": "Man V Seagull",
|
||||||
|
"diamondCost": 15000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/e5d/e5d95d519ee0ed7922de14f224a9504d/e80d8e840dd44cdf20de4c572c25e0f4.webp"
|
||||||
|
},
|
||||||
"9087": {
|
"9087": {
|
||||||
"id": 9087,
|
"id": 9087,
|
||||||
"name": "Flame heart",
|
"name": "Flame heart",
|
||||||
@@ -4673,6 +4781,12 @@
|
|||||||
"diamondCost": 41999,
|
"diamondCost": 41999,
|
||||||
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/bfb8425a7e8fa03f9fec05a973a4a506.png~tplv-obj.jpg"
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/bfb8425a7e8fa03f9fec05a973a4a506.png~tplv-obj.jpg"
|
||||||
},
|
},
|
||||||
|
"9095": {
|
||||||
|
"id": 9095,
|
||||||
|
"name": "Birthday Party",
|
||||||
|
"diamondCost": 6999,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/d0d/d0d1164a9ed81239b70cb25b93927023/d0dba293643c67dc33c1f4dda04e5b50.webp"
|
||||||
|
},
|
||||||
"9096": {
|
"9096": {
|
||||||
"id": 9096,
|
"id": 9096,
|
||||||
"name": "Birthday Crown",
|
"name": "Birthday Crown",
|
||||||
@@ -4685,6 +4799,18 @@
|
|||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"
|
"image": "https://storage.streamdps.com/iblock/5b9/5b9eca4a99e965cb25183681a07a5276/c28f7e9c4a8e42460225ff2d12300ae7.webp"
|
||||||
},
|
},
|
||||||
|
"9138": {
|
||||||
|
"id": 9138,
|
||||||
|
"name": "Trending Figure",
|
||||||
|
"diamondCost": 999,
|
||||||
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/df7b556ccf369bf9a42fe83ec8a77acf.png~tplv-obj.jpg"
|
||||||
|
},
|
||||||
|
"9139": {
|
||||||
|
"id": 9139,
|
||||||
|
"name": "Team Bracelet",
|
||||||
|
"diamondCost": 2,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/54cb1eeca369e5bea1b97707ca05d189.png~tplv-obj.png"
|
||||||
|
},
|
||||||
"9147": {
|
"9147": {
|
||||||
"id": 9147,
|
"id": 9147,
|
||||||
"name": "Bigfoot",
|
"name": "Bigfoot",
|
||||||
@@ -4708,5 +4834,53 @@
|
|||||||
"name": "Pretzel",
|
"name": "Pretzel",
|
||||||
"diamondCost": 1,
|
"diamondCost": 1,
|
||||||
"image": "https://storage.streamdps.com/iblock/a67/a6797793eb382a99d38b2a0c37ec9b58/04ea1042707a361ad0f4668d0d759daa.webp"
|
"image": "https://storage.streamdps.com/iblock/a67/a6797793eb382a99d38b2a0c37ec9b58/04ea1042707a361ad0f4668d0d759daa.webp"
|
||||||
|
},
|
||||||
|
"9184": {
|
||||||
|
"id": 9184,
|
||||||
|
"name": "Cube",
|
||||||
|
"diamondCost": 10,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/69d/69dab4e352882c0bd29c3864e24d80de/258857221189c76260b6af5eeb43e93b.webp"
|
||||||
|
},
|
||||||
|
"9240": {
|
||||||
|
"id": 9240,
|
||||||
|
"name": "Dancing queens",
|
||||||
|
"diamondCost": 20000,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/c79/c793af446369ecef5238e73312c84ccd/464a76f3e6eaee9afc771f45a4bba9df.webp"
|
||||||
|
},
|
||||||
|
"9255": {
|
||||||
|
"id": 9255,
|
||||||
|
"name": "Aerobic headband",
|
||||||
|
"diamondCost": 99,
|
||||||
|
"image": "https://storage.streamdps.com/iblock/3d9/3d98c2fbc96922da37a9d22881bb06b9/0a99af132ab8e3fe9806d2412abc6bf0.webp"
|
||||||
|
},
|
||||||
|
"9463": {
|
||||||
|
"id": 9463,
|
||||||
|
"name": "Fairy Wings",
|
||||||
|
"diamondCost": 1,
|
||||||
|
"image": "https://p19-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/e504dc2f313b8c6df9e99a848e1b3a99.png~tplv-obj.png"
|
||||||
|
},
|
||||||
|
"9465": {
|
||||||
|
"id": 9465,
|
||||||
|
"name": "Fruit Friends",
|
||||||
|
"diamondCost": 299,
|
||||||
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/1153dd51308c556cb4fcc48c7d62209f.png~tplv-obj.jpg"
|
||||||
|
},
|
||||||
|
"9466": {
|
||||||
|
"id": 9466,
|
||||||
|
"name": "Amusement Park",
|
||||||
|
"diamondCost": 17000,
|
||||||
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/12ecc01c2984c5d85bb508e80103a3cb.png~tplv-obj.jpg"
|
||||||
|
},
|
||||||
|
"9467": {
|
||||||
|
"id": 9467,
|
||||||
|
"name": "Lili the Leopard",
|
||||||
|
"diamondCost": 6599,
|
||||||
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/7be03e1af477d1dbc6eb742d0c969372.png~tplv-obj.jpg"
|
||||||
|
},
|
||||||
|
"9468": {
|
||||||
|
"id": 9468,
|
||||||
|
"name": "Rhythmic Bear",
|
||||||
|
"diamondCost": 2999,
|
||||||
|
"image": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/resource/16eacf541e4bd6816e88139d079519f5.png~tplv-obj.jpg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2
pom.xml
2
pom.xml
@@ -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>0.0.25-Release</version>
|
<version>1.0.4-Release</version>
|
||||||
<modules>
|
<modules>
|
||||||
<module>API</module>
|
<module>API</module>
|
||||||
<module>Client</module>
|
<module>Client</module>
|
||||||
|
|||||||
Reference in New Issue
Block a user