add download form
Marco Andronaco andronacomarco@gmail.com
Fri, 18 Oct 2024 16:17:47 +0200
6 files changed,
111 insertions(+),
11 deletions(-)
M
src/app/handlers.go
→
src/app/handlers.go
@@ -95,15 +95,17 @@ videoURL = fmt.Sprintf("/proxy/%s/%d", videoID, formatID)
} data := map[string]interface{}{ - "VideoID": videoID, - "VideoURL": videoURL, - "Author": video.Author, - "Title": video.Title, - "Description": video.Description, - "Thumbnail": thumbnail, - "Duration": video.Duration, - "Captions": getCaptions(*video), - "Heading": template.HTML(heading), + "VideoID": videoID, + "VideoURL": videoURL, + "Author": video.Author, + "Title": video.Title, + "Description": video.Description, + "Thumbnail": thumbnail, + "Duration": video.Duration, + "Captions": getCaptions(*video), + "Heading": template.HTML(heading), + "VideoFormats": video.Formats.Select(formatsSelectFnVideo), + "AudioFormats": video.Formats.Select(formatsSelectFnAudio), } err = g.XT.ExecuteTemplate(w, "video.tmpl", data)@@ -112,6 +114,40 @@ log.Println("indexHandler ERROR:", err)
http.Error(w, err500, http.StatusInternalServerError) return } +} + +func downloadHandler(w http.ResponseWriter, r *http.Request) { + videoID := r.FormValue("video") + if videoID == "" { + http.Error(w, "Missing video ID", http.StatusBadRequest) + return + } + + if !videoRegex.MatchString(videoID) { + log.Println("Invalid video ID:", videoID) + http.Error(w, err404, http.StatusNotFound) + return + } + + itagno := r.FormValue("itagno") + if itagno == "" { + http.Error(w, "Missing ItagNo", http.StatusBadRequest) + return + } + + video, err := g.KS.Get(videoID) + if err != nil || video == nil { + http.Error(w, err404, http.StatusNotFound) + return + } + + formats := video.Formats.Quality(itagno) + if len(formats) == 0 { + http.Error(w, err404, http.StatusNotFound) + return + } + + http.Redirect(w, r, formats[0].URL, http.StatusFound) } func cacheHandler(w http.ResponseWriter, r *http.Request) {
M
src/app/main.go
→
src/app/main.go
@@ -65,6 +65,8 @@ r.HandleFunc("GET /proxy/{videoID}", proxyHandler)
r.HandleFunc("GET /proxy/{videoID}/{formatID}", proxyHandler) r.HandleFunc("GET /sub/{videoID}/{language}", subHandler) + r.HandleFunc("POST /download", downloadHandler) + r.HandleFunc("GET /cache", cacheHandler) log.Println("Serving on port " + g.Port)
M
src/app/video.go
→
src/app/video.go
@@ -72,6 +72,14 @@ func formatsSelectFnBest(f youtube.Format) bool {
return f.AudioChannels > 1 && strings.HasPrefix(f.MimeType, "video/mp4") } +func formatsSelectFnAudio(f youtube.Format) bool { + return f.QualityLabel == "" +} + +func formatsSelectFnVideo(f youtube.Format) bool { + return !formatsSelectFnAudio(f) +} + func getURL(videoID string) string { return fmt.Sprintf(fmtYouTubeURL, videoID) }
M
src/globals/globals.go
→
src/globals/globals.go
@@ -2,7 +2,11 @@ package globals
import ( "bytes" + "fmt" + "html/template" "net/http" + "strconv" + "strings" "time" "github.com/birabittoh/myks"@@ -17,11 +21,45 @@ Port string
C = http.DefaultClient YT = youtube.Client{} - XT = extemplate.New() + XT = extemplate.New().Funcs(funcMap) KS = myks.New[youtube.Video](3 * time.Hour) PKS *myks.KeyStore[bytes.Buffer] AdminUser string AdminPass string + + funcMap = template.FuncMap{"parseFormat": parseFormat} ) + +func parseFormat(f youtube.Format) (res string) { + isAudio := f.QualityLabel == "" + + if isAudio { + bitrate := f.AverageBitrate + if bitrate == 0 { + bitrate = f.Bitrate + } + res = strconv.Itoa(bitrate/1000) + "kbps" + } else { + res = f.QualityLabel + } + + mime := strings.Split(f.MimeType, ";") + res += " - " + mime[0] + + codecs := " (" + strings.Split(mime[1], "\"")[1] + ")" + + if isAudio { + return res + " - audio only" + codecs + } + + res += fmt.Sprintf(" (%d FPS)", f.FPS) + + if f.AudioChannels == 0 { + res += " - video only" + } + + res += codecs + return +}
M
templates/index.tmpl
→
templates/index.tmpl
@@ -17,7 +17,7 @@
<section> <header> <h3 style="margin-bottom: 4px">How to use</h3> - <p>Replace <code>www.youtube.com</code> or <code>youtu.be</code> with <span id="changeme">this domain</span> to fix embeds for short videos.</p> + <p>Replace <code>www.youtube.com</code> or <code>youtu.be</code> with <noscript id="changeme">this domain</noscript> to fix embeds for short videos.</p> </header> <video src="https://github.com/birabittoh/FixYouTube-legacy/assets/26506860/2896d39e-a86e-47ce-939a-785b73d11683"
M
templates/video.tmpl
→
templates/video.tmpl
@@ -33,6 +33,22 @@ </video>
<h2>{{ .Title }}</h2> <h3>> {{ .Author }}</h3> <pre style="white-space: pre-wrap">{{ .Description }}</pre> + <form action="/download" method="post" rel="noopener" target="_blank" style="display: grid; grid-template-columns: auto auto; justify-content: space-between;"> + <input type="hidden" name="video" value="{{ .VideoID }}"> + <select name="itagno"> + {{ range .VideoFormats }} + <option value="{{ .ItagNo }}"> + {{ parseFormat . }} + </option> + {{ end }} + {{ range .AudioFormats }} + <option value="{{ .ItagNo }}"> + {{ parseFormat . }} + </option> + {{ end }} + </select> + <button type="submit">Download</button> + </form> <a href="https://www.youtube.com/watch?v={{ .VideoID }}">Watch on YouTube</a> <br /> <a href="/">What is this?</a>