diff --git a/database.go b/database.go index e93f93b..d468f5f 100644 --- a/database.go +++ b/database.go @@ -34,7 +34,7 @@ func load() { } for rows.Next() { - var video tele.Video + var video []*tele.Video err = rows.Scan(&filename, &bytes) if err != nil { @@ -87,10 +87,10 @@ func load() { } } -func saveVideo(video *tele.Video) { +func saveVideo(video *[]*tele.Video) { bytes, _ := json.Marshal(video) - _, err := db.Exec("INSERT INTO video (filename, video) VALUES (?, ?)", video.FileName, bytes) + _, err := db.Exec("INSERT INTO video (filename, video) VALUES (?, ?)", (*video)[0].FileName, bytes) if err != nil { lit.Error("Error executing query, %s", err) return diff --git a/events.go b/events.go index dbd416b..54bdab9 100644 --- a/events.go +++ b/events.go @@ -16,9 +16,27 @@ func videoDownload(c tele.Context) error { if filename != "" { if media == Video { - err := c.Reply(cacheVideo[filename], tele.Silent) - if err == nil && !hit { - go saveVideo(cacheVideo[filename]) + if _, ok := cacheVideo[filename]; ok { + videos := *cacheVideo[filename] + album := make(tele.Album, 0, 10) + + for i := 0; i < len(videos); i += 10 { + // Add photos to album + for j := 0; j < 10; j++ { + if i+j < len(videos) { + album = append(album, videos[i+j]) + } + } + + err := c.SendAlbum(album, tele.Silent) + if err != nil { + lit.Error(err.Error()) + } + } + + if !hit { + go saveVideo(cacheVideo[filename]) + } } } else { if _, ok := cacheAlbum[filename]; ok { @@ -96,14 +114,15 @@ func inlineQuery(c tele.Context) error { go saveVideo(cacheVideo[filename]) } - // Create result - results = append(results, &tele.VideoResult{ - Cache: cacheVideo[filename].FileID, - Title: "Send video", - MIME: "video/mp4", - }) + for i, v := range *cacheVideo[filename] { + results = append(results, &tele.VideoResult{ + Cache: v.FileID, + Title: "Send video", + MIME: "video/mp4", + }) - results[0].SetResultID(filename) + results[i].SetResultID(filename) + } } else { if _, ok := cacheAlbum[filename]; ok { photos := *cacheAlbum[filename] diff --git a/main.go b/main.go index c35b8ef..f71c546 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,7 @@ import ( var ( cfg config - cacheVideo map[string]*tele.Video + cacheVideo map[string]*[]*tele.Video cacheAlbum map[string]*[]*tele.Photo cacheAudio map[string]*tele.Audio db *sql.DB @@ -41,7 +41,7 @@ func init() { lit.LogLevel = lit.LogDebug } - cacheVideo = make(map[string]*tele.Video) + cacheVideo = make(map[string]*[]*tele.Video) cacheAlbum = make(map[string]*[]*tele.Photo) cacheAudio = make(map[string]*tele.Audio) diff --git a/structure.go b/structure.go index c7ed0db..7bb4881 100644 --- a/structure.go +++ b/structure.go @@ -26,3 +26,7 @@ type Downloader struct { WatermarkImageList []string `json:"watermark_image_list"` } `json:"image_data"` } + +type ytdlp struct { + Url string `json:"url"` +} diff --git a/utilities.go b/utilities.go index e3f32c0..9b61f5d 100644 --- a/utilities.go +++ b/utilities.go @@ -9,6 +9,7 @@ import ( "net/http" "net/url" "os/exec" + "strconv" "strings" ) @@ -49,27 +50,66 @@ func downloadYtDlp(link string) (string, bool) { filename := idGen(link) + ".mp4" if _, ok := cacheVideo[filename]; !ok { - // Starts yt-dlp with the arguments to select the best audio - ytDlp := exec.Command("yt-dlp", "-f", "bestvideo+bestaudio", "-f", "mp4", "-q", "-a", "-", "--geo-bypass", "-o", "-") - ytDlp.Stdin = strings.NewReader(link) - out, _ := ytDlp.StdoutPipe() - _ = ytDlp.Start() + hit = false - cacheVideo[filename] = &tele.Video{File: tele.FromReader(out), FileName: filename, MIME: "video/mp4"} + // Gets info about songs + info := exec.Command("yt-dlp", "--ignore-errors", "-q", "--no-warnings", "-j", "-a", "-") + info.Stdin = strings.NewReader(link) - go func() { - err := ytDlp.Wait() - if err != nil { - lit.Error(err.Error()) - } - }() + out, err := info.CombinedOutput() + if err != nil { + lit.Error(err.Error()) + return "", hit + } - hit = false + splittedOut := strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") + + // yt-dlp returned nothing + if strings.TrimSpace(splittedOut[0]) == "" { + return "", hit + } + + // If it's only one video, use the usual downloader + if len(splittedOut) < 1 { + cacheVideo[filename] = &[]*tele.Video{downloadSingleVideo(link, filename)} + } else { + var count int + + cacheVideo[filename] = &[]*tele.Video{} + + for _, l := range splittedOut { + var data ytdlp + err := json.Unmarshal([]byte(l), &data) + if err == nil { + // We need to proxy the requests for telegram when downloading + *cacheVideo[filename] = append(*cacheVideo[filename], downloadSingleVideo(data.Url, filename, "--playlist-items", strconv.Itoa(count+1))) + count++ + } + } + } } return filename, hit } +func downloadSingleVideo(link string, filename string, arguments ...string) *tele.Video { + // Starts yt-dlp with the arguments to select the best audio + arguments = append(arguments, "-f", "bestvideo+bestaudio", "-f", "mp4", "-q", "-a", "-", "--geo-bypass", "-o", "-") + ytDlp := exec.Command("yt-dlp", arguments...) + ytDlp.Stdin = strings.NewReader(link) + out, _ := ytDlp.StdoutPipe() + _ = ytDlp.Start() + + go func() { + err := ytDlp.Wait() + if err != nil { + lit.Error(err.Error()) + } + }() + + return &tele.Video{File: tele.FromReader(out), FileName: filename, MIME: "video/mp4"} +} + func downloadAudio(link string) (string, bool) { hit := true @@ -129,7 +169,7 @@ func downloadTikTok(link string) (string, bool, Media) { switch d.Type { case "video": filename += ".mp4" - cacheVideo[filename] = &tele.Video{File: tele.FromURL(d.VideoData.NwmVideoUrlHQ), MIME: "video/mp4", FileName: filename} + cacheVideo[filename] = &[]*tele.Video{{File: tele.FromURL(d.VideoData.NwmVideoUrlHQ), MIME: "video/mp4", FileName: filename}} return filename, false, Video case "image": album := make([]*tele.Photo, len(d.ImageData.NoWatermarkImageList))