Compare commits

...

21 Commits

Author SHA1 Message Date
jacek.wolniewicz
b1954a708c Fix issue: no events where triggered 2024-06-30 06:59:26 +02:00
kohlerpop1
14317337e9 Optimized TikTokLiveEventHandler 2024-06-29 23:57:53 -04:00
kohlerpop1
947c9c49a2 Improve addProxy(String addressPort) in ProxyClientSettings
Added @param action description and return values
Optimized methods in TikTokLiveMapper
Optimized Thread in TikTokWebSocketPingingTask
Optimized TikTokLiveEventHandler and TikTokLiveMessageHandler methods
2024-06-29 23:28:49 -04:00
jacek.wolniewicz
f2bd07377b Introduce dependecy injection container
- TikTokLiveClientBuilder this class has been higly modify to support DI container
2024-06-29 23:23:48 +02:00
jacek.wolniewicz
3f268f3a1a Introduce dependecy injection container
- TikTokLiveClientBuilder this class has been higly modify to support DI container
2024-06-29 23:12:24 +02:00
jacek.wolniewicz
55fcf83870 Introduce dependecy injection container
- TikTokLiveClientBuilder this class has been higly modify to support DI container
2024-06-29 23:07:50 +02:00
jacek.wolniewicz
8d3828cca8 Introduce dependecy injection container
- TikTokLiveClientBuilder this class has been higly modify to support DI container
2024-06-29 23:04:53 +02:00
jacek.wolniewicz
1c88491b8c Merge branch 'refs/heads/dev-dependecy-injection' into develop-1.7.3
# Conflicts:
#	API/src/main/java/io/github/jwdeveloper/tiktok/data/settings/ProxyClientSettings.java
#	Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokLiveClientBuilder.java
2024-06-29 22:57:56 +02:00
jacek.wolniewicz
47b050d0ba Introduce dependecy injection container
- TikTokLiveClientBuilder this class has been higly modify to support DI container
2024-06-29 22:52:39 +02:00
kohlerpop1
cfef082d3b Updated ProxyData exceptions to include previous exception to finish stacktrace
Updated LiveUserData.Request to throw an IllegalArgumentException when a null or blank username is provided
Updated HttpClientSettings to use setProxyClientSettings instead of direct access
Fixed ProxyRotation bug starting at index 1 instead of 0 and made methods default to synchronized in case concurrency is used in implementors code
Changed HttpClient#toUrl to toUri
Added @Getter to HttpClientFactory for liveClientSettings
Added consumer to TikTokLive#requests so that way proxies can be used when calling the fetch methods
Changed LiveUserData.Response#startTime to clarify the variable name
2024-06-28 23:07:10 -04:00
GitHub Action
34ddc74189 Update version in pom.xml 2024-06-24 14:16:40 +00:00
Jacek W
9a66d240bc Merge pull request #85 from jwdeveloper/develop-1.7.2
Develop 1.7.2
2024-06-24 08:38:22 +02:00
kohlerpop1
d825803187 Added while loop condition so it does not exit when getConnectionState returns Disconnected and stopOnDisconnect is false! 2024-06-23 23:06:05 -04:00
kohlerpop1
77c9cd6b52 Converted Consumer to BiConsumer to also accept liveClient! 2024-06-20 16:51:42 -04:00
kohlerpop1
0329d3cfeb Removed useless imports and altered logger message! 2024-06-18 22:01:47 -04:00
kohlerpop1
26659bb37d Removed not needed/used RecorderSettings#startOnConnected 2024-06-18 15:36:03 -04:00
kohlerpop1
0b9852c4d4 Moved ActionResult#message to top of toJson() for easier reading
Change Recording settings to accept an output file instead of directory and filename
2024-06-18 15:21:05 -04:00
GitHub Action
31618a16ba Update version in pom.xml 2024-06-07 10:55:14 +00:00
GitHub Action
243791f6b8 Update version in pom.xml 2024-06-02 20:11:19 +00:00
David Kohler
4f74a0f1b7 MINOR 2024-06-02 16:09:45 -04:00
GitHub Action
d1eec34fca Update version in pom.xml 2024-06-02 20:07:58 +00:00
56 changed files with 948 additions and 409 deletions

View File

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

View File

