Skip to content

Commit

Permalink
feat: download multiple videos from a single link
Browse files Browse the repository at this point in the history
Used for instagram reels with multiple videos
  • Loading branch information
TheTipo01 committed Feb 11, 2024
1 parent ee29902 commit fc379cb
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 29 deletions.
6 changes: 3 additions & 3 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
39 changes: 29 additions & 10 deletions events.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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]
Expand Down
4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)

Expand Down
4 changes: 4 additions & 0 deletions structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ type Downloader struct {
WatermarkImageList []string `json:"watermark_image_list"`
} `json:"image_data"`
}

type ytdlp struct {
Url string `json:"url"`
}
68 changes: 54 additions & 14 deletions utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"net/url"
"os/exec"
"strconv"
"strings"
)

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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))
Expand Down

0 comments on commit fc379cb

Please sign in to comment.