Compare commits
27 Commits
bugfixes/c
...
feature/ma
Author | SHA1 | Date | |
---|---|---|---|
15809f3fbd | |||
f4c947e359 | |||
5b31fef0c7 | |||
a4ff706a28 | |||
4b6bb780d4 | |||
e8463ecc25 | |||
2083e8279f | |||
19e011dfac | |||
bb96bcde61 | |||
15416e3728 | |||
feccbc05e6 | |||
7d16552d65 | |||
268bbdf9b7 | |||
8ab6b9d986 | |||
2261e753d5 | |||
88dd3b5908 | |||
f8f94b4afc | |||
309d7c0cd3 | |||
f37beb0a5d | |||
eec1050e17 | |||
8ffd920007 | |||
846b7d10d8 | |||
5adc9b7b9f | |||
3eb412bd6e | |||
1949c7af1b | |||
993a94ddb1 | |||
26dcd962b8 |
@ -4,11 +4,6 @@ type: docker
|
||||
name: publish-bot
|
||||
|
||||
steps:
|
||||
- name: build-dotnet
|
||||
image: mcr.microsoft.com/dotnet/sdk:6.0
|
||||
commands:
|
||||
- dotnet publish
|
||||
|
||||
- name: build-image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
@ -17,10 +12,8 @@ steps:
|
||||
from_secret: DOCKER_USER
|
||||
password:
|
||||
from_secret: DOCKER_PASS
|
||||
repo: git.kizaing.ca/kizaing/TeleTok
|
||||
repo: git.kizaing.ca/kizaing/teletok
|
||||
tags: latest
|
||||
platform: linux/amd64,linux/arm64
|
||||
|
||||
|
||||
# Commented out until stuff actually works
|
||||
trigger:
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
bin
|
||||
obj
|
||||
obj
|
||||
.vscode
|
||||
config.Dev.json
|
46
CryptographyService.cs
Normal file
46
CryptographyService.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using Sodium;
|
||||
|
||||
namespace TeleTok
|
||||
{
|
||||
public class CryptographyService
|
||||
{
|
||||
public string ToHexString(byte[] input)
|
||||
{
|
||||
var hexString = BitConverter.ToString(input);
|
||||
|
||||
string result = hexString.Replace("-", "");
|
||||
|
||||
return result.ToLower();
|
||||
}
|
||||
|
||||
public byte[] GenerateLoginDigest()
|
||||
{
|
||||
long now = DateTimeOffset.UtcNow.ToUnixTimeSeconds() * 1000;
|
||||
var message = $"login:{now / 1000 / (5 * 60)}";
|
||||
|
||||
return GenericHash.Hash(message, (byte[]?) null, 32);
|
||||
}
|
||||
|
||||
public KeyPair GenerateEd25519KeyPair(string seed)
|
||||
{
|
||||
byte[] hash = GenericHash.Hash(seed, (byte[]?) null, 32);
|
||||
|
||||
return PublicKeyAuth.GenerateKeyPair(hash);
|
||||
}
|
||||
|
||||
public string GenerateHexSignature(byte[] loginDigest, byte[] secretKey)
|
||||
{
|
||||
byte[] signature = PublicKeyAuth.SignDetached(loginDigest, secretKey);
|
||||
|
||||
return ToHexString(signature);
|
||||
}
|
||||
|
||||
public string GenerateHexId(byte[] publicKey)
|
||||
{
|
||||
byte[] hash = GenericHash.Hash(publicKey, null, publicKey.Length);
|
||||
|
||||
return ToHexString(hash);
|
||||
}
|
||||
}
|
||||
}
|
13
Dockerfile
13
Dockerfile
@ -1,7 +1,14 @@
|
||||
FROM mcr.microsoft.com/dotnet/runtime:6.0-alpine3
|
||||
#Builds the bot from source
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-task
|
||||
|
||||
COPY . /build
|
||||
RUN cd /build && dotnet publish
|
||||
|
||||
# Actually runs the bot
|
||||
FROM mcr.microsoft.com/dotnet/runtime:6.0
|
||||
|
||||
WORKDIR /app/teletok
|
||||
|
||||
COPY bin/Debug/net6.0/publish/* /app/teletok/
|
||||
COPY --from=build-task /build/bin/Debug/net6.0/publish/* /app/teletok/
|
||||
|
||||
CMD [ "TeleTok" ]
|
||||
CMD [ "./TeleTok" ]
|
114
MatrixListener.cs
Normal file
114
MatrixListener.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using Matrix.Sdk;
|
||||
using Matrix.Sdk.Core.Domain.MatrixRoom;
|
||||
using Matrix.Sdk.Core.Domain.RoomEvent;
|
||||
using Matrix.Sdk.Core.Infrastructure.Dto.Room.Create;
|
||||
using Sodium;
|
||||
|
||||
namespace TeleTok
|
||||
{
|
||||
public class MatrixListener
|
||||
{
|
||||
private static readonly CryptographyService CryptographyService = new();
|
||||
|
||||
public record LoginRequest(Uri BaseAddress, string Username, string Password, string DeviceId);
|
||||
|
||||
public async Task RunListener()
|
||||
{
|
||||
var factory = new MatrixClientFactory();
|
||||
var anotherFactory = new MatrixClientFactory();
|
||||
|
||||
IMatrixClient client = factory.Create();
|
||||
IMatrixClient anotherClient = anotherFactory.Create();
|
||||
|
||||
client.OnMatrixRoomEventsReceived += (sender, eventArgs) =>
|
||||
{
|
||||
foreach (BaseRoomEvent roomEvent in eventArgs.MatrixRoomEvents)
|
||||
{
|
||||
if (roomEvent is not TextMessageEvent textMessageEvent)
|
||||
continue;
|
||||
|
||||
(string roomId, string senderUserId, string message) = textMessageEvent;
|
||||
if (client.UserId != senderUserId)
|
||||
TeleTok.LogMessage($"RoomId: {roomId} received message from {senderUserId}: {message}.");
|
||||
}
|
||||
};
|
||||
|
||||
anotherClient.OnMatrixRoomEventsReceived += (sender, eventArgs) =>
|
||||
{
|
||||
foreach (BaseRoomEvent roomEvent in eventArgs.MatrixRoomEvents)
|
||||
{
|
||||
if (roomEvent is not TextMessageEvent textMessageEvent)
|
||||
continue;
|
||||
|
||||
(string roomId, string senderUserId, string message) = textMessageEvent;
|
||||
if (anotherClient.UserId != senderUserId)
|
||||
TeleTok.LogMessage($"RoomId: {roomId} received message from {senderUserId}: {message}.");
|
||||
}
|
||||
};
|
||||
|
||||
(Uri matrixNodeAddress, string username, string password, string deviceId) = CreateLoginRequest();
|
||||
await client.LoginAsync(matrixNodeAddress, username, password, deviceId);
|
||||
|
||||
LoginRequest request2 = CreateLoginRequest();
|
||||
await anotherClient.LoginAsync(request2.BaseAddress, request2.Username, request2.Password, request2.DeviceId);
|
||||
|
||||
if(client.IsLoggedIn)
|
||||
{
|
||||
TeleTok.LogMessage($"client.IsLoggedIn: {client.IsLoggedIn}");
|
||||
TeleTok.LogMessage($"client.IsSyncing: {client.IsSyncing}");
|
||||
}
|
||||
|
||||
client.Start();
|
||||
anotherClient.Start();
|
||||
|
||||
CreateRoomResponse createRoomResponse = await client.CreateTrustedPrivateRoomAsync(new[]
|
||||
{
|
||||
anotherClient.UserId
|
||||
});
|
||||
|
||||
await anotherClient.JoinTrustedPrivateRoomAsync(createRoomResponse.RoomId);
|
||||
|
||||
var spin = new SpinWait();
|
||||
while(anotherClient.JoinedRooms.Length ==0)
|
||||
spin.SpinOnce();
|
||||
|
||||
await client.SendMessageAsync(createRoomResponse.RoomId, "Hello");
|
||||
await anotherClient.SendMessageAsync(anotherClient.JoinedRooms[0].Id, ", ");
|
||||
|
||||
await client.SendMessageAsync(createRoomResponse.RoomId, "World");
|
||||
await anotherClient.SendMessageAsync(anotherClient.JoinedRooms[0].Id, "!");
|
||||
|
||||
TeleTok.LogMessage($"client.IsLoggedIn: {client.IsLoggedIn}");
|
||||
TeleTok.LogMessage($"client.IsSyncing: {client.IsSyncing}");
|
||||
|
||||
Console.ReadLine();
|
||||
|
||||
client.Stop();
|
||||
anotherClient.Stop();
|
||||
|
||||
Console.WriteLine($"client.IsLoggedIn: {client.IsLoggedIn}");
|
||||
Console.WriteLine($"client.IsSyncing: {client.IsSyncing}");
|
||||
|
||||
}
|
||||
|
||||
private static LoginRequest CreateLoginRequest()
|
||||
{
|
||||
var seed = Guid.NewGuid().ToString();
|
||||
KeyPair keyPair = CryptographyService.GenerateEd25519KeyPair(seed);
|
||||
|
||||
byte[] loginDigest = CryptographyService.GenerateLoginDigest();
|
||||
string hexSignature = CryptographyService.GenerateHexSignature(loginDigest, keyPair.PrivateKey);
|
||||
string publicKeyHex = CryptographyService.ToHexString(keyPair.PublicKey);
|
||||
string hexId = CryptographyService.GenerateHexId(keyPair.PublicKey);
|
||||
|
||||
var password = $"ed:{hexSignature}:{publicKeyHex}";
|
||||
string deviceId = publicKeyHex;
|
||||
|
||||
LoginRequest loginRequest = new LoginRequest(TeleTok.mAddress, TeleTok.mBotUser, TeleTok.mBotPass, deviceId);
|
||||
|
||||
return loginRequest;
|
||||
}
|
||||
}
|
||||
}
|
94
Program.cs
94
Program.cs
@ -10,17 +10,99 @@ namespace TeleTok
|
||||
.AddJsonFile("config.json", true)
|
||||
.Build();
|
||||
|
||||
// Value to see what bot mode to run in
|
||||
public static string botMode = config.GetSection("TeleTokConf:botMode").Value;
|
||||
|
||||
// Telegram bot config
|
||||
public static string token = config.GetSection("TeleTokConf:token").Value;
|
||||
public static string ptInstance = config.GetSection("TeleTokConf:proxitokInstance").Value;
|
||||
public static string ptInstance = config.GetSection("TeleTokConf:ptInstance").Value;
|
||||
|
||||
// Matrix bot config
|
||||
public static string matrixAddress = config.GetSection("TeleTokConf:matrixAddress").Value;
|
||||
public static Uri mAddress;
|
||||
public static string mBotUser = config.GetSection("TeleTokConf:mBotUser").Value;
|
||||
public static string mBotPass = config.GetSection("TeleTokConf:mBotPass").Value;
|
||||
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
|
||||
TelegramListener listener = new TelegramListener();
|
||||
Console.WriteLine("Now listening...");
|
||||
//Checks to see what mode to run the bot in
|
||||
LogMessage($"The current running config is: \n Bot Mode: {botMode} \n Telegram Token: {token} \n ProxiTok Instance: {ptInstance} \n Matrix Homeserver: {matrixAddress} \n Matrix Bot User: {mBotUser}");
|
||||
|
||||
listener.RunListener();
|
||||
|
||||
if(botMode == "telegram")
|
||||
{
|
||||
//Checks if the config json data is valid
|
||||
if(!ConfigCheck(token))
|
||||
{
|
||||
LogMessage("Telegram bot token is invalid! Exiting...");
|
||||
}
|
||||
else if(!ConfigCheck(ptInstance))
|
||||
{
|
||||
LogMessage("Proxitok instance is invalid! Exiting...");
|
||||
}
|
||||
else
|
||||
{
|
||||
TelegramListener tListener = new TelegramListener();
|
||||
LogMessage("Now listening...");
|
||||
|
||||
tListener.RunListener();
|
||||
}
|
||||
}
|
||||
else if(botMode == "matrix")
|
||||
{
|
||||
//Checks if the config json data is valid
|
||||
if(Uri.IsWellFormedUriString(matrixAddress, UriKind.Absolute))
|
||||
{
|
||||
mAddress = new Uri(matrixAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMessage("Matrix server address is not a valid URL! Exiting...");
|
||||
}
|
||||
|
||||
if(!ConfigCheck(mBotUser))
|
||||
{
|
||||
LogMessage("Matrix bot username is invalid! Exiting...");
|
||||
}
|
||||
else if(!ConfigCheck(mBotPass))
|
||||
{
|
||||
LogMessage("Matrix bot password is invalid! Exiting...");
|
||||
}
|
||||
else
|
||||
{
|
||||
MatrixListener mListener = new MatrixListener();
|
||||
LogMessage("Now listening...");
|
||||
|
||||
await mListener.RunListener();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMessage("Bot mode is not configured! Enter either \'telegram\' or \'matrix\'");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ConfigCheck(string confItem)
|
||||
{
|
||||
if(confItem == "" || confItem == null
|
||||
|| confItem == "INSERT TOKEN HERE"
|
||||
|| confItem == "PROXITOK INSTANCE URL"
|
||||
|| confItem == "SYNAPSE SERVER URL"
|
||||
|| confItem == "MATRIX BOT USERNAMEL"
|
||||
|| confItem == "MATRIX BOT PASSWORD")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void LogMessage(string text)
|
||||
{
|
||||
DateTime now =DateTime.Now;
|
||||
|
||||
Console.WriteLine("[" + now.ToString() + "] " + text);
|
||||
}
|
||||
}
|
||||
}
|
30
README.md
30
README.md
@ -1,5 +1,33 @@
|
||||
[](https://ci.kizaing.ca/kizaing/TeleTok)
|
||||
|
||||
# TeleTok Telegram Bot
|
||||
This bot will monitor any chats for TikTok links that are posted, and then will run the link through a [ProxiTok](https://github.com/pablouser1/ProxiTok) instance to generate a download link. The resulting video file will then get directly uploaded directly to your chat.
|
||||
|
||||
This bot is in early development, but the end goal is to have this bot automatically convert all tiktok links in a chat into a videofile that can be re-uploaded to the telegram chat
|
||||
## Building
|
||||
Requirements: Dotnet SDK 6.0
|
||||
|
||||
Run `dotnet build` for a Debug instance
|
||||
Run `dotnet publish` for a full release
|
||||
|
||||
## Installation
|
||||
### Requirements
|
||||
* A telegram bot token
|
||||
* A working [ProxiTok](https://github.com/pablouser1/ProxiTok) instance, either public or hosted yourself. (Please be kind and take bandwidth into account when using a public instance)
|
||||
|
||||
### Binary
|
||||
1. Either build the application or download a release zip for your OS/architecture
|
||||
2. Edit the config.json and put your telegram bot token in the "token" field, and your chosen ProxiTok instance in the "ptInstance" field
|
||||
3. Run the TeleTok.exe/TeleTok executable
|
||||
|
||||
### Docker
|
||||
1. You can build an image for yourself with `docker build teletok .` or you can pull a prebuilt image with `docker pull kizaing/teletok:latest`
|
||||
2. Copy the placeholder config.json from the repo to a location of your choosing
|
||||
3. Edit the config.json and put your telegram bot token in the "token" field, and your chosen ProxiTok instance in the "ptInstance" field
|
||||
4. Run the container with `docker run -v ${PWD}/config.json:/app/teletok/config.json -d kizaing/teletok:latest`
|
||||
|
||||
|
||||
## To Do
|
||||
- [x] Add better error and link handling
|
||||
- [x] Process videos into telegram
|
||||
- [ ] Add [Matrix](https://matrix.org) support
|
||||
- [ ] Automate binary release publishing
|
@ -8,8 +8,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Matrix.Sdk" Version="1.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Sodium.Core" Version="1.3.3" />
|
||||
<PackageReference Include="Telegram.Bot" Version="17.0.0" />
|
||||
<PackageReference Include="Telegram.Bot.Extensions.Polling" Version="1.0.2" />
|
||||
</ItemGroup>
|
||||
|
@ -55,22 +55,15 @@ namespace TeleTok
|
||||
// Passes the url along to the video downloader if it is valid AND a tiktok link
|
||||
if (isUri)
|
||||
{
|
||||
try
|
||||
if(messageText.Contains("tiktok.com"))
|
||||
{
|
||||
if(messageText.Contains("tiktok.com"))
|
||||
{
|
||||
proxyUrl = VidDownload.TikTokURL(messageText);
|
||||
proxyUrl = VidDownload.TikTokURL(messageText);
|
||||
|
||||
Message ttVideo = await botClient.SendVideoAsync(
|
||||
chatId: chatId,
|
||||
video: proxyUrl,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Valid TikTok URI was sent, but was not a video!");
|
||||
Message ttVideo = await botClient.SendVideoAsync(
|
||||
chatId: chatId,
|
||||
video: proxyUrl,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,7 +77,7 @@ namespace TeleTok
|
||||
_ => exception.ToString()
|
||||
};
|
||||
|
||||
Console.WriteLine(ErrorMessage);
|
||||
TeleTok.LogMessage(ErrorMessage);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,16 @@ namespace TeleTok
|
||||
string url = videourl;
|
||||
string proxyUrl;
|
||||
|
||||
TeleTok.LogMessage("Video for " + videourl + " processing..");
|
||||
|
||||
if(url.Contains("vm.tiktok.com"))
|
||||
{
|
||||
url = UnshortenUrl(url);
|
||||
}
|
||||
|
||||
proxyUrl = TeleTok.ptInstance + "/download?url=" + url;
|
||||
Console.WriteLine("Video for " + url + " has been sent..");
|
||||
proxyUrl = CreateDownloadLink(url);
|
||||
|
||||
TeleTok.LogMessage("Sending video link for " + proxyUrl);
|
||||
|
||||
return proxyUrl;
|
||||
}
|
||||
@ -33,5 +36,25 @@ namespace TeleTok
|
||||
|
||||
return realUrl;
|
||||
}
|
||||
|
||||
//Breaks apart the URL and extracts the User and Video ID to be processed into a working download link
|
||||
static string CreateDownloadLink(string videourl)
|
||||
{
|
||||
Uri segmentedUri = new Uri(videourl);
|
||||
segmentedUri = new Uri(segmentedUri.AbsoluteUri.Replace(segmentedUri.Query, string.Empty));
|
||||
|
||||
string videoUser = segmentedUri.Segments[1];
|
||||
videoUser = videoUser.Replace(@"/", "");
|
||||
string videoID = segmentedUri.Segments[3];
|
||||
|
||||
string fixedUrl = "https://www.tiktok.com/" + videoUser + "/video/" + videoID + @"&id=" + videoID + @"&user=" + videoUser.Remove(0, 1);
|
||||
|
||||
string proxyLink = TeleTok.ptInstance + "/download?url=" + fixedUrl;
|
||||
|
||||
TeleTok.LogMessage("Input User ID is: " + videoUser);
|
||||
TeleTok.LogMessage("Input video ID is: " + videoID);
|
||||
|
||||
return proxyLink;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
{
|
||||
"TeleTokConf": {
|
||||
"botMode": "telegram",
|
||||
"token": "INSERT TOKEN HERE",
|
||||
"proxitokInstance": "PROXITOK INSTANCE URL"
|
||||
"ptInstance": "PROXITOK INSTANCE URL",
|
||||
"matrixAddress": "SYNAPSE SERVER URL",
|
||||
"mBotUser": "MATRIX BOT USERNAME",
|
||||
"mBotPass": "MATRIX BOT PASSWORD"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user