Skip to content

Commit

Permalink
FfmpegTranscode
Browse files Browse the repository at this point in the history
  • Loading branch information
shoce committed Nov 4, 2024
1 parent c7b1699 commit b8cdbb6
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 121 deletions.
27 changes: 14 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@

# https://hub.docker.com/_/golang/tags
FROM golang:1.23.2 AS build
ARG TARGETARCH

RUN apt update
RUN apt -y -q install xz-utils

RUN mkdir -p /root/ffmpeg/
WORKDIR /root/ffmpeg/
RUN curl -s -S -L -O https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-$TARGETARCH-static.tar.xz
RUN tar -x -J -f ffmpeg-release-$TARGETARCH-static.tar.xz
RUN mv ffmpeg-*-static/ffmpeg ffmpeg
RUN ls -l -a
RUN ./ffmpeg -version
#ARG TARGETARCH
#
#RUN apt update
#RUN apt -y -q install xz-utils
#
#RUN mkdir -p /root/ffmpeg/
#WORKDIR /root/ffmpeg/
#RUN curl -s -S -L -O https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-$TARGETARCH-static.tar.xz
#RUN tar -x -J -f ffmpeg-release-$TARGETARCH-static.tar.xz
#RUN mv ffmpeg-*-static/ffmpeg ffmpeg
#RUN ls -l -a
#RUN ./ffmpeg -version

RUN mkdir -p /root/tgzebot/
WORKDIR /root/tgzebot/
Expand All @@ -30,8 +31,8 @@ FROM alpine:3.20.3
RUN apk add --no-cache tzdata
RUN apk add --no-cache gcompat && ln -s -f -v ld-linux-x86-64.so.2 /lib/libresolv.so.2

COPY --from=build /root/ffmpeg/ffmpeg /root/tgzebot/tgzebot /bin/
RUN ls -l -a /bin/ffmpeg /bin/tgzebot
#COPY --from=build /root/ffmpeg/ffmpeg /bin/
COPY --from=build /root/tgzebot/tgzebot /bin/

