Recently I started using my WD MyCloud EX2 network drive to download youtube videos to watch them via Plex. The first iteration of this was a hacky PHP script to download the video, now I’ve rewritten the script as a Go application.
The code is still hacky, it will only work without any concurrent requests – but it still works for me and maybe you are interested to have a starting point for your own adventures. So, here we go:
package main import ( "bufio" "fmt" "log" "net/http" "os" "os/exec" "strconv" "github.com/gorilla/mux" ) var ( Log *log.Logger Output string ) func _execute(url string) (error) { // reset last output Output = "" cmd := exec.Command("/usr/local/bin/youtube-dl", "-f", "best", "--newline", "--no-call-home", "--no-check-certificate", "-o", "/mnt/HD/HD_a2/Public/Shared Videos/%(uploader)s/%(title)s-%(id)s.%(ext)s", url) out, err := cmd.StdoutPipe() if err != nil { return err } cmd.Start() scanner := bufio.NewScanner(out) for scanner.Scan() { Output = fmt.Sprintf("%s\n%s", Output, scanner.Text()) } cmd.Wait() return nil } func showOutput(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "text/plain") fmt.Fprintf(w, "%s", Output) } func download(w http.ResponseWriter, r *http.Request) { url := r.PostFormValue("url") go _execute(url) w.Header().Set("Location", "/static/success.html") w.WriteHeader(http.StatusFound) } func redirect(w http.ResponseWriter, r *http.Request) { w.Header().Set("Location", "/static/") w.WriteHeader(http.StatusFound) } func main() { Log = log.New(os.Stdout, "youtube-ex2", log.Lshortfile) port := 8080 if len(os.Args) == 2 { args := os.Args[1:] port, _ = strconv.Atoi(args[0]) } r := mux.NewRouter() r.HandleFunc("/", redirect) r.HandleFunc("/download", download).Methods("POST") r.HandleFunc("/progress", showOutput) r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) sport := fmt.Sprintf(":%d", port) log.Printf("Listening on %s", sport) log.Fatal(http.ListenAndServe(sport, r)) }
The app is meant to be installed in /opt/app
and bootstrap has to be available in a subdirectory /opt/app/static/{css|js}
. You also have to install youtube-dl
, follow the description in my original article.
To compile it, I used the following two commands to make sure it will work on the MyCloud EX2, which is an ARM architecture:
go get GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 go build
I also wrote a simple startup script to put into directory /etc/init.d/
and name it youtube
.
#!/bin/bash PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin DESC="youtube-dl webserver" NAME=youtube PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME # Exit if the package is not installed [ -x /opt/app/app ] || exit 0 . /etc/system.conf DAEMON_ARGS="8080" # # Function that starts the daemon/service # do_start_app() { ps x | grep "/opt/app/app $DAEMON_ARGS" | grep -qv grep if [ $? == 0 ]; then echo "$NAME is already running " return 1 fi echo "Starting $DESC " "$NAME" cd /opt/app /opt/app/app $DAEMON_ARGS & pid=$! status=$? if [ $status = 0 ]; then echo $pid > $PIDFILE echo "$NAME started" else echo "$NAME failed to start" fi } do_start() { do_start_app } do_stop_app() { [ ! -f $PIDFILE ] && echo "$NAME not running ..." && return 0 PID=`cat $PIDFILE` if ps -e | grep -q $PID then echo "Stopping $DESC" "$NAME $PID" kill $PID rm $PIDFILE fi } # # Function that stops the daemon/service # do_stop() { do_stop_app } case "$1" in start) do_start ;; stop) do_stop ;; status) ps x | grep "/opt/app/app $DAEMON_ARGS" | grep -qv grep if [ $? == 0 ]; then echo "$NAME is running " else echo "$NAME is not running " fi exit 0 ;; restart|force-reload) do_stop && sleep 1 && do_start ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 1 ;; esac exit 0
Now you can execute the following command to start the Go webserver for the youtube-dl wrapper:
/etc/init.d/youtube start
If you now browse to http://yourmycloud:8080 you should see a simple form to paste the URL of a youtube video (or any other supported source) into and start the download. The webpage will show the output, so you can check if it’s done.
If you want to use this, feel free but make sure you know what you do before destroying your network drive. đ
Eine Antwort auf âRewriting my youtube-dl wrapper in Goâ
[…] messed with my youtube-dl wrapper again, to be a bit more robust and handling concurrent downloads. It reads the path to binaries and […]