summaryrefslogtreecommitdiff
path: root/internal/image/download_policy.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/image/download_policy.go')
-rw-r--r--internal/image/download_policy.go102
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
+}