/* * Copyright 2022 Justin Reichardt * * This file is part of viddown. * * fedset is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * viddown is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with fedset. If not, see . */ package main import ( "encoding/json" "flag" "io" "io/ioutil" "log" "net/http" "os" "os/exec" "path" "strconv" "strings" ) const template = ` Download

` // Used to request an operation (download) type ops struct { URL string Res chan string } // List of the operations currently being worked on var currentWork map[int]string // program configurations var config struct { // Where files should be saved saveLocation string // Where to find youtube-dl program, must be full name youtubedll string // The port the server listens on port int } // Global channel to send operation requests to var opsc = make(chan ops) // handleRequest handles http requests func handleRequest(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet && r.URL.Path == "/currentwork" { list, err := json.Marshal(currentWork) if err != nil { log.Panic(err) } w.Write(list) return } else if r.Method == http.MethodGet { log.Print("New Get request: " + r.URL.Path) } else if r.Method == http.MethodPost { r.ParseForm() go func() { var o ops o.URL = r.FormValue("URL") opsc <- o }() } else { } // Modify template and send it to the requester var insert string for _, url := range currentWork { insert += "
" + url } temp := strings.Replace(template, "currentWork", insert, 1) io.WriteString(w, temp) } func downloadVid(r *http.Request) { } // operationHandler waits for operation requests and initiates them func operationHandler() { // Simple index for sorting video work for i := 0; true; i++ { o := <-opsc log.Print("Start Downloading: " + o.URL) // Spin off a go routine to handle a download so the handler can continue to receive requests go func() { // Create a unique directory to download the video in dir := path.Join(config.saveLocation, ".viddown", strconv.Itoa(i)) os.MkdirAll(dir, 0755) // Build the download command cmd := exec.Command(config.youtubedll, o.URL) cmd.Dir = dir + "/" currentWork[i] = o.URL // Adds the URL to list of current work output, err := cmd.CombinedOutput() log.Print("Finished: " + o.URL) if err != nil { log.Print("Failed to download") log.Print(err) } log.Print(string(output)) delete(currentWork, i) // Remove the URL from list of current work // Clean up directory files, err := ioutil.ReadDir(dir + "/") if err != nil { log.Print(err) } for _, file := range files { log.Print("Moving: " + file.Name()) err := os.Rename(dir+"/"+file.Name(), file.Name()) if err != nil { log.Print(err) log.Print("Failed to move: " + dir + "/" + file.Name() + " to: " + file.Name()) } } err = os.RemoveAll(dir) if err != nil { log.Print("Failed to remove: " + dir) } }() } log.Fatal("Exited operationsHandler") } // handleConfigs configures the program at start, handling any flags or env variables func handleConfigs() { flag.StringVar(&config.saveLocation, "o", "./", "The output location for videos") flag.StringVar(&config.youtubedll, "y", "youtube-dl", "The full location of youtube-dl") flag.IntVar(&config.port, "p", 8080, "The port the server listens on") flag.Parse() log.Println("Downloading files to: " + config.saveLocation) } func main() { handleConfigs() // initialize currentWork with a blank map currentWork = make(map[int]string) // Create the work directory os.MkdirAll(path.Join(config.saveLocation, ".viddown"), 0755) // Start the operations handler go operationHandler() // Start the http server handler := http.HandlerFunc(handleRequest) http.Handle("/", handler) log.Printf("Starting server on " + strconv.Itoa(config.port)) http.ListenAndServe(":"+strconv.Itoa(config.port), nil) }