package main import ( "net/http" "os" "path/filepath" "slices" "sort" "strings" ) type fsEntry struct { Name string `json:"name"` Path string `json:"path"` Dir bool `json:"dir"` Size int64 `json:"size"` Mod int64 `json:"mod"` } // handleFSList backs the built-in file browser (used when no native file // dialog is available). func (a *App) handleFSList(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() dir := strings.TrimSpace(q.Get("path")) showAll := q.Get("all") == "1" home, _ := os.UserHomeDir() if dir == "" { dir = home if v := filepath.Join(home, "Videos"); isDir(v) { dir = v } } dir, _ = filepath.Abs(dir) if st, err := os.Stat(dir); err == nil && !st.IsDir() { dir = filepath.Dir(dir) } des, err := os.ReadDir(dir) if err != nil { writeError(w, http.StatusBadRequest, "cannot open folder: "+err.Error()) return } entries := []fsEntry{} for _, de := range des { name := de.Name() if strings.HasPrefix(name, ".") || strings.Contains(name, ".vibedit-part") { continue } info, err := de.Info() if err != nil { continue } isD := info.IsDir() if !isD && info.Mode()&os.ModeSymlink != 0 { if st, err := os.Stat(filepath.Join(dir, name)); err == nil { isD, info = st.IsDir(), st } } if !isD && !showAll { ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(name), ".")) if !slices.Contains(mediaExts, ext) { continue } } entries = append(entries, fsEntry{Name: name, Path: filepath.Join(dir, name), Dir: isD, Size: info.Size(), Mod: info.ModTime().Unix()}) } sort.Slice(entries, func(i, j int) bool { if entries[i].Dir != entries[j].Dir { return entries[i].Dir } return strings.ToLower(entries[i].Name) < strings.ToLower(entries[j].Name) }) parent := filepath.Dir(dir) if parent == dir { parent = "" } writeJSON(w, map[string]any{ "path": dir, "parent": parent, "entries": entries, "roots": listRoots(), "home": home, }) } func isDir(p string) bool { st, err := os.Stat(p) return err == nil && st.IsDir() }