package files import ( "bytes" "net/http" "path/filepath" "strings" ) type PreviewResult struct { Type string `json:"type"` Content string `json:"content,omitempty"` Mime string `json:"mime"` Size int64 `json:"size"` } var textMimes = map[string]bool{ "text/plain": true, "text/html": true, "text/css": true, "text/javascript": true, "application/json": true, "application/xml": true, "application/xhtml+xml": true, "application/javascript": true, } var imageMimes = map[string]bool{ "image/png": true, "image/jpeg": true, "image/gif": true, "image/webp": true, "image/svg+xml": true, "image/bmp": true, "image/tiff": true, } func Preview(path string, max int64, allowedRoots []string) (*PreviewResult, error) { data, err := ReadFile(path, max, allowedRoots) if err != nil { return nil, err } mime := http.DetectContentType(data) size := int64(len(data)) trimmed := bytes.TrimSpace(data) if len(trimmed) > 0 { mime = http.DetectContentType(trimmed) } result := &PreviewResult{ Mime: mime, Size: size, } if imageMimes[mime] || strings.HasPrefix(mime, "image/") { result.Type = "image" return result, nil } if textMimes[mime] || strings.HasPrefix(mime, "text/") || isLikelyText(trimmed) { result.Type = "text" if size > 0 { result.Content = string(data) if int64(len(result.Content)) > max { result.Content = result.Content[:max] } } return result, nil } result.Type = "binary" return result, nil } func isLikelyText(data []byte) bool { if len(data) == 0 { return false } nulls := 0 for _, b := range data { gb := int(b) if (gb < 32 && gb != 9 && gb != 10 && gb != 13) || gb == 127 { nulls++ } } return float64(nulls)/float64(len(data)) < 0.1 } func ExtensionIcon(name string) string { ext := strings.ToLower(filepath.Ext(name)) switch ext { case ".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".bmp", ".ico": return "image" case ".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv", ".webm": return "video" case ".mp3", ".wav", ".ogg", ".flac", ".aac", ".wma": return "audio" case ".zip", ".tar", ".gz", ".bz2", ".xz", ".rar", ".7z": return "archive" case ".pdf": return "pdf" case ".doc", ".docx", ".odt", ".rtf": return "word" case ".xls", ".xlsx", ".csv", ".ods": return "spreadsheet" case ".txt", ".md", ".log", ".cfg", ".conf", ".ini", ".yaml", ".yml", ".toml", ".json", ".xml": return "text" default: return "file" } }