@@ -50,16 +50,12 @@ public class ProxyData
return new ProxyData(address, port); return new ProxyData(address, port);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new IllegalArgumentException("Port must be a valid integer!"); throw new IllegalArgumentException("Port must be a valid integer!", e);
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
throw new IllegalArgumentException("Address must be valid IPv4, IPv6, or domain name!"); throw new IllegalArgumentException("Address must be valid IPv4, IPv6, or domain name!", e);
} }
} }
public ProxyData clone() {
return new ProxyData(address, port);
}
public InetSocketAddress toSocketAddress() { public InetSocketAddress toSocketAddress() {
return new InetSocketAddress(address, port); return new InetSocketAddress(address, port);
} }

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.data.models.battles; package io.github.jwdeveloper.tiktok.data.models.battles;
public abstract class Team { public abstract class Team {

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.data.models.battles; package io.github.jwdeveloper.tiktok.data.models.battles;
import io.github.jwdeveloper.tiktok.data.models.users.User; import io.github.jwdeveloper.tiktok.data.models.users.User;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.data.models.battles; package io.github.jwdeveloper.tiktok.data.models.battles;
import io.github.jwdeveloper.tiktok.data.models.users.User; import io.github.jwdeveloper.tiktok.data.models.users.User;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.data.models.battles; package io.github.jwdeveloper.tiktok.data.models.battles;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.data.models.gifts; package io.github.jwdeveloper.tiktok.data.models.gifts;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.data.models.users; package io.github.jwdeveloper.tiktok.data.models.users;
import lombok.Getter; import lombok.Getter;

View File

@@ -27,18 +27,23 @@ import lombok.*;
public class LiveUserData { public class LiveUserData {
@Getter @Getter
@AllArgsConstructor
public static class Request { public static class Request {
private String userName; private final String userName;
public Request(String userName) {
if (userName == null || userName.isBlank())
throw new IllegalArgumentException("Invalid empty username!");
this.userName = userName;
}
} }
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public static class Response { public static class Response {
private String json; private final String json;
private UserStatus userStatus; private final UserStatus userStatus;
private String roomId; private final String roomId;
private long startedAtTimeStamp; private final long startTime;
public boolean isLiveOnline() { public boolean isLiveOnline() {
return userStatus == LiveUserData.UserStatus.Live || userStatus == LiveUserData.UserStatus.LivePaused; return userStatus == LiveUserData.UserStatus.Live || userStatus == LiveUserData.UserStatus.LivePaused;

View File

@@ -97,7 +97,7 @@ public class HttpClientSettings {
newSettings.getHeaders().putAll(new TreeMap<>(this.headers)); newSettings.getHeaders().putAll(new TreeMap<>(this.headers));
newSettings.getCookies().putAll(new TreeMap<>(this.cookies)); newSettings.getCookies().putAll(new TreeMap<>(this.cookies));
newSettings.getParams().putAll(new TreeMap<>(this.params)); newSettings.getParams().putAll(new TreeMap<>(this.params));
newSettings.proxyClientSettings = this.proxyClientSettings; newSettings.setProxyClientSettings(this.proxyClientSettings);
return newSettings; return newSettings;
} }

View File

@@ -31,17 +31,17 @@ import java.util.function.Consumer;
@Getter @Getter
@Setter @Setter
public class ProxyClientSettings implements Iterator<ProxyData> public class ProxyClientSettings implements Iterator<ProxyData>, Iterable<ProxyData>
{ {
private boolean enabled, autoDiscard = true, fallback = true; private boolean enabled, autoDiscard = true, fallback = true;
private Rotation rotation = Rotation.CONSECUTIVE; private Rotation rotation = Rotation.CONSECUTIVE;
private final List<ProxyData> proxyList = new ArrayList<>(); private final List<ProxyData> proxyList = new ArrayList<>();
private int index = -1; private int index;
private Proxy.Type type = Proxy.Type.DIRECT; private Proxy.Type type = Proxy.Type.DIRECT;
private Consumer<ProxyData> onProxyUpdated = x -> {}; private Consumer<ProxyData> onProxyUpdated = x -> {};
public boolean addProxy(String addressPort) { public boolean addProxy(String addressPort) {
return proxyList.add(ProxyData.map(addressPort)); return addProxy(ProxyData.map(addressPort).toSocketAddress());
} }
public boolean addProxy(String address, int port) { public boolean addProxy(String address, int port) {
@@ -57,33 +57,27 @@ public class ProxyClientSettings implements Iterator<ProxyData>
} }
@Override @Override
public boolean hasNext() { public synchronized boolean hasNext() {
return !proxyList.isEmpty(); return !proxyList.isEmpty();
} }
@Override @Override
public ProxyData next() { public synchronized ProxyData next() {
var nextProxy = switch (rotation) try {
{ var nextProxy = proxyList.get(index);
case CONSECUTIVE -> { onProxyUpdated.accept(nextProxy);
index = (index+1) % proxyList.size(); return nextProxy;
yield proxyList.get(index).clone(); } finally {
switch (rotation) {
case CONSECUTIVE -> index = ++index % proxyList.size();
case RANDOM -> index = (int) (Math.random() * proxyList.size());
case NONE -> index = Math.max(index, 0);
} }
case RANDOM -> { }
index = new Random().nextInt(proxyList.size()); }
yield proxyList.get(index).clone();
}
case NONE -> {
index = Math.max(index, 0);
yield proxyList.get(index).clone();
}
};
onProxyUpdated.accept(nextProxy);
return nextProxy;
}
@Override @Override
public void remove() { public synchronized void remove() {
proxyList.remove(index); proxyList.remove(index);
} }
@@ -97,8 +91,8 @@ public class ProxyClientSettings implements Iterator<ProxyData>
} }
} }
public ProxyClientSettings clone() @Override
{ public ProxyClientSettings clone() {
ProxyClientSettings settings = new ProxyClientSettings(); ProxyClientSettings settings = new ProxyClientSettings();
settings.setEnabled(enabled); settings.setEnabled(enabled);
settings.setRotation(rotation); settings.setRotation(rotation);
@@ -109,6 +103,27 @@ public class ProxyClientSettings implements Iterator<ProxyData>
return settings; return settings;
} }
@Override
public String toString() {
return "ProxyClientSettings{" +
"enabled=" + enabled +
", autoDiscard=" + autoDiscard +
", fallback=" + fallback +
", rotation=" + rotation +
", proxyList=" + proxyList +
", index=" + index +
", type=" + type +
'}';
}
/**
* With {@code Iterable<ProxyData>} interface, you can use this object inside for loop!
*/
@Override
public Iterator<ProxyData> iterator() {
return this;
}
public enum Rotation public enum Rotation
{ {
/** Rotate addresses consecutively, from proxy 0 -> 1 -> 2 -> ...etc. */ /** Rotate addresses consecutively, from proxy 0 -> 1 -> 2 -> ...etc. */

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.listener; package io.github.jwdeveloper.tiktok.listener;
import io.github.jwdeveloper.tiktok.data.events.*; import io.github.jwdeveloper.tiktok.data.events.*;

View File

@@ -25,6 +25,7 @@ package io.github.jwdeveloper.tiktok.live.builder;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
@FunctionalInterface
public interface EventConsumer<T extends TikTokEvent> public interface EventConsumer<T extends TikTokEvent>
{ {
void onEvent(LiveClient liveClient, T event); void onEvent(LiveClient liveClient, T event);

View File

@@ -52,77 +52,70 @@ public interface EventsBuilder<T> {
/** /**
* Invoked whenever any event is triggered * Invoked whenever any event is triggered
* *
* @param action * @param action consumable action
* @return * @return self instance
*/ */
T onEvent(EventConsumer<TikTokEvent> action); T onEvent(EventConsumer<TikTokEvent> action);
/** /**
* Invoked when information about room (live) got updated such as viewer count, etc.. * Invoked when information about room (live) got updated such as viewer count, etc..
* *
* @param action * @param action consumable action
* @return * @return self instance
*/ */
T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> action); T onRoomInfo(EventConsumer<TikTokRoomInfoEvent> action);
/** /**
* Invoked when someone send message to chat * Invoked when someone send message to chat
* * @param action consumable action
* @param action * @return self instance
* @return
*/ */
T onComment(EventConsumer<TikTokCommentEvent> action); T onComment(EventConsumer<TikTokCommentEvent> action);
/** /**
* Invoked when TikTokLiveJava makes http request and getting response * Invoked when TikTokLiveJava makes http request and getting response
* * @param action consumable action
* @param action * @return self instance
* @return
*/ */
T onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action); T onHttpResponse(EventConsumer<TikTokHttpResponseEvent> action);
/** /**
* Invoked when TikTok protocolBuffer data "message" was successfully mapped to event * Invoked when TikTok protocolBuffer data "message" was successfully mapped to event
* events contains protocol-buffer "Message" and TikTokLiveJava "Event" * events contains protocol-buffer "Message" and TikTokLiveJava "Event"
* * @param action consumable action
* @param action * @return self instance
* @return
*/ */
T onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> action); T onWebsocketMessage(EventConsumer<TikTokWebsocketMessageEvent> action);
/** /**
* Invoked when there was not found event mapper for TikTok protocolBuffer data "message" * Invoked when there was not found event mapper for TikTok protocolBuffer data "message"
* * @param action consumable action
* @param action * @return self instance
* @return
*/ */
T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> action); T onWebsocketUnhandledMessage(EventConsumer<TikTokWebsocketUnhandledMessageEvent> action);
/** /**
* Invoked every time TikTok sends protocolBuffer data to websocket * Invoked every time TikTok sends protocolBuffer data to websocket
* Response contains list of messages that are later mapped to events * Response contains list of messages that are later mapped to events
* @param action * @param action consumable action
* @return * @return self instance
*/ */
T onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> action); T onWebsocketResponse(EventConsumer<TikTokWebsocketResponseEvent> action);
/** /**
* Invoked for gifts that has no combo, or when combo finishes * Invoked for gifts that has no combo, or when combo finishes
* @param action * @param action consumable action
* @return * @return self instance
*/ */
T onGift(EventConsumer<TikTokGiftEvent> action); T onGift(EventConsumer<TikTokGiftEvent> action);
/** /**
* Invoked for gifts that has combo options such as roses * Invoked for gifts that has combo options such as roses
* @param action * @param action consumable action
* @return * @return self instance
*/ */
T onGiftCombo(EventConsumer<TikTokGiftComboEvent> action); T onGiftCombo(EventConsumer<TikTokGiftComboEvent> action);
T onQuestion(EventConsumer<TikTokQuestionEvent> action); T onQuestion(EventConsumer<TikTokQuestionEvent> action);
T onSubscribe(EventConsumer<TikTokSubscribeEvent> action); T onSubscribe(EventConsumer<TikTokSubscribeEvent> action);
@@ -145,36 +138,36 @@ public interface EventsBuilder<T> {
/** /**
* Invoked when client has been successfully connected to live * Invoked when client has been successfully connected to live
* @param action * @param action consumable action
* @return * @return self instance
*/ */
T onConnected(EventConsumer<TikTokConnectedEvent> action); T onConnected(EventConsumer<TikTokConnectedEvent> action);
/** /**
* Invoked before client has been successfully connected to live * Invoked before client has been successfully connected to live
* @param action * @param action consumable action
* @return * @return self instance
*/ */
T onPreConnection(EventConsumer<TikTokPreConnectionEvent> action); T onPreConnection(EventConsumer<TikTokPreConnectionEvent> action);
/** /**
* Invoked when client tries to reconnect * Invoked when client tries to reconnect
* @param action * @param action consumable action
* @return * @return self instance
*/ */
T onReconnecting(EventConsumer<TikTokReconnectingEvent> action); T onReconnecting(EventConsumer<TikTokReconnectingEvent> action);
/** /**
* Invoked when client disconnected * Invoked when client disconnected
* @param action * @param action consumable action
* @return * @return self instance
*/ */
T onDisconnected(EventConsumer<TikTokDisconnectedEvent> action); T onDisconnected(EventConsumer<TikTokDisconnectedEvent> action);
/** /**
* Invoked when exception was throed inside client or event handler * Invoked when exception was throed inside client or event handler
* @param action * @param action consumable action
* @return * @return self instance
*/ */
T onError(EventConsumer<TikTokErrorEvent> action); T onError(EventConsumer<TikTokErrorEvent> action);

View File

@@ -5,12 +5,18 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.6.3-Release</version> <version>1.7.2-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>Client</artifactId> <artifactId>Client</artifactId>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency> <dependency>
@@ -24,7 +30,12 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.jwdeveloper.DepenDance</groupId>
<artifactId>DepenDance-Full</artifactId>
<version>0.0.18-Release</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>com.google.protobuf</groupId> <groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId> <artifactId>protobuf-java</artifactId>

View File

@@ -23,19 +23,21 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftsManager; import io.github.jwdeveloper.tiktok.gifts.TikTokGiftsManager;
import io.github.jwdeveloper.tiktok.http.LiveHttpClient; import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.live.GiftsManager; import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder; import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public class TikTokLive { public class TikTokLive {
/** /**
* Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo' * Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo'
* *
* @param hostName profile name of Tiktok user could be found in profile link * @param hostName profile name of TikTok user could be found in profile link
* @return LiveClientBuilder * @return LiveClientBuilder
*/ */
public static LiveClientBuilder newClient(String hostName) { public static LiveClientBuilder newClient(String hostName) {
@@ -45,7 +47,7 @@ public class TikTokLive {
/** /**
* Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo' * Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo'
* *
* @param hostName profile name of Tiktok user could be found in profile link * @param hostName profile name of TikTok user could be found in profile link
* @return true if live is Online, false if is offline * @return true if live is Online, false if is offline
*/ */
public static boolean isLiveOnline(String hostName) { public static boolean isLiveOnline(String hostName) {
@@ -55,7 +57,7 @@ public class TikTokLive {
/** /**
* Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo' * Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo'
* *
* @param hostName profile name of Tiktok user could be found in profile link * @param hostName profile name of TikTok user could be found in profile link
* @return true if live is Online, false if is offline * @return true if live is Online, false if is offline
*/ */
public static CompletableFuture<Boolean> isLiveOnlineAsync(String hostName) { public static CompletableFuture<Boolean> isLiveOnlineAsync(String hostName) {
@@ -65,7 +67,7 @@ public class TikTokLive {
/** /**
* Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo' * Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo'
* *
* @param hostName profile name of Tiktok user could be found in profile link * @param hostName profile name of TikTok user could be found in profile link
* @return true is hostName name is valid and exists, false if not * @return true is hostName name is valid and exists, false if not
*/ */
public static boolean isHostNameValid(String hostName) { public static boolean isHostNameValid(String hostName) {
@@ -75,20 +77,29 @@ public class TikTokLive {
/** /**
* Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo' * Example: https://www.tiktok.com/@dostawcavideo - hostName would be 'dostawcavideo'
* *
* @param hostName profile name of Tiktok user could be found in profile link * @param hostName profile name of TikTok user could be found in profile link
* @return true is hostName name is valid and exists, false if not * @return true is hostName name is valid and exists, false if not
*/ */
public static CompletableFuture<Boolean> isHostNameValidAsync(String hostName) { public static CompletableFuture<Boolean> isHostNameValidAsync(String hostName) {
return CompletableFuture.supplyAsync(() -> isHostNameValid(hostName)); return CompletableFuture.supplyAsync(() -> isHostNameValid(hostName));
} }
/**
* Use to get some data from TikTok about users are lives
*
* @return LiveHttpClient
*/
public static LiveHttpClient requests(Consumer<LiveClientSettings> consumer) {
return new TikTokLiveHttpClient(consumer);
}
/** /**
* Use to get some data from TikTok about users are lives * Use to get some data from TikTok about users are lives
* *
* @return LiveHttpClient * @return LiveHttpClient
*/ */
public static LiveHttpClient requests() { public static LiveHttpClient requests() {
return new TikTokLiveHttpClient(); return requests(liveClientSettings -> {});
} }
private static GiftsManager giftsManager; private static GiftsManager giftsManager;

View File

@@ -23,6 +23,7 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import io.github.jwdeveloper.dependance.injector.api.annotations.Inject;
import io.github.jwdeveloper.tiktok.data.events.*; import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.control.*; import io.github.jwdeveloper.tiktok.data.events.control.*;
@@ -43,13 +44,14 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Logger; import java.util.logging.Logger;
public class TikTokLiveClient implements LiveClient { public class TikTokLiveClient implements LiveClient
{
private final TikTokRoomInfo liveRoomInfo; private final TikTokRoomInfo liveRoomInfo;
private final LiveHttpClient httpClient; private final LiveHttpClient httpClient;
private final SocketClient webSocketClient; private final SocketClient webSocketClient;
private final TikTokLiveEventHandler tikTokEventHandler; private final TikTokLiveEventHandler tikTokEventHandler;
private final LiveClientSettings clientSettings; private final LiveClientSettings clientSettings;
private final TikTokListenersManager listenersManager; private final ListenersManager listenersManager;
private final Logger logger; private final Logger logger;
private final GiftsManager giftsManager; private final GiftsManager giftsManager;
private final TikTokLiveMessageHandler messageHandler; private final TikTokLiveMessageHandler messageHandler;
@@ -62,7 +64,7 @@ public class TikTokLiveClient implements LiveClient {
SocketClient webSocketClient, SocketClient webSocketClient,
TikTokLiveEventHandler tikTokEventHandler, TikTokLiveEventHandler tikTokEventHandler,
LiveClientSettings clientSettings, LiveClientSettings clientSettings,
TikTokListenersManager listenersManager, ListenersManager listenersManager,
Logger logger) { Logger logger) {
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
this.giftsManager = giftsManager; this.giftsManager = giftsManager;
@@ -125,7 +127,7 @@ public class TikTokLiveClient implements LiveClient {
tikTokEventHandler.publish(this, new TikTokConnectingEvent()); tikTokEventHandler.publish(this, new TikTokConnectingEvent());
var userDataRequest = new LiveUserData.Request(liveRoomInfo.getHostName()); var userDataRequest = new LiveUserData.Request(liveRoomInfo.getHostName());
var userData = httpClient.fetchLiveUserData(userDataRequest); var userData = httpClient.fetchLiveUserData(userDataRequest);
liveRoomInfo.setStartTime(userData.getStartedAtTimeStamp()); liveRoomInfo.setStartTime(userData.getStartTime());
liveRoomInfo.setRoomId(userData.getRoomId()); liveRoomInfo.setRoomId(userData.getRoomId());
if (clientSettings.isFetchGifts()) if (clientSettings.isFetchGifts())

View File

@@ -22,6 +22,9 @@
*/ */
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.dependance.Dependance;
import io.github.jwdeveloper.dependance.api.DependanceContainer;
import io.github.jwdeveloper.tiktok.mappers.MessagesMapperFactory;
import io.github.jwdeveloper.tiktok.common.LoggerFactory; import io.github.jwdeveloper.tiktok.common.LoggerFactory;
import io.github.jwdeveloper.tiktok.data.events.*; import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
@@ -38,13 +41,15 @@ import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftsManager; import io.github.jwdeveloper.tiktok.gifts.TikTokGiftsManager;
import io.github.jwdeveloper.tiktok.http.HttpClientFactory; import io.github.jwdeveloper.tiktok.http.HttpClientFactory;
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
import io.github.jwdeveloper.tiktok.listener.*; import io.github.jwdeveloper.tiktok.listener.*;
import io.github.jwdeveloper.tiktok.live.*; import io.github.jwdeveloper.tiktok.live.*;
import io.github.jwdeveloper.tiktok.live.builder.*; import io.github.jwdeveloper.tiktok.live.builder.*;
import io.github.jwdeveloper.tiktok.mappers.*; import io.github.jwdeveloper.tiktok.mappers.*;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult; import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokCommonEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.*; import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokGiftEventHandler;
import io.github.jwdeveloper.tiktok.messages.webcast.*; import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokRoomInfoEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokSocialMediaEventHandler;
import io.github.jwdeveloper.tiktok.websocket.*; import io.github.jwdeveloper.tiktok.websocket.*;
import java.util.*; import java.util.*;
@@ -52,28 +57,23 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Logger; import java.util.logging.Logger;
import static io.github.jwdeveloper.tiktok.messages.enums.LinkMessageType.*;
public class TikTokLiveClientBuilder implements LiveClientBuilder { public class TikTokLiveClientBuilder implements LiveClientBuilder {
protected final LiveClientSettings clientSettings; protected final LiveClientSettings clientSettings;
protected final TikTokLiveEventHandler eventHandler; protected final TikTokLiveEventHandler eventHandler;
protected final List<TikTokEventListener> listeners; protected final List<TikTokEventListener> listeners;
protected Consumer<TikTokMapper> onCustomMappings; protected final List<Consumer<TikTokMapper>> onCustomMappings;
protected Logger logger;
protected GiftsManager giftsManager;
public TikTokLiveClientBuilder(String userName) { public TikTokLiveClientBuilder(String userName) {
this.clientSettings = LiveClientSettings.createDefault(); this.clientSettings = LiveClientSettings.createDefault();
this.clientSettings.setHostName(userName); this.clientSettings.setHostName(userName);
this.eventHandler = new TikTokLiveEventHandler(); this.eventHandler = new TikTokLiveEventHandler();
this.listeners = new ArrayList<>(); this.listeners = new ArrayList<>();
this.onCustomMappings = (e) -> { this.onCustomMappings = new ArrayList<>();
};
} }
public LiveClientBuilder onMapping(Consumer<TikTokMapper> onCustomMappings) { public LiveClientBuilder onMapping(Consumer<TikTokMapper> consumer) {
this.onCustomMappings = onCustomMappings; this.onCustomMappings.add(consumer);
return this; return this;
} }
@@ -104,169 +104,81 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
var httpSettings = clientSettings.getHttpSettings(); var httpSettings = clientSettings.getHttpSettings();
httpSettings.getParams().put("app_language", clientSettings.getClientLanguage()); httpSettings.getParams().put("app_language", clientSettings.getClientLanguage());
httpSettings.getParams().put("webcast_language", clientSettings.getClientLanguage()); httpSettings.getParams().put("webcast_language", clientSettings.getClientLanguage());
this.logger = LoggerFactory.create(clientSettings.getHostName(), clientSettings);
this.giftsManager = clientSettings.isFetchGifts() ? TikTokLive.gifts() : new TikTokGiftsManager(List.of());
} }
//TODO each class registered to container should implement own interface,
public LiveClient build() { public LiveClient build() {
validate(); validate();
var tiktokRoomInfo = new TikTokRoomInfo(); //Docs: https://github.com/jwdeveloper/DepenDance?tab=readme-ov-file#01-basic
tiktokRoomInfo.setHostName(clientSettings.getHostName()); var dependance = Dependance.newContainer();
var listenerManager = new TikTokListenersManager(listeners, eventHandler); //config
dependance.registerSingleton(LiveClientSettings.class, clientSettings);
dependance.registerSingleton(Logger.class, LoggerFactory.create(clientSettings.getHostName(), clientSettings));
dependance.registerSingleton(TikTokRoomInfo.class, container ->
{
var roomInfo = new TikTokRoomInfo();
roomInfo.setHostName(clientSettings.getHostName());
return roomInfo;
});
var httpClientFactory = new HttpClientFactory(clientSettings); //messages
dependance.registerSingleton(TikTokLiveEventHandler.class, eventHandler);
dependance.registerSingleton(TikTokLiveMessageHandler.class);
var liveHttpClient = clientSettings.isOffline() ? //listeners
new TikTokLiveHttpOfflineClient() : dependance.registerSingletonList(TikTokEventListener.class, (e) -> listeners);
new TikTokLiveHttpClient(httpClientFactory, clientSettings); dependance.registerSingleton(ListenersManager.class, TikTokListenersManager.class);
var eventsMapper = createMapper(giftsManager, tiktokRoomInfo); //networking
var messageHandler = new TikTokLiveMessageHandler(eventHandler, eventsMapper); dependance.registerSingleton(HttpClientFactory.class);
if (clientSettings.isOffline()) {
dependance.registerSingleton(SocketClient.class, TikTokWebSocketOfflineClient.class);
dependance.registerSingleton(LiveHttpClient.class, TikTokLiveHttpOfflineClient.class);
} else {
dependance.registerSingleton(SocketClient.class, TikTokWebSocketClient.class);
dependance.registerSingleton(LiveHttpClient.class, TikTokLiveHttpClient.class);
}
var webSocketClient = clientSettings.isOffline() ? /* TODO in future, custom proxy implementation that can be provided via builder
new TikTokWebSocketOfflineClient(eventHandler) : * if(customProxy != null)
new TikTokWebSocketClient( * dependance.registerSingleton(TikTokProxyProvider.class,customProxy);
clientSettings, * else
messageHandler, * dependance.registerSingleton(TikTokProxyProvider.class,DefaultProxyProvider.class);
eventHandler); */
return new TikTokLiveClient( //gifts
messageHandler, if (clientSettings.isFetchGifts()) {
giftsManager, dependance.registerSingleton(GiftsManager.class, TikTokLive.gifts());
tiktokRoomInfo, } else {
liveHttpClient, dependance.registerSingleton(GiftsManager.class, new TikTokGiftsManager(List.of()));
webSocketClient, }
eventHandler,
clientSettings, //mapper
listenerManager, dependance.registerSingleton(TikTokGenericEventMapper.class);
logger); dependance.registerSingleton(TikTokMapperHelper.class, TikTokLiveMapperHelper.class);
dependance.registerSingleton(TikTokMapper.class, (container) ->
{
var dependace = (DependanceContainer) container.find(DependanceContainer.class);
var mapper = MessagesMapperFactory.create(dependace);
onCustomMappings.forEach(action -> action.accept(mapper));
return mapper;
});
//mapper handlers
dependance.registerSingleton(TikTokCommonEventHandler.class);
dependance.registerSingleton(TikTokGiftEventHandler.class);
dependance.registerSingleton(TikTokRoomInfoEventHandler.class);
dependance.registerSingleton(TikTokSocialMediaEventHandler.class);
//client
dependance.registerSingleton(LiveClient.class, TikTokLiveClient.class);
var container = dependance.build();
return container.find(LiveClient.class);
} }
public TikTokLiveMapper createMapper(GiftsManager giftsManager, TikTokRoomInfo roomInfo) {
var eventMapper = new TikTokGenericEventMapper();
var mapper = new TikTokLiveMapper(new TikTokLiveMapperHelper(eventMapper));
//ConnectionEvents events
var commonHandler = new TikTokCommonEventHandler();
var giftHandler = new TikTokGiftEventHandler(giftsManager, roomInfo);
var roomInfoHandler = new TikTokRoomInfoEventHandler(roomInfo);
var socialHandler = new TikTokSocialMediaEventHandler(roomInfo);
mapper.forMessage(WebcastControlMessage.class, commonHandler::handleWebcastControlMessage);
//Room status events
mapper.forMessage(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
mapper.forMessage(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
mapper.forMessage(WebcastCaptionMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastCaptionMessage.class);
return MappingResult.of(messageObject, new TikTokCaptionEvent(messageObject));
});
//User Interactions events
mapper.forMessage(WebcastChatMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
return MappingResult.of(messageObject, new TikTokCommentEvent(messageObject));
});
mapper.forMessage(WebcastSubNotifyMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastSubNotifyMessage.class);
return MappingResult.of(messageObject, new TikTokSubscribeEvent(messageObject));
});
mapper.forMessage(WebcastEmoteChatMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastEmoteChatMessage.class);
return MappingResult.of(messageObject, new TikTokEmoteEvent(messageObject));
});
mapper.forMessage(WebcastQuestionNewMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastQuestionNewMessage.class);
return MappingResult.of(messageObject, new TikTokQuestionEvent(messageObject));
});
mapper.forMessage(WebcastLikeMessage.class, roomInfoHandler::handleLike);
mapper.forMessage(WebcastGiftMessage.class, giftHandler::handleGifts);
mapper.forMessage(WebcastSocialMessage.class, socialHandler::handle);
mapper.forMessage(WebcastMemberMessage.class, roomInfoHandler::handleMemberMessage);
//Host Interaction events
mapper.forMessage(WebcastPollMessage.class, commonHandler::handlePollEvent);
mapper.forMessage(WebcastRoomPinMessage.class, commonHandler::handlePinMessage);
mapper.forMessage(WebcastChatMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
return MappingResult.of(messageObject, new TikTokCommentEvent(messageObject));
});
//LinkMic events
mapper.forMessage(WebcastLinkMicBattle.class, (inputBytes, messageName, mapperHelper) -> {
var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMicBattle.class);
return MappingResult.of(message, new TikTokLinkMicBattleEvent(message));
});
mapper.forMessage(WebcastLinkMicArmies.class, (inputBytes, messageName, mapperHelper) -> {
var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMicArmies.class);
return MappingResult.of(message, new TikTokLinkMicArmiesEvent(message));
});
mapper.forMessage(WebcastLinkMessage.class, ((inputBytes, messageName, mapperHelper) -> {
var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMessage.class);
return MappingResult.of(message, switch (message.getMessageType()) {
case TYPE_LINKER_INVITE -> new TikTokLinkInviteEvent(message);
case TYPE_LINKER_REPLY -> new TikTokLinkReplyEvent(message);
case TYPE_LINKER_CREATE -> new TikTokLinkCreateEvent(message);
case TYPE_LINKER_CLOSE -> new TikTokLinkCloseEvent(message);
case TYPE_LINKER_ENTER -> new TikTokLinkEnterEvent(message);
case TYPE_LINKER_LEAVE -> new TikTokLinkLeaveEvent(message);
case TYPE_LINKER_CANCEL_INVITE, TYPE_LINKER_CANCEL_APPLY -> new TikTokLinkCancelEvent(message);
case TYPE_LINKER_KICK_OUT -> new TikTokLinkKickOutEvent(message);
case TYPE_LINKER_LINKED_LIST_CHANGE -> new TikTokLinkLinkedListChangeEvent(message);
case TYPE_LINKER_UPDATE_USER -> new TikTokLinkUpdateUserEvent(message);
case TYPE_LINKER_WAITING_LIST_CHANGE, TYPE_LINKER_WAITING_LIST_CHANGE_V2 -> new TikTokLinkWaitListChangeEvent(message);
case TYPE_LINKER_MUTE -> new TikTokLinkMuteEvent(message);
case TYPE_LINKER_MATCH -> new TikTokLinkRandomMatchEvent(message);
case TYPE_LINKER_UPDATE_USER_SETTING -> new TikTokLinkUpdateUserSettingEvent(message);
case TYPE_LINKER_MIC_IDX_UPDATE -> new TikTokLinkMicIdxUpdateEvent(message);
case TYPE_LINKER_LINKED_LIST_CHANGE_V2 -> new TikTokLinkListChangeEvent(message);
case TYPE_LINKER_COHOST_LIST_CHANGE -> new TikTokLinkCohostListChangeEvent(message);
case TYPE_LINKER_MEDIA_CHANGE -> new TikTokLinkMediaChangeEvent(message);
case TYPE_LINKER_ACCEPT_NOTICE -> new TikTokLinkAcceptNoticeEvent(message);
case TYPE_LINKER_SYS_KICK_OUT -> new TikTokLinkSysKickOutEvent(message);
case TYPE_LINKMIC_USER_TOAST -> new TikTokLinkUserToastEvent(message);
default -> new TikTokLinkEvent(message);
});
}));
// mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
//Rank events
// mapper.webcastObjectToConstructor(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
// mapper.webcastObjectToConstructor(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
// mapper.webcastObjectToConstructor(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
//Others events
// mapper.webcastObjectToConstructor(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
// mapper.webcastObjectToConstructor(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
// mapper.webcastObjectToConstructor(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
// mapper.webcastObjectToConstructor(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
// mapper.webcastObjectToConstructor(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
// mapper.webcastObjectToConstructor(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
// mapper.bytesToEvents(WebcastEnvelopeMessage.class, commonHandler::handleEnvelop);
onCustomMappings.accept(mapper);
return mapper;
}
public LiveClient buildAndConnect() { public LiveClient buildAndConnect() {
var client = build(); var client = build();
client.connect(); client.connect();
@@ -277,6 +189,10 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return build().connectAsync(); return build().connectAsync();
} }
/**
* To do figure out how to use Annotation processor.
* Goal is to generates methods for all possible events, everytime library is compiled
*/
public TikTokLiveClientBuilder onUnhandledSocial(EventConsumer<TikTokUnhandledSocialEvent> event) { public TikTokLiveClientBuilder onUnhandledSocial(EventConsumer<TikTokUnhandledSocialEvent> event) {
eventHandler.subscribe(TikTokUnhandledSocialEvent.class, event); eventHandler.subscribe(TikTokUnhandledSocialEvent.class, event);
return this; return this;

View File

@@ -26,10 +26,7 @@ import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.builder.EventConsumer; import io.github.jwdeveloper.tiktok.live.builder.EventConsumer;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import java.util.HashMap; import java.util.*;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class TikTokLiveEventHandler { public class TikTokLiveEventHandler {
private final Map<Class<?>, Set<EventConsumer>> events; private final Map<Class<?>, Set<EventConsumer>> events;
@@ -39,21 +36,8 @@ public class TikTokLiveEventHandler {
} }
public void publish(LiveClient tikTokLiveClient, TikTokEvent tikTokEvent) { public void publish(LiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
if (events.containsKey(TikTokEvent.class)) { Optional.ofNullable(events.get(TikTokEvent.class)).ifPresent(handlers -> handlers.forEach(handler -> handler.onEvent(tikTokLiveClient, tikTokEvent)));
var handlers = events.get(TikTokEvent.class); Optional.ofNullable(events.get(tikTokEvent.getClass())).ifPresent(handlers -> handlers.forEach(handler -> handler.onEvent(tikTokLiveClient, tikTokEvent)));
for (var handle : handlers) {
handle.onEvent(tikTokLiveClient, tikTokEvent);
}
}
if (!events.containsKey(tikTokEvent.getClass())) {
return;
}
var handlers = events.get(tikTokEvent.getClass());
for (var handler : handlers) {
handler.onEvent(tikTokLiveClient, tikTokEvent);
}
} }
public <T extends TikTokEvent> void subscribe(Class<?> clazz, EventConsumer<T> event) { public <T extends TikTokEvent> void subscribe(Class<?> clazz, EventConsumer<T> event) {
@@ -65,22 +49,10 @@ public class TikTokLiveEventHandler {
} }
public <T extends TikTokEvent> void unsubscribe(EventConsumer<T> consumer) { public <T extends TikTokEvent> void unsubscribe(EventConsumer<T> consumer) {
for (var entry : events.entrySet()) { events.forEach((key, value) -> value.remove(consumer));
entry.getValue().remove(consumer);
}
} }
public <T extends TikTokEvent> void unsubscribe(Class<?> clazz, EventConsumer<T> consumer) { public <T extends TikTokEvent> void unsubscribe(Class<?> clazz, EventConsumer<T> consumer) {
if (clazz == null) { Optional.ofNullable(clazz).map(events::get).ifPresent(consumers -> consumers.remove(consumer));
return; }
} }
if (!events.containsKey(clazz)) {
return;
}
var eventSet = events.get(clazz);
eventSet.remove(consumer);
}
}

View File

@@ -23,6 +23,7 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import io.github.jwdeveloper.dependance.injector.api.annotations.Inject;
import io.github.jwdeveloper.tiktok.common.*; import io.github.jwdeveloper.tiktok.common.*;
import io.github.jwdeveloper.tiktok.data.requests.*; import io.github.jwdeveloper.tiktok.data.requests.*;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings; import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
@@ -32,6 +33,7 @@ import io.github.jwdeveloper.tiktok.http.mappers.*;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.util.function.Consumer;
import java.util.logging.Logger; import java.util.logging.Logger;
public class TikTokLiveHttpClient implements LiveHttpClient public class TikTokLiveHttpClient implements LiveHttpClient
@@ -53,17 +55,19 @@ public class TikTokLiveHttpClient implements LiveHttpClient
private final GiftsDataMapper giftsDataMapper; private final GiftsDataMapper giftsDataMapper;
private final Logger logger; private final Logger logger;
public TikTokLiveHttpClient(HttpClientFactory factory, LiveClientSettings settings) { @Inject
public TikTokLiveHttpClient(HttpClientFactory factory) {
this.httpFactory = factory; this.httpFactory = factory;
this.clientSettings = settings; this.clientSettings = factory.getLiveClientSettings();
this.logger = LoggerFactory.create("HttpClient-"+hashCode(), clientSettings); this.logger = LoggerFactory.create("HttpClient-"+hashCode(), clientSettings);
liveUserDataMapper = new LiveUserDataMapper(); liveUserDataMapper = new LiveUserDataMapper();
liveDataMapper = new LiveDataMapper(); liveDataMapper = new LiveDataMapper();
giftsDataMapper = new GiftsDataMapper(); giftsDataMapper = new GiftsDataMapper();
} }
public TikTokLiveHttpClient() { public TikTokLiveHttpClient(Consumer<LiveClientSettings> consumer) {
this(new HttpClientFactory(LiveClientSettings.createDefault()), LiveClientSettings.createDefault()); this(new HttpClientFactory(LiveClientSettings.createDefault()));
consumer.accept(clientSettings);
} }
public GiftsData.Response fetchRoomGiftsData(String room_id) { public GiftsData.Response fetchRoomGiftsData(String room_id) {
@@ -191,7 +195,7 @@ public class TikTokLiveHttpClient implements LiveHttpClient
.withParam("internal_ext", webcastResponse.getInternalExt()) .withParam("internal_ext", webcastResponse.getInternalExt())
.withParams(webcastResponse.getRouteParamsMapMap()) .withParams(webcastResponse.getRouteParamsMapMap())
.build() .build()
.toUrl(); .toUri();
return new LiveConnectionData.Response(websocketCookie, webSocketUrl, webcastResponse); return new LiveConnectionData.Response(websocketCookie, webSocketUrl, webcastResponse);
} catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) {

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.models.Picture; import io.github.jwdeveloper.tiktok.data.models.Picture;

View File

@@ -31,6 +31,7 @@ import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketUnhandl
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper; import io.github.jwdeveloper.tiktok.mappers.TikTokLiveMapper;
import io.github.jwdeveloper.tiktok.mappers.TikTokMapper;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.Stopwatch; import io.github.jwdeveloper.tiktok.utils.Stopwatch;
@@ -41,9 +42,9 @@ public class TikTokLiveMessageHandler {
private final TikTokLiveEventHandler tikTokEventHandler; private final TikTokLiveEventHandler tikTokEventHandler;
private final TikTokLiveMapper mapper; private final TikTokLiveMapper mapper;
public TikTokLiveMessageHandler(TikTokLiveEventHandler tikTokEventHandler, TikTokLiveMapper mapper) { public TikTokLiveMessageHandler(TikTokLiveEventHandler tikTokEventHandler, TikTokMapper mapper) {
this.tikTokEventHandler = tikTokEventHandler; this.tikTokEventHandler = tikTokEventHandler;
this.mapper = mapper; this.mapper = (TikTokLiveMapper) mapper;
} }
public void handle(LiveClient client, WebcastResponse webcastResponse) { public void handle(LiveClient client, WebcastResponse webcastResponse) {
@@ -61,20 +62,19 @@ public class TikTokLiveMessageHandler {
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message) public void handleSingleMessage(LiveClient client, WebcastResponse.Message message)
{ {
var messageClassName = message.getMethod(); var messageClassName = message.getMethod();
if (!mapper.isRegistered(messageClassName)) { if (!mapper.isRegistered(messageClassName))
tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message)); tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message));
return; else {
} var stopwatch = new Stopwatch();
var stopwatch = new Stopwatch(); stopwatch.start();
stopwatch.start(); var events = mapper.handleMapping(messageClassName, message.getPayload().toByteArray());
var events = mapper.handleMapping(messageClassName, message.getPayload().toByteArray()); var handlingTimeInMs = stopwatch.stop();
var handlingTimeInMs = stopwatch.stop(); var metadata = new MessageMetaData(Duration.ofNanos(handlingTimeInMs));
var metadata = new MessageMetaData(Duration.ofNanos(handlingTimeInMs));
for (var event : events) { for (var event : events) {
tikTokEventHandler.publish(client, new TikTokWebsocketMessageEvent(message, event, metadata)); tikTokEventHandler.publish(client, new TikTokWebsocketMessageEvent(message, event, metadata));
tikTokEventHandler.publish(client, event); tikTokEventHandler.publish(client, event);
}
} }
} }
}
}

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.common; package io.github.jwdeveloper.tiktok.common;
import com.google.gson.*; import com.google.gson.*;
@@ -100,8 +122,8 @@ public class ActionResult<T> {
public JsonObject toJson() { public JsonObject toJson() {
JsonObject map = new JsonObject(); JsonObject map = new JsonObject();
map.addProperty("success", success); map.addProperty("success", success);
map.add("content", gson.toJsonTree(content));
map.addProperty("message", message); map.addProperty("message", message);
map.add("content", gson.toJsonTree(content));
map.add("previous", hasPrevious() ? previous.toJson() : null); map.add("previous", hasPrevious() ? previous.toJson() : null);
return map; return map;
} }

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.common; package io.github.jwdeveloper.tiktok.common;
import lombok.Setter; import lombok.Setter;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.common; package io.github.jwdeveloper.tiktok.common;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings; import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.gifts; package io.github.jwdeveloper.tiktok.gifts;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift; import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
@@ -7,6 +29,7 @@ import java.util.*;
import java.util.function.*; import java.util.function.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
//TODO I should've been called it TikTokGiftsRepository
public class TikTokGiftsManager implements GiftsManager { public class TikTokGiftsManager implements GiftsManager {
private final Map<Integer, Gift> giftsByIdIndex; private final Map<Integer, Gift> giftsByIdIndex;

View File

@@ -90,14 +90,14 @@ public class HttpClient {
return toResponse().map(HttpResponse::body); return toResponse().map(HttpResponse::body);
} }
public URI toUrl() { public URI toUri() {
var stringUrl = prepareUrlWithParameters(url, httpClientSettings.getParams()); var stringUrl = prepareUrlWithParameters(url, httpClientSettings.getParams());
return URI.create(stringUrl); return URI.create(stringUrl);
} }
protected HttpRequest prepareGetRequest() { protected HttpRequest prepareGetRequest() {
var requestBuilder = HttpRequest.newBuilder().GET(); var requestBuilder = HttpRequest.newBuilder().GET();
requestBuilder.uri(toUrl()); requestBuilder.uri(toUri());
requestBuilder.timeout(httpClientSettings.getTimeout()); requestBuilder.timeout(httpClientSettings.getTimeout());
httpClientSettings.getHeaders().forEach(requestBuilder::setHeader); httpClientSettings.getHeaders().forEach(requestBuilder::setHeader);

View File

@@ -23,7 +23,9 @@
package io.github.jwdeveloper.tiktok.http; package io.github.jwdeveloper.tiktok.http;
import io.github.jwdeveloper.tiktok.data.settings.*; import io.github.jwdeveloper.tiktok.data.settings.*;
import lombok.Getter;
@Getter
public class HttpClientFactory { public class HttpClientFactory {
private final LiveClientSettings liveClientSettings; private final LiveClientSettings liveClientSettings;

View File

@@ -95,7 +95,7 @@ public class HttpProxyClient extends HttpClient {
public X509Certificate[] getAcceptedIssuers() { return null; } public X509Certificate[] getAcceptedIssuers() { return null; }
}}, null); }}, null);
URL url = toUrl().toURL(); URL url = toUri().toURL();
if (proxySettings.hasNext()) { if (proxySettings.hasNext()) {
try { try {
@@ -117,7 +117,7 @@ public class HttpProxyClient extends HttpClient {
var responseInfo = createResponseInfo(socksConnection.getResponseCode(), headers); var responseInfo = createResponseInfo(socksConnection.getResponseCode(), headers);
var response = createHttpResponse(body, toUrl(), responseInfo); var response = createHttpResponse(body, toUri(), responseInfo);
return ActionResult.success(response); return ActionResult.success(response);
} catch (IOException e) { } catch (IOException e) {

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.http.mappers; package io.github.jwdeveloper.tiktok.http.mappers;
import com.google.gson.*; import com.google.gson.*;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.http.mappers; package io.github.jwdeveloper.tiktok.http.mappers;
import com.google.gson.*; import com.google.gson.*;

View File

@@ -0,0 +1,155 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.mappers;
import io.github.jwdeveloper.dependance.api.DependanceContainer;
import io.github.jwdeveloper.dependance.injector.api.containers.Container;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.data.events.*;
import io.github.jwdeveloper.tiktok.data.events.link.*;
import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokCommonEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokGiftEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokRoomInfoEventHandler;
import io.github.jwdeveloper.tiktok.mappers.handlers.TikTokSocialMediaEventHandler;
import io.github.jwdeveloper.tiktok.messages.webcast.*;
import static io.github.jwdeveloper.tiktok.messages.enums.LinkMessageType.*;
public class MessagesMapperFactory {
public static TikTokLiveMapper create(DependanceContainer container) {
var helper = container.find(TikTokMapperHelper.class);
var mapper = new TikTokLiveMapper(helper);
//ConnectionEvents events
var commonHandler = container.find(TikTokCommonEventHandler.class);
var giftHandler = container.find(TikTokGiftEventHandler.class);
var roomInfoHandler = container.find(TikTokRoomInfoEventHandler.class);
var socialHandler = container.find(TikTokSocialMediaEventHandler.class);
mapper.forMessage(WebcastControlMessage.class, commonHandler::handleWebcastControlMessage);
//Room status events
mapper.forMessage(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
mapper.forMessage(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
mapper.forMessage(WebcastCaptionMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastCaptionMessage.class);
return MappingResult.of(messageObject, new TikTokCaptionEvent(messageObject));
});
//User Interactions events
mapper.forMessage(WebcastChatMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
return MappingResult.of(messageObject, new TikTokCommentEvent(messageObject));
});
mapper.forMessage(WebcastSubNotifyMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastSubNotifyMessage.class);
return MappingResult.of(messageObject, new TikTokSubscribeEvent(messageObject));
});
mapper.forMessage(WebcastEmoteChatMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastEmoteChatMessage.class);
return MappingResult.of(messageObject, new TikTokEmoteEvent(messageObject));
});
mapper.forMessage(WebcastQuestionNewMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastQuestionNewMessage.class);
return MappingResult.of(messageObject, new TikTokQuestionEvent(messageObject));
});
mapper.forMessage(WebcastLikeMessage.class, roomInfoHandler::handleLike);
mapper.forMessage(WebcastGiftMessage.class, giftHandler::handleGifts);
mapper.forMessage(WebcastSocialMessage.class, socialHandler::handle);
mapper.forMessage(WebcastMemberMessage.class, roomInfoHandler::handleMemberMessage);
//Host Interaction events
mapper.forMessage(WebcastPollMessage.class, commonHandler::handlePollEvent);
mapper.forMessage(WebcastRoomPinMessage.class, commonHandler::handlePinMessage);
mapper.forMessage(WebcastChatMessage.class, (inputBytes, messageName, mapperHelper) ->
{
var messageObject = mapperHelper.bytesToWebcastObject(inputBytes, WebcastChatMessage.class);
return MappingResult.of(messageObject, new TikTokCommentEvent(messageObject));
});
//LinkMic events
mapper.forMessage(WebcastLinkMicBattle.class, (inputBytes, messageName, mapperHelper) -> {
var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMicBattle.class);
return MappingResult.of(message, new TikTokLinkMicBattleEvent(message));
});
mapper.forMessage(WebcastLinkMicArmies.class, (inputBytes, messageName, mapperHelper) -> {
var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMicArmies.class);
return MappingResult.of(message, new TikTokLinkMicArmiesEvent(message));
});
mapper.forMessage(WebcastLinkMessage.class, ((inputBytes, messageName, mapperHelper) -> {
var message = mapperHelper.bytesToWebcastObject(inputBytes, WebcastLinkMessage.class);
return MappingResult.of(message, switch (message.getMessageType()) {
case TYPE_LINKER_INVITE -> new TikTokLinkInviteEvent(message);
case TYPE_LINKER_CREATE -> new TikTokLinkCreateEvent(message);
case TYPE_LINKER_CLOSE -> new TikTokLinkCloseEvent(message);
case TYPE_LINKER_ENTER -> new TikTokLinkEnterEvent(message);
case TYPE_LINKER_LEAVE -> new TikTokLinkLeaveEvent(message);
case TYPE_LINKER_CANCEL_INVITE, TYPE_LINKER_CANCEL_APPLY -> new TikTokLinkCancelEvent(message);
case TYPE_LINKER_KICK_OUT -> new TikTokLinkKickOutEvent(message);
case TYPE_LINKER_LINKED_LIST_CHANGE -> new TikTokLinkLinkedListChangeEvent(message);
case TYPE_LINKER_UPDATE_USER -> new TikTokLinkUpdateUserEvent(message);
case TYPE_LINKER_WAITING_LIST_CHANGE, TYPE_LINKER_WAITING_LIST_CHANGE_V2 ->
new TikTokLinkWaitListChangeEvent(message);
case TYPE_LINKER_MUTE -> new TikTokLinkMuteEvent(message);
case TYPE_LINKER_MATCH -> new TikTokLinkRandomMatchEvent(message);
case TYPE_LINKER_UPDATE_USER_SETTING -> new TikTokLinkUpdateUserSettingEvent(message);
case TYPE_LINKER_MIC_IDX_UPDATE -> new TikTokLinkMicIdxUpdateEvent(message);
case TYPE_LINKER_LINKED_LIST_CHANGE_V2 -> new TikTokLinkListChangeEvent(message);
case TYPE_LINKER_COHOST_LIST_CHANGE -> new TikTokLinkCohostListChangeEvent(message);
case TYPE_LINKER_MEDIA_CHANGE -> new TikTokLinkMediaChangeEvent(message);
case TYPE_LINKER_ACCEPT_NOTICE -> new TikTokLinkAcceptNoticeEvent(message);
case TYPE_LINKER_SYS_KICK_OUT -> new TikTokLinkSysKickOutEvent(message);
case TYPE_LINKMIC_USER_TOAST -> new TikTokLinkUserToastEvent(message);
default -> new TikTokLinkEvent(message);
});
}));
// mapper.webcastObjectToConstructor(WebcastLinkMicMethod.class, TikTokLinkMicMethodEvent.class);
// mapper.webcastObjectToConstructor(WebcastLinkMicFanTicketMethod.class, TikTokLinkMicFanTicketEvent.class);
//Rank events
// mapper.webcastObjectToConstructor(WebcastRankTextMessage.class, TikTokRankTextEvent.class);
// mapper.webcastObjectToConstructor(WebcastRankUpdateMessage.class, TikTokRankUpdateEvent.class);
// mapper.webcastObjectToConstructor(WebcastHourlyRankMessage.class, TikTokRankUpdateEvent.class);
//Others events
// mapper.webcastObjectToConstructor(WebcastInRoomBannerMessage.class, TikTokInRoomBannerEvent.class);
// mapper.webcastObjectToConstructor(WebcastMsgDetectMessage.class, TikTokDetectEvent.class);
// mapper.webcastObjectToConstructor(WebcastBarrageMessage.class, TikTokBarrageEvent.class);
// mapper.webcastObjectToConstructor(WebcastUnauthorizedMemberMessage.class, TikTokUnauthorizedMemberEvent.class);
// mapper.webcastObjectToConstructor(WebcastOecLiveShoppingMessage.class, TikTokShopEvent.class);
// mapper.webcastObjectToConstructor(WebcastImDeleteMessage.class, TikTokIMDeleteEvent.class);
// mapper.bytesToEvents(WebcastEnvelopeMessage.class, commonHandler::handleEnvelop);
return mapper;
}
}

View File

@@ -23,14 +23,10 @@
package io.github.jwdeveloper.tiktok.mappers; package io.github.jwdeveloper.tiktok.mappers;
import com.google.protobuf.GeneratedMessageV3; import com.google.protobuf.GeneratedMessageV3;
import io.github.jwdeveloper.tiktok.TikTokLive;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.mappers.data.MappingAction; import io.github.jwdeveloper.tiktok.mappers.data.*;
import io.github.jwdeveloper.tiktok.mappers.data.MappingResult;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
public class TikTokLiveMapper implements TikTokMapper { public class TikTokLiveMapper implements TikTokMapper {
@@ -47,11 +43,7 @@ public class TikTokLiveMapper implements TikTokMapper {
@Override @Override
public TikTokMapperModel forMessage(String messageName) { public TikTokMapperModel forMessage(String messageName) {
if (!isRegistered(messageName)) { return mappers.computeIfAbsent(messageName, TikTokLiveMapperModel::new);
var model = new TikTokLiveMapperModel(messageName);
mappers.put(messageName, model);
}
return mappers.get(messageName);
} }
@Override @Override
@@ -66,7 +58,6 @@ public class TikTokLiveMapper implements TikTokMapper {
return model; return model;
} }
@Override @Override
public TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName, MappingAction<MappingResult> onMapping) { public TikTokMapperModel forMessage(Class<? extends GeneratedMessageV3> mapperName, MappingAction<MappingResult> onMapping) {
var model = forMessage(mapperName); var model = forMessage(mapperName);
@@ -84,7 +75,6 @@ public class TikTokLiveMapper implements TikTokMapper {
return globalMapperModel; return globalMapperModel;
} }
public boolean isRegistered(String mapperName) { public boolean isRegistered(String mapperName) {
return mappers.containsKey(mapperName); return mappers.containsKey(mapperName);
} }
@@ -94,23 +84,19 @@ public class TikTokLiveMapper implements TikTokMapper {
} }
public List<TikTokEvent> handleMapping(String messageName, byte[] bytes) { public List<TikTokEvent> handleMapping(String messageName, byte[] bytes) {
if (!isRegistered(messageName)) {
return List.of();
}
var mapperModel = mappers.get(messageName); var mapperModel = mappers.get(messageName);
if (mapperModel == null)
return List.of();
var inputBytes = mapperModel.getOnBeforeMapping().onMapping(bytes, messageName, mapperUtils); var inputBytes = mapperModel.getOnBeforeMapping().onMapping(bytes, messageName, mapperUtils);
var globalInputBytes = globalMapperModel.getOnBeforeMapping().onMapping(inputBytes, messageName, mapperUtils); var globalInputBytes = globalMapperModel.getOnBeforeMapping().onMapping(inputBytes, messageName, mapperUtils);
var mappingResult = mapperModel.getOnMapping().onMapping(globalInputBytes, messageName, mapperUtils); var mappingResult = mapperModel.getOnMapping().onMapping(globalInputBytes, messageName, mapperUtils);
if (mappingResult == null) { if (mappingResult == null)
mappingResult = globalMapperModel.getOnMapping().onMapping(globalInputBytes, messageName, mapperUtils); mappingResult = globalMapperModel.getOnMapping().onMapping(globalInputBytes, messageName, mapperUtils);
}
var afterMappingResult = mapperModel.getOnAfterMapping().apply(mappingResult); var afterMappingResult = mapperModel.getOnAfterMapping().apply(mappingResult);
var globalAfterMappingResult = globalMapperModel.getOnAfterMapping().apply(MappingResult.of(mappingResult.getSource(), afterMappingResult)); return globalMapperModel.getOnAfterMapping().apply(MappingResult.of(mappingResult.getSource(), afterMappingResult));
return globalAfterMappingResult;
} }
} }

View File

@@ -75,5 +75,4 @@ public class TikTokLiveMapperModel implements TikTokMapperModel {
return this; return this;
} }
} }

View File

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

View File

@@ -22,6 +22,7 @@
*/ */
package io.github.jwdeveloper.tiktok.websocket; package io.github.jwdeveloper.tiktok.websocket;
import io.github.jwdeveloper.dependance.injector.api.containers.Container;
import io.github.jwdeveloper.tiktok.*; import io.github.jwdeveloper.tiktok.*;
import io.github.jwdeveloper.tiktok.data.dto.ProxyData; import io.github.jwdeveloper.tiktok.data.dto.ProxyData;
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData; import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.websocket; package io.github.jwdeveloper.tiktok.websocket;
import io.github.jwdeveloper.tiktok.TikTokLiveEventHandler; import io.github.jwdeveloper.tiktok.TikTokLiveEventHandler;

View File

@@ -1,9 +1,29 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.websocket; package io.github.jwdeveloper.tiktok.websocket;
import org.java_websocket.WebSocket; import org.java_websocket.WebSocket;
import java.util.Random;
public class TikTokWebSocketPingingTask public class TikTokWebSocketPingingTask
{ {
private Thread thread; private Thread thread;
@@ -14,7 +34,7 @@ public class TikTokWebSocketPingingTask
public void run(WebSocket webSocket, long pingTaskTime) public void run(WebSocket webSocket, long pingTaskTime)
{ {
stop(); stop();
thread = new Thread(() -> pingTask(webSocket, pingTaskTime)); thread = new Thread(() -> pingTask(webSocket, pingTaskTime), "pinging-task");
isRunning = true; isRunning = true;
thread.start(); thread.start();
} }
@@ -28,18 +48,16 @@ public class TikTokWebSocketPingingTask
private void pingTask(WebSocket webSocket, long pingTaskTime) private void pingTask(WebSocket webSocket, long pingTaskTime)
{ {
var random = new Random();
while (isRunning) { while (isRunning) {
try { try {
if (!webSocket.isOpen()) { if (webSocket.isOpen()) {
webSocket.sendPing();
Thread.sleep(pingTaskTime+(int)(Math.random() * MAX_TIMEOUT));
} else
Thread.sleep(SLEEP_TIME); Thread.sleep(SLEEP_TIME);
continue;
}
webSocket.sendPing();
Thread.sleep(pingTaskTime+random.nextInt(MAX_TIMEOUT));
} }
catch (Exception e) { catch (Exception e) {
//TODO we should display some kind of error message
isRunning = false; isRunning = false;
} }
} }

View File

@@ -41,7 +41,7 @@
<parent> <parent>
<artifactId>TikTokLiveJava</artifactId> <artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<version>1.6.3-Release</version> <version>1.7.2-Release</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -75,7 +75,7 @@
<dependency> <dependency>
<groupId>io.github.jwdeveloper.tiktok</groupId> <groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>extension-collector</artifactId> <artifactId>extension-collector</artifactId>
<version>1.6.3-Release</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -32,7 +32,7 @@ import java.time.Duration;
import java.util.logging.Level; import java.util.logging.Level;
public class ConnectionExample { public class ConnectionExample {
public static String TIKTOK_HOSTNAME = "kvadromama_marina1"; public static String TIKTOK_HOSTNAME = "yttvandroid";
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.TikTokCommentEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokCommentEvent;
@@ -47,9 +69,7 @@ public class Events_And_Gifts_Testing_Example
var fakeGift = TikTokGiftEvent.of(roseGift); var fakeGift = TikTokGiftEvent.of(roseGift);
var fakeComboGift = TikTokGiftComboEvent.of(roseGift, 12, GiftComboStateType.Begin); var fakeComboGift = TikTokGiftComboEvent.of(roseGift, 12, GiftComboStateType.Begin);
var fakeMessage = TikTokCommentEvent.of("Mark", "Hello world"); var fakeMessage = TikTokCommentEvent.of("Mark", "Hello world");
var fakeSubscriber = TikTokSubscribeEvent.of("Mark"); var fakeSubscriber = TikTokSubscribeEvent.of("Mark");
var fakeFollow = TikTokFollowEvent.of("Mark"); var fakeFollow = TikTokFollowEvent.of("Mark");
var fakeLike = TikTokLikeEvent.of("Mark", 12); var fakeLike = TikTokLikeEvent.of("Mark", 12);

View File

@@ -26,6 +26,8 @@ package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.extension.recorder.TikTokLiveRecorder; import io.github.jwdeveloper.tiktok.extension.recorder.TikTokLiveRecorder;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.event.TikTokLiveRecorderStartedEvent; import io.github.jwdeveloper.tiktok.extension.recorder.impl.event.TikTokLiveRecorderStartedEvent;
import java.io.File;
public class RecorderExample { public class RecorderExample {
public static void main(String[] args) { public static void main(String[] args) {
@@ -39,11 +41,10 @@ public class RecorderExample {
{ {
event.getException().printStackTrace(); event.getException().printStackTrace();
}) })
.addListener(TikTokLiveRecorder.use(recorderSettings -> .addListener(TikTokLiveRecorder.use((recorderSettings, liveClient) ->
{ {
recorderSettings.setFfmpegPath("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\extension-recorder\\libs\\ffmpeg.exe"); recorderSettings.setFfmpegPath("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\extension-recorder\\libs\\ffmpeg.exe");
recorderSettings.setOutputPath("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\extension-recorder\\out"); recorderSettings.setOutputFile(new File("C:\\Users\\ja\\IdeaProjects\\TikTokLiveJava\\extension-recorder\\out", "test.flv"));
recorderSettings.setOutputFileName("test.flv");
})) }))
.onEvent(TikTokLiveRecorderStartedEvent.class, (liveClient, event) -> .onEvent(TikTokLiveRecorderStartedEvent.class, (liveClient, event) ->
{ {
@@ -52,4 +53,4 @@ public class RecorderExample {
.buildAndConnect(); .buildAndConnect();
} }
} }

View File

@@ -70,7 +70,7 @@ Maven
<dependency> <dependency>
<groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId> <groupId>com.github.jwdeveloper.TikTok-Live-Java</groupId>
<artifactId>Client</artifactId> <artifactId>Client</artifactId>
<version>1.6.0-Release</version> <version>1.7.0-Release</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

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

View File

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

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.extension.collector.api; package io.github.jwdeveloper.tiktok.extension.collector.api;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.extension.collector.api; package io.github.jwdeveloper.tiktok.extension.collector.api;
import org.bson.Document; import org.bson.Document;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.extension.collector.api.settings; package io.github.jwdeveloper.tiktok.extension.collector.api.settings;
import io.github.jwdeveloper.tiktok.extension.collector.api.CollectorEvent; import io.github.jwdeveloper.tiktok.extension.collector.api.CollectorEvent;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.extension.collector.impl; package io.github.jwdeveloper.tiktok.extension.collector.impl;
import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver; import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.extension.collector.impl.storages; package io.github.jwdeveloper.tiktok.extension.collector.impl.storages;
import io.github.jwdeveloper.tiktok.extension.collector.api.Storage; import io.github.jwdeveloper.tiktok.extension.collector.api.Storage;

View File

@@ -1,3 +1,25 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.extension.collector.impl.storages; package io.github.jwdeveloper.tiktok.extension.collector.impl.storages;
import com.mongodb.ConnectionString; import com.mongodb.ConnectionString;

View File

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

View File

@@ -25,18 +25,19 @@ package io.github.jwdeveloper.tiktok.extension.recorder;
import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder; import io.github.jwdeveloper.tiktok.extension.recorder.api.LiveRecorder;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.RecorderListener; import io.github.jwdeveloper.tiktok.extension.recorder.impl.RecorderListener;
import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.RecorderSettings; import io.github.jwdeveloper.tiktok.extension.recorder.impl.data.RecorderSettings;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import java.util.function.Consumer; import java.util.function.*;
public class TikTokLiveRecorder public class TikTokLiveRecorder
{ {
public static LiveRecorder use(Consumer<RecorderSettings> consumer) public static LiveRecorder use(BiConsumer<RecorderSettings, LiveClient> consumer)
{ {
return new RecorderListener(consumer); return new RecorderListener(consumer);
} }
public static LiveRecorder use() public static LiveRecorder use()
{ {
return use(x ->{}); return use((x,y) ->{});
} }
} }

View File

@@ -37,26 +37,23 @@ import io.github.jwdeveloper.tiktok.models.ConnectionState;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
import java.io.*; import java.io.*;
import java.net.URL; import java.net.URL;
import java.util.concurrent.TimeUnit; import java.util.function.*;
import java.util.function.Consumer;
import static java.nio.charset.StandardCharsets.UTF_8;
public class RecorderListener implements LiveRecorder { public class RecorderListener implements LiveRecorder {
private final Consumer<RecorderSettings> consumer; private final BiConsumer<RecorderSettings, LiveClient> consumer;
private RecorderSettings settings; private RecorderSettings settings;
private DownloadData downloadData; private DownloadData downloadData;
private Thread liveDownloadThread; private Thread liveDownloadThread;
public RecorderListener(Consumer<RecorderSettings> consumer) { public RecorderListener(BiConsumer<RecorderSettings, LiveClient> consumer) {
this.consumer = consumer; this.consumer = consumer;
} }
@TikTokEventObserver @TikTokEventObserver
private void onResponse(LiveClient liveClient, TikTokRoomDataResponseEvent event) { private void onResponse(LiveClient liveClient, TikTokRoomDataResponseEvent event) {
settings = RecorderSettings.DEFAULT(); settings = RecorderSettings.DEFAULT();
consumer.accept(settings); consumer.accept(settings, liveClient);
var json = event.getLiveData().getJson(); var json = event.getLiveData().getJson();
@@ -76,10 +73,9 @@ public class RecorderListener implements LiveRecorder {
if (isConnected()) if (isConnected())
return; return;
liveDownloadThread = new Thread(() -> { liveDownloadThread = new Thread(() -> {
try { try {
liveClient.getLogger().info("Recording started"); liveClient.getLogger().info("Recording started "+liveClient.getRoomInfo().getHostName());
var url = new URL(downloadData.getFullUrl()); var url = new URL(downloadData.getFullUrl());
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
var headers = LiveClientSettings.DefaultRequestHeaders(); var headers = LiveClientSettings.DefaultRequestHeaders();
@@ -87,18 +83,17 @@ public class RecorderListener implements LiveRecorder {
connection.setRequestProperty(entry.getKey(), entry.getValue()); connection.setRequestProperty(entry.getKey(), entry.getValue());
} }
var path = settings.getOutputPath() + File.separator + settings.getOutputFileName(); var file = settings.getOutputFile();
var file = new File(path);
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();
file.createNewFile(); file.createNewFile();
try ( try (
var in = connection.getInputStream(); var in = connection.getInputStream();
var fos = new FileOutputStream(file) var fos = new FileOutputStream(file)
) { ) {
byte[] dataBuffer = new byte[1024]; byte[] dataBuffer = new byte[1024];
int bytesRead; int bytesRead;
while (liveClient.getRoomInfo().getConnectionState() == ConnectionState.CONNECTED && (bytesRead = in.read(dataBuffer)) != -1) { while ((!settings.isStopOnDisconnect() || liveClient.getRoomInfo().getConnectionState() == ConnectionState.CONNECTED) && (bytesRead = in.read(dataBuffer)) != -1) {
fos.write(dataBuffer, 0, bytesRead); fos.write(dataBuffer, 0, bytesRead);
fos.flush(); fos.flush();
} }
@@ -113,11 +108,10 @@ public class RecorderListener implements LiveRecorder {
var recordingStartedEvent = new TikTokLiveRecorderStartedEvent(downloadData); var recordingStartedEvent = new TikTokLiveRecorderStartedEvent(downloadData);
liveClient.publishEvent(recordingStartedEvent); liveClient.publishEvent(recordingStartedEvent);
if (recordingStartedEvent.isCanceled()) { if (recordingStartedEvent.isCanceled())
liveClient.getLogger().info("Recording cancelled"); liveClient.getLogger().info("Recording cancelled");
return; else
} liveDownloadThread.start();
liveDownloadThread.start();
} }
@TikTokEventObserver @TikTokEventObserver

View File

@@ -27,6 +27,7 @@ import io.github.jwdeveloper.tiktok.extension.recorder.impl.enums.LiveFormat;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.io.File;
import java.util.function.Function; import java.util.function.Function;
@Getter @Getter
@@ -36,10 +37,8 @@ public class RecorderSettings {
private String ffmpegPath; private String ffmpegPath;
private String quality; private String quality;
private String format; private String format;
private String outputPath; private File outputFile;
private String outputFileName;
private Function<String,DownloadData> prepareDownloadData; private Function<String,DownloadData> prepareDownloadData;
private boolean startOnConnected;
private boolean stopOnDisconnect = true; private boolean stopOnDisconnect = true;
public static RecorderSettings DEFAULT() { public static RecorderSettings DEFAULT() {

View File

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