func parseRSS(c appengine.Context, body []byte, charsetReader func(string, io.Reader) (io.Reader, error)) (*Feed, []*Story, error) { var f Feed var s []*Story r := rss.Rss{} d := xml.NewDecoder(bytes.NewReader(body)) d.CharsetReader = charsetReader d.DefaultSpace = "DefaultSpace" if err := d.Decode(&r); err != nil { return nil, nil, err } f.Title = r.Title if t, err := parseDate(c, &f, r.LastBuildDate, r.PubDate); err == nil { f.Updated = t } else { c.Warningf("no rss feed date: %v", f.Link) } f.Link = r.BaseLink() f.Hub = r.Hub() for _, i := range r.Items { st := Story{ Link: i.Link, Author: i.Author, } if i.Content != "" { st.content = i.Content } else if i.Description != "" { st.content = i.Description } if i.Title != "" { st.Title = i.Title } else if i.Description != "" { st.Title = i.Description } if st.content == st.Title { st.Title = "" } st.Title = textTitle(st.Title) if i.Guid != nil { st.Id = i.Guid.Guid } if i.Enclosure != nil && strings.HasPrefix(i.Enclosure.Type, "audio/") { st.MediaContent = i.Enclosure.Url } else if i.Media != nil && strings.HasPrefix(i.Media.Type, "audio/") { st.MediaContent = i.Media.URL } if t, err := parseDate(c, &f, i.PubDate, i.Date, i.Published); err == nil { st.Published = t st.Updated = t } s = append(s, &st) } return &f, s, nil }
// makeOpf creates an epub opf for the specified rss feed. func (e FeedEpub) makeOpf(rssFeed rss.Rss) (epub.Opf, []epub.Chapter, error) { if len(rssFeed.Items) == 0 { return epub.Opf{}, nil, errors.New("No feed items to build") } ids := []epub.Identifier{ {Value: rssFeed.BaseLink(), IdentifierType: codelist5.URN}} creator := epub.Creator{ Name: rssFeed.Items[0].Author, Role: "aut", } metadata := epub.Metadata{ Language: "en", // maybe, lol! Title: rssFeed.Title, Creator: creator, Date: rssFeed.LastBuildDate, } var manifestItems []epub.ManifestItem var chapters []epub.Chapter // TODO: This is a totally naive build of file names that may be non-unique. for i, item := range rssFeed.Items { var manifestItem epub.ManifestItem var chapter epub.Chapter // TODO: in a better world this would be generated by sanitized filename manifestItem.Id = fmt.Sprintf("manifest_id_%d", i) filename := "chapters/" + item.Title + ".xhtml" manifestItem.Href = filename manifestItem.Title = &item.Title chapter.FileName = filename // TODO: we should fetch all the assets used in each rss item and put them in the // epub in an assets directory, then rewrite the paths to each asset. At the // very least we should rewrite relative urls to actually point to the feed. chapter.Contents = item.Description manifestItem.MediaType = xhtmlMediaType manifestItems = append(manifestItems, manifestItem) chapters = append(chapters, chapter) } manifest := epub.Manifest{ ManifestItems: manifestItems, } opfRootFile := epub.OpfRootFile{ FullPath: fmt.Sprintf("OEBPS/%s.opf", rssFeed.Title), MediaType: "application/oebps-package+xml", Identifiers: ids, Metadata: metadata, Manifest: manifest, } opf := epub.Opf{ RootFiles: []epub.OpfRootFile{opfRootFile}, } return opf, chapters, nil }