We need this because godot can't handle pipes
This commit is contained in:
		
							parent
							
								
									3805679ec4
								
							
						
					
					
						commit
						acd70fe70d
					
				
					 3 changed files with 236 additions and 0 deletions
				
			
		
							
								
								
									
										5
									
								
								dlserver/go.mod
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								dlserver/go.mod
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | module dlserver | ||||||
|  | 
 | ||||||
|  | go 1.14 | ||||||
|  | 
 | ||||||
|  | require github.com/gorilla/mux v1.8.0 | ||||||
							
								
								
									
										2
									
								
								dlserver/go.sum
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								dlserver/go.sum
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | ||||||
|  | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= | ||||||
|  | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= | ||||||
							
								
								
									
										229
									
								
								dlserver/main.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								dlserver/main.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,229 @@ | ||||||
|  | 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()) | ||||||
|  | 
 | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue