diff options
Diffstat (limited to 'internal/image/download_policy.go')
| -rw-r--r-- | internal/image/download_policy.go | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/internal/image/download_policy.go b/internal/image/download_policy.go new file mode 100644 index 0000000..b62e011 --- /dev/null +++ b/internal/image/download_policy.go @@ -0,0 +1,102 @@ +package image + +import ( + "fmt" + "path/filepath" + "strings" +) + +type downloadPathPolicy struct { + options *DownloadOptions +} + +func newDownloadPathPolicy(options *DownloadOptions) downloadPathPolicy { + return downloadPathPolicy{options: options} +} + +func (p downloadPathPolicy) generateFileName(word string, result *SearchResult, index int) string { + filename := "" + if p.options != nil { + filename = p.options.FileNamePattern + } + if filename == "" { + filename = "{word}_{source}" + } + + filename = strings.ReplaceAll(filename, "{word}", sanitizeFileName(word)) + if result != nil { + filename = strings.ReplaceAll(filename, "{source}", sanitizeFileName(result.Source)) + filename = strings.ReplaceAll(filename, "{id}", sanitizeFileName(result.ID)) + } + filename = strings.ReplaceAll(filename, "{index}", fmt.Sprintf("%d", index)) + + ext := "" + if result != nil { + ext = filepath.Ext(result.URL) + if strings.HasPrefix(result.URL, geminiDataPrefix) { + ext = ".png" + } else if ext == "" || len(ext) > 5 { + ext = ".jpg" + } + } + + if filepath.Ext(filename) == "" { + filename += ext + } + + return filename +} + +func (p downloadPathPolicy) resolveOutputPath(name string) (string, error) { + baseDir := "./images" + if p.options != nil && p.options.OutputDir != "" { + baseDir = p.options.OutputDir + } + + if strings.TrimSpace(baseDir) == "" { + baseDir = "." + } + + cleanBase, err := filepath.Abs(baseDir) + if err != nil { + return "", fmt.Errorf("resolve base dir: %w", err) + } + + fullPath, err := filepath.Abs(filepath.Join(cleanBase, name)) + if err != nil { + return "", fmt.Errorf("resolve output path: %w", err) + } + + rel, err := filepath.Rel(cleanBase, fullPath) + if err != nil { + return "", fmt.Errorf("relativize output path: %w", err) + } + if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) { + return "", fmt.Errorf("path escapes base dir") + } + + return fullPath, nil +} + +func sanitizeFileName(name string) string { + replacer := strings.NewReplacer( + "/", "_", + "\\", "_", + ":", "_", + "*", "_", + "?", "_", + "\"", "_", + "<", "_", + ">", "_", + "|", "_", + " ", "_", + ".", "_", + ) + + sanitized := replacer.Replace(name) + if len(sanitized) > 50 { + sanitized = sanitized[:50] + } + + return sanitized +} |
