- TikTokHttpResponseEvent
  - Fixed User attributes in CommentEvent
  - Redesign .onMapper method
This commit is contained in:
JW
2023-12-19 04:01:06 +01:00
parent d6c0d50ac3
commit 3eed982d6b
95 changed files with 3200 additions and 1653 deletions

View File

@@ -22,13 +22,35 @@
*/
package io.github.jwdeveloper.tiktok.webviewer;
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
import io.github.jwdeveloper.tiktok.webviewer.handlers.TikTokHandler;
import io.github.jwdeveloper.tiktok.webviewer.services.TikTokCollectorService;
import io.github.jwdeveloper.tiktok.webviewer.services.TikTokDatabaseService;
import io.javalin.Javalin;
public class Main {
public static void main(String[] args) {
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.sql.SQLException;
import java.util.concurrent.ExecutionException;
var manager = new TikTokManager();
public class Main {
public static void main(String[] args) throws SQLException, ExecutionException, InterruptedException, IOException {
var settings = new Settings();
settings.setUserName("szalonamoniaxx");
settings.setSessionTag("battle");
settings.setDbName("db-battle");
settings.setPort(8002);
var db = new TikTokDatabase(settings.getDbName());
db.connect();
var service = new TikTokDatabaseService(db);
var collectorService = new TikTokCollectorService(settings, db);
var handler = new TikTokHandler(service, settings, collectorService);
// var manager = new TikTokManager(service);
var app = Javalin.create(config ->
{
config.plugins.enableCors(corsContainer ->
@@ -39,13 +61,19 @@ public class Main {
});
});
config.staticFiles.add("/public");
}).start(8001);
}).start(settings.getPort());
var handler = new TikTokHandler(manager);
app.get("/tiktok/status", handler::connectionStatus);
app.get("/tiktok/connect", handler::connect);
app.get("/tiktok/disconnect", handler::disconnect);
app.get("/tiktok/events", handler::events);
app.get("/tiktok/events/pages", handler::eventPages);
app.get("/tiktok/events/message", handler::eventMessage);
app.get("/tiktok/data/pages", handler::getDataPages);
app.get("/tiktok/data/names", handler::getDataNames);
app.get("/tiktok/data", handler::getData);
app.get("/tiktok/update", handler::updateSearch);
app.get("/tiktok/sessions", handler::getUserSessionTags);
app.get("/tiktok/users", handler::getUsers);
app.get("/tiktok/data-types", handler::getDataTypes);
}
}

View File

@@ -0,0 +1,14 @@
package io.github.jwdeveloper.tiktok.webviewer;
import lombok.Data;
@Data
public class Settings
{
private int port;
private String dbName;
private String userName;
private String sessionTag;
}

View File

@@ -1,137 +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.webviewer;
import com.google.protobuf.InvalidProtocolBufferException;
import io.github.jwdeveloper.tiktok.tools.collector.client.MessageCollector;
import io.github.jwdeveloper.tiktok.tools.collector.client.TikTokMessageCollectorClient;
import io.github.jwdeveloper.tiktok.tools.collector.client.TikTokMessagessCollectorBuilder;
import io.github.jwdeveloper.tiktok.tools.util.MessageUtil;
import lombok.Value;
import java.sql.SQLException;
import java.util.Base64;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
public class TikTokManager {
TikTokMessagessCollectorBuilder client;
MessageCollector msgCollector;
public static String dbName= "log";
public TikTokManager() {
msgCollector = new MessageCollector(dbName);
}
public void connect(String name) throws SQLException {
disconnect();
client = TikTokMessageCollectorClient.create(msgCollector, dbName)
.addOnBuilder(liveClientBuilder ->
{
liveClientBuilder.onRoomInfo((liveClient, event) ->
{
});
liveClientBuilder.onGift((liveClient, event) ->
{
});
liveClientBuilder.onWebsocketUnhandledMessage((liveClient, event) ->
{
System.out.println("UNHANDLED MESSAGE! "+event.getMessage().getMethod());
});
})
.addUser(name);
client.buildAndRun();
}
public List<String> getEventsNames() {
return msgCollector.getMessages().keySet().stream().toList();
}
public List<String> getEventMessages(String eventName) {
return msgCollector.getMessages().get(eventName).stream().map(MessageCollector.MessageData::getEventData).toList();
}
public MessageDto getMessage(String event, String index) throws InvalidProtocolBufferException {
var eventData = msgCollector.getMessages().get(event);
var messages = eventData.stream().toList();
var random = new Random();
var msgIndex = 0;
if (index != null && !index.isEmpty()) {
msgIndex = Integer.parseInt(index);
msgIndex = Math.min(msgIndex, messages.size() - 1);
msgIndex = Math.max(msgIndex, 0);
}
var msg = messages.get(msgIndex);
var bytes = Base64.getDecoder().decode(msg.getEventData());
var content = MessageUtil.getContent(event, bytes);
return new MessageDto(content, msg.getEventData(), event);
}
public PagesDto getPages(String event) throws InvalidProtocolBufferException {
var eventData = msgCollector.getMessages().get(event);
var messages = eventData.stream().toList();
var counter = new AtomicInteger(-1);
var pages = messages.stream().map(e ->
{
return "http://localhost:8001/tiktok/events/message?eventName=" + event + "&page=" + counter.incrementAndGet();
}).toList();
return new PagesDto(event, messages.size(), pages);
}
@Value
public class PagesDto {
String eventName;
int pages;
List<String> links;
}
@Value
public class MessageDto {
String content;
String base64;
String eventName;
}
public void disconnect() {
if (client == null) {
return;
}
client.stop();
}
}

View File

@@ -0,0 +1,105 @@
/*
* 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.webviewer;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkLayerMessage;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastLinkMessage;
import io.github.jwdeveloper.tiktok.tools.TikTokLiveTools;
import java.io.IOException;
public class ToolsExamples {
private static final String tiktokUser = "debb.cl";
private static final String db = "db-battle";
private static final String sessionTag = "gifts";
public static void main(String[] args) throws IOException {
// runCollector();
runCollector();
//runTester();
System.in.read();
}
/*
WebcastLinkMicArmies
WebcastLinkMicBattle
*/
//WebcastLinkMicArmies battle data?
//WebcastLinkMicBattlePunishFinish end of battle?
//WebcastLinkLayerMessage send after end of battle
// send after LinkLayer -> WebcastLinkMessage
private static void runCollector() {
TikTokLiveTools.createCollector(db)
.addUser(tiktokUser)
.setSessionTag(sessionTag)
.configureLiveClient(liveClientBuilder ->
{
liveClientBuilder.configure(clientSettings ->
{
clientSettings.setPrintToConsole(true);
});
liveClientBuilder.onWebsocketResponse((liveClient, event) ->
{
for (var msg : event.getResponse().getMessagesList()) {
System.out.println(msg.getMethod());
}
});
liveClientBuilder.onConnected((liveClient, event) ->
{
liveClient.getLogger().info("Connected");
});
}).buildAndRun();
}
private static void runTester() {
TikTokLiveTools.createTester(db)
.setSessionTag(sessionTag)
.setUser(tiktokUser)
.configureLiveClient(liveClientBuilder ->
{
liveClientBuilder.onError((liveClient, event) ->
{
event.getException().printStackTrace();
;
});
liveClientBuilder.onWebsocketResponse((liveClient, event) ->
{
System.out.println("Response =====================================");
for (var msg : event.getResponse().getMessagesList()) {
System.out.println("Message -> " + msg.getMethod());
}
});
liveClientBuilder.onEvent((liveClient, event) ->
{
System.out.println("Event -> " + event.getClass().getSimpleName());
});
})
.buildAndRun();
}
}

View File

@@ -25,61 +25,153 @@ package io.github.jwdeveloper.tiktok.webviewer.handlers;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.protobuf.InvalidProtocolBufferException;
import io.github.jwdeveloper.tiktok.webviewer.TikTokManager;
import io.github.jwdeveloper.tiktok.webviewer.Settings;
import io.github.jwdeveloper.tiktok.webviewer.services.TikTokCollectorService;
import io.github.jwdeveloper.tiktok.webviewer.services.TikTokDatabaseService;
import io.javalin.http.Context;
import lombok.Value;
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class TikTokHandler {
private final TikTokManager tikTokManager;
private final TikTokDatabaseService databaseService;
private final Settings settings;
private final TikTokCollectorService collectorService;
public TikTokHandler(TikTokManager tikTokManager) {
this.tikTokManager = tikTokManager;
public TikTokHandler(TikTokDatabaseService databaseService,
Settings settings,
TikTokCollectorService collectorService) {
this.databaseService = databaseService;
this.settings = settings;
this.collectorService = collectorService;
}
public void connect(Context context) throws SQLException {
String name = context.queryParam("name");
if (name.equals(" ")) {
context.result("Name can not be empty");
context.status(400);
return;
}
tikTokManager.connect(name);
public void connect(Context context) {
var name = context.queryParam("name");
var sessionTag = context.queryParam("session");
System.out.println("Session tag" + sessionTag);
collectorService.start(name, sessionTag);
settings.setUserName(name);
context.status(200);
}
public void disconnect(Context context){
tikTokManager.disconnect();
context.status(200);
}
public void events(Context context) {
var events = tikTokManager.getEventsNames();
var gson = getGson();
var result = gson.toJson(events);
public void connectionStatus(Context context) {
var isWorking = collectorService.isRunning();
var result = getGson().toJson(isWorking);
context.result(result);
context.status(200);
}
public void eventMessage(Context context) throws InvalidProtocolBufferException {
String name = context.queryParam("eventName");
String page = context.queryParam("page");
public void disconnect(Context context) {
var result = tikTokManager.getMessage(name, page);
var gson = getGson();
context.result(gson.toJson(result));
collectorService.stop();
context.status(200);
}
public void eventPages(Context context) throws InvalidProtocolBufferException {
String name = context.queryParam("eventName");
var result = tikTokManager.getPages(name);
public void getUsers(Context context) {
var users = databaseService.getUsers();
var result = getGson().toJson(users);
context.result(result);
context.status(200);
}
public void getUserSessionTags(Context context) {
var dataType = context.queryParam("user");
var sessionsTags = databaseService.getSessionTag(dataType);
var result = getGson().toJson(sessionsTags);
context.result(result);
context.status(200);
}
public void getDataTypes(Context context) {
var result = getGson().toJson(List.of("event", "message", "response"));
context.result(result);
context.status(200);
}
public void updateSearch(Context context) {
var userName = context.queryParam("user");
var sessionTag = context.queryParam("session");
settings.setUserName(userName);
settings.setSessionTag(sessionTag);
context.status(200);
}
public void getDataNames(Context context) {
var dataType = context.queryParam("type");
var dataNames = databaseService.getDataNames(dataType, settings.getUserName(), settings.getSessionTag());
var gson = getGson();
context.result(gson.toJson(result));
var result = gson.toJson(dataNames);
context.result(result);
context.status(200);
}
public void getData(Context context) {
var page = context.queryParam("page");
var dataType = context.queryParam("type");
var dataName = context.queryParam("name");
if (page == null) {
page = "0";
}
var asProto = context.queryParam("asProto");
var asJson = asProto == null;
var dto = new TikTokDatabaseService.DatabaseDataDto(dataType, dataName, settings.getUserName(), settings.getSessionTag(), asJson);
var result = databaseService.getData(dto);
var content = result.get(Integer.parseInt(page));
var response = new MessageDto(content, "", dataName);
var gson = getGson();
context.result(gson.toJson(response));
}
public void getDataPages(Context context) throws InvalidProtocolBufferException {
var dataType = context.queryParam("type");
var dataName = context.queryParam("name");
var asJson = true;
var dto = new TikTokDatabaseService.DatabaseDataDto(dataType, dataName, settings.getUserName(), settings.getSessionTag(), asJson);
var result = databaseService.getData(dto);
var counter = new AtomicInteger(-1);
var pages = result.stream().map(e ->
{
return "http://localhost:" + settings.getPort() + "/tiktok/data?type=" + dataType + "&page=" + counter.incrementAndGet() + "&name=" + dataName;
}).toList();
var response = new PagesDto(dataName, counter.get(), pages);
var gson = getGson();
context.result(gson.toJson(response));
}
public Gson getGson() {
return new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
}
@Value
public class PagesDto {
String eventName;
int pages;
List<String> links;
}
@Value
public class MessageDto {
String content;
String base64;
String eventName;
}
}

View File

@@ -0,0 +1,89 @@
package io.github.jwdeveloper.tiktok.webviewer.services;
import io.github.jwdeveloper.tiktok.tools.TikTokLiveTools;
import io.github.jwdeveloper.tiktok.tools.collector.api.DataCollector;
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
import io.github.jwdeveloper.tiktok.webviewer.Settings;
public class TikTokCollectorService {
private final Settings settings;
private final TikTokDatabase database;
private boolean isConnected = false;
private DataCollector collector;
public TikTokCollectorService(Settings settings, TikTokDatabase database) {
this.settings = settings;
this.database = database;
}
public void start(String user, String sessionTag) {
stop();
collector = createClient(user, sessionTag);
collector.connect();
}
public boolean isRunning()
{
if(collector == null)
{
return false;
}
return isConnected;
}
public void stop() {
if (collector != null) {
collector.disconnect(true);
}
isConnected =false;
collector = null;
try {
database.close();
database.connect();
}
catch (Exception e)
{
e.printStackTrace();
}
}
private DataCollector createClient(String user, String sessionTag) {
return TikTokLiveTools.createCollector("dupa")
.addUser(user)
.setSessionTag(sessionTag)
.setDatabase(database)
.configureLiveClient(liveClientBuilder ->
{
liveClientBuilder.configure(clientSettings ->
{
clientSettings.setPrintToConsole(true);
});
liveClientBuilder.onWebsocketResponse((liveClient, event) ->
{
for (var msg : event.getResponse().getMessagesList()) {
System.out.println(msg.getMethod());
}
});
liveClientBuilder.onDisconnected((liveClient, event) ->
{
liveClient.getLogger().info("Disconnected");
isConnected = false;
});
liveClientBuilder.onError((liveClient, event) ->
{
event.getException().printStackTrace();
});
liveClientBuilder.onConnected((liveClient, event) ->
{
liveClient.getLogger().info("Connected");
isConnected = true;
});
}).build();
}
}

View File

@@ -0,0 +1,118 @@
package io.github.jwdeveloper.tiktok.webviewer.services;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.tools.db.TikTokDataTableDAO;
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokDataTable;
import io.github.jwdeveloper.tiktok.tools.util.MessageUtil;
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import io.github.jwdeveloper.tiktok.utils.ProtocolUtils;
import java.util.Base64;
import java.util.List;
public class TikTokDatabaseService {
public TikTokDatabase tikTokDatabase;
private TikTokDataTableDAO table;
public record DatabaseDataDto(String dataType, String dataName, String user, String sessionTag, boolean asJson) {
}
public TikTokDatabaseService(TikTokDatabase databaseName) {
tikTokDatabase = databaseName;
table = tikTokDatabase.getDataTableDAO();
}
public List<String> getUsers() {
return table.getUsers();
}
public List<String> getSessionTag(String user) {
return table.getSessionTagByUser(user);
}
public List<String> getDataNames(String dataType, String user, String sessionTag) {
return tikTokDatabase.getDataNames(dataType, sessionTag, user);
}
public List<String> getData(DatabaseDataDto dataDto) {
var data = tikTokDatabase.getDataTableDAO().selectSessionData(dataDto.dataType(), dataDto.sessionTag(), dataDto.user());
switch (dataDto.dataType()) {
case "message" -> {
return getMessages(dataDto.dataName(), data, dataDto.asJson);
}
case "event" -> {
return getEvents(dataDto.dataName(), data);
}
case "response" -> {
return getResponse(data,dataDto.dataName());
}
}
return List.of("unknown dataType");
}
private List<String> getMessages(String messageName, List<TikTokDataTable> data, boolean asJson) {
var messages = data.stream()
.filter(e -> e.getDataTypeName().equals(messageName))
.map(e ->
{
try {
var bytes = Base64.getDecoder().decode(e.getContent());
if (asJson == false) {
return ProtocolUtils.getProtocolBufferStructure(bytes).toJson();
}
var parsedMessage = MessageUtil.getContent(messageName, bytes);
return parsedMessage;
} catch (Exception ex) {
ex.printStackTrace();
return "";
}
})
.toList();
return messages;
}
private List<String> getResponse(List<TikTokDataTable> data,String dataTypeName)
{
var messages = data.stream()
.filter(e -> e.getDataTypeName().equals(dataTypeName))
.map(e ->
{
if(e.getDataTypeName().equals("Http"))
{
return e.getContent();
}
try
{
var bytes = Base64.getDecoder().decode(e.getContent());
var parsedMessage = WebcastResponse.parseFrom(bytes);
var json = JsonUtil.toJson(parsedMessage);
return json;
} catch (Exception ex) {
ex.printStackTrace();
return "error";
}
})
.toList();
return messages;
}
private List<String> getEvents(String dataName, List<TikTokDataTable> data) {
var messages = data.stream()
.filter(e -> e.getDataTypeName().equals(dataName))
.map(TikTokDataTable::getContent)
.toList();
return messages;
}
}

View File

@@ -0,0 +1,135 @@
body, html {
height: 100%;
margin: 0;
display: flex;
flex-direction: column;
color: whitesmoke;
}
.header {
margin-bottom: 20px;
}
.connect-btn
{
width: 100%;
}
.dropdown
{
width: 100%;
}
.dropdown-toggle
{
background-color: #2c2c2c;
border-color: #2c2c2c;
width: 100%;
}
.btn-primary
{
background-color: #2c2c2c;
border-color: #2c2c2c;
}
.btn-primary:hover
{
background-color: #474747;
border-color: #474747;
}
.margin
{
margin-top: 2em;
}
.form
{
padding: 1em;
border-bottom: 2px solid #676767
}
.form-label
{
color: whitesmoke;
}
.editor-parent
{
height: 2000px;
}
.editor-container
{
resize: vertical;
overflow: auto;
}
.list-group-item:hover
{
background-color: #474747;
color: azure;
cursor: pointer;
}
.list-group-item
{
background-color: #2c2c2c;
color: azure;
border-color: #252424;
}
.margin-left
{
margin-right: 0.2em;
}
.content {
flex-grow: 1; /* Takes up the remaining space */
display: flex;
}
.col-md-10, .col-md-2 {
padding: 0; /* Remove default padding */
height: 100%;
}
.scrollable-element {
overflow-y: scroll; /* Enable vertical scrollbar */
/* Other styles as needed */
scrollbar-width: thin;
height: 800px;
scrollbar-color: #275c9c #000000; /* thumb and track color */
}
.dropdown-menu
{
width: 100%;
background-color: #414040;
color: whitesmoke;
}
.dropdown-item
{
-webkit-user-select: none; /* For webkit browsers */
-moz-user-select: none; /* For Firefox */
-ms-user-select: none; /* For Microsoft browsers */
user-select: none; /* Standard syntax */
color: whitesmoke;
}
.dropdown-item:hover
{
background-color: #696868;
color: whitesmoke;
}
.dropdown-item:hover
{
cursor: pointer;
}
::-webkit-scrollbar {
width: 10px; /* Set width of the scrollbar */
}
::-webkit-scrollbar-track {
background: #1e1e23; /* Track color */
}
::-webkit-scrollbar-thumb {
background: #123054; /* Thumb color */
border-radius: 5px; /* Rounded corners */
}

View File

@@ -3,252 +3,132 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Bootstrap Styled Javalin App</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" type="text/javascript" charset="utf-8"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" type="text/javascript"
charset="utf-8"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/editor/editor.main.css">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/editor/editor.main.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/loader.min.js"></script>
<style>
body, html {
height: 100%;
margin: 0;
display: flex;
flex-direction: column;
background-color: #121212; /* Dark background */
}
#app {
height: 100vh; /* 100% of the viewport height */
display: flex;
flex-direction: column;
}
.header {
margin-bottom: 20px;
}
.btn-primary
{
background-color: #2c2c2c;
border-color: #2c2c2c;
}
.btn-primary:hover
{
background-color: #474747;
border-color: #474747;
}
#editor {
overflow-y: auto;
white-space: pre-wrap;
height: 100%;
overflow-y: auto;
}
.editor-container
{
padding: 10em;
}
.list-group-item:hover
{
background-color: #474747;
color: azure;
cursor: pointer;
}
.list-group-item
{
background-color: #2c2c2c;
color: azure;
border-color: #252424;
}
.content {
flex-grow: 1; /* Takes up the remaining space */
display: flex;
}
.col-md-10, .col-md-2 {
padding: 0; /* Remove default padding */
height: 100%;
}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/editor/editor.main.css">
<!-- Load Monaco Editor's main loader script -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/loader.min.js"></script>
<!-- Configure the loader -->
<script>
require.config({
paths: {'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs'}
});
</script>
<!-- Load the editor -->
<script>
var editor;
require(['vs/editor/editor.main'], function() {
editor = monaco.editor.create(document.getElementById('editor'), {
value: [
'function x() {',
'\tconsole.log("Hello world!");',
'}'
].join('\n'),
language: 'json',
theme: 'vs-dark'
});
editor.onDidChangeModelContent(function () {
console.log("hello")
});
});
</script>
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/editor/editor.main.css">
<link rel="stylesheet" , href="index.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/loader.min.js"></script>
<script>
require.config({
paths: {'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs'}
});
</script>
<script>
var editor;
var editor2;
require(['vs/editor/editor.main'], function () {
editor = monaco.editor.create(document.getElementById('editor'), {
value: [
'Hello world!',
].join('\n'),
language: 'json',
theme: 'vs-dark',
automaticLayout: true
});
editor2 = monaco.editor.create(document.getElementById('editor2'), {
value: [
'Hello world!',
].join('\n'),
language: 'json',
theme: 'vs-dark',
automaticLayout: true
});
});
</script>
</head>
<body class="bg-dark">
<div id="app" class="container-fluid mt-5">
<div >
<div class="mb-3">
<label for="name" class="form-label">Name:</label>
<input type="text" id="name" name="name" class="form-control">
<body class="container-fluid bg-dark">
<div class="row ">
<div class="col-2 ">
<div class="form margin">
<h5 >Data collector</h5>
<div class="form-group ">
<label for="name" class="form-label">TikTok username</label>
<input type="text" id="name" class="form-control">
</div>
<button type="button" onclick="connect()" class="btn btn-primary">Connect</button>
<button type="button" onclick="disconnect()" class="btn btn-primary">Disconnect</button>
<button onclick="showEvents()" class="btn btn-primary">Show Events</button>
</div>
<div class="content row mt-5">
<div class="col-md-2 ">
<ul id="eventList" class="list-group" style="max-height: 100%; overflow-y: auto;">
<!-- List items will be added dynamically -->
<div class="form-group ">
<label class="form-label">SessionTag</label>
<input type="text" id="sessionTag" class="form-control">
</div>
<button id="connectionButton" type="button" class="btn btn-primary mt-3 connect-btn">Connect </button>
</div>
<div>
<div class="dropdown mt-3" id="usersDropDown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="usersDropDownButton"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
User
</button>
<div id="userDropdownContent" class="dropdown-menu" aria-labelledby="usersDropDownButton">
</div>
</div>
<div class="dropdown mt-3" id="sessionTagDropDown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="sessionTagDropDownButton"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
SessionTag
</button>
<div class="dropdown-menu" aria-labelledby="sessionTagDropDownButton">
</div>
</div>
<div class="dropdown mt-3" id="dataTypeDropDown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Data Type
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
</div>
</div>
</div>
<div class="mt-5">
<ul id="dataList" class="list-group scrollable-element">
</ul>
</div>
<div class="col-md-10 editor-container ">
<nav aria-label="Page navigation example">
<ul id="pages" class="pagination">
<li class="page-item btn-primary"><a class="page-link" href="#">Previous</a></li>
<li class="page-item"><a class="page-link" href="#">Next</a></li>
</ul>
</nav>
<div id="editor"></div>
</div>
</div>
</div>
</div>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="col-10 margin">
<nav aria-label="Page navigation example">
<ul id="pages" class="pagination">
</ul>
</nav>
<div class="row editor-parent">
<div class="col-6 editor-container" id="editor"></div>
<div class="col-6 editor-container" id="editor2"></div>
</div>
</div>
</div>
<script>
async function connect() {
let name = document.getElementById('name').value;
// name = "bangbetmenygy"
let response = await fetch(`http://localhost:8001/tiktok/connect?name=${name}`);
let greeting = await response.text();
console.log("connect",greeting);
connected = true;
}
async function disconnect() {
let response = await fetch(`http://localhost:8001/tiktok/disconnect`);
let greeting = await response.text();
console.log("disconnect",greeting);
connected = false;
}
async function loadMessage(event)
{
let response = await fetch(`http://localhost:8001/tiktok/events/message?eventName=${event}`);
let json = await response.text();
let root= JSON.parse(json);
editor.setValue(root.content);
}
async function loadMessageLink(link)
{
let response = await fetch(link);
let json = await response.text();
let root= JSON.parse(json);
editor.setValue(root.content);
}
async function loadPagination(event)
{
let response = await fetch(`http://localhost:8001/tiktok/events/pages?eventName=${event}`);
let json = await response.text();
let object = JSON.parse(json);
let pages = object.links;
console.log("PAGES: ",pages)
$("#pages").empty();
$.each(pages, function(index, element) {
let content = $('<button>',{
class: 'btn btn-primary',
text: index
}).click(async function()
{
await loadMessageLink(element);
console.log(editor)
});
$("#pages").append(content);
});
}
async function showEvents() {
let response = await fetch(`http://localhost:8001/tiktok/events`);
let json = await response.text();
console.log("events:",json);
let events= JSON.parse(json);
$("#eventList").empty();
$.each(events, function(index, event) {
let listItem = $('<li>', {
class: 'list-group-item',
text: event
}).click(async function()
{
await loadMessage(event);
await loadPagination(event);
});
$("#eventList").append(listItem);
});
}
async function loop()
{
if(!connected)
{
return;
}
console.log("updating");
await showEvents();
}
var connected = false;
var paginationIndex = 0;
var maxPages = 10;
var pages = [];
setInterval(loop, 1000)
showEvents()
</script>
<script src="index.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.3/dist/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

View File

@@ -0,0 +1,210 @@
var dataType = "messages"
var connected = false;
var paginationIndex = 0;
var maxPages = 10;
var pages = [];
var userName = "";
var port = 8002;
var baseUrl = `http://localhost:${port}`
var data =
{
dataType: "event",
dataName: "",
user: "",
sessionTag: "",
page: 0,
collector:
{
connected: false,
user: "",
sessionTag: "",
}
}
dropDown("usersDropDown", () => `${baseUrl}/tiktok/users`, async (e) => {
data.user = e;
update();
})
dropDown("dataTypeDropDown", () => `${baseUrl}/tiktok/data-types`, async (e) => {
data.dataType = e;
update();
})
dropDown("sessionTagDropDown", () => `${baseUrl}/tiktok/sessions?user=${data.user}`, async (e) => {
data.sessionTag = e;
update();
})
function update() {
new Promise(async function (resolve, reject) {
await updateAsync();
resolve(true);
});
}
async function updateAsync() {
console.log(data);
await updateConnectionButton()
await updateDataNamesList(async (dataName) => {
data.dataName = dataName;
data.page = 0;
await updateContent();
await updatePagination(async (page, link) => {
data.page = page;
let response = await fetch(link);
let json = await response.text();
console.log(link)
let root = JSON.parse(json);
editor.setValue(root.content);
if(data.dataType === 'message')
{
console.log("sending proto version")
let response2 = await fetch(`${link}&asProto=true`);
let json2 = await response2.text();
let root2 = JSON.parse(json2);
editor2.setValue(root2.content);
}
});
});
await fetch(`${baseUrl}/tiktok/update?user=${data.user}&session=${data.sessionTag}`);
}
async function updatePagination(onSelect) {
let response = await fetch(`${baseUrl}/tiktok/data/pages?name=${data.dataName}&type=${data.dataType}`);
let json = await response.text();
let object = JSON.parse(json);
let pages = object.links;
$("#pages").empty();
let page = 0;
$.each(pages, function (index, element) {
let currentPage = page;
page++;
let content = $('<button>', {
class: 'btn btn-primary margin-left',
text: index
}).click(async function () {
await onSelect(currentPage, element);
});
$("#pages").append(content);
});
}
async function updateContent() {
console.log("updating content", data)
let response = await fetch(`${baseUrl}/tiktok/data?name=${data.dataName}&type=${data.dataType}&page=${data.page}`);
let json = await response.text();
let root = JSON.parse(json);
editor.setValue(root.content);
if(data.dataType === 'message')
{
console.log("sending proto version")
let response2 = await fetch(`${baseUrl}/tiktok/data?name=${data.dataName}&type=${data.dataType}&page=${data.page}&asProto=true`);
let json2 = await response2.text();
let root2 = JSON.parse(json2);
editor2.setValue(root2.content);
}
}
async function updateDataNamesList(onSelect) {
let response = await fetch(`${baseUrl}/tiktok/data/names?type=${data.dataType}`);
let json = await response.text();
let responce = JSON.parse(json);
let element = $("#dataList");
console.log(responce)
element.empty();
$.each(responce, function (index, dataName) {
let listItem = $('<li>', {
class: 'list-group-item',
text: dataName
}).click(async function () {
onSelect(dataName)
});
element.append(listItem);
});
}
function dropDown(elementId, onUrl, onSelect) {
let dropDown = $("#" + elementId);
dropDown.on('show.bs.dropdown', async function (e, b) {
let response = await fetch(onUrl());
let json = await response.text();
let values = JSON.parse(json);
let optionsElement = dropDown.find("div")
optionsElement.empty();
let displayElement = dropDown.find("button")
for (let value of values) {
let dropDownItem = $('<p>', {
class: 'dropdown-item',
text: value
}).click(async function () {
displayElement.text(value)
onSelect(value)
});
optionsElement.append(dropDownItem)
}
})
}
setInterval(() => {
new Promise(async (a, b) => {
await updateConnectionButton()
});
}, 1000)
$("#connectionButton").on('click', async (a) => {
if (!data.collector.connected) {
console.log("connecting")
await connect()
} else {
console.log("disconnecting")
await disconnect()
}
});
async function updateConnectionButton() {
let button = $("#connectionButton");
let response = await fetch(`${baseUrl}/tiktok/status`);
let json = await response.text();
let values = JSON.parse(json);
console.log(values)
data.collector.connected = values;
if (data.collector.connected) {
button.text("disconnect");
} else {
button.text("connect");
}
}
async function connect() {
let name = document.getElementById('name').value;
let session = document.getElementById('sessionTag').value;
data.collector.name = name
data.collector.sessionTag =session
let response = await fetch(`${baseUrl}/tiktok/connect?name=${data.collector.name}&session=${data.collector.sessionTag}`);
let greeting = await response.text();
}
async function disconnect() {
let response = await fetch(`${baseUrl}/tiktok/disconnect`);
let greeting = await response.text();
}
update()