34 Commits

Author SHA1 Message Date
8461afd08f Fixed runner repo links
Some checks failed
Push Docker image to registries
2023-03-20 20:14:41 -04:00
30d4c41eee Added repo auth
Some checks failed
Push Docker image to registries
2023-03-20 20:11:22 -04:00
fadc678ac3 Fixed pipeline trigger
Some checks failed
Push Docker image to registries
2023-03-20 20:01:52 -04:00
9b06a629f0 Added gitea runner 2023-03-20 19:58:20 -04:00
bb96bcde61 Fixed bug deleting entire user variable
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 16:33:57 -05:00
15416e3728 Fixed log date 2023-02-15 16:33:45 -05:00
feccbc05e6 Updated readme
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 14:12:00 -05:00
7d16552d65 Updated .gitignore 2023-02-15 13:55:16 -05:00
268bbdf9b7 Added json field checks 2023-02-15 13:53:47 -05:00
8ab6b9d986 Added log message
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 12:25:05 -05:00
2261e753d5 Implemented timestamp logging
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 12:20:23 -05:00
88dd3b5908 Added better link processing and logging 2023-02-15 12:20:07 -05:00
f8f94b4afc Added better link processing 2023-02-15 12:19:40 -05:00
309d7c0cd3 Added better log messaging 2023-02-15 12:17:08 -05:00
f37beb0a5d Removed try/catch it broke
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 10:05:30 -05:00
eec1050e17 Added datetime for logging 2023-02-15 10:05:14 -05:00
8ffd920007 Updated CMD command
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-14 15:29:55 -05:00
846b7d10d8 Fixed tag to be lowercase
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-14 15:17:53 -05:00
5adc9b7b9f Fixed image tag
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-14 15:13:30 -05:00
3eb412bd6e Fixed missing step
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-14 15:09:57 -05:00
1949c7af1b Merge branch 'main' of git.kizaing.ca:kizaing/TeleTok
Some checks reported errors
continuous-integration/drone/push Build encountered an error
continuous-integration/drone Build encountered an error
2023-02-14 15:07:27 -05:00
993a94ddb1 Updated build task 2023-02-14 15:06:39 -05:00
26dcd962b8 Merge pull request 'bugfixes/crash-handler' (#1) from bugfixes/crash-handler into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #1
2023-02-14 11:53:45 -08:00
8b42fb35b3 Added branch trigger 2023-02-14 14:52:27 -05:00
9faaeef68f Added try catch for URL parsing 2023-02-14 14:48:47 -05:00
e05e4fb5e5 Updated drone yaml 2023-02-14 14:48:38 -05:00
a00cc167c3 Updated Dockerfile 2023-02-14 14:48:16 -05:00
38d0539a5f Fixed method code (It works!) 2023-02-14 13:59:20 -05:00
31733aa673 Refactored classes 2023-02-14 12:29:11 -05:00
46fcc45931 Changed to use Proxitok
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-02-14 12:04:24 -05:00
a6c7f1ef2a Removed port, added proxitok entry
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone Build was killed
2023-02-14 10:16:03 -05:00
ae4c436a1a Updated video download code
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-02-14 00:35:28 -05:00
724e48da04 Added pipeline type 2023-02-14 00:34:54 -05:00
be8f1caf35 Removed trigger
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-02-13 19:19:55 -05:00
10 changed files with 255 additions and 102 deletions

View File

@ -1,20 +1,21 @@
---
kind: pipeline
name: build-app
type: docker
name: publish-bot
steps:
- name: build-dotnet
image: mcr.microsoft.com/dotnet/sdk:6.0
commands:
- dotnet build
steps:
- name: build-docker
image: docker:dind
volumes:
- name: dockersock
path: /var/run/docker.sock
- name: build-image
image: plugins/docker
settings:
registry: git.kizaing.ca
username:
from_secret: DOCKER_USER
password:
from_secret: DOCKER_PASS
repo: git.kizaing.ca/kizaing/teletok
tags: latest
# Commented out until stuff actually works
trigger:
branch:
- main

View 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

4
.gitignore vendored
View File

@ -1,2 +1,4 @@
bin
obj
obj
.vscode
config.Dev.json

View File

@ -1,11 +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
RUN apk update && apk add --update nodejs nodejs-npm
COPY --from=build-task /build/bin/Debug/net6.0/publish/* /app/teletok/
RUN npm i -g tiktok-scraper
COPY bin/Debug/net6.0/* /app/teletok/
CMD [ "TeleTok" ]
CMD [ "./TeleTok" ]

View File

@ -1,93 +1,43 @@
using Microsoft.Extensions.Configuration;
using System;
using System.Web;
using System.Text.RegularExpressions;
using Telegram.Bot;
using Telegram.Bot.Exceptions;
using Telegram.Bot.Polling;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
namespace TeleTok
{
class TeleTok
public class TeleTok
{
public static IConfigurationRoot config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("config.json", true)
.Build();
public static string token = config.GetSection("TeleTokConf:token").Value;
public static string ptInstance = config.GetSection("TeleTokConf:proxitokInstance").Value;
static async Task Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("config.json", true)
.Build();
var token = config.GetSection("TeleTokConf:token").Value;
var botClient = new TelegramBotClient(token);
using var cts = new CancellationTokenSource();
// StartReceiving does not block the caller thread. Receiving is done on the ThreadPool.
ReceiverOptions receiverOptions = new ()
//Checks if the config json data is valid
if(token == "" || token == null || token == "INSERT TOKEN HERE")
{
AllowedUpdates = Array.Empty<UpdateType>() // receive all update types
};
// HandleUpdateAsync and HandlePollingErrorAsync no worky Tyler help
botClient.StartReceiving(
updateHandler: HandleUpdateAsync,
pollingErrorHandler: HandlePollingErrorAsync,
receiverOptions: receiverOptions,
cancellationToken: cts.Token
);
var me = await botClient.GetMeAsync();
Console.WriteLine($"Start listening for @{me.Username}");
while (true)
{
// Do nothing until the stuff happens
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...");
cts.Cancel();
listener.RunListener();
}
}
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;
public static void LogMessage(string text)
{
DateTime now =DateTime.Now;
var chatId = message.Chat.Id;
bool isUri = Uri.IsWellFormedUriString(message.ToString(), UriKind.RelativeOrAbsolute);
if (isUri)
{
Regex isTikTok = new Regex(@"(?x)(http(s)?:\/\/)?(?:www|m)\.(?:tiktok.com)\/(?:v|embed|trending)(?:\/)?(?:\?shareId=)?(?P<id>[\da-z]+)", RegexOptions.Singleline);
}
Console.WriteLine($"Received a '{messageText}' message in chat {chatId}.");
// Echo received message text
Message sentMessage = await botClient.SendTextMessageAsync(
chatId: chatId,
text: "You said:\n" + messageText,
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()
};
Console.WriteLine(ErrorMessage);
return Task.CompletedTask;
Console.WriteLine("[" + now.ToString() + "] " + text);
}
}
}

View File

@ -1,5 +1,31 @@
[![Build Status](https://ci.kizaing.ca/api/badges/kizaing/TeleTok/status.svg)](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

View File

@ -10,7 +10,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.2" />
<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>
</Project>

84
TelegramListener.cs Normal file
View 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;
}
}
}

View File

@ -1,10 +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;
}
}
}

View File

@ -1,6 +1,6 @@
{
"TeleTokConf": {
"token": "INSERT TOKEN HERE",
"port": 5000
"proxitokInstance": "PROXITOK INSTANCE URL"
}
}