From 9a68591255747c82fd4ce99351bca6d43349cafa Mon Sep 17 00:00:00 2001 From: tjpcc Date: Sun, 3 Sep 2023 19:58:18 -0600 Subject: implement gophernicus extensions for gophermaps --- gopher/gophermap/listdir.go | 154 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 gopher/gophermap/listdir.go (limited to 'gopher/gophermap/listdir.go') diff --git a/gopher/gophermap/listdir.go b/gopher/gophermap/listdir.go new file mode 100644 index 0000000..8d66277 --- /dev/null +++ b/gopher/gophermap/listdir.go @@ -0,0 +1,154 @@ +package gophermap + +import ( + "bufio" + "net/url" + "os" + "path" + "path/filepath" + "strings" + + "tildegit.org/tjp/sliderule/gopher" + "tildegit.org/tjp/sliderule/internal/types" +) + +// ListDir builds a gopher menu representing the contents of a directory. +func ListDir(dir string, location *url.URL) (gopher.MapDocument, error) { + return listDir(dir, location, nil, nil) +} + +func listDir(dir string, location *url.URL, hidden map[string]struct{}, extensions map[string]types.Status) (gopher.MapDocument, error) { + contents, err := os.ReadDir(dir) + if err != nil { + return nil, err + } + + doc := gopher.MapDocument{} + + for _, entry := range contents { + name := entry.Name() + + if _, ok := hidden[name]; ok || name == "gophermap" { + continue + } + + var code types.Status + + ext := strings.TrimPrefix(filepath.Ext(name), ".") + if entry.IsDir() { + code = gopher.MenuType + } else if c, ok := extensions[ext]; ok && ext != "" { + code = c + } else { + switch ext { + case "gophermap": + code = gopher.MenuType + case "exe", "bin", "out": + code = gopher.BinaryFileType + case "gif": + code = gopher.GifFileType + case "jpg", "jpeg", "tif", "tiff": + code = gopher.ImageFileType + case "bmp": + code = gopher.BitmapType + case "mp4", "mov", "avi", "wmv", "webm": + code = gopher.MovieFileType + case "pcm", "aiff", "mp3", "aac", "ogg", "wma", "flac", "alac": + code = gopher.SoundFileType + case "doc", "docx", "odt", "fodt": + code = gopher.DocumentType + case "html": + code = gopher.HTMLType + case "png": + code = gopher.PngImageFileType + case "rtf": + code = gopher.RtfDocumentType + case "wav": + code = gopher.WavSoundFileType + case "pdf": + code = gopher.PdfDocumentType + case "xml", "atom": + code = gopher.XmlDocumentType + default: + code = gopher.TextFileType + } + } + + doc = append(doc, gopher.MapItem{ + Type: code, + Display: displayName(dir, entry), + Selector: path.Join(path.Dir(location.Path), name), + Hostname: location.Hostname(), + Port: location.Port(), + }) + } + + return doc, nil +} + +func displayName(dir string, entry os.DirEntry) string { + fname := entry.Name() + + // if is a gophermap, use !title or filename + if strings.HasSuffix(fname, ".gophermap") { + if title := gophermapTitle(dir, fname); title != "" { + return title + } + return fname + } + + if entry.IsDir() { + if tag := tagTitle(dir, fname); tag != "" { + return tag + } + + if title := gophermapTitle(dir, filepath.Join(fname, "gophermap")); title != "" { + return title + } + } + + return fname +} + +func gophermapTitle(dir, name string) string { + file, err := os.Open(filepath.Join(dir, name)) + if err != nil { + return "" + } + defer func() { + _ = file.Close() + }() + + rdr := bufio.NewReader(file) + line, err := rdr.ReadString('\n') + if err != nil { + return "" + } + + if !strings.HasPrefix(line, "!") { + return "" + } + return strings.TrimRight(line[1:], "\r\n") +} + +func tagTitle(parent, name string) string { + file, err := os.Open(filepath.Join(parent, name, "gophertag")) + if err != nil { + return "" + } + defer func() { + _ = file.Close() + }() + + stat, err := file.Stat() + if err != nil || stat.IsDir() { + return "" + } + + rdr := bufio.NewReader(file) + line, err := rdr.ReadString('\n') + if err != nil { + return "" + } + return strings.TrimRight(line, "\r\n") +} -- cgit v1.2.3