diff --git a/doc/changelog.txt b/doc/changelog.txt index a4a1b48..f4dd73a 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,3 +1,7 @@ +# upcoming + +- (fix) handle opml files not following the spec (thanks to @huangnauh for the report) + # v2.0 (2021-04-18) - (new) user interface tweaks diff --git a/src/server/opml/read.go b/src/server/opml/read.go index 1ea1f4d..cebb6db 100644 --- a/src/server/opml/read.go +++ b/src/server/opml/read.go @@ -13,6 +13,7 @@ type opml struct { type outline struct { Type string `xml:"type,attr,omitempty"` Title string `xml:"text,attr"` + Title2 string `xml:"title,attr,omitempty"` FeedUrl string `xml:"xmlUrl,attr,omitempty"` SiteUrl string `xml:"htmlUrl,attr,omitempty"` Outlines []outline `xml:"outline,omitempty"` @@ -21,14 +22,18 @@ type outline struct { func buildFolder(title string, outlines []outline) Folder { folder := Folder{Title: title} for _, outline := range outlines { - if outline.Type == "rss" { + if outline.Type == "rss" || outline.FeedUrl != "" { folder.Feeds = append(folder.Feeds, Feed{ Title: outline.Title, FeedUrl: outline.FeedUrl, SiteUrl: outline.SiteUrl, }) } else { - subfolder := buildFolder(outline.Title, outline.Outlines) + title := outline.Title + if title == "" { + title = outline.Title2 + } + subfolder := buildFolder(title, outline.Outlines) folder.Folders = append(folder.Folders, subfolder) } } diff --git a/src/server/opml/read_test.go b/src/server/opml/read_test.go index 93ce9cd..5f6b7c2 100644 --- a/src/server/opml/read_test.go +++ b/src/server/opml/read_test.go @@ -56,3 +56,34 @@ func TestParse(t *testing.T) { t.Fatal("invalid opml") } } + +func TestParseFallback(t *testing.T) { + // as reported in https://github.com/nkanaev/yarr/pull/56 + // the feed below comes without `outline[text]` & `outline[type=rss]` attributes + have, _ := Parse(strings.NewReader(` + + + + Newsflow + + + + + + + + `)) + want := Folder{ + Folders: []Folder{{ + Title: "foldertitle", + Feeds: []Feed{ + {Title: "feedtext", FeedUrl: "https://example.com/feed.xml", SiteUrl: "https://example.com"}, + }, + }}, + } + if !reflect.DeepEqual(want, have) { + t.Logf("want: %#v", want) + t.Logf("have: %#v", have) + t.Fatal("invalid opml") + } +}