package rss import ( "bytes" "encoding/xml" "fmt" "time" ) func parseAtom(data []byte) (*Feed, error) { warnings := false feed := atomFeed{} p := xml.NewDecoder(bytes.NewReader(data)) p.CharsetReader = charsetReader err := p.Decode(&feed) if err != nil { return nil, err } out := new(Feed) out.Title = feed.Title out.Description = feed.Description for _, link := range feed.Link { if link.Rel == "alternate" || link.Rel == "" { out.Link = link.Href } if link.Rel == "hub" { out.HubURL = link.Href } } out.Image = feed.Image.Image() out.Refresh = time.Now().Add(10 * time.Minute) out.Items = make([]*Item, 0, len(feed.Items)) out.ItemMap = make(map[string]struct{}) // Process items. for _, item := range feed.Items { // Skip items already known. if _, ok := out.ItemMap[item.ID]; ok { continue } next := new(Item) next.Title = item.Title next.Summary = item.Summary next.Content = item.Content if item.Date != "" { next.Date, err = parseTime(item.Date) if err == nil { item.DateValid = true } } next.ID = item.ID for _, link := range item.Links { if link.Rel == "alternate" || link.Rel == "" { next.Link = link.Href } else { next.Enclosures = append(next.Enclosures, &Enclosure{ URL: link.Href, Type: link.Type, Length: link.Length, }) } } next.Read = false if next.ID == "" { if debug { fmt.Printf("[w] Item %q has no ID and will be ignored.\n", next.Title) fmt.Printf("[w] %#v\n", item) } warnings = true continue } if _, ok := out.ItemMap[next.ID]; ok { if debug { fmt.Printf("[w] Item %q has duplicate ID.\n", next.Title) fmt.Printf("[w] %#v\n", next) } warnings = true continue } out.Items = append(out.Items, next) out.ItemMap[next.ID] = struct{}{} out.Unread++ } if warnings && debug { fmt.Printf("[i] Encountered warnings:\n%s\n", data) } return out, nil } // RAWContent is the innerxml type RAWContent struct { RAWContent string `xml:",innerxml"` } type atomFeed struct { XMLName xml.Name `xml:"feed"` Title string `xml:"title"` Description string `xml:"subtitle"` Link []atomLink `xml:"link"` Image atomImage `xml:"image"` Items []atomItem `xml:"entry"` Updated string `xml:"updated"` } type atomItem struct { XMLName xml.Name `xml:"entry"` Title string `xml:"title"` Summary string `xml:"summary"` Content string `xml:"content"` Links []atomLink `xml:"link"` Date string `xml:"updated"` DateValid bool ID string `xml:"id"` } type atomImage struct { XMLName xml.Name `xml:"image"` Title string `xml:"title"` URL string `xml:"url"` Height int `xml:"height"` Width int `xml:"width"` } type atomLink struct { Href string `xml:"href,attr"` Rel string `xml:"rel,attr"` Type string `xml:"type,attr"` Length uint `xml:"length,attr"` } func (a *atomImage) Image() *Image { out := new(Image) out.Title = a.Title out.URL = a.URL out.Height = uint32(a.Height) out.Width = uint32(a.Width) return out }