WORKDIR /root/
ENTRYPOINT ["/bin/tgzebot"]
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ require (
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd // indirect
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
github.com/google/pprof v0.0.0-20241023014458-598669927662 // indirect
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 // indirect
golang.org/x/text v0.19.0 // indirect
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd h1:QMSNEh9uQkDjyPwu/J5
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q=
github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsPdLHF5dNyxq3jOWwu9w9UyH5vA=
github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 h1:sAGdeJj0bnMgUNVeUpp6AYlVdCt3/GdI3pGRqsNSQLs=
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/kkdai/youtube/v2 v2.10.2-0.20240422131028-23aa415a6747 h1:GZ9tzPREMEMR574FluoxNFx9PKaF3KS/vBGzLg4NdIU=
github.com/kkdai/youtube/v2 v2.10.2-0.20240422131028-23aa415a6747/go.mod h1:qL8JZv7Q1IoDs4nnaL51o/hmITXEIvyCIXopB0oqgVM=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
Expand Down
196 changes: 91 additions & 105 deletions tgzebot.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
https://pkg.go.dev/github.com/kkdai/youtube/v2/
https://core.telegram.org/bots/api/
https://johnvansickle.com/ffmpeg/
curl -s -S -L https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz | tar -x -J
mv ./ffmpeg-*-amd64-static/ffmpeg ./ffmpeg
go get -a -u -v
go get github.com/kkdai/youtube/v2@master
go mod tidy
Expand Down Expand Up @@ -113,8 +108,8 @@ func init() {
ytRe = regexp.MustCompile(YtReString)
ytlistRe = regexp.MustCompile(YtListReString)

if os.Getenv("YamlConfigPath") != "" {
YamlConfigPath = os.Getenv("YamlConfigPath")
if v := os.Getenv("YamlConfigPath"); v != "" {
YamlConfigPath = v
}
if YamlConfigPath == "" {
log("WARNING YamlConfigPath empty")
Expand Down Expand Up @@ -161,8 +156,8 @@ func init() {
Ctx = context.TODO()

YtProxy := http.ProxyFromEnvironment
if GetVar("YtProxyList") != "" {
pp := strings.Split(GetVar("YtProxyList"), " ")
if v := GetVar("YtProxyList"); v != "" {
pp := strings.Split(v, " ")
rand.Seed(time.Now().UnixNano())
if err := SetVar("YtProxy", pp[rand.Intn(len(pp))]); err != nil {
log("WARNING SetVar YtProxy: %v", err)
Expand Down Expand Up @@ -213,11 +208,11 @@ func init() {
TgUpdateLog = append(TgUpdateLog, i)
}

if GetVar("TgZeChatId") == "" {
if v := GetVar("TgZeChatId"); v == "" {
log("ERROR TgZeChatId empty")
os.Exit(1)
} else {
TgZeChatId, err = strconv.ParseInt(GetVar("TgZeChatId"), 10, 0)
TgZeChatId, err = strconv.ParseInt(v, 10, 0)
if err != nil {
log("ERROR invalid TgZeChatId: %v", err)
os.Exit(1)
Expand Down Expand Up @@ -251,29 +246,29 @@ func init() {
os.Exit(1)
}

if GetVar("YtMaxResults") != "" {
YtMaxResults, err = strconv.ParseInt(GetVar("YtMaxResults"), 10, 0)
if v := GetVar("YtMaxResults"); v != "" {
YtMaxResults, err = strconv.ParseInt(v, 10, 0)
if err != nil {
log("ERROR invalid YtMaxResults: %v", err)
os.Exit(1)
}
}

if GetVar("YtHttpClientUserAgent") != "" {
YtHttpClientUserAgent = GetVar("YtHttpClientUserAgent")
if v := GetVar("YtHttpClientUserAgent"); v != "" {
YtHttpClientUserAgent = v
}
if GetVar("YtReString") != "" {
YtReString = GetVar("YtReString")
if v := GetVar("YtReString"); v != "" {
YtReString = v
}
if GetVar("YtListReString") != "" {
YtListReString = GetVar("YtListReString")
if v := GetVar("YtListReString"); v != "" {
YtListReString = v
}

if GetVar("FfmpegPath") != "" {
FfmpegPath = GetVar("FfmpegPath")
if v := GetVar("FfmpegPath"); v != "" {
FfmpegPath = v
}
if GetVar("FfmpegGlobalOptions") != "" {
FfmpegGlobalOptions = strings.Split(GetVar("FfmpegGlobalOptions"), " ")
if v := GetVar("FfmpegGlobalOptions"); v != "" {
FfmpegGlobalOptions = strings.Split(v, " ")
}

for _, s := range strings.Split(GetVar("TgAllChannelsChatIds"), " ") {
Expand Down Expand Up @@ -1402,52 +1397,17 @@ func postVideo(v YtVideo, vinfo *ytdl.Video, m TgMessage) error {
}
}

if targetVideoBitrateKbps > 0 {
log("transcoding to audio:%dkbps video:%dkbps", TgAudioBitrateKbps, targetVideoBitrateKbps)
tgvideoTranscodedFilename := fmt.Sprintf("%s.%s.%dk.mp4", ts(), v.Id, targetVideoBitrateKbps)
ffmpegArgs := FfmpegGlobalOptions
ffmpegArgs = append(ffmpegArgs,
"-i", tgvideoFilename,
"-f", "mp4",
"-c:a", "aac",
"-b:a", fmt.Sprintf("%dk", TgAudioBitrateKbps),
"-c:v", "h264",
"-b:v", fmt.Sprintf("%dk", targetVideoBitrateKbps),
tgvideoTranscodedFilename,
)
ffmpegCmd := exec.Command(FfmpegPath, ffmpegArgs...)

ffmpegCmdStderrPipe, err := ffmpegCmd.StderrPipe()
if err != nil {
return fmt.Errorf("Ffmpeg StderrPipe: %w", err)
}

t0 := time.Now()
err = ffmpegCmd.Start()
if err != nil {
return fmt.Errorf("Ffmpeg Start: %w", err)
}

log("started command `%s`", ffmpegCmd.String())

_, err = io.Copy(os.Stderr, ffmpegCmdStderrPipe)
if err != nil {
log("copy from ffmpeg stderr: %w", err)
}

err = ffmpegCmd.Wait()
if FfmpegPath != "" && targetVideoBitrateKbps > 0 {
filename2 := fmt.Sprintf("%s.%s.v%dk.a%dk.mp4", ts(), v.Id, targetVideoBitrateKbps, TgAudioBitrateKbps)
err := FfmpegTranscode(tgvideoFilename, filename2, targetVideoBitrateKbps, TgAudioBitrateKbps)
if err != nil {
return fmt.Errorf("Ffmpeg Wait: %w", err)
return fmt.Errorf("FfmpegTranscode `%s`: %w", tgvideoFilename, err)
}

log("transcoded video in %v", time.Since(t0).Truncate(time.Second))

tgvideoCaption += NL + fmt.Sprintf("(transcoded to video:%dkbps audio:%dkbps)", targetVideoBitrateKbps, TgAudioBitrateKbps)
if err := os.Remove(tgvideoFilename); err != nil {
log("os.Remove: %v", err)
log("os.Remove `%s`: %v", tgvideoFilename, err)
}

tgvideoCaption += NL + fmt.Sprintf("(transcoded to audio:%dkbps video:%dkbps)", TgAudioBitrateKbps, targetVideoBitrateKbps)
tgvideoFilename = tgvideoTranscodedFilename
tgvideoFilename = filename2
}

tgvideoReader, err := os.Open(tgvideoFilename)
Expand Down Expand Up @@ -1595,50 +1555,17 @@ func postAudio(v YtVideo, vinfo *ytdl.Video, m TgMessage) error {
}
}

if targetAudioBitrateKbps > 0 {
log("transcoding to audio:%dkbps", targetAudioBitrateKbps)
tgaudioTranscodedFilename := fmt.Sprintf("%s.%s.%dk.m4a", ts(), v.Id, targetAudioBitrateKbps)
ffmpegArgs := FfmpegGlobalOptions
ffmpegArgs = append(ffmpegArgs,
"-i", tgaudioFilename,
"-f", "mp4",
"-c:a", "aac",
"-b:a", fmt.Sprintf("%dk", targetAudioBitrateKbps),
tgaudioTranscodedFilename,
)
ffmpegCmd := exec.Command(FfmpegPath, ffmpegArgs...)

ffmpegCmdStderrPipe, err := ffmpegCmd.StderrPipe()
if err != nil {
return fmt.Errorf("Ffmpeg StderrPipe: %w", err)
}

t0 := time.Now()
err = ffmpegCmd.Start()
if err != nil {
return fmt.Errorf("Ffmpeg Start: %w", err)
}

log("started command `%s`", ffmpegCmd.String())

_, err = io.Copy(os.Stderr, ffmpegCmdStderrPipe)
if err != nil {
log("ERROR copy from ffmpeg stderr: %v", err)
}

err = ffmpegCmd.Wait()
if FfmpegPath != "" && targetAudioBitrateKbps > 0 {
filename2 := fmt.Sprintf("%s.%s.a%dk.m4a", ts(), v.Id, targetAudioBitrateKbps)
err := FfmpegTranscode(tgaudioFilename, filename2, 0, targetAudioBitrateKbps)
if err != nil {
return fmt.Errorf("Ffmpeg Wait: %w", err)
return fmt.Errorf("FfmpegTranscode `%s`: %w", tgaudioFilename, err)
}

log("transcoded audio in %v", time.Since(t0).Truncate(time.Second))

tgaudioCaption += NL + fmt.Sprintf("(transcoded to audio:%dkbps)", targetAudioBitrateKbps)
if err := os.Remove(tgaudioFilename); err != nil {
log("os.Remove: %v", err)
log("os.Remove `%s`: %v", tgaudioFilename, err)
}

tgaudioCaption += NL + fmt.Sprintf("(transcoded to %dkbps)", targetAudioBitrateKbps)
tgaudioFilename = tgaudioTranscodedFilename
tgaudioFilename = filename2
}

tgaudioReader, err := os.Open(tgaudioFilename)
Expand Down Expand Up @@ -2075,3 +2002,62 @@ func tgdeleteMessage(chatid, messageid int64) error {

return nil
}

func FfmpegTranscode(filename, filename2 string, videoBitrateKbps, audioBitrateKbps int64) (err error) {
if videoBitrateKbps > 0 {
log("transcoding to video:%dkbps audio:%dkbps ", videoBitrateKbps, audioBitrateKbps)
} else if audioBitrateKbps > 0 {
log("transcoding to audio:%dkbps", audioBitrateKbps)
} else {
return fmt.Errorf("empty both videoBitrateKbps and audioBitrateKbps")
}

ffmpegArgs := append(FfmpegGlobalOptions,
"-i", filename,
"-f", "mp4",
)
if videoBitrateKbps > 0 {
ffmpegArgs = append(ffmpegArgs,
"-c:v", "h264",
"-b:v", fmt.Sprintf("%dk", videoBitrateKbps),
)
}
if audioBitrateKbps > 0 {
ffmpegArgs = append(ffmpegArgs,
"-c:a", "aac",
"-b:a", fmt.Sprintf("%dk", audioBitrateKbps),
)
}
ffmpegArgs = append(ffmpegArgs,
filename2,
)

ffmpegCmd := exec.Command(FfmpegPath, ffmpegArgs...)

ffmpegCmdStderrPipe, err := ffmpegCmd.StderrPipe()
if err != nil {
return fmt.Errorf("ffmpeg StderrPipe: %w", err)
}

t0 := time.Now()
err = ffmpegCmd.Start()
if err != nil {
return fmt.Errorf("ffmpeg Start: %w", err)
}

log("started command `%s`", ffmpegCmd.String())

_, err = io.Copy(os.Stderr, ffmpegCmdStderrPipe)
if err != nil {
log("copy from ffmpeg stderr: %w", err)
}

err = ffmpegCmd.Wait()
if err != nil {
return fmt.Errorf("ffmpeg Wait: %w", err)
}

log("transcoded in %v", time.Since(t0).Truncate(time.Second))

return nil
}

0 comments on commit b8cdbb6

Please sign in to comment.