Compare commits
36 Commits
4fa6863b0d
...
main
Author | SHA1 | Date | |
---|---|---|---|
8461afd08f | |||
30d4c41eee | |||
fadc678ac3 | |||
9b06a629f0 | |||
bb96bcde61 | |||
15416e3728 | |||
feccbc05e6 | |||
7d16552d65 | |||
268bbdf9b7 | |||
8ab6b9d986 | |||
2261e753d5 | |||
88dd3b5908 | |||
f8f94b4afc | |||
309d7c0cd3 | |||
f37beb0a5d | |||
eec1050e17 | |||
8ffd920007 | |||
846b7d10d8 | |||
5adc9b7b9f | |||
3eb412bd6e | |||
1949c7af1b | |||
993a94ddb1 | |||
26dcd962b8 | |||
8b42fb35b3 | |||
9faaeef68f | |||
e05e4fb5e5 | |||
a00cc167c3 | |||
38d0539a5f | |||
31733aa673 | |||
46fcc45931 | |||
a6c7f1ef2a | |||
ae4c436a1a | |||
724e48da04 | |||
be8f1caf35 | |||
27a480d2b0 | |||
1f15b65bf5 |
25
.drone.yml
25
.drone.yml
@ -1,20 +1,21 @@
|
|||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
name: build-app
|
type: docker
|
||||||
|
name: publish-bot
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build-dotnet
|
- name: build-image
|
||||||
image: mcr.microsoft.com/dotnet/sdk:6.0
|
image: plugins/docker
|
||||||
commands:
|
settings:
|
||||||
- dotnet build
|
registry: git.kizaing.ca
|
||||||
|
username:
|
||||||
steps:
|
from_secret: DOCKER_USER
|
||||||
- name: build-docker
|
password:
|
||||||
image: docker:dind
|
from_secret: DOCKER_PASS
|
||||||
volumes:
|
repo: git.kizaing.ca/kizaing/teletok
|
||||||
- name: dockersock
|
tags: latest
|
||||||
path: /var/run/docker.sock
|
|
||||||
|
|
||||||
|
# Commented out until stuff actually works
|
||||||
trigger:
|
trigger:
|
||||||
branch:
|
branch:
|
||||||
- main
|
- main
|
||||||
|
36
.gitea/workflows/build.yml
Normal file
36
.gitea/workflows/build.yml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# .gitea/workflows/build.yaml
|
||||||
|
name: Publish Docker image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
push_to_registry:
|
||||||
|
name: Push Docker image to registries
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out the repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: https://github.com/docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USER }}
|
||||||
|
password: ${{ secrets.DOCKER_TOKEN }}
|
||||||
|
|
||||||
|
- name: Login to Gitea registry
|
||||||
|
uses: https://github.com/docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: git.kizaing.ca
|
||||||
|
username: ${{ gitea.actor }}
|
||||||
|
password: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
uses: https://github.com/docker/build-push-action@v4
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: git.kizaing.ca/kizaing/teletok:latest, kizaing
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
bin
|
bin
|
||||||
obj
|
obj
|
||||||
|
.vscode
|
||||||
|
config.Dev.json
|
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#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 --from=build-task /build/bin/Debug/net6.0/publish/* /app/teletok/
|
||||||
|
|
||||||
|
CMD [ "./TeleTok" ]
|
36
Program.cs
36
Program.cs
@ -1,25 +1,43 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using Telegram.Bot;
|
|
||||||
|
|
||||||
namespace TeleTok
|
namespace TeleTok
|
||||||
{
|
{
|
||||||
class TeleTok
|
public class TeleTok
|
||||||
{
|
{
|
||||||
static async Task Main(string[] args)
|
public static IConfigurationRoot config = new ConfigurationBuilder()
|
||||||
{
|
|
||||||
var config = new ConfigurationBuilder()
|
|
||||||
.SetBasePath(Directory.GetCurrentDirectory())
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
.AddJsonFile("config.json", true)
|
.AddJsonFile("config.json", true)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var token = config.GetSection("TeleTokConf:token").Value;
|
public static string token = config.GetSection("TeleTokConf:token").Value;
|
||||||
|
public static string ptInstance = config.GetSection("TeleTokConf:proxitokInstance").Value;
|
||||||
|
|
||||||
var botClient = new TelegramBotClient(token);
|
static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
//Checks if the config json data is valid
|
||||||
|
if(token == "" || token == null || token == "INSERT TOKEN HERE")
|
||||||
|
{
|
||||||
|
LogMessage("Telegram bot token is invalid! Exiting...");
|
||||||
|
}
|
||||||
|
else if(ptInstance == "" || ptInstance == null || ptInstance == "PROXITOK INSTANCE URL")
|
||||||
|
{
|
||||||
|
LogMessage("Proxitok instance is invalid! Exiting...");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TelegramListener listener = new TelegramListener();
|
||||||
|
LogMessage("Now listening...");
|
||||||
|
|
||||||
var me = await botClient.GetMeAsync();
|
listener.RunListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Console.WriteLine($"Hello world! I am user {me.Id} and my name is {me.FirstName}.");
|
public static void LogMessage(string text)
|
||||||
|
{
|
||||||
|
DateTime now =DateTime.Now;
|
||||||
|
|
||||||
|
Console.WriteLine("[" + now.ToString() + "] " + text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
32
README.md
32
README.md
@ -1,5 +1,31 @@
|
|||||||
[](https://ci.kizaing.ca/kizaing/TeleTok)
|
|
||||||
|
|
||||||
# TeleTok Telegram Bot
|
# 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
|
@ -10,7 +10,8 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||||
<PackageReference Include="Telegram.Bot" Version="18.0.0" />
|
<PackageReference Include="Telegram.Bot" Version="17.0.0" />
|
||||||
|
<PackageReference Include="Telegram.Bot.Extensions.Polling" Version="1.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
84
TelegramListener.cs
Normal file
84
TelegramListener.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using System;
|
||||||
|
using System.Configuration;
|
||||||
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Exceptions;
|
||||||
|
using Telegram.Bot.Extensions.Polling;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
|
using Telegram.Bot.Types.Enums;
|
||||||
|
|
||||||
|
namespace TeleTok
|
||||||
|
{
|
||||||
|
public class TelegramListener
|
||||||
|
{
|
||||||
|
public void RunListener()
|
||||||
|
{
|
||||||
|
var botClient = new TelegramBotClient(TeleTok.token);
|
||||||
|
using var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
// StartReceiving does not block the caller thread. Receiving is done on the ThreadPool.
|
||||||
|
ReceiverOptions receiverOptions = new ()
|
||||||
|
{
|
||||||
|
AllowedUpdates = Array.Empty<UpdateType>() // receive all update types
|
||||||
|
};
|
||||||
|
|
||||||
|
botClient.StartReceiving(
|
||||||
|
updateHandler: HandleUpdateAsync,
|
||||||
|
errorHandler: HandlePollingErrorAsync,
|
||||||
|
receiverOptions: receiverOptions,
|
||||||
|
cancellationToken: cts.Token
|
||||||
|
);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Do nothing until the stuff happens
|
||||||
|
};
|
||||||
|
|
||||||
|
cts.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Only process Message updates: https://core.telegram.org/bots/api#message
|
||||||
|
if (update.Message is not { } message)
|
||||||
|
return;
|
||||||
|
// Only process text messages
|
||||||
|
if (message.Text is not { } messageText)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var chatId = message.Chat.Id;
|
||||||
|
|
||||||
|
string proxyUrl;
|
||||||
|
|
||||||
|
// Checks if the text contains a valid URL
|
||||||
|
bool isUri = Uri.IsWellFormedUriString(messageText, UriKind.RelativeOrAbsolute);
|
||||||
|
|
||||||
|
// Passes the url along to the video downloader if it is valid AND a tiktok link
|
||||||
|
if (isUri)
|
||||||
|
{
|
||||||
|
if(messageText.Contains("tiktok.com"))
|
||||||
|
{
|
||||||
|
proxyUrl = VidDownload.TikTokURL(messageText);
|
||||||
|
|
||||||
|
Message ttVideo = await botClient.SendVideoAsync(
|
||||||
|
chatId: chatId,
|
||||||
|
video: proxyUrl,
|
||||||
|
cancellationToken: cancellationToken
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Task HandlePollingErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var ErrorMessage = exception switch
|
||||||
|
{
|
||||||
|
ApiRequestException apiRequestException
|
||||||
|
=> $"Telegram API Error:\n[{apiRequestException.ErrorCode}]\n{apiRequestException.Message}",
|
||||||
|
_ => exception.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
TeleTok.LogMessage(ErrorMessage);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
VidDownload.cs
Normal file
60
VidDownload.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace TeleTok
|
||||||
|
{
|
||||||
|
public class VidDownload
|
||||||
|
{
|
||||||
|
// Takes the scraped TikTok URL and appends it to the proxy downloader link then returns it
|
||||||
|
public static string TikTokURL(string videourl)
|
||||||
|
{
|
||||||
|
string url = videourl;
|
||||||
|
string proxyUrl;
|
||||||
|
|
||||||
|
TeleTok.LogMessage("Video for " + videourl + " processing..");
|
||||||
|
|
||||||
|
if(url.Contains("vm.tiktok.com"))
|
||||||
|
{
|
||||||
|
url = UnshortenUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyUrl = CreateDownloadLink(url);
|
||||||
|
|
||||||
|
TeleTok.LogMessage("Sending video link for " + proxyUrl);
|
||||||
|
|
||||||
|
return proxyUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs the URL through a web request then returns the full url
|
||||||
|
static string UnshortenUrl(string videourl)
|
||||||
|
{
|
||||||
|
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(videourl);
|
||||||
|
req.AllowAutoRedirect = false;
|
||||||
|
var resp = req.GetResponse();
|
||||||
|
string realUrl = resp.Headers["Location"];
|
||||||
|
|
||||||
|
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,6 @@
|
|||||||
{
|
{
|
||||||
"TeleTokConf": {
|
"TeleTokConf": {
|
||||||
"token": "INSERT TOKEN HERE",
|
"token": "INSERT TOKEN HERE",
|
||||||
"port": 5000
|
"proxitokInstance": "PROXITOK INSTANCE URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user