230 lines
6.3 KiB
Go
230 lines
6.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"regexp"
|
|
"runtime"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
func limitLength(s string, length int) string {
|
|
if len(s) < length {
|
|
return s
|
|
}
|
|
return s[:length]
|
|
}
|
|
|
|
// globals, huh, faster than channels and oddly more appropriate, we care less about races than feedback.
|
|
var lastPercentage float64
|
|
var lastFilename string
|
|
|
|
func convertFile(sourceFileName string, destinationFilename string) error {
|
|
launch := "./ffmpeg"
|
|
if runtime.GOOS == "windows" {
|
|
launch += ".exe"
|
|
}
|
|
|
|
os.Remove(destinationFilename)
|
|
DurationRe := regexp.MustCompile(`DURATION *: ([0-9]+):([0-9]+):([0-9]+)\.([0-9]+)`)
|
|
FrameRe := regexp.MustCompile(`frame= ?([0-9]+) `)
|
|
FPSValue := 0.0
|
|
finalFramesValue := 0.0
|
|
FPSRe := regexp.MustCompile(`, ([0-9\.]+) fps,`)
|
|
fmt.Printf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s", launch, "-loglevel", "repeat+level+verbose", "-i", sourceFileName, "-c:v", "libvpx", "-crf", "10", "-b:v", "1M", "-c:a", "libvorbis", "-y", destinationFilename)
|
|
cmd := exec.Command(launch, "-progress", "pipe:2", "-i", sourceFileName, "-c:v", "libvpx", "-crf", "10", "-b:v", "1M", "-c:a", "libvorbis", "-y", destinationFilename)
|
|
stdout, err := cmd.StderrPipe()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if err := cmd.Start(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Start reading from the file with a reader.
|
|
reader := bufio.NewReader(stdout)
|
|
var line string
|
|
for {
|
|
line, err = reader.ReadString('\n')
|
|
if err != nil && err != io.EOF {
|
|
break
|
|
}
|
|
fpses := FPSRe.FindAllStringSubmatch(line, 1)
|
|
if len(fpses) > 0 {
|
|
fmt.Printf("FPS' is %v\n", fpses)
|
|
FPSValue, _ = strconv.ParseFloat(fpses[0][1], 64)
|
|
}
|
|
durations := DurationRe.FindAllStringSubmatch(line, 1)
|
|
if len(durations) > 0 {
|
|
fmt.Printf("Durations is %v\n", durations)
|
|
if FPSValue != 0.0 {
|
|
// we have an fps, we can work out max frames!
|
|
hrs, _ := strconv.ParseFloat(durations[0][1], 64)
|
|
mins, _ := strconv.ParseFloat(durations[0][2], 64)
|
|
secs, _ := strconv.ParseFloat(durations[0][3], 64)
|
|
aaand, _ := strconv.ParseFloat("0."+durations[0][4], 64)
|
|
total := (hrs * 60 * 60) + (mins * 60) + secs + aaand
|
|
finalFramesValue = total * FPSValue
|
|
fmt.Printf("%0f:%0f:%0f%0.4f * %0.2f = %0.2f seconds = %0.2f frames\n", hrs, mins, secs, aaand, FPSValue, total, finalFramesValue)
|
|
}
|
|
}
|
|
currentFrames := FrameRe.FindAllStringSubmatch(line, 1)
|
|
if len(currentFrames) > 0 {
|
|
currentFrame, _ := strconv.ParseFloat(currentFrames[0][1], 64)
|
|
percentage := currentFrame / finalFramesValue * 100
|
|
lastPercentage = (percentage / 2) + 50
|
|
fmt.Printf("Frame %0f / %0f = Percent : %0.2f\n", currentFrame, finalFramesValue, lastPercentage)
|
|
}
|
|
|
|
if len(fpses) == 0 && len(durations) == 0 && len(currentFrames) == 0 {
|
|
//fmt.Printf("X: %s", line)
|
|
}
|
|
if err != nil {
|
|
break
|
|
}
|
|
}
|
|
if err != io.EOF {
|
|
fmt.Printf(" > Failed with error: %v\n", err)
|
|
return err
|
|
}
|
|
lastPercentage = 100
|
|
fmt.Printf("Setting to %0f percent.\n", lastPercentage)
|
|
os.Remove(sourceFileName)
|
|
go func() {
|
|
time.Sleep(10 * time.Second)
|
|
lastPercentage = 0
|
|
}()
|
|
return nil
|
|
}
|
|
|
|
func downloadFile(sourceURL string, outputFile string, statusChannel chan float64, nameChannel chan string) error {
|
|
progressBackwards := false
|
|
lastLastPercentage := 0.0
|
|
launch := "./youtube-dl"
|
|
if runtime.GOOS == "windows" {
|
|
launch += ".exe"
|
|
}
|
|
fmt.Printf("%s %s %s %s %s\n", launch, sourceURL, "-o", outputFile, "--newline")
|
|
cmd := exec.Command(launch, sourceURL, "-o", outputFile, "--newline")
|
|
stdout, err := cmd.StdoutPipe()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if err := cmd.Start(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
re := regexp.MustCompile(`([0-9.]+)%`)
|
|
reName := regexp.MustCompile(`Merging formats into "([^"]+)"`)
|
|
|
|
// Start reading from the file with a reader.
|
|
reader := bufio.NewReader(stdout)
|
|
var line string
|
|
for {
|
|
line, err = reader.ReadString('\n')
|
|
if err != nil && err != io.EOF {
|
|
break
|
|
}
|
|
percentages := re.FindAllStringSubmatch(line, 1)
|
|
if len(percentages) > 0 {
|
|
p, err := strconv.ParseFloat(string(percentages[0][1]), 64)
|
|
if err != nil {
|
|
fmt.Printf("What kind of number is %v", percentages[0][1])
|
|
} else {
|
|
if lastLastPercentage > p {
|
|
progressBackwards = true
|
|
}
|
|
lastLastPercentage = p
|
|
if progressBackwards {
|
|
// youtube-dl does video, then audio - it's not really half but an estimation
|
|
lastPercentage = float64(25) + p/4
|
|
} else {
|
|
lastPercentage = p / 4
|
|
}
|
|
statusChannel <- lastPercentage
|
|
}
|
|
}
|
|
fmt.Printf("%s\n", line)
|
|
if err != nil {
|
|
break
|
|
}
|
|
filenames := reName.FindAllStringSubmatch(line, 1)
|
|
if len(filenames) > 0 {
|
|
fmt.Printf("Filename: %v", filenames)
|
|
lastFilename = filenames[0][1]
|
|
nameChannel <- filenames[0][1]
|
|
}
|
|
}
|
|
if err := cmd.Wait(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if err != io.EOF {
|
|
fmt.Printf(" > Failed with error: %v\n", err)
|
|
return err
|
|
}
|
|
return convertFile(lastFilename, "converted.webm")
|
|
}
|
|
|
|
func HomeHandler(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
fmt.Fprintf(w, "Hello %s\n", "world")
|
|
}
|
|
|
|
var c chan float64
|
|
var n chan string
|
|
|
|
func FetchHandler(w http.ResponseWriter, r *http.Request) {
|
|
//vars := mux.Vars(r)
|
|
w.WriteHeader(http.StatusOK)
|
|
if lastFilename != "" {
|
|
os.Remove(lastFilename)
|
|
}
|
|
go downloadFile(r.FormValue("url"), "test", c, n)
|
|
fmt.Fprint(w, "OK\n")
|
|
}
|
|
|
|
func StatusHandler(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
// Oddly, using channels here is slower and we don't actually care if there's a race condition.
|
|
/* if len(c) > 0 {
|
|
lastPercentage = <-c
|
|
}
|
|
if len(n) > 0 {
|
|
lastFilename = <-n
|
|
} */
|
|
fmt.Printf("Returning %0.2f for %s\n", lastPercentage, lastFilename)
|
|
fmt.Fprintf(w, `{"filename": "%s","percentage":%0.2f}`+"\n", lastFilename, lastPercentage)
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) > 0 {
|
|
os.Chdir(os.Args[1])
|
|
}
|
|
r := mux.NewRouter()
|
|
r.SkipClean(true)
|
|
r.Path("/get").Queries("url", "{.*}").HandlerFunc(FetchHandler)
|
|
r.HandleFunc("/status/", StatusHandler)
|
|
r.HandleFunc("/", HomeHandler)
|
|
http.Handle("/", r)
|
|
c = make(chan float64, 999)
|
|
n = make(chan string, 999)
|
|
srv := &http.Server{
|
|
Handler: r,
|
|
Addr: "127.0.0.1:10435",
|
|
// Good practice: enforce timeouts for servers you create!
|
|
WriteTimeout: 15 * time.Second,
|
|
ReadTimeout: 15 * time.Second,
|
|
}
|
|
|
|
log.Fatal(srv.ListenAndServe())
|
|
|
|
}
|