1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
package importer
import (
"log"
"os"
"adammathes.com/neko/models/feed"
"github.com/gilliek/go-opml/opml"
)
// ImportOPML imports feeds from an OPML file.
func ImportOPML(filename string) {
log.Printf("Importing OPML file: %s", filename)
// Step 2: Open the file specified by filename.
// Note: opml.NewOPMLFromFile handles file opening internally.
// So, we directly use it.
// Step 3: Parse the OPML data from the opened file.
opmlDoc, err := opml.NewOPMLFromFile(filename)
if err != nil {
log.Println("Error parsing OPML file:", err)
return
}
if opmlDoc.Body == nil {
log.Println("OPML body is nil, no outlines to process.")
return
}
// Step 4: Iterate through opmlDoc.Body.Outlines recursively.
processOutlines(opmlDoc.Body.Outlines)
}
// processOutlines is a helper function to recursively traverse OPML outlines.
func processOutlines(outlines []opml.Outline) {
for _, outline := range outlines {
// Step 5a: Check if outline.XMLURL is not empty.
if outline.XMLURL == "" {
log.Printf("Skipping outline with empty XMLURL (likely a category): %s", getTitle(outline))
// Recursively process children if any, even if it's a category
if len(outline.Outlines) > 0 {
processOutlines(outline.Outlines)
}
continue
}
// Step 5b: Create a feed.Feed object.
f := feed.Feed{}
// Step 5c: Set f.Url from outline.XMLURL.
f.Url = outline.XMLURL
// Step 5d: Set f.Title from outline.Title or outline.Text.
if outline.Title != "" {
f.Title = outline.Title
} else if outline.Text != "" {
f.Title = outline.Text
} else {
// Fallback if both Title and Text are empty
f.Title = "Untitled Feed"
log.Printf("Feed with URL %s has no Title or Text, using default 'Untitled Feed'", f.Url)
}
// Step 5e: Set f.WebUrl from outline.HTMLURL.
f.WebUrl = outline.HTMLURL // HTMLURL can be empty, which is fine.
// Step 5f: Check if a feed with f.Url already exists.
existingFeed, err := f.ByUrl(f.Url)
if err != nil {
// Step 5g: If the feed does not exist (error is not nil), then call f.Create().
// Assuming error means not found. A more specific error check might be needed
// depending on the actual behavior of f.ByUrl (e.g., if it returns a specific error type for "not found").
log.Printf("Feed with URL %s not found, creating new entry: %s", f.Url, f.Title)
if createErr := f.Create(); createErr != nil {
log.Println("Error creating feed:", createErr)
} else {
log.Printf("Successfully added feed: %s (%s)", f.Title, f.Url)
}
} else if existingFeed != nil && existingFeed.Id > 0 { // Check if a valid feed was returned
// Step 5h: If the feed already exists, log that it's being skipped.
log.Printf("Feed already exists, skipping: %s (%s)", existingFeed.Title, existingFeed.Url)
} else {
// This case could occur if f.ByUrl returns (nil, nil) or an error that isn't truly "not found"
// but also doesn't return an existing feed. Treat as "not found" for robustness.
log.Printf("Feed with URL %s not found (or ambiguous check), creating new entry: %s", f.Url, f.Title)
if createErr := f.Create(); createErr != nil {
log.Println("Error creating feed:", createErr)
} else {
log.Printf("Successfully added feed: %s (%s)", f.Title, f.Url)
}
}
// Recursively process children if any (feeds can be nested within other feeds in OPML)
if len(outline.Outlines) > 0 {
processOutlines(outline.Outlines)
}
}
}
// getTitle is a helper to get a display title for an outline,
// preferring Title, then Text. Used for logging categories.
func getTitle(outline opml.Outline) string {
if outline.Title != "" {
return outline.Title
}
if outline.Text != "" {
return outline.Text
}
return "[No Title/Text]"
}
|