github.com/serge-v/zero@v1.0.2-0.20220911142406-af4b6a19e68a/examples/audio/main.go (about) 1 package main 2 3 import ( 4 "embed" 5 "flag" 6 "html/template" 7 "io" 8 "io/fs" 9 "io/ioutil" 10 "log" 11 "net/http" 12 "net/url" 13 "path/filepath" 14 "regexp" 15 "sort" 16 "strconv" 17 "strings" 18 19 _ "embed" 20 _ "time/tzdata" 21 ) 22 23 type fit []fs.FileInfo 24 25 func (fi fit) Len() int { 26 return len(fi) 27 } 28 29 func (fi fit) Swap(i, j int) { 30 fi[i], fi[j] = fi[j], fi[i] 31 } 32 33 var rex = regexp.MustCompile("[0-9]+") 34 35 func (fi fit) Less(i, j int) bool { 36 s1 := rex.FindString(fi[i].Name()) 37 s2 := rex.FindString(fi[j].Name()) 38 n1, _ := strconv.Atoi(s1) 39 n2, _ := strconv.Atoi(s2) 40 return n1 < n2 41 } 42 43 func getFiles(subdir string) ([]fs.FileInfo, error) { 44 files, err := ioutil.ReadDir(filepath.Join(dir, subdir)) 45 if err != nil { 46 return nil, err 47 } 48 49 sort.Sort(fit(files)) 50 return files, nil 51 } 52 53 //go:embed *.html *.js favicon.ico 54 var resourses embed.FS 55 var templates *template.Template 56 57 //go:embed login_token~.txt 58 var loginToken string 59 60 func reloadTemplates(w http.ResponseWriter) { 61 var err error 62 templates, err = template.ParseFiles("player.html") 63 if err != nil { 64 http.Error(w, err.Error(), http.StatusInternalServerError) 65 return 66 } 67 } 68 69 func handlePlayer(w http.ResponseWriter, r *http.Request) { 70 if *debug { 71 reloadTemplates(w) 72 } 73 74 var err error 75 76 d := struct { 77 Dirs []string 78 }{} 79 80 d.Dirs, err = getDirs() 81 if err != nil { 82 http.Error(w, err.Error(), http.StatusInternalServerError) 83 return 84 } 85 86 if err := templates.ExecuteTemplate(w, "player", d); err != nil { 87 http.Error(w, err.Error(), http.StatusInternalServerError) 88 return 89 } 90 } 91 92 func getDirs() ([]string, error) { 93 files, err := ioutil.ReadDir(dir) 94 if err != nil { 95 return nil, err 96 } 97 var list []string 98 for _, f := range files { 99 if f.IsDir() { 100 list = append(list, f.Name()) 101 } 102 } 103 104 sort.Strings(list) 105 return list, nil 106 } 107 108 func handleFileList(w http.ResponseWriter, r *http.Request) { 109 subdir := r.URL.Query().Get("dir") 110 files, err := getFiles(subdir) 111 if err != nil { 112 http.Error(w, err.Error(), http.StatusInternalServerError) 113 return 114 } 115 116 var fnames []string 117 for _, f := range files { 118 if filepath.Ext(f.Name()) != ".mp3" && filepath.Ext(f.Name()) != ".webm" { 119 continue 120 } 121 fnames = append(fnames, ` "`+url.PathEscape(filepath.Join(subdir, f.Name()))+`"`) 122 } 123 io.WriteString(w, "[\n"+strings.Join(fnames, ",\n")+"\n]\n") 124 } 125 126 func handleSongList(w http.ResponseWriter, r *http.Request) { 127 subdir := r.URL.Query().Get("dir") 128 files, err := getFiles(subdir) 129 if err != nil { 130 http.Error(w, err.Error(), http.StatusInternalServerError) 131 return 132 } 133 134 var fnames []string 135 for _, f := range files { 136 if filepath.Ext(f.Name()) != ".mp3" && filepath.Ext(f.Name()) != ".webm" { 137 continue 138 } 139 fname := strings.TrimSuffix(f.Name(), ".mp3") 140 fname = strings.TrimSuffix(fname, ".web,") 141 fnames = append(fnames, fname) 142 } 143 w.Header().Set("Content-Type", "text/html") 144 io.WriteString(w, strings.Join(fnames, "<hr>\n")) 145 } 146 147 func authHandler(next http.Handler) http.Handler { 148 f := func(w http.ResponseWriter, r *http.Request) { 149 token := r.URL.Query().Get("token") 150 if token != "" && loginToken == token { 151 c := http.Cookie{Name: "token", Value: token} 152 http.SetCookie(w, &c) 153 http.Redirect(w, r, "/", http.StatusFound) 154 return 155 } 156 157 c, err := r.Cookie("token") 158 if err != nil || c.Value != loginToken { 159 http.Error(w, "invalid cookie", http.StatusForbidden) 160 return 161 } 162 163 next.ServeHTTP(w, r) 164 } 165 return http.HandlerFunc(f) 166 } 167 168 var debug = flag.Bool("d", false, "debug") 169 var dir = "/audiofiles/" 170 171 func main() { 172 flag.Parse() 173 174 var err error 175 176 templates, err = template.ParseFS(resourses, "player.html") 177 if err != nil { 178 log.Fatal(err) 179 } 180 181 if *debug { 182 dir = "." + dir 183 } 184 185 mux := http.NewServeMux() 186 187 res := http.FileServer(http.FS(resourses)) 188 mux.Handle("/favicon.ico", res) 189 mux.Handle("/player.js", res) 190 mux.HandleFunc("/", handlePlayer) 191 mux.HandleFunc("/files", handleFileList) 192 mux.HandleFunc("/songlist", handleSongList) 193 mux.Handle("/audio/", http.StripPrefix("/audio/", http.FileServer(http.Dir(dir)))) 194 195 log.Println("starting on 8101") 196 if err := http.ListenAndServe("127.0.0.1:8101", authHandler(mux)); err != nil { 197 log.Fatal(err) 198 } 199 }