Compare commits
10 Commits
5184d43d78
...
f2c9c4e388
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2c9c4e388 | ||
|
|
f9d5615320 | ||
|
|
a1c66784d2 | ||
|
|
6b67239a90 | ||
|
|
2b3658ceed | ||
|
|
548e7effb7 | ||
|
|
1d75df37cf | ||
|
|
f1724719ec | ||
|
|
540ddc2bad | ||
|
|
d5b81a3b5a |
@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.20 as builder
|
FROM golang:1.22 AS builder
|
||||||
WORKDIR /app/
|
WORKDIR /app/
|
||||||
COPY go.mod go.sum /app/
|
COPY go.mod go.sum /app/
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
@ -6,8 +6,6 @@ COPY . .
|
|||||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v
|
||||||
|
|
||||||
FROM python:alpine
|
FROM python:alpine
|
||||||
RUN wget https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -O /usr/local/bin/yt-dlp && \
|
|
||||||
chmod 755 /usr/local/bin/yt-dlp
|
|
||||||
RUN apk update && apk upgrade && apk add --no-cache ffmpeg
|
RUN apk update && apk upgrade && apk add --no-cache ffmpeg
|
||||||
COPY --from=builder /app/yt-dlp-telegram-bot /app/yt-dlp-telegram-bot
|
COPY --from=builder /app/yt-dlp-telegram-bot /app/yt-dlp-telegram-bot
|
||||||
COPY --from=builder /app/yt-dlp.conf /root/yt-dlp.conf
|
COPY --from=builder /app/yt-dlp.conf /root/yt-dlp.conf
|
||||||
|
|||||||
@ -89,7 +89,8 @@ cookie file.
|
|||||||
|
|
||||||
## Supported commands
|
## Supported commands
|
||||||
|
|
||||||
- `/dlp` - Download
|
- `/dlp` - Download given URL. If the first attribute is "mp3" then only the
|
||||||
|
audio stream will be downloaded and converted (if needed) to 320k MP3
|
||||||
- `/dlpcancel` - Cancel ongoing download
|
- `/dlpcancel` - Cancel ongoing download
|
||||||
|
|
||||||
You don't need to enter the `/dlp` command if you send an URL to the bot using
|
You don't need to enter the `/dlp` command if you send an URL to the bot using
|
||||||
|
|||||||
49
convert.go
49
convert.go
@ -40,6 +40,8 @@ type ffmpegProbeData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Converter struct {
|
type Converter struct {
|
||||||
|
Format string
|
||||||
|
|
||||||
VideoCodecs string
|
VideoCodecs string
|
||||||
VideoConvertNeeded bool
|
VideoConvertNeeded bool
|
||||||
SingleVideoStreamNeeded bool
|
SingleVideoStreamNeeded bool
|
||||||
@ -76,10 +78,19 @@ func (c *Converter) Probe(rr *ReReadCloser) error {
|
|||||||
fmt.Println(" error parsing duration:", err)
|
fmt.Println(" error parsing duration:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compatibleVideoCodecsCopy := compatibleVideoCodecs
|
||||||
|
if c.Format == "mp3" {
|
||||||
|
compatibleVideoCodecsCopy = []string{}
|
||||||
|
}
|
||||||
|
compatibleAudioCodecsCopy := compatibleAudioCodecs
|
||||||
|
if c.Format == "mp3" {
|
||||||
|
compatibleAudioCodecsCopy = []string{"mp3"}
|
||||||
|
}
|
||||||
|
|
||||||
gotVideoStream := false
|
gotVideoStream := false
|
||||||
gotAudioStream := false
|
gotAudioStream := false
|
||||||
for _, stream := range pd.Streams {
|
for _, stream := range pd.Streams {
|
||||||
if stream.CodecType == "video" {
|
if stream.CodecType == "video" && len(compatibleVideoCodecsCopy) > 0 {
|
||||||
if c.VideoCodecs != "" {
|
if c.VideoCodecs != "" {
|
||||||
c.VideoCodecs += ", "
|
c.VideoCodecs += ", "
|
||||||
}
|
}
|
||||||
@ -107,7 +118,7 @@ func (c *Converter) Probe(rr *ReReadCloser) error {
|
|||||||
fmt.Println(" got additional audio stream")
|
fmt.Println(" got additional audio stream")
|
||||||
c.SingleAudioStreamNeeded = true
|
c.SingleAudioStreamNeeded = true
|
||||||
} else if !c.AudioConvertNeeded {
|
} else if !c.AudioConvertNeeded {
|
||||||
if !slices.Contains(compatibleAudioCodecs, stream.CodecName) {
|
if !slices.Contains(compatibleAudioCodecsCopy, stream.CodecName) {
|
||||||
fmt.Println(" found not compatible audio codec:", stream.CodecName)
|
fmt.Println(" found not compatible audio codec:", stream.CodecName)
|
||||||
c.AudioConvertNeeded = true
|
c.AudioConvertNeeded = true
|
||||||
} else {
|
} else {
|
||||||
@ -118,7 +129,7 @@ func (c *Converter) Probe(rr *ReReadCloser) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !gotVideoStream {
|
if len(compatibleVideoCodecsCopy) > 0 && !gotVideoStream {
|
||||||
return fmt.Errorf("no video stream found in file")
|
return fmt.Errorf("no video stream found in file")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,33 +192,55 @@ func (c *Converter) GetActionsNeeded() string {
|
|||||||
return strings.Join(convertNeeded, ", ")
|
return strings.Join(convertNeeded, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Converter) ConvertIfNeeded(ctx context.Context, rr *ReReadCloser) (io.ReadCloser, error) {
|
func (c *Converter) ConvertIfNeeded(ctx context.Context, rr *ReReadCloser) (reader io.ReadCloser, outputFormat string, err error) {
|
||||||
reader, writer := io.Pipe()
|
reader, writer := io.Pipe()
|
||||||
var cmd *Cmd
|
var cmd *Cmd
|
||||||
|
|
||||||
fmt.Print(" converting ", c.GetActionsNeeded(), "...\n")
|
fmt.Print(" converting ", c.GetActionsNeeded(), "...\n")
|
||||||
|
|
||||||
args := ffmpeg_go.KwArgs{"format": "mp4", "movflags": "frag_keyframe+empty_moov+faststart"}
|
videoNeeded := true
|
||||||
|
outputFormat = "mp4"
|
||||||
|
if c.Format == "mp3" {
|
||||||
|
videoNeeded = false
|
||||||
|
outputFormat = "mp3"
|
||||||
|
}
|
||||||
|
|
||||||
|
args := ffmpeg_go.KwArgs{"format": outputFormat}
|
||||||
|
|
||||||
|
if videoNeeded {
|
||||||
|
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"movflags": "frag_keyframe+empty_moov+faststart"}})
|
||||||
|
|
||||||
if c.VideoConvertNeeded {
|
if c.VideoConvertNeeded {
|
||||||
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"c:v": "libx264", "crf": 30, "preset": "veryfast"}})
|
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"c:v": "libx264", "crf": 30, "preset": "veryfast"}})
|
||||||
} else {
|
} else {
|
||||||
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"c:v": "copy"}})
|
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"c:v": "copy"}})
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"vn": ""}})
|
||||||
|
}
|
||||||
|
|
||||||
if c.AudioConvertNeeded {
|
if c.AudioConvertNeeded {
|
||||||
|
if c.Format == "mp3" {
|
||||||
|
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"c:a": "mp3", "b:a": "320k"}})
|
||||||
|
} else {
|
||||||
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"c:a": "mp3", "q:a": 0}})
|
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"c:a": "mp3", "q:a": 0}})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"c:a": "copy"}})
|
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"c:a": "copy"}})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if videoNeeded {
|
||||||
if c.SingleVideoStreamNeeded || c.SingleAudioStreamNeeded {
|
if c.SingleVideoStreamNeeded || c.SingleAudioStreamNeeded {
|
||||||
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"map": "0:v:0,0:a:0"}})
|
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"map": "0:v:0,0:a:0"}})
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if c.SingleAudioStreamNeeded {
|
||||||
|
args = ffmpeg_go.MergeKwArgs([]ffmpeg_go.KwArgs{args, {"map": "0:a:0"}})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ff := ffmpeg_go.Input("pipe:0").Output("pipe:1", args)
|
ff := ffmpeg_go.Input("pipe:0").Output("pipe:1", args)
|
||||||
|
|
||||||
var err error
|
|
||||||
var progressSock net.Listener
|
var progressSock net.Listener
|
||||||
if c.UpdateProgressPercentCallback != nil {
|
if c.UpdateProgressPercentCallback != nil {
|
||||||
if c.Duration > 0 {
|
if c.Duration > 0 {
|
||||||
@ -239,8 +272,8 @@ func (c *Converter) ConvertIfNeeded(ctx context.Context, rr *ReReadCloser) (io.R
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writer.Close()
|
writer.Close()
|
||||||
return nil, fmt.Errorf("error converting: %w", err)
|
return nil, outputFormat, fmt.Errorf("error converting: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return reader, nil
|
return reader, outputFormat, nil
|
||||||
}
|
}
|
||||||
|
|||||||
23
dl.go
23
dl.go
@ -26,7 +26,7 @@ func (l goYouTubeDLLogger) Print(v ...interface{}) {
|
|||||||
fmt.Println(v...)
|
fmt.Println(v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) downloadURL(dlCtx context.Context, url string) (rr *ReReadCloser, err error) {
|
func (d *Downloader) downloadURL(dlCtx context.Context, url string) (rr *ReReadCloser, title string, err error) {
|
||||||
result, err := goutubedl.New(dlCtx, url, goutubedl.Options{
|
result, err := goutubedl.New(dlCtx, url, goutubedl.Options{
|
||||||
Type: goutubedl.TypeSingle,
|
Type: goutubedl.TypeSingle,
|
||||||
DebugLog: goYouTubeDLLogger{},
|
DebugLog: goYouTubeDLLogger{},
|
||||||
@ -35,39 +35,40 @@ func (d *Downloader) downloadURL(dlCtx context.Context, url string) (rr *ReReadC
|
|||||||
SortingFormat: "res:720", // Prefer videos no larger than 720p to keep their size small.
|
SortingFormat: "res:720", // Prefer videos no larger than 720p to keep their size small.
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("preparing download %q: %w", url, err)
|
return nil, "", fmt.Errorf("preparing download %q: %w", url, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dlResult, err := result.Download(dlCtx, "")
|
dlResult, err := result.Download(dlCtx, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("downloading %q: %w", url, err)
|
return nil, "", fmt.Errorf("downloading %q: %w", url, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewReReadCloser(dlResult), nil
|
return NewReReadCloser(dlResult), result.Info.Title, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) DownloadAndConvertURL(ctx context.Context, url string) (r io.ReadCloser, err error) {
|
func (d *Downloader) DownloadAndConvertURL(ctx context.Context, url, format string) (r io.ReadCloser, outputFormat, title string, err error) {
|
||||||
rr, err := d.downloadURL(ctx, url)
|
rr, title, err := d.downloadURL(ctx, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
conv := Converter{
|
conv := Converter{
|
||||||
|
Format: format,
|
||||||
UpdateProgressPercentCallback: d.UpdateProgressPercentFunc,
|
UpdateProgressPercentCallback: d.UpdateProgressPercentFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := conv.Probe(rr); err != nil {
|
if err := conv.Probe(rr); err != nil {
|
||||||
return nil, err
|
return nil, "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.ConvertStartFunc != nil {
|
if d.ConvertStartFunc != nil {
|
||||||
d.ConvertStartFunc(ctx, conv.VideoCodecs, conv.AudioCodecs, conv.GetActionsNeeded())
|
d.ConvertStartFunc(ctx, conv.VideoCodecs, conv.AudioCodecs, conv.GetActionsNeeded())
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err = conv.ConvertIfNeeded(ctx, rr)
|
r, outputFormat, err = conv.ConvertIfNeeded(ctx, rr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return r, nil
|
return r, outputFormat, title, nil
|
||||||
}
|
}
|
||||||
|
|||||||
5
go.mod
5
go.mod
@ -1,13 +1,14 @@
|
|||||||
module github.com/nonoo/yt-dlp-telegram-bot
|
module github.com/nonoo/yt-dlp-telegram-bot
|
||||||
|
|
||||||
go 1.20
|
go 1.22
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dustin/go-humanize v1.0.1
|
github.com/dustin/go-humanize v1.0.1
|
||||||
|
github.com/flytam/filenamify v1.2.0
|
||||||
github.com/google/go-github/v53 v53.2.0
|
github.com/google/go-github/v53 v53.2.0
|
||||||
github.com/gotd/td v0.84.0
|
github.com/gotd/td v0.84.0
|
||||||
github.com/u2takey/ffmpeg-go v0.5.0
|
github.com/u2takey/ffmpeg-go v0.5.0
|
||||||
github.com/wader/goutubedl v0.0.0-20230815212531-02ec4fe77de3
|
github.com/wader/goutubedl v0.0.0-20240626070646-8cef76d0c092
|
||||||
golang.org/x/exp v0.0.0-20230116083435-1de6713980de
|
golang.org/x/exp v0.0.0-20230116083435-1de6713980de
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
15
go.sum
15
go.sum
@ -3,6 +3,7 @@ github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0g
|
|||||||
github.com/aws/aws-sdk-go v1.38.20 h1:QbzNx/tdfATbdKfubBpkt84OM6oBkxQZRw6+bW2GyeA=
|
github.com/aws/aws-sdk-go v1.38.20 h1:QbzNx/tdfATbdKfubBpkt84OM6oBkxQZRw6+bW2GyeA=
|
||||||
github.com/aws/aws-sdk-go v1.38.20/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
github.com/aws/aws-sdk-go v1.38.20/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||||
|
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
@ -15,6 +16,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
|
github.com/flytam/filenamify v1.2.0 h1:7RiSqXYR4cJftDQ5NuvljKMfd/ubKnW/j9C6iekChgI=
|
||||||
|
github.com/flytam/filenamify v1.2.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
|
||||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
@ -54,6 +57,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI=
|
github.com/google/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI=
|
||||||
github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao=
|
github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao=
|
||||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
@ -76,6 +80,7 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC
|
|||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
@ -85,6 +90,7 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
|||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@ -104,6 +110,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
|||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/u2takey/ffmpeg-go v0.5.0 h1:r7d86XuL7uLWJ5mzSeQ03uvjfIhiJYvsRAJFCW4uklU=
|
github.com/u2takey/ffmpeg-go v0.5.0 h1:r7d86XuL7uLWJ5mzSeQ03uvjfIhiJYvsRAJFCW4uklU=
|
||||||
github.com/u2takey/ffmpeg-go v0.5.0/go.mod h1:ruZWkvC1FEiUNjmROowOAps3ZcWxEiOpFoHCvk97kGc=
|
github.com/u2takey/ffmpeg-go v0.5.0/go.mod h1:ruZWkvC1FEiUNjmROowOAps3ZcWxEiOpFoHCvk97kGc=
|
||||||
github.com/u2takey/go-utils v0.3.1 h1:TaQTgmEZZeDHQFYfd+AdUT1cT4QJgJn/XVPELhHw4ys=
|
github.com/u2takey/go-utils v0.3.1 h1:TaQTgmEZZeDHQFYfd+AdUT1cT4QJgJn/XVPELhHw4ys=
|
||||||
@ -112,8 +119,8 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
|||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/wader/goutubedl v0.0.0-20230815212531-02ec4fe77de3 h1:JS151H65F6dF4KYtSSo2PRj7s4Gb+YhOz40e24zO/e8=
|
github.com/wader/goutubedl v0.0.0-20240626070646-8cef76d0c092 h1:BQ+eGEAUeSzrXx3ruK+pLM50FczmxhhtdA1UNYWRioQ=
|
||||||
github.com/wader/goutubedl v0.0.0-20230815212531-02ec4fe77de3/go.mod h1:5KXd5tImdbmz4JoVhePtbIokCwAfEhUVVx3WLHmjYuw=
|
github.com/wader/goutubedl v0.0.0-20240626070646-8cef76d0c092/go.mod h1:5KXd5tImdbmz4JoVhePtbIokCwAfEhUVVx3WLHmjYuw=
|
||||||
github.com/wader/osleaktest v0.0.0-20191111175233-f643b0fed071 h1:QkrG4Zr5OVFuC9aaMPmFI0ibfhBZlAgtzDYWfu7tqQk=
|
github.com/wader/osleaktest v0.0.0-20191111175233-f643b0fed071 h1:QkrG4Zr5OVFuC9aaMPmFI0ibfhBZlAgtzDYWfu7tqQk=
|
||||||
github.com/wader/osleaktest v0.0.0-20191111175233-f643b0fed071/go.mod h1:XD6emOFPHVzb0+qQpiNOdPL2XZ0SRUM0N5JHuq6OmXo=
|
github.com/wader/osleaktest v0.0.0-20191111175233-f643b0fed071/go.mod h1:XD6emOFPHVzb0+qQpiNOdPL2XZ0SRUM0N5JHuq6OmXo=
|
||||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||||
@ -123,6 +130,7 @@ go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLk
|
|||||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||||
|
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
|
go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
|
||||||
@ -162,6 +170,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||||
|
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@ -178,7 +187,9 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
|
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
|
||||||
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||||
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
|
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
|
||||||
|
|||||||
49
main.go
49
main.go
@ -6,6 +6,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ import (
|
|||||||
"github.com/gotd/td/telegram/message"
|
"github.com/gotd/td/telegram/message"
|
||||||
"github.com/gotd/td/telegram/uploader"
|
"github.com/gotd/td/telegram/uploader"
|
||||||
"github.com/gotd/td/tg"
|
"github.com/gotd/td/tg"
|
||||||
|
"github.com/wader/goutubedl"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,6 +24,13 @@ var telegramUploader *uploader.Uploader
|
|||||||
var telegramSender *message.Sender
|
var telegramSender *message.Sender
|
||||||
|
|
||||||
func handleCmdDLP(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage, msg *tg.Message) {
|
func handleCmdDLP(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage, msg *tg.Message) {
|
||||||
|
format := "video"
|
||||||
|
s := strings.Split(msg.Message, " ")
|
||||||
|
if len(s) >= 2 && s[0] == "mp3" {
|
||||||
|
msg.Message = strings.Join(s[1:], " ")
|
||||||
|
format = "mp3"
|
||||||
|
}
|
||||||
|
|
||||||
// Check if message is an URL.
|
// Check if message is an URL.
|
||||||
validURI := true
|
validURI := true
|
||||||
uri, err := url.ParseRequestURI(msg.Message)
|
uri, err := url.ParseRequestURI(msg.Message)
|
||||||
@ -39,7 +48,7 @@ func handleCmdDLP(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMess
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dlQueue.Add(ctx, entities, u, msg.Message)
|
dlQueue.Add(ctx, entities, u, msg.Message, format)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleCmdDLPCancel(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage, msg *tg.Message) {
|
func handleCmdDLPCancel(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage, msg *tg.Message) {
|
||||||
@ -77,20 +86,21 @@ func handleMsg(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if message is a command.
|
// Check if message is a command.
|
||||||
if msg.Message[0] == '/' {
|
if msg.Message[0] == '/' || msg.Message[0] == '!' {
|
||||||
cmd := strings.Split(msg.Message, " ")[0]
|
cmd := strings.Split(msg.Message, " ")[0]
|
||||||
|
msg.Message = strings.TrimPrefix(msg.Message, cmd+" ")
|
||||||
if strings.Contains(cmd, "@") {
|
if strings.Contains(cmd, "@") {
|
||||||
cmd = strings.Split(cmd, "@")[0]
|
cmd = strings.Split(cmd, "@")[0]
|
||||||
}
|
}
|
||||||
msg.Message = strings.TrimPrefix(msg.Message, cmd+" ")
|
cmd = cmd[1:] // Cutting the command character.
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case "/dlp":
|
case "dlp":
|
||||||
handleCmdDLP(ctx, entities, u, msg)
|
handleCmdDLP(ctx, entities, u, msg)
|
||||||
return nil
|
return nil
|
||||||
case "/dlpcancel":
|
case "dlpcancel":
|
||||||
handleCmdDLPCancel(ctx, entities, u, msg)
|
handleCmdDLPCancel(ctx, entities, u, msg)
|
||||||
return nil
|
return nil
|
||||||
case "/start":
|
case "start":
|
||||||
fmt.Println(" (start cmd)")
|
fmt.Println(" (start cmd)")
|
||||||
if fromGroup == nil {
|
if fromGroup == nil {
|
||||||
_, _ = telegramSender.Reply(entities, u).Text(ctx, "🤖 Welcome! This bot downloads videos from various "+
|
_, _ = telegramSender.Reply(entities, u).Text(ctx, "🤖 Welcome! This bot downloads videos from various "+
|
||||||
@ -152,20 +162,43 @@ func main() {
|
|||||||
telegramUploader = uploader.NewUploader(api).WithProgress(dlUploader)
|
telegramUploader = uploader.NewUploader(api).WithProgress(dlUploader)
|
||||||
telegramSender = message.NewSender(api).WithUploader(telegramUploader)
|
telegramSender = message.NewSender(api).WithUploader(telegramUploader)
|
||||||
|
|
||||||
|
goutubedl.Path, err = exec.LookPath(goutubedl.Path)
|
||||||
|
if err != nil {
|
||||||
|
goutubedl.Path, err = ytdlpDownloadLatest(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprint("error: ", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dlQueue.Init(ctx)
|
dlQueue.Init(ctx)
|
||||||
|
|
||||||
dispatcher.OnNewMessage(handleMsg)
|
dispatcher.OnNewMessage(handleMsg)
|
||||||
|
|
||||||
fmt.Println("telegram connection up")
|
fmt.Println("telegram connection up")
|
||||||
|
|
||||||
ytdlpVersionCheckStr, _ := ytdlpVersionCheckGetStr(ctx)
|
ytdlpVersionCheckStr, updateNeeded, _ := ytdlpVersionCheckGetStr(ctx)
|
||||||
|
if updateNeeded {
|
||||||
|
goutubedl.Path, err = ytdlpDownloadLatest(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprint("error: ", err))
|
||||||
|
}
|
||||||
|
ytdlpVersionCheckStr, _, _ = ytdlpVersionCheckGetStr(ctx)
|
||||||
|
}
|
||||||
sendTextToAdmins(ctx, "🤖 Bot started, "+ytdlpVersionCheckStr)
|
sendTextToAdmins(ctx, "🤖 Bot started, "+ytdlpVersionCheckStr)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
time.Sleep(24 * time.Hour)
|
time.Sleep(24 * time.Hour)
|
||||||
if s, updateNeededOrError := ytdlpVersionCheckGetStr(ctx); updateNeededOrError {
|
s, updateNeeded, gotError := ytdlpVersionCheckGetStr(ctx)
|
||||||
|
if gotError {
|
||||||
sendTextToAdmins(ctx, s)
|
sendTextToAdmins(ctx, s)
|
||||||
|
} else if updateNeeded {
|
||||||
|
goutubedl.Path, err = ytdlpDownloadLatest(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprint("error: ", err))
|
||||||
|
}
|
||||||
|
ytdlpVersionCheckStr, _, _ = ytdlpVersionCheckGetStr(ctx)
|
||||||
|
sendTextToAdmins(ctx, "🤖 Bot updated, "+ytdlpVersionCheckStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -79,10 +78,6 @@ func (p *paramsType) Init() error {
|
|||||||
if goutubedl.Path == "" {
|
if goutubedl.Path == "" {
|
||||||
goutubedl.Path = "yt-dlp"
|
goutubedl.Path = "yt-dlp"
|
||||||
}
|
}
|
||||||
goutubedl.Path, err = exec.LookPath(goutubedl.Path)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("yt-dlp not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
if allowedUserIDs == "" {
|
if allowedUserIDs == "" {
|
||||||
allowedUserIDs = os.Getenv("ALLOWED_USERIDS")
|
allowedUserIDs = os.Getenv("ALLOWED_USERIDS")
|
||||||
|
|||||||
13
queue.go
13
queue.go
@ -22,6 +22,7 @@ const progressBarLength = 10
|
|||||||
|
|
||||||
type DownloadQueueEntry struct {
|
type DownloadQueueEntry struct {
|
||||||
URL string
|
URL string
|
||||||
|
Format string
|
||||||
|
|
||||||
OrigEntities tg.Entities
|
OrigEntities tg.Entities
|
||||||
OrigMsgUpdate *tg.UpdateNewMessage
|
OrigMsgUpdate *tg.UpdateNewMessage
|
||||||
@ -87,7 +88,7 @@ func (e *DownloadQueue) getQueuePositionString(pos int) string {
|
|||||||
return "👨👦👦 Request queued at position #" + fmt.Sprint(pos)
|
return "👨👦👦 Request queued at position #" + fmt.Sprint(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *DownloadQueue) Add(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage, url string) {
|
func (q *DownloadQueue) Add(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage, url, format string) {
|
||||||
q.mutex.Lock()
|
q.mutex.Lock()
|
||||||
|
|
||||||
var replyStr string
|
var replyStr string
|
||||||
@ -100,6 +101,7 @@ func (q *DownloadQueue) Add(ctx context.Context, entities tg.Entities, u *tg.Upd
|
|||||||
|
|
||||||
newEntry := DownloadQueueEntry{
|
newEntry := DownloadQueueEntry{
|
||||||
URL: url,
|
URL: url,
|
||||||
|
Format: format,
|
||||||
OrigEntities: entities,
|
OrigEntities: entities,
|
||||||
OrigMsgUpdate: u,
|
OrigMsgUpdate: u,
|
||||||
OrigMsg: u.Message.(*tg.Message),
|
OrigMsg: u.Message.(*tg.Message),
|
||||||
@ -200,7 +202,10 @@ func (q *DownloadQueue) processQueueEntry(ctx context.Context, qEntry *DownloadQ
|
|||||||
if audioCodecs == "" {
|
if audioCodecs == "" {
|
||||||
q.currentlyDownloadedEntry.sourceCodecInfo += ", no audio"
|
q.currentlyDownloadedEntry.sourceCodecInfo += ", no audio"
|
||||||
} else {
|
} else {
|
||||||
q.currentlyDownloadedEntry.sourceCodecInfo += " / " + audioCodecs
|
if videoCodecs != "" {
|
||||||
|
q.currentlyDownloadedEntry.sourceCodecInfo += " / "
|
||||||
|
}
|
||||||
|
q.currentlyDownloadedEntry.sourceCodecInfo += audioCodecs
|
||||||
}
|
}
|
||||||
if convertActionsNeeded == "" {
|
if convertActionsNeeded == "" {
|
||||||
q.currentlyDownloadedEntry.sourceCodecInfo += " (no conversion needed)"
|
q.currentlyDownloadedEntry.sourceCodecInfo += " (no conversion needed)"
|
||||||
@ -212,7 +217,7 @@ func (q *DownloadQueue) processQueueEntry(ctx context.Context, qEntry *DownloadQ
|
|||||||
UpdateProgressPercentFunc: q.HandleProgressPercentUpdate,
|
UpdateProgressPercentFunc: q.HandleProgressPercentUpdate,
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := downloader.DownloadAndConvertURL(qEntry.Ctx, qEntry.OrigMsg.Message)
|
r, outputFormat, title, err := downloader.DownloadAndConvertURL(qEntry.Ctx, qEntry.OrigMsg.Message, qEntry.Format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(" error downloading:", err)
|
fmt.Println(" error downloading:", err)
|
||||||
q.currentlyDownloadedEntry.progressPercentUpdateMutex.Lock()
|
q.currentlyDownloadedEntry.progressPercentUpdateMutex.Lock()
|
||||||
@ -228,7 +233,7 @@ func (q *DownloadQueue) processQueueEntry(ctx context.Context, qEntry *DownloadQ
|
|||||||
q.updateProgress(ctx, qEntry, processStr, q.currentlyDownloadedEntry.lastProgressPercent)
|
q.updateProgress(ctx, qEntry, processStr, q.currentlyDownloadedEntry.lastProgressPercent)
|
||||||
q.currentlyDownloadedEntry.progressPercentUpdateMutex.Unlock()
|
q.currentlyDownloadedEntry.progressPercentUpdateMutex.Unlock()
|
||||||
|
|
||||||
err = dlUploader.UploadFile(qEntry.Ctx, qEntry.OrigEntities, qEntry.OrigMsgUpdate, r)
|
err = dlUploader.UploadFile(qEntry.Ctx, qEntry.OrigEntities, qEntry.OrigMsgUpdate, r, outputFormat, title)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(" error processing:", err)
|
fmt.Println(" error processing:", err)
|
||||||
q.currentlyDownloadedEntry.progressPercentUpdateMutex.Lock()
|
q.currentlyDownloadedEntry.progressPercentUpdateMutex.Lock()
|
||||||
|
|||||||
1
run.sh
1
run.sh
@ -14,4 +14,5 @@ ALLOWED_USERIDS=$ALLOWED_USERIDS \
|
|||||||
ADMIN_USERIDS=$ADMIN_USERIDS \
|
ADMIN_USERIDS=$ADMIN_USERIDS \
|
||||||
ALLOWED_GROUPIDS=$ALLOWED_GROUPIDS \
|
ALLOWED_GROUPIDS=$ALLOWED_GROUPIDS \
|
||||||
MAX_SIZE=$MAX_SIZE \
|
MAX_SIZE=$MAX_SIZE \
|
||||||
|
YTDLP_PATH=$YTDLP_PATH \
|
||||||
$bin
|
$bin
|
||||||
|
|||||||
11
upload.go
11
upload.go
@ -8,6 +8,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
|
"github.com/flytam/filenamify"
|
||||||
"github.com/gotd/td/telegram/message"
|
"github.com/gotd/td/telegram/message"
|
||||||
"github.com/gotd/td/telegram/uploader"
|
"github.com/gotd/td/telegram/uploader"
|
||||||
"github.com/gotd/td/tg"
|
"github.com/gotd/td/tg"
|
||||||
@ -22,7 +23,7 @@ func (p Uploader) Chunk(ctx context.Context, state uploader.ProgressState) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Uploader) UploadFile(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage, f io.ReadCloser) error {
|
func (p *Uploader) UploadFile(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage, f io.ReadCloser, format, title string) error {
|
||||||
// Reading to a buffer first, because we don't know the file size.
|
// Reading to a buffer first, because we don't know the file size.
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
for {
|
for {
|
||||||
@ -49,7 +50,13 @@ func (p *Uploader) UploadFile(ctx context.Context, entities tg.Entities, u *tg.U
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now we have uploaded file handle, sending it as styled message. First, preparing message.
|
// Now we have uploaded file handle, sending it as styled message. First, preparing message.
|
||||||
document := message.UploadedDocument(upload).Video()
|
var document message.MediaOption
|
||||||
|
filename, _ := filenamify.Filenamify(title+"."+format, filenamify.Options{Replacement: " "})
|
||||||
|
if format == "mp3" {
|
||||||
|
document = message.UploadedDocument(upload).Filename(filename).Audio().Title(title)
|
||||||
|
} else {
|
||||||
|
document = message.UploadedDocument(upload).Filename(filename).Video()
|
||||||
|
}
|
||||||
|
|
||||||
// Sending message with media.
|
// Sending message with media.
|
||||||
if _, err := telegramSender.Answer(entities, u).Media(ctx, document); err != nil {
|
if _, err := telegramSender.Answer(entities, u).Media(ctx, document); err != nil {
|
||||||
|
|||||||
107
vercheck.go
107
vercheck.go
@ -2,7 +2,12 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-github/v53/github"
|
"github.com/google/go-github/v53/github"
|
||||||
@ -11,12 +16,100 @@ import (
|
|||||||
|
|
||||||
const ytdlpVersionCheckTimeout = time.Second * 10
|
const ytdlpVersionCheckTimeout = time.Second * 10
|
||||||
|
|
||||||
func ytdlpVersionCheck(ctx context.Context) (latestVersion, currentVersion string, err error) {
|
func ytdlpGetLatestRelease(ctx context.Context) (release *github.RepositoryRelease, err error) {
|
||||||
client := github.NewClient(nil)
|
client := github.NewClient(nil)
|
||||||
|
|
||||||
release, _, err := client.Repositories.GetLatestRelease(ctx, "yt-dlp", "yt-dlp")
|
release, _, err = client.Repositories.GetLatestRelease(ctx, "yt-dlp", "yt-dlp")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", fmt.Errorf("getting latest yt-dlp version: %w", err)
|
return nil, fmt.Errorf("getting latest yt-dlp version: %w", err)
|
||||||
|
}
|
||||||
|
return release, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ytdlpGithubReleaseAsset struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
URL string `json:"browser_download_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ytdlpGetLatestReleaseURL(ctx context.Context) (url string, err error) {
|
||||||
|
release, err := ytdlpGetLatestRelease(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
assetsURL := release.GetAssetsURL()
|
||||||
|
if assetsURL == "" {
|
||||||
|
return "", fmt.Errorf("downloading latest yt-dlp: no assets url")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Get(assetsURL)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("downloading latest yt-dlp: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("downloading latest yt-dlp: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var assets []ytdlpGithubReleaseAsset
|
||||||
|
err = json.Unmarshal(body, &assets)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("downloading latest yt-dlp: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(assets) == 0 {
|
||||||
|
return "", fmt.Errorf("downloading latest yt-dlp: no release assets")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, asset := range assets {
|
||||||
|
if asset.Name == "yt-dlp" {
|
||||||
|
url = asset.URL
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if url == "" {
|
||||||
|
return "", fmt.Errorf("downloading latest yt-dlp: no release asset url")
|
||||||
|
}
|
||||||
|
return url, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ytdlpDownloadLatest(ctx context.Context) (path string, err error) {
|
||||||
|
url, err := ytdlpGetLatestReleaseURL(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("downloading latest yt-dlp: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
file, err := os.Create(filepath.Join(os.TempDir(), "yt-dlp"))
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("downloading latest yt-dlp: %w", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(file, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Chmod(file.Name(), 0755)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return file.Name(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ytdlpVersionCheck(ctx context.Context) (latestVersion, currentVersion string, err error) {
|
||||||
|
release, err := ytdlpGetLatestRelease(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
}
|
}
|
||||||
latestVersion = release.GetTagName()
|
latestVersion = release.GetTagName()
|
||||||
|
|
||||||
@ -27,19 +120,19 @@ func ytdlpVersionCheck(ctx context.Context) (latestVersion, currentVersion strin
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ytdlpVersionCheckGetStr(ctx context.Context) (res string, updateNeededOrError bool) {
|
func ytdlpVersionCheckGetStr(ctx context.Context) (res string, updateNeeded, gotError bool) {
|
||||||
verCheckCtx, verCheckCtxCancel := context.WithTimeout(ctx, ytdlpVersionCheckTimeout)
|
verCheckCtx, verCheckCtxCancel := context.WithTimeout(ctx, ytdlpVersionCheckTimeout)
|
||||||
defer verCheckCtxCancel()
|
defer verCheckCtxCancel()
|
||||||
|
|
||||||
var latestVersion, currentVersion string
|
var latestVersion, currentVersion string
|
||||||
var err error
|
var err error
|
||||||
if latestVersion, currentVersion, err = ytdlpVersionCheck(verCheckCtx); err != nil {
|
if latestVersion, currentVersion, err = ytdlpVersionCheck(verCheckCtx); err != nil {
|
||||||
return errorStr + ": " + err.Error(), true
|
return errorStr + ": " + err.Error(), false, true
|
||||||
}
|
}
|
||||||
|
|
||||||
updateNeededOrError = currentVersion != latestVersion
|
updateNeeded = currentVersion != latestVersion
|
||||||
res = "yt-dlp version: " + currentVersion
|
res = "yt-dlp version: " + currentVersion
|
||||||
if updateNeededOrError {
|
if updateNeeded {
|
||||||
res = "📢 " + res + " 📢 Update needed! Latest version is " + latestVersion + " 📢"
|
res = "📢 " + res + " 📢 Update needed! Latest version is " + latestVersion + " 📢"
|
||||||
} else {
|
} else {
|
||||||
res += " (up to date)"
|
res += " (up to date)"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user