aboutsummaryrefslogtreecommitdiffstats
path: root/importer/importer.go
blob: 10a0a667e81a567e7d2388f26b077cc618c1d124 (plain) (blame)
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]"
}