refactor ffmpeg, download styling

This commit is contained in:
Carl Pearson
2024-10-14 05:36:34 -06:00
parent ccd21636cf
commit 30a2407e46
11 changed files with 145 additions and 71 deletions

View File

@@ -8,6 +8,7 @@ RUN wget -q -d https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_
ADD *.go /src/.
ADD database /src/database
Add ffmpeg /src/ffmpeg
ADD handlers /src/handlers
ADD media /src/media
ADD originals /src/originals

36
ffmpeg/ffmpeg.go Normal file
View File

@@ -0,0 +1,36 @@
package ffmpeg
import (
"bytes"
"fmt"
"os/exec"
"strings"
)
func Clip(src, dst string, from, to float64) error {
_, _, err := Ffmpeg("-i", src,
"-ss", fmt.Sprintf("%f", from),
"-to", fmt.Sprintf("%f", to),
"-c", "copy",
dst)
return err
}
// runs ffprobe with the provided args and returns (stdout, stderr, error)
func Ffmpeg(args ...string) ([]byte, []byte, error) {
ffmpeg := "ffmpeg"
log.Infoln(ffmpeg, strings.Join(args, " "))
cmd := exec.Command(ffmpeg, args...)
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
log.Errorf("ffmpeg error: %v", err)
}
log.Infoln("stdout:", stdout.String())
log.Infoln("stderr:", stderr.String())
return stdout.Bytes(), stderr.Bytes(), err
}

26
ffmpeg/ffprobe.go Normal file
View File

@@ -0,0 +1,26 @@
package ffmpeg
import (
"bytes"
"os/exec"
"strings"
)
// runs ffprobe with the provided args and returns (stdout, stderr, error)
func Ffprobe(args ...string) ([]byte, []byte, error) {
ffprobe := "ffprobe"
log.Infoln(ffprobe, strings.Join(args, " "))
cmd := exec.Command(ffprobe, args...)
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
log.Errorf("ffprobe error: %v", err)
}
log.Infoln("stdout:", stdout.String())
log.Infoln("stderr:", stderr.String())
return stdout.Bytes(), stderr.Bytes(), err
}

12
ffmpeg/init.go Normal file
View File

@@ -0,0 +1,12 @@
package ffmpeg
import "github.com/sirupsen/logrus"
var log *logrus.Logger
func Init(logger *logrus.Logger) error {
log = logger.WithFields(logrus.Fields{
"component": "ffmpeg",
}).Logger
return nil
}

View File

