Add length and download sizes
This commit is contained in:
69
handlers.go
69
handlers.go
@@ -129,6 +129,59 @@ func getMeta(url string) (Meta, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return the length in seconds of a video file at `path`
|
||||||
|
func getLength(path string) (float64, error) {
|
||||||
|
cmd := exec.Command("ffprobe", "-v", "error", "-show_entries", "format=duration",
|
||||||
|
"-of", "default=noprint_wrappers=1:nokey=1", path)
|
||||||
|
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("getLength cmd error:", err)
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := strconv.ParseFloat(strings.TrimSpace(stdout.String()), 64)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("getLength parse error:", err, stdout.String())
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func humanLength(s float64) string {
|
||||||
|
ss := int64(s)
|
||||||
|
mm, ss := ss/60, ss%60
|
||||||
|
hh, mm := mm/60, mm%60
|
||||||
|
|
||||||
|
return fmt.Sprintf("%d:%02d:%02d", hh, mm, ss)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSize(path string) (int64, error) {
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
return fi.Size(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func humanSize(bytes int64) string {
|
||||||
|
const (
|
||||||
|
KiB = 1024
|
||||||
|
MiB = 1024 * KiB
|
||||||
|
GiB = 1024 * MiB
|
||||||
|
)
|
||||||
|
|
||||||
|
if bytes >= GiB {
|
||||||
|
return fmt.Sprintf("%.1f GiB", float64(bytes)/float64(GiB))
|
||||||
|
} else if bytes >= MiB {
|
||||||
|
return fmt.Sprintf("%.1f MiB", float64(bytes)/float64(MiB))
|
||||||
|
} else if bytes >= KiB {
|
||||||
|
return fmt.Sprintf("%.1f KiB", float64(bytes)/float64(KiB))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d bytes", bytes)
|
||||||
|
}
|
||||||
|
|
||||||
func startDownload(videoID uint, videoURL string) {
|
func startDownload(videoID uint, videoURL string) {
|
||||||
db.Model(&Video{}).Where("id = ?", videoID).Update("status", "downloading")
|
db.Model(&Video{}).Where("id = ?", videoID).Update("status", "downloading")
|
||||||
|
|
||||||
@@ -177,6 +230,22 @@ func startDownload(videoID uint, videoURL string) {
|
|||||||
"audio_filename": audioFilename,
|
"audio_filename": audioFilename,
|
||||||
"status": "completed",
|
"status": "completed",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
length, err := getLength(videoFilepath)
|
||||||
|
if err == nil {
|
||||||
|
db.Model(&Video{}).Where("id = ?", videoID).Update("length", humanLength(length))
|
||||||
|
}
|
||||||
|
|
||||||
|
videoSize, err := getSize(videoFilepath)
|
||||||
|
if err == nil {
|
||||||
|
db.Model(&Video{}).Where("id = ?", videoID).Update("video_size", humanSize(videoSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
audioSize, err := getSize(audioFilepath)
|
||||||
|
if err == nil {
|
||||||
|
db.Model(&Video{}).Where("id = ?", videoID).Update("audio_size", humanSize(audioSize))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func videosHandler(c echo.Context) error {
|
func videosHandler(c echo.Context) error {
|
||||||
|
@@ -15,6 +15,9 @@ type Video struct {
|
|||||||
VideoFilename string
|
VideoFilename string
|
||||||
AudioFilename string
|
AudioFilename string
|
||||||
UserID uint
|
UserID uint
|
||||||
|
Length string
|
||||||
|
AudioSize string
|
||||||
|
VideoSize string
|
||||||
Status string // "pending", "downloading", "completed", "failed", "cancelled"
|
Status string // "pending", "downloading", "completed", "failed", "cancelled"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Downloaded Videos</title>
|
<title>Downloaded Videos</title>
|
||||||
<meta http-equiv="refresh" content="5">
|
<meta http-equiv="refresh" content="10">
|
||||||
<style>
|
<style>
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -27,20 +27,22 @@
|
|||||||
<h1>Downloaded Videos</h1>
|
<h1>Downloaded Videos</h1>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>URL</th>
|
|
||||||
<th>Title</th>
|
<th>Title</th>
|
||||||
|
<th>URL</th>
|
||||||
|
<th>Length</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
{{range .videos}}
|
{{range .videos}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{.URL}}</td>
|
|
||||||
<td>{{.Title}}</td>
|
<td>{{.Title}}</td>
|
||||||
|
<td>{{.URL}}</td>
|
||||||
|
<td>{{.Length}}</td>
|
||||||
<td>{{.Status}}</td>
|
<td>{{.Status}}</td>
|
||||||
<td>
|
<td>
|
||||||
{{if eq .Status "completed"}}
|
{{if eq .Status "completed"}}
|
||||||
<a href="/downloads/video/{{.VideoFilename}}">Download Video</a> |
|
<a href="/downloads/video/{{.VideoFilename}}">Download Video ({{.VideoSize}})</a> |
|
||||||
<a href="/downloads/audio/{{.AudioFilename}}">Download Audio</a>
|
<a href="/downloads/audio/{{.AudioFilename}}">Download Audio ({{.AudioSize}})</a>
|
||||||
{{else if eq .Status "failed"}}
|
{{else if eq .Status "failed"}}
|
||||||
<form action="/video/{{.ID}}/restart" method="post" style="display:inline;">
|
<form action="/video/{{.ID}}/restart" method="post" style="display:inline;">
|
||||||
<button type="submit">Restart</button>
|
<button type="submit">Restart</button>
|
||||||
|
Reference in New Issue
Block a user