|
8 | 8 | "fmt" |
9 | 9 | "io" |
10 | 10 | "net/http" |
| 11 | + "net/url" |
11 | 12 | "os" |
12 | 13 | "path/filepath" |
13 | 14 | "regexp" |
@@ -388,17 +389,18 @@ func processPDFForUser(jobID string, form map[string]string, userID uuid.UUID) ( |
388 | 389 | return "backend.status.no_url", nil, fmt.Errorf("no URL") |
389 | 390 | } |
390 | 391 |
|
391 | | - // Check if this is a direct PDF/EPUB URL or a web article |
392 | | - lowerURL := strings.ToLower(match) |
393 | | - if strings.HasSuffix(lowerURL, ".pdf") || strings.HasSuffix(lowerURL, ".epub") { |
| 392 | + // Detect content type from URL path extension or HTTP sniffing |
| 393 | + contentType := detectURLContentType(match) |
| 394 | + |
| 395 | + if contentType == "application/pdf" || contentType == "application/epub+zip" { |
394 | 396 | // Direct download of PDF/EPUB |
395 | 397 | manager.Logf("DownloadPDF: tmp=true, prefix=%q", prefix) |
396 | 398 | jobStore.UpdateWithOperation(jobID, "Running", "backend.status.downloading", nil, "downloading") |
397 | 399 | localPath, err = downloader.DownloadPDFForUser(match, true, prefix, userID, nil) |
398 | 400 | if err != nil { |
399 | 401 | return "backend.status.download_error", nil, err |
400 | 402 | } |
401 | | - } else if strings.HasSuffix(lowerURL, ".md") || strings.HasSuffix(lowerURL, ".markdown") { |
| 403 | + } else if contentType == "text/markdown" || contentType == "text/plain" { |
402 | 404 | // Markdown URL - fetch raw content and convert |
403 | 405 | manager.Logf("Fetching markdown from URL: %s", match) |
404 | 406 | jobStore.UpdateWithOperation(jobID, "Running", "backend.status.fetching_url", nil, "fetching") |
@@ -1127,6 +1129,28 @@ func isURL(s string) bool { |
1127 | 1129 | return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://") |
1128 | 1130 | } |
1129 | 1131 |
|
| 1132 | +// detectURLContentType determines content type for a URL. |
| 1133 | +// First checks URL path extension (fast), then falls back to HTTP sniffing. |
| 1134 | +func detectURLContentType(urlStr string) string { |
| 1135 | + if parsedURL, err := url.Parse(urlStr); err == nil { |
| 1136 | + ext := strings.ToLower(filepath.Ext(parsedURL.Path)) |
| 1137 | + switch ext { |
| 1138 | + case ".pdf": |
| 1139 | + return "application/pdf" |
| 1140 | + case ".epub": |
| 1141 | + return "application/epub+zip" |
| 1142 | + case ".md", ".markdown": |
| 1143 | + return "text/markdown" |
| 1144 | + } |
| 1145 | + } |
| 1146 | + |
| 1147 | + if mime, err := downloader.SniffMime(urlStr); err == nil { |
| 1148 | + return mime |
| 1149 | + } |
| 1150 | + |
| 1151 | + return "text/html" |
| 1152 | +} |
| 1153 | + |
1130 | 1154 | // trackDocumentUpload records a document upload in the database |
1131 | 1155 | func trackDocumentUpload(userID uuid.UUID, localPath, remoteName, rmDir string) error { |
1132 | 1156 | if database.DB == nil { |
|
0 commit comments