@@ -1,12 +1,11 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"os/exec"
"strconv"
"strings"
"ytdlp-site/ffmpeg"
)
type FFProbeOutput struct {
@@ -15,27 +14,8 @@ type FFProbeOutput struct {
} `json:"streams"`
}
// runs ffprobe with the provided args and returns (stdout, stderr, error)
func runFfprobe(args ...string) ([]byte, []byte, error) {
ffprobe := "ffprobe"
log.Infoln(ffprobe, strings.Join(args, " "))
cmd := exec.Command(ffprobe, args...)
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
log.Errorf("ffprobe error: %v", err)
}
log.Infoln("stdout:", stdout.String())
log.Infoln("stderr:", stderr.String())
return stdout.Bytes(), stderr.Bytes(), err
}
func getAudioFormat(filename string) (string, error) {
output, _, err := runFfprobe("-v", "quiet", "-print_format", "json", "-show_streams", filename)
output, _, err := ffmpeg.Ffprobe("-v", "quiet", "-print_format", "json", "-show_streams", filename)
if err != nil {
log.Errorln("ffprobe error:", err)
return "", err
@@ -65,7 +45,7 @@ func getStreamBitrate(path string, stream int) (uint, error) {
"-of", "default=noprint_wrappers=1:nokey=1",
path}
stdout, _, err := runFfprobe(ffprobeArgs...)
stdout, _, err := ffmpeg.Ffprobe(ffprobeArgs...)
if err != nil {
fmt.Println("ffprobe error:", err, string(stdout))
return 0, err
@@ -87,7 +67,7 @@ func getFormatBitrate(path string) (uint, error) {
"-of", "default=noprint_wrappers=1:nokey=1",
path}
stdout, _, err := runFfprobe(ffprobeArgs...)
stdout, _, err := ffmpeg.Ffprobe(ffprobeArgs...)
if err != nil {
fmt.Println("ffprobe error:", err, string(stdout))
return 0, err

View File

@@ -16,6 +16,7 @@ import (
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"ytdlp-site/ffmpeg"
"ytdlp-site/media"
"ytdlp-site/originals"
"ytdlp-site/playlists"
@@ -258,7 +259,7 @@ func getYtdlpVideoMeta(url string) (Meta, error) {
// return the length in seconds of a video file at `path`
func getLength(path string) (float64, error) {
stdout, _, err := runFfprobe("-v", "error", "-show_entries", "format=duration",
stdout, _, err := ffmpeg.Ffprobe("-v", "error", "-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1", path)
if err != nil {
log.Errorln("ffprobe error:", err)
@@ -273,7 +274,7 @@ func getLength(path string) (float64, error) {
}
func getVideoWidth(path string) (uint, error) {
stdout, _, err := runFfprobe("-v", "error", "-select_streams",
stdout, _, err := ffmpeg.Ffprobe("-v", "error", "-select_streams",
"v:0", "-count_packets", "-show_entries",
"stream=width", "-of", "csv=p=0", path)
@@ -290,7 +291,7 @@ func getVideoWidth(path string) (uint, error) {
}
func getVideoHeight(path string) (uint, error) {
stdout, _, err := runFfprobe("-v", "error", "-select_streams",
stdout, _, err := ffmpeg.Ffprobe("-v", "error", "-select_streams",
"v:0", "-count_packets", "-show_entries",
"stream=height", "-of", "csv=p=0", path)
@@ -308,7 +309,7 @@ func getVideoHeight(path string) (uint, error) {
func getVideoFPS(path string) (float64, error) {
stdout, _, err := runFfprobe("-v", "error", "-select_streams",
stdout, _, err := ffmpeg.Ffprobe("-v", "error", "-select_streams",
"v:0", "-count_packets", "-show_entries",
"stream=r_frame_rate", "-of", "csv=p=0", path)
if err != nil {
@@ -421,7 +422,7 @@ func getVideoMeta(path string) (VideoMeta, error) {
func getAudioDuration(path string) (float64, error) {
stdout, _, err := runFfprobe("-v", "error",
stdout, _, err := ffmpeg.Ffprobe("-v", "error",
"-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1",
path)

View File

@@ -17,6 +17,7 @@ import (
"gorm.io/gorm/logger"
"ytdlp-site/database"
"ytdlp-site/ffmpeg"
"ytdlp-site/handlers"
"ytdlp-site/media"
"ytdlp-site/originals"
@@ -52,6 +53,7 @@ func main() {
log.Infof("GitSHA: %s", getGitSHA())
log.Infof("BuildDate: %s", getBuildDate())
ffmpeg.Init(log)
handlers.Init(log)
ytdlp.Init(log)

39
static/style/download.css Normal file
View File

@@ -0,0 +1,39 @@
h1 {
font-size: 24px;
margin-bottom: 20px;
}
form {
display: flex;
flex-direction: column;
gap: 15px;
}
input[type="url"] {
width: 100%;
padding: 1rem;
font-size: 1.25rem;
}
.radio-group {
display: flex;
gap: 10px;
/* align-items: center; */
justify-content: center;
}
.radio-group label {
display: flex;
align-items: center;
gap: 5px;
cursor: pointer;
}
button {
background-color: #007bff;
color: white;
border: none;
padding: 12px;
font-size: 16px;
cursor: pointer;
}

View File

@@ -5,6 +5,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/style/common.css">
<link rel="stylesheet" href="/static/style/download.css">
{{template "footer-css" .}}
<title>Download Video</title>
</head>
@@ -13,11 +14,12 @@
<h1>Download Video</h1>
<form method="POST">
<input type="url" name="url" placeholder="Video URL" required>
<input type="radio" id="audio-video" name="color" value="audio-video" checked>
<label for="audio-video">Audio/Video</label>
<input type="radio" id="audio-video" name="color" value="audio">
<label for="audio">Audio Only</label>
<div class="radio-group">
<input type="radio" id="audio-video" name="color" value="audio-video" checked>
<label for="audio-video">Audio/Video</label>
<input type="radio" id="audio-video" name="color" value="audio">
<label for="audio">Audio Only</label>
</div>
<button type="submit">Download</button>
</form>
<a href="/videos">View Downloaded Videos</a>

View File

@@ -1,13 +1,11 @@
package main
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"ytdlp-site/ffmpeg"
"ytdlp-site/media"
"ytdlp-site/originals"
@@ -48,20 +46,14 @@ func videoToVideo(transID uint, height uint, srcFilepath string) {
}
// start ffmpeg
ffmpeg := "ffmpeg"
ffmpegArgs := []string{"-i", srcFilepath,
db.Model(&Transcode{}).Where("id = ?", transID).Update("status", "running")
stdout, stderr, err := ffmpeg.Ffmpeg("-i", srcFilepath,
"-vf", fmt.Sprintf("scale=-2:%d", height), "-c:v", "libx264",
"-crf", "23", "-preset", "veryfast", "-c:a", "aac", "-b:a", fmt.Sprintf("%dk", audioBitrate),
dstFilepath}
fmt.Println(ffmpeg, strings.Join(ffmpegArgs, " "))
cmd := exec.Command(ffmpeg, ffmpegArgs...)
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout, cmd.Stderr = &stdout, &stderr
db.Model(&Transcode{}).Where("id = ?", transID).Update("status", "running")
err = cmd.Run()
dstFilepath)
if err != nil {
fmt.Println("Error: convert to video file", srcFilepath, "->", dstFilepath, stdout.String(), stderr.String())
fmt.Println("Error: convert to video file", srcFilepath, "->", dstFilepath, string(stdout), string(stderr))
db.Model(&Transcode{}).Where("id = ?", transID).Update("status", "failed")
return
}
@@ -112,15 +104,11 @@ func videoToAudio(transID uint, kbps uint, videoFilepath string) {
return
}
ffmpeg := "ffmpeg"
ffmpegArgs := []string{"-i", videoFilepath, "-vn", "-acodec",
db.Model(&Transcode{}).Where("id = ?", transID).Update("status", "running")
_, _, err = ffmpeg.Ffmpeg("-i", videoFilepath, "-vn", "-acodec",
"mp3", "-b:a",
fmt.Sprintf("%dk", kbps),
audioFilepath}
fmt.Println(ffmpeg, strings.Join(ffmpegArgs, " "))
cmd := exec.Command(ffmpeg, ffmpegArgs...)
db.Model(&Transcode{}).Where("id = ?", transID).Update("status", "running")
err = cmd.Run()
audioFilepath)
if err != nil {
fmt.Println("Error: convert to audio file", videoFilepath, "->", audioFilepath)
db.Model(&Transcode{}).Where("id = ?", transID).Update("status", "failed")
@@ -170,15 +158,11 @@ func audioToAudio(transID uint, kbps uint, srcFilepath string) {
return
}
ffmpeg := "ffmpeg"
ffmpegArgs := []string{"-i", srcFilepath, "-vn", "-acodec",
db.Model(&Transcode{}).Where("id = ?", transID).Update("status", "running")
_, _, err = ffmpeg.Ffmpeg("-i", srcFilepath, "-vn", "-acodec",
"mp3", "-b:a",
fmt.Sprintf("%dk", kbps),
dstFilepath}
fmt.Println(ffmpeg, strings.Join(ffmpegArgs, " "))
cmd := exec.Command(ffmpeg, ffmpegArgs...)
db.Model(&Transcode{}).Where("id = ?", transID).Update("status", "running")
err = cmd.Run()
dstFilepath)
if err != nil {
fmt.Println("Error: convert to audio file", srcFilepath, "->", dstFilepath)
db.Model(&Transcode{}).Where("id = ?", transID).Update("status", "failed")

View File

@@ -2,7 +2,6 @@ package ytdlp
import (
"bytes"
"fmt"
"os/exec"
"strings"
)
@@ -25,11 +24,3 @@ func Run(args ...string) ([]byte, []byte, error) {
log.Infoln("stderr:", stderr.String())
return stdout.Bytes(), stderr.Bytes(), err
}
func Clip(src, dst string, from, to float64) error {
_, _, err := Run("-i", src,
"-ss", fmt.Sprintf("%f", from),
"-to", fmt.Sprintf("%f", to),
dst)
return err
}