bloaterbot/commands/download/download.go
watn3y 6375fe5af1 A bunch of Changes
Docker is broken as of now, will fix later
2023-12-29 05:15:23 +01:00

226 lines
6.6 KiB
Go

package download
import (
"errors"
"io"
log2 "log"
"math/rand"
"net/http"
"net/url"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"watn3y.de/bloaterbot/botIO"
"watn3y.de/bloaterbot/commonlogic"
"watn3y.de/bloaterbot/config"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"github.com/rs/zerolog/log"
)
//TODO logging
func Download(update tgbotapi.Update, bot *tgbotapi.BotAPI) {
log.Debug().Int64("chat", update.Message.Chat.ID).Int64("user", update.Message.From.ID).Msg("starting download")
commandArgs := strings.Fields(update.Message.CommandArguments())
msg := tgbotapi.MessageConfig{
BaseChat: tgbotapi.BaseChat{ChatID: update.Message.Chat.ID, ReplyToMessageID: update.Message.MessageID},
Text: "Downloading your YouTube Video...",
}
workingMessage := botIO.SendMessage(msg, bot)
if len(commandArgs) >= 1 && matchURL(commandArgs[0]) != "" {
} else {
log.Error().Int64("chat", update.Message.Chat.ID).Int64("user", update.Message.From.ID).Str("args", update.Message.CommandArguments()).Msg("Failed to download YouTube Video. Empty args")
message := tgbotapi.EditMessageTextConfig{
BaseEdit: tgbotapi.BaseEdit{ChatID: workingMessage.Chat.ID, MessageID: workingMessage.MessageID},
Text: "Please specify a valid YouTube URL.",
}
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("data/videos/" + downloadTarget)
if err != nil {
log.Error().Err(err).Msg("failed to download. unable to read target directory")
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.Error().Err(err).Msg("failed to download. 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())
log2.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(5 * time.Second)
log.Info().Msg("downloaded file")
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", "data/videos/"+targetDir+"/"+"%(title)s.%(ext)s", "--write-thumbnail", "--convert-thumbnails", "jpg", "-o", "thumbnail:data/videos/"+targetDir+"thumb"+"/"+"%(title)s.%(ext)s", URL)
out, err := cmd.CombinedOutput()
var (
ee *exec.ExitError
pe *os.PathError
)
if errors.As(err, &ee) {
log2.Println("[download.ytdl] Failed to download URL "+URL, " NON ZERO EXIT CODE: ", ee.ExitCode())
success = false
} else if errors.As(err, &pe) {
log2.Println("[download.ytdl] Failed to download URL "+URL, " OS PATH ERROR: ", pe.Error())
success = false
} else if err != nil {
log2.Println("[download.ytdl] Failed to download URL "+URL, " GENERAL ERROR: ", err.Error())
success = false
} else {
log2.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 {
log2.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 {
log2.Fatal(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log2.Fatal(err)
}
return string(body)
}
func serveMedia(update tgbotapi.Update, bot *tgbotapi.BotAPI, randomNoise string, file string) {
fsPath := "data/videos/" + randomNoise + "/" + file
fsThumbPath := "data/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)
}
}