Merge pull request 'add download feature' (#1) from test into master
Reviewed-on: https://git.owlynights.com/watn3y/bloaterbot/pulls/1
This commit is contained in:
commit
f71d15ac2c
10 changed files with 310 additions and 6 deletions
|
@ -5,7 +5,10 @@ WORKDIR /tmp/build
|
|||
#install update system and install packages
|
||||
RUN apk update
|
||||
RUN apk upgrade --available
|
||||
RUN apk add alpine-sdk
|
||||
RUN apk add alpine-sdk ffmpeg python3 py3-pip
|
||||
|
||||
#install yt-dlp
|
||||
RUN pip3 install yt-dlp
|
||||
|
||||
#build bloaterbot
|
||||
COPY . .
|
||||
|
|
|
@ -5,20 +5,52 @@ import (
|
|||
"log"
|
||||
)
|
||||
|
||||
func SendMessage(message tgbotapi.MessageConfig, bot *tgbotapi.BotAPI) {
|
||||
_, err := bot.Send(message)
|
||||
func SendMessage(message tgbotapi.MessageConfig, bot *tgbotapi.BotAPI) (result tgbotapi.Message) {
|
||||
result, err := bot.Send(message)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send message: %v\n", err)
|
||||
return
|
||||
}
|
||||
log.Printf("[bot] Sent Message: %s", message.Text)
|
||||
return result
|
||||
}
|
||||
|
||||
func SendSticker(sticker tgbotapi.StickerConfig, bot *tgbotapi.BotAPI) {
|
||||
_, err := bot.Send(sticker)
|
||||
func EditMessage(message tgbotapi.EditMessageTextConfig, bot *tgbotapi.BotAPI) (result tgbotapi.Message) {
|
||||
result, err := bot.Send(message)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send message: %v\n", err)
|
||||
return
|
||||
}
|
||||
log.Printf("[bot] Edited Message: %s", message.Text)
|
||||
return result
|
||||
}
|
||||
|
||||
func SendVideo(message tgbotapi.VideoConfig, bot *tgbotapi.BotAPI) (result tgbotapi.Message) {
|
||||
result, err := bot.Send(message)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send message: %v\n", err)
|
||||
return
|
||||
}
|
||||
log.Printf("[bot] Sent Video: %s", message.File)
|
||||
return result
|
||||
}
|
||||
|
||||
func SendPhoto(message tgbotapi.PhotoConfig, bot *tgbotapi.BotAPI) (result tgbotapi.Message) {
|
||||
result, err := bot.Send(message)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send message: %v\n", err)
|
||||
return
|
||||
}
|
||||
log.Printf("[bot] Sent Photo: %s", message.File)
|
||||
return result
|
||||
}
|
||||
|
||||
func SendSticker(sticker tgbotapi.StickerConfig, bot *tgbotapi.BotAPI) (result tgbotapi.Message) {
|
||||
result, err := bot.Send(sticker)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send Sticker: %v\n", err)
|
||||
return
|
||||
}
|
||||
log.Printf("[bot] Sent Sticker")
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
"watn3y/bloaterbotv3/botIO"
|
||||
"watn3y/bloaterbotv3/commands/download"
|
||||
"watn3y/bloaterbotv3/commands/gaypoints"
|
||||
"watn3y/bloaterbotv3/commands/notify"
|
||||
"watn3y/bloaterbotv3/config"
|
||||
|
@ -30,6 +31,10 @@ func Commands(update tgbotapi.Update, bot *tgbotapi.BotAPI) {
|
|||
gaypoints.SetGP(update, bot)
|
||||
case "remindme":
|
||||
notify.Reminder(update, bot)
|
||||
case "download":
|
||||
go download.Download(update, bot)
|
||||
case "dl":
|
||||
go download.Download(update, bot)
|
||||
case "help":
|
||||
help(update, bot)
|
||||
case "info":
|
||||
|
|
221
commands/download/download.go
Normal file
221
commands/download/download.go
Normal file
|
@ -0,0 +1,221 @@
|
|||
package download
|
||||
|
||||
import (
|
||||
"errors"
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"watn3y/bloaterbotv3/botIO"
|
||||
"watn3y/bloaterbotv3/commonlogic"
|
||||
"watn3y/bloaterbotv3/config"
|
||||
)
|
||||
|
||||
func Download(update tgbotapi.Update, bot *tgbotapi.BotAPI) {
|
||||
|
||||
log.Println("[download] Downloading URL " + update.Message.CommandArguments() + " for " + strconv.FormatInt(update.Message.From.ID, 10) + " in chat " + strconv.FormatInt(update.Message.Chat.ID, 10))
|
||||
|
||||
commandArgs := strings.Fields(update.Message.CommandArguments())
|
||||
|
||||
msg := tgbotapi.MessageConfig{
|
||||
BaseChat: tgbotapi.BaseChat{ChatID: update.Message.Chat.ID, ReplyToMessageID: update.Message.MessageID},
|
||||
Text: "Downloading your media...",
|
||||
}
|
||||
workingMessage := botIO.SendMessage(msg, bot)
|
||||
|
||||
if len(commandArgs) >= 1 && matchURL(commandArgs[0]) != "" {
|
||||
//TODO distinguish
|
||||
//service := matchURL(commandArgs[0])
|
||||
} else {
|
||||
log.Println("[download] Failed to download URL " + update.Message.CommandArguments() + " NO URL")
|
||||
message := tgbotapi.EditMessageTextConfig{
|
||||
BaseEdit: tgbotapi.BaseEdit{ChatID: workingMessage.Chat.ID, MessageID: workingMessage.MessageID},
|
||||
Text: "Please specify a valid YouTube URL to download something.",
|
||||
}
|
||||
botIO.EditMessage(message, bot)
|
||||
return
|
||||
}
|
||||
|
||||
downloadTarget := randomString(20)
|
||||
|
||||
downloaded := runYTDL(commandArgs[0], downloadTarget)
|
||||
|
||||
if !downloaded {
|
||||
message := tgbotapi.EditMessageTextConfig{
|
||||
BaseEdit: tgbotapi.BaseEdit{ChatID: workingMessage.Chat.ID, MessageID: workingMessage.MessageID},
|
||||
Text: "Something went wrong while downloading your media :(",
|
||||
}
|
||||
botIO.EditMessage(message, bot)
|
||||
return
|
||||
}
|
||||
|
||||
files, err := os.ReadDir("./videos/" + downloadTarget)
|
||||
|
||||
if err != nil {
|
||||
log.Println("[download] Failed to process URL "+update.Message.CommandArguments(), " FAILED TO READ DIRECTORY: ", err.Error())
|
||||
|
||||
message := tgbotapi.EditMessageTextConfig{
|
||||
BaseEdit: tgbotapi.BaseEdit{ChatID: workingMessage.Chat.ID, MessageID: workingMessage.MessageID},
|
||||
Text: "Something went wrong while downloading your media :(",
|
||||
}
|
||||
botIO.EditMessage(message, bot)
|
||||
return
|
||||
}
|
||||
|
||||
if len(files) > 1 {
|
||||
log.Println("[download] Failed to process URL "+update.Message.CommandArguments(), " TOO MANY FILES")
|
||||
message := tgbotapi.EditMessageTextConfig{
|
||||
BaseEdit: tgbotapi.BaseEdit{ChatID: workingMessage.Chat.ID, MessageID: workingMessage.MessageID},
|
||||
Text: "Something went wrong while downloading your media :(",
|
||||
}
|
||||
botIO.EditMessage(message, bot)
|
||||
return
|
||||
}
|
||||
|
||||
message := tgbotapi.EditMessageTextConfig{
|
||||
BaseEdit: tgbotapi.BaseEdit{ChatID: workingMessage.Chat.ID, MessageID: workingMessage.MessageID},
|
||||
Text: "Downloaded! Uploading now",
|
||||
}
|
||||
botIO.EditMessage(message, bot)
|
||||
|
||||
serveMedia(update, bot, downloadTarget, files[0].Name())
|
||||
log.Println("[download] Served URL " + update.Message.CommandArguments() + " for " + strconv.FormatInt(update.Message.From.ID, 10) + " in chat " + strconv.FormatInt(update.Message.Chat.ID, 10))
|
||||
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
bot.Send(tgbotapi.NewDeleteMessage(workingMessage.Chat.ID, workingMessage.MessageID))
|
||||
|
||||
}
|
||||
|
||||
func randomString(n int) string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var letters = []rune("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
b := make([]rune, n)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func runYTDL(URL string, targetDir string) (success bool) {
|
||||
|
||||
cmd := exec.Command("yt-dlp", "-f", "bv*[ext=mp4]+ba[ext=m4a] / bv*+ba/b", "--no-playlist", "-o", "videos/"+targetDir+"/"+"%(title)s.%(ext)s", "--write-thumbnail", "--convert-thumbnails", "jpg", "-o", "thumbnail:videos/"+targetDir+"thumb"+"/"+"%(title)s.%(ext)s", URL)
|
||||
|
||||
out, err := cmd.CombinedOutput()
|
||||
var (
|
||||
ee *exec.ExitError
|
||||
pe *os.PathError
|
||||
)
|
||||
|
||||
if errors.As(err, &ee) {
|
||||
log.Println("[download.ytdl] Failed to download URL "+URL, " NON ZERO EXIT CODE: ", ee.ExitCode())
|
||||
success = false
|
||||
|
||||
} else if errors.As(err, &pe) {
|
||||
log.Println("[download.ytdl] Failed to download URL "+URL, " OS PATH ERROR: ", pe.Error())
|
||||
success = false
|
||||
|
||||
} else if err != nil {
|
||||
log.Println("[download.ytdl] Failed to download URL "+URL, " GENERAL ERROR: ", err.Error())
|
||||
success = false
|
||||
|
||||
} else {
|
||||
log.Println("[download.ytdl] Downloaded URL " + URL)
|
||||
success = true
|
||||
}
|
||||
|
||||
if config.BotConfig.DebugMode {
|
||||
print(string(out))
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
|
||||
func matchURL(URL string) (matchedURL string) {
|
||||
parsedURL, err := url.Parse(URL)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
}
|
||||
|
||||
var domainRegex = regexp.MustCompile(`(youtube\.com$)|(youtu\.be$)`)
|
||||
|
||||
m := domainRegex.FindStringSubmatch(parsedURL.Hostname())
|
||||
|
||||
if len(m) >= 1 {
|
||||
return m[0]
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func shortURL(URL string) (shorturl string) {
|
||||
resp, err := http.Get(config.BotConfig.Download.Yourls.APIPath + "?signature=" + config.BotConfig.Download.Yourls.Signature + "&action=shorturl&format=simple&url=" + URL)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return string(body)
|
||||
}
|
||||
|
||||
func serveMedia(update tgbotapi.Update, bot *tgbotapi.BotAPI, randomNoise string, file string) {
|
||||
fsPath := "./videos/" + randomNoise + "/" + file
|
||||
fsThumbPath := "./videos/" + randomNoise + "thumb" + "/" + strings.TrimSuffix(file, "mp4") + "jpg"
|
||||
fExt := filepath.Ext(fsPath)
|
||||
|
||||
imageTypes := []string{".jpg", ".jpeg", ".png"}
|
||||
|
||||
shortURL := shortURL(url.PathEscape(config.BotConfig.Download.Prefix + "/" + randomNoise + "/" + url.PathEscape(file)))
|
||||
|
||||
fsPathStat, _ := os.Stat(fsPath)
|
||||
|
||||
if fsPathStat.Size() >= 52428800 {
|
||||
fExt = "thisfuckingshitistoobig"
|
||||
}
|
||||
|
||||
if fExt == ".mp4" {
|
||||
vid := tgbotapi.VideoConfig{
|
||||
BaseFile: tgbotapi.BaseFile{BaseChat: tgbotapi.BaseChat{ChatID: update.Message.Chat.ID, ReplyToMessageID: update.Message.MessageID}, File: tgbotapi.FilePath(fsPath)},
|
||||
Thumb: tgbotapi.FilePath(fsThumbPath),
|
||||
Caption: shortURL,
|
||||
SupportsStreaming: true,
|
||||
}
|
||||
if _, err := os.Stat(fsThumbPath); err != nil {
|
||||
vid.Thumb = nil
|
||||
}
|
||||
botIO.SendVideo(vid, bot)
|
||||
|
||||
} else if commonlogic.ContainsString(imageTypes, fExt) {
|
||||
pic := tgbotapi.PhotoConfig{
|
||||
BaseFile: tgbotapi.BaseFile{BaseChat: tgbotapi.BaseChat{ChatID: update.Message.Chat.ID, ReplyToMessageID: update.Message.MessageID}, File: tgbotapi.FilePath(fsPath)},
|
||||
Caption: shortURL,
|
||||
}
|
||||
botIO.SendPhoto(pic, bot)
|
||||
} else {
|
||||
message := tgbotapi.MessageConfig{
|
||||
BaseChat: tgbotapi.BaseChat{ChatID: update.Message.Chat.ID, ReplyToMessageID: update.Message.MessageID},
|
||||
DisableWebPagePreview: false,
|
||||
ParseMode: "html",
|
||||
Text: shortURL,
|
||||
}
|
||||
botIO.SendMessage(message, bot)
|
||||
}
|
||||
}
|
|
@ -9,3 +9,13 @@ func ContainsInt64(a []int64, b int64) bool {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
func ContainsString(a []string, b string) bool {
|
||||
for _, v := range a {
|
||||
if v == b {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -15,4 +15,11 @@ TriggerWords = ["french","france","baguette","casque bleu"]
|
|||
|
||||
[GayPoints]
|
||||
EnabledChats = [-00000,-111111,-22222]
|
||||
ModifyUsers = [-00000,-111111,-22222]
|
||||
ModifyUsers = [-00000,-111111,-22222]
|
||||
|
||||
[Download]
|
||||
Prefix = "http://192.168.0.10:3556"
|
||||
[Download.Yourls]
|
||||
APIPath = "https://yourl.tld/yourls-api.php"
|
||||
Signature = "u8zibfd876sfvb"
|
||||
|
||||
|
|
|
@ -26,6 +26,13 @@ type config struct {
|
|||
EnabledChats []int64
|
||||
ModifyUsers []int64
|
||||
}
|
||||
Download struct {
|
||||
Prefix string
|
||||
Yourls struct {
|
||||
APIPath string
|
||||
Signature string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var BotConfig config
|
||||
|
|
2
main.go
2
main.go
|
@ -4,12 +4,14 @@ import (
|
|||
"watn3y/bloaterbotv3/commands/gaypoints"
|
||||
"watn3y/bloaterbotv3/commands/notify"
|
||||
"watn3y/bloaterbotv3/config"
|
||||
"watn3y/bloaterbotv3/webserver"
|
||||
)
|
||||
|
||||
func main() {
|
||||
config.LoadConfig()
|
||||
gaypoints.InitDB()
|
||||
notify.InitDB()
|
||||
go webserver.RunWeb()
|
||||
bot()
|
||||
|
||||
}
|
||||
|
|
0
videos/index.html
Normal file
0
videos/index.html
Normal file
17
webserver/webserver.go
Normal file
17
webserver/webserver.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package webserver
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func RunWeb() {
|
||||
fs := http.FileServer(http.Dir("./videos"))
|
||||
http.Handle("/", fs)
|
||||
|
||||
log.Print("Listening on :3556...")
|
||||
err := http.ListenAndServe(":3556", nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue