2019-02-20 20:23:48 +01:00
package gofeed
import (
"fmt"
"strings"
"time"
"github.com/mmcdole/gofeed/atom"
2020-05-14 16:07:09 +02:00
ext "github.com/mmcdole/gofeed/extensions"
2019-02-20 20:23:48 +01:00
"github.com/mmcdole/gofeed/internal/shared"
2020-10-24 12:37:32 +02:00
"github.com/mmcdole/gofeed/json"
2019-02-20 20:23:48 +01:00
"github.com/mmcdole/gofeed/rss"
)
2020-10-24 12:37:32 +02:00
// Translator converts a particular feed (atom.Feed or rss.Feed of json.Feed)
2019-02-20 20:23:48 +01:00
// into the generic Feed struct
type Translator interface {
Translate ( feed interface { } ) ( * Feed , error )
}
// DefaultRSSTranslator converts an rss.Feed struct
// into the generic Feed struct.
//
// This default implementation defines a set of
// mapping rules between rss.Feed -> Feed
// for each of the fields in Feed.
type DefaultRSSTranslator struct { }
// Translate converts an RSS feed into the universal
// feed type.
func ( t * DefaultRSSTranslator ) Translate ( feed interface { } ) ( * Feed , error ) {
rss , found := feed . ( * rss . Feed )
if ! found {
return nil , fmt . Errorf ( "Feed did not match expected type of *rss.Feed" )
}
result := & Feed { }
result . Title = t . translateFeedTitle ( rss )
result . Description = t . translateFeedDescription ( rss )
result . Link = t . translateFeedLink ( rss )
result . FeedLink = t . translateFeedFeedLink ( rss )
2021-12-13 10:35:45 +01:00
result . Links = t . translateFeedLinks ( rss )
2019-02-20 20:23:48 +01:00
result . Updated = t . translateFeedUpdated ( rss )
result . UpdatedParsed = t . translateFeedUpdatedParsed ( rss )
result . Published = t . translateFeedPublished ( rss )
result . PublishedParsed = t . translateFeedPublishedParsed ( rss )
result . Author = t . translateFeedAuthor ( rss )
2021-12-13 10:35:45 +01:00
result . Authors = t . translateFeedAuthors ( rss )
2019-02-20 20:23:48 +01:00
result . Language = t . translateFeedLanguage ( rss )
result . Image = t . translateFeedImage ( rss )
result . Copyright = t . translateFeedCopyright ( rss )
result . Generator = t . translateFeedGenerator ( rss )
result . Categories = t . translateFeedCategories ( rss )
result . Items = t . translateFeedItems ( rss )
result . ITunesExt = rss . ITunesExt
result . DublinCoreExt = rss . DublinCoreExt
result . Extensions = rss . Extensions
result . FeedVersion = rss . Version
result . FeedType = "rss"
return result , nil
}
func ( t * DefaultRSSTranslator ) translateFeedItem ( rssItem * rss . Item ) ( item * Item ) {
item = & Item { }
item . Title = t . translateItemTitle ( rssItem )
item . Description = t . translateItemDescription ( rssItem )
item . Content = t . translateItemContent ( rssItem )
item . Link = t . translateItemLink ( rssItem )
2021-12-13 10:35:45 +01:00
item . Links = t . translateItemLinks ( rssItem )
2019-02-20 20:23:48 +01:00
item . Published = t . translateItemPublished ( rssItem )
item . PublishedParsed = t . translateItemPublishedParsed ( rssItem )
item . Author = t . translateItemAuthor ( rssItem )
2021-12-13 10:35:45 +01:00
item . Authors = t . translateItemAuthors ( rssItem )
2019-02-20 20:23:48 +01:00
item . GUID = t . translateItemGUID ( rssItem )
item . Image = t . translateItemImage ( rssItem )
item . Categories = t . translateItemCategories ( rssItem )
item . Enclosures = t . translateItemEnclosures ( rssItem )
item . DublinCoreExt = rssItem . DublinCoreExt
item . ITunesExt = rssItem . ITunesExt
item . Extensions = rssItem . Extensions
2021-12-13 10:35:45 +01:00
item . Custom = rssItem . Custom
2019-02-20 20:23:48 +01:00
return
}
func ( t * DefaultRSSTranslator ) translateFeedTitle ( rss * rss . Feed ) ( title string ) {
if rss . Title != "" {
title = rss . Title
} else if rss . DublinCoreExt != nil && rss . DublinCoreExt . Title != nil {
title = t . firstEntry ( rss . DublinCoreExt . Title )
}
return
}
func ( t * DefaultRSSTranslator ) translateFeedDescription ( rss * rss . Feed ) ( desc string ) {
return rss . Description
}
func ( t * DefaultRSSTranslator ) translateFeedLink ( rss * rss . Feed ) ( link string ) {
if rss . Link != "" {
link = rss . Link
} else if rss . ITunesExt != nil && rss . ITunesExt . Subtitle != "" {
link = rss . ITunesExt . Subtitle
}
return
}
func ( t * DefaultRSSTranslator ) translateFeedFeedLink ( rss * rss . Feed ) ( link string ) {
atomExtensions := t . extensionsForKeys ( [ ] string { "atom" , "atom10" , "atom03" } , rss . Extensions )
for _ , ex := range atomExtensions {
if links , ok := ex [ "link" ] ; ok {
for _ , l := range links {
2020-05-14 16:07:09 +02:00
if l . Attrs [ "rel" ] == "self" {
link = l . Attrs [ "href" ]
2019-02-20 20:23:48 +01:00
}
}
}
}
return
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultRSSTranslator ) translateFeedLinks ( rss * rss . Feed ) ( links [ ] string ) {
if rss . Link != "" {
links = append ( links , rss . Link )
}
if rss . ITunesExt != nil && rss . ITunesExt . Subtitle != "" {
links = append ( links , rss . ITunesExt . Subtitle )
}
atomExtensions := t . extensionsForKeys ( [ ] string { "atom" , "atom10" , "atom03" } , rss . Extensions )
for _ , ex := range atomExtensions {
if lks , ok := ex [ "link" ] ; ok {
for _ , l := range lks {
if l . Attrs [ "rel" ] == "" || l . Attrs [ "rel" ] == "alternate" || l . Attrs [ "rel" ] == "self" {
links = append ( links , l . Attrs [ "href" ] )
}
}
}
}
return
}
2019-02-20 20:23:48 +01:00
func ( t * DefaultRSSTranslator ) translateFeedUpdated ( rss * rss . Feed ) ( updated string ) {
if rss . LastBuildDate != "" {
updated = rss . LastBuildDate
} else if rss . DublinCoreExt != nil && rss . DublinCoreExt . Date != nil {
updated = t . firstEntry ( rss . DublinCoreExt . Date )
}
return
}
func ( t * DefaultRSSTranslator ) translateFeedUpdatedParsed ( rss * rss . Feed ) ( updated * time . Time ) {
if rss . LastBuildDateParsed != nil {
updated = rss . LastBuildDateParsed
} else if rss . DublinCoreExt != nil && rss . DublinCoreExt . Date != nil {
dateText := t . firstEntry ( rss . DublinCoreExt . Date )
date , err := shared . ParseDate ( dateText )
if err == nil {
updated = & date
}
}
return
}
func ( t * DefaultRSSTranslator ) translateFeedPublished ( rss * rss . Feed ) ( published string ) {
return rss . PubDate
}
func ( t * DefaultRSSTranslator ) translateFeedPublishedParsed ( rss * rss . Feed ) ( published * time . Time ) {
return rss . PubDateParsed
}
func ( t * DefaultRSSTranslator ) translateFeedAuthor ( rss * rss . Feed ) ( author * Person ) {
if rss . ManagingEditor != "" {
name , address := shared . ParseNameAddress ( rss . ManagingEditor )
author = & Person { }
author . Name = name
author . Email = address
} else if rss . WebMaster != "" {
name , address := shared . ParseNameAddress ( rss . WebMaster )
author = & Person { }
author . Name = name
author . Email = address
} else if rss . DublinCoreExt != nil && rss . DublinCoreExt . Author != nil {
dcAuthor := t . firstEntry ( rss . DublinCoreExt . Author )
name , address := shared . ParseNameAddress ( dcAuthor )
author = & Person { }
author . Name = name
author . Email = address
} else if rss . DublinCoreExt != nil && rss . DublinCoreExt . Creator != nil {
dcCreator := t . firstEntry ( rss . DublinCoreExt . Creator )
name , address := shared . ParseNameAddress ( dcCreator )
author = & Person { }
author . Name = name
author . Email = address
} else if rss . ITunesExt != nil && rss . ITunesExt . Author != "" {
name , address := shared . ParseNameAddress ( rss . ITunesExt . Author )
author = & Person { }
author . Name = name
author . Email = address
}
return
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultRSSTranslator ) translateFeedAuthors ( rss * rss . Feed ) ( authors [ ] * Person ) {
if author := t . translateFeedAuthor ( rss ) ; author != nil {
authors = [ ] * Person { author }
}
return
}
2019-02-20 20:23:48 +01:00
func ( t * DefaultRSSTranslator ) translateFeedLanguage ( rss * rss . Feed ) ( language string ) {
if rss . Language != "" {
language = rss . Language
} else if rss . DublinCoreExt != nil && rss . DublinCoreExt . Language != nil {
language = t . firstEntry ( rss . DublinCoreExt . Language )
}
return
}
func ( t * DefaultRSSTranslator ) translateFeedImage ( rss * rss . Feed ) ( image * Image ) {
if rss . Image != nil {
image = & Image { }
image . Title = rss . Image . Title
image . URL = rss . Image . URL
} else if rss . ITunesExt != nil && rss . ITunesExt . Image != "" {
image = & Image { }
image . URL = rss . ITunesExt . Image
}
return
}
func ( t * DefaultRSSTranslator ) translateFeedCopyright ( rss * rss . Feed ) ( rights string ) {
if rss . Copyright != "" {
rights = rss . Copyright
} else if rss . DublinCoreExt != nil && rss . DublinCoreExt . Rights != nil {
rights = t . firstEntry ( rss . DublinCoreExt . Rights )
}
return
}
func ( t * DefaultRSSTranslator ) translateFeedGenerator ( rss * rss . Feed ) ( generator string ) {
return rss . Generator
}
func ( t * DefaultRSSTranslator ) translateFeedCategories ( rss * rss . Feed ) ( categories [ ] string ) {
cats := [ ] string { }
if rss . Categories != nil {
for _ , c := range rss . Categories {
cats = append ( cats , c . Value )
}
}
if rss . ITunesExt != nil && rss . ITunesExt . Keywords != "" {
keywords := strings . Split ( rss . ITunesExt . Keywords , "," )
for _ , k := range keywords {
cats = append ( cats , k )
}
}
if rss . ITunesExt != nil && rss . ITunesExt . Categories != nil {
for _ , c := range rss . ITunesExt . Categories {
cats = append ( cats , c . Text )
if c . Subcategory != nil {
cats = append ( cats , c . Subcategory . Text )
}
}
}
if rss . DublinCoreExt != nil && rss . DublinCoreExt . Subject != nil {
for _ , c := range rss . DublinCoreExt . Subject {
cats = append ( cats , c )
}
}
if len ( cats ) > 0 {
categories = cats
}
return
}
func ( t * DefaultRSSTranslator ) translateFeedItems ( rss * rss . Feed ) ( items [ ] * Item ) {
items = [ ] * Item { }
for _ , i := range rss . Items {
items = append ( items , t . translateFeedItem ( i ) )
}
return
}
func ( t * DefaultRSSTranslator ) translateItemTitle ( rssItem * rss . Item ) ( title string ) {
if rssItem . Title != "" {
title = rssItem . Title
} else if rssItem . DublinCoreExt != nil && rssItem . DublinCoreExt . Title != nil {
title = t . firstEntry ( rssItem . DublinCoreExt . Title )
}
return
}
func ( t * DefaultRSSTranslator ) translateItemDescription ( rssItem * rss . Item ) ( desc string ) {
if rssItem . Description != "" {
desc = rssItem . Description
} else if rssItem . DublinCoreExt != nil && rssItem . DublinCoreExt . Description != nil {
desc = t . firstEntry ( rssItem . DublinCoreExt . Description )
}
return
}
func ( t * DefaultRSSTranslator ) translateItemContent ( rssItem * rss . Item ) ( content string ) {
return rssItem . Content
}
func ( t * DefaultRSSTranslator ) translateItemLink ( rssItem * rss . Item ) ( link string ) {
return rssItem . Link
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultRSSTranslator ) translateItemLinks ( rssItem * rss . Item ) ( links [ ] string ) {
if rssItem . Link == "" {
return nil
}
return [ ] string { rssItem . Link }
}
2019-02-20 20:23:48 +01:00
func ( t * DefaultRSSTranslator ) translateItemUpdated ( rssItem * rss . Item ) ( updated string ) {
if rssItem . DublinCoreExt != nil && rssItem . DublinCoreExt . Date != nil {
updated = t . firstEntry ( rssItem . DublinCoreExt . Date )
}
return updated
}
func ( t * DefaultRSSTranslator ) translateItemUpdatedParsed ( rssItem * rss . Item ) ( updated * time . Time ) {
if rssItem . DublinCoreExt != nil && rssItem . DublinCoreExt . Date != nil {
updatedText := t . firstEntry ( rssItem . DublinCoreExt . Date )
updatedDate , err := shared . ParseDate ( updatedText )
if err == nil {
updated = & updatedDate
}
}
return
}
func ( t * DefaultRSSTranslator ) translateItemPublished ( rssItem * rss . Item ) ( pubDate string ) {
if rssItem . PubDate != "" {
return rssItem . PubDate
} else if rssItem . DublinCoreExt != nil && rssItem . DublinCoreExt . Date != nil {
return t . firstEntry ( rssItem . DublinCoreExt . Date )
}
return
}
func ( t * DefaultRSSTranslator ) translateItemPublishedParsed ( rssItem * rss . Item ) ( pubDate * time . Time ) {
if rssItem . PubDateParsed != nil {
return rssItem . PubDateParsed
} else if rssItem . DublinCoreExt != nil && rssItem . DublinCoreExt . Date != nil {
pubDateText := t . firstEntry ( rssItem . DublinCoreExt . Date )
pubDateParsed , err := shared . ParseDate ( pubDateText )
if err == nil {
pubDate = & pubDateParsed
}
}
return
}
func ( t * DefaultRSSTranslator ) translateItemAuthor ( rssItem * rss . Item ) ( author * Person ) {
if rssItem . Author != "" {
name , address := shared . ParseNameAddress ( rssItem . Author )
author = & Person { }
author . Name = name
author . Email = address
} else if rssItem . DublinCoreExt != nil && rssItem . DublinCoreExt . Author != nil {
dcAuthor := t . firstEntry ( rssItem . DublinCoreExt . Author )
name , address := shared . ParseNameAddress ( dcAuthor )
author = & Person { }
author . Name = name
author . Email = address
} else if rssItem . DublinCoreExt != nil && rssItem . DublinCoreExt . Creator != nil {
dcCreator := t . firstEntry ( rssItem . DublinCoreExt . Creator )
name , address := shared . ParseNameAddress ( dcCreator )
author = & Person { }
author . Name = name
author . Email = address
} else if rssItem . ITunesExt != nil && rssItem . ITunesExt . Author != "" {
name , address := shared . ParseNameAddress ( rssItem . ITunesExt . Author )
author = & Person { }
author . Name = name
author . Email = address
}
return
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultRSSTranslator ) translateItemAuthors ( rssItem * rss . Item ) ( authors [ ] * Person ) {
if author := t . translateItemAuthor ( rssItem ) ; author != nil {
authors = [ ] * Person { author }
}
return
}
2019-02-20 20:23:48 +01:00
func ( t * DefaultRSSTranslator ) translateItemGUID ( rssItem * rss . Item ) ( guid string ) {
if rssItem . GUID != nil {
guid = rssItem . GUID . Value
}
return
}
func ( t * DefaultRSSTranslator ) translateItemImage ( rssItem * rss . Item ) ( image * Image ) {
if rssItem . ITunesExt != nil && rssItem . ITunesExt . Image != "" {
image = & Image { }
image . URL = rssItem . ITunesExt . Image
}
return
}
func ( t * DefaultRSSTranslator ) translateItemCategories ( rssItem * rss . Item ) ( categories [ ] string ) {
cats := [ ] string { }
if rssItem . Categories != nil {
for _ , c := range rssItem . Categories {
cats = append ( cats , c . Value )
}
}
if rssItem . ITunesExt != nil && rssItem . ITunesExt . Keywords != "" {
keywords := strings . Split ( rssItem . ITunesExt . Keywords , "," )
for _ , k := range keywords {
cats = append ( cats , k )
}
}
if rssItem . DublinCoreExt != nil && rssItem . DublinCoreExt . Subject != nil {
for _ , c := range rssItem . DublinCoreExt . Subject {
cats = append ( cats , c )
}
}
if len ( cats ) > 0 {
categories = cats
}
return
}
func ( t * DefaultRSSTranslator ) translateItemEnclosures ( rssItem * rss . Item ) ( enclosures [ ] * Enclosure ) {
if rssItem . Enclosure != nil {
e := & Enclosure { }
e . URL = rssItem . Enclosure . URL
e . Type = rssItem . Enclosure . Type
e . Length = rssItem . Enclosure . Length
enclosures = [ ] * Enclosure { e }
}
return
}
func ( t * DefaultRSSTranslator ) extensionsForKeys ( keys [ ] string , extensions ext . Extensions ) ( matches [ ] map [ string ] [ ] ext . Extension ) {
matches = [ ] map [ string ] [ ] ext . Extension { }
if extensions == nil {
return
}
for _ , key := range keys {
if match , ok := extensions [ key ] ; ok {
matches = append ( matches , match )
}
}
return
}
func ( t * DefaultRSSTranslator ) firstEntry ( entries [ ] string ) ( value string ) {
if entries == nil {
return
}
if len ( entries ) == 0 {
return
}
return entries [ 0 ]
}
// DefaultAtomTranslator converts an atom.Feed struct
// into the generic Feed struct.
//
// This default implementation defines a set of
// mapping rules between atom.Feed -> Feed
// for each of the fields in Feed.
type DefaultAtomTranslator struct { }
// Translate converts an Atom feed into the universal
// feed type.
func ( t * DefaultAtomTranslator ) Translate ( feed interface { } ) ( * Feed , error ) {
atom , found := feed . ( * atom . Feed )
if ! found {
return nil , fmt . Errorf ( "Feed did not match expected type of *atom.Feed" )
}
result := & Feed { }
result . Title = t . translateFeedTitle ( atom )
result . Description = t . translateFeedDescription ( atom )
result . Link = t . translateFeedLink ( atom )
result . FeedLink = t . translateFeedFeedLink ( atom )
2021-12-13 10:35:45 +01:00
result . Links = t . translateFeedLinks ( atom )
2019-02-20 20:23:48 +01:00
result . Updated = t . translateFeedUpdated ( atom )
result . UpdatedParsed = t . translateFeedUpdatedParsed ( atom )
result . Author = t . translateFeedAuthor ( atom )
2021-12-13 10:35:45 +01:00
result . Authors = t . translateFeedAuthors ( atom )
2019-02-20 20:23:48 +01:00
result . Language = t . translateFeedLanguage ( atom )
result . Image = t . translateFeedImage ( atom )
result . Copyright = t . translateFeedCopyright ( atom )
result . Categories = t . translateFeedCategories ( atom )
result . Generator = t . translateFeedGenerator ( atom )
result . Items = t . translateFeedItems ( atom )
result . Extensions = atom . Extensions
result . FeedVersion = atom . Version
result . FeedType = "atom"
return result , nil
}
func ( t * DefaultAtomTranslator ) translateFeedItem ( entry * atom . Entry ) ( item * Item ) {
item = & Item { }
item . Title = t . translateItemTitle ( entry )
item . Description = t . translateItemDescription ( entry )
item . Content = t . translateItemContent ( entry )
item . Link = t . translateItemLink ( entry )
2021-12-13 10:35:45 +01:00
item . Links = t . translateItemLinks ( entry )
2019-02-20 20:23:48 +01:00
item . Updated = t . translateItemUpdated ( entry )
item . UpdatedParsed = t . translateItemUpdatedParsed ( entry )
item . Published = t . translateItemPublished ( entry )
item . PublishedParsed = t . translateItemPublishedParsed ( entry )
item . Author = t . translateItemAuthor ( entry )
2021-12-13 10:35:45 +01:00
item . Authors = t . translateItemAuthors ( entry )
2019-02-20 20:23:48 +01:00
item . GUID = t . translateItemGUID ( entry )
item . Image = t . translateItemImage ( entry )
item . Categories = t . translateItemCategories ( entry )
item . Enclosures = t . translateItemEnclosures ( entry )
item . Extensions = entry . Extensions
return
}
func ( t * DefaultAtomTranslator ) translateFeedTitle ( atom * atom . Feed ) ( title string ) {
return atom . Title
}
func ( t * DefaultAtomTranslator ) translateFeedDescription ( atom * atom . Feed ) ( desc string ) {
return atom . Subtitle
}
func ( t * DefaultAtomTranslator ) translateFeedLink ( atom * atom . Feed ) ( link string ) {
l := t . firstLinkWithType ( "alternate" , atom . Links )
if l != nil {
link = l . Href
}
return
}
func ( t * DefaultAtomTranslator ) translateFeedFeedLink ( atom * atom . Feed ) ( link string ) {
feedLink := t . firstLinkWithType ( "self" , atom . Links )
if feedLink != nil {
link = feedLink . Href
}
return
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultAtomTranslator ) translateFeedLinks ( atom * atom . Feed ) ( links [ ] string ) {
for _ , l := range atom . Links {
if l . Rel == "" || l . Rel == "alternate" || l . Rel == "self" {
links = append ( links , l . Href )
}
}
return
}
2019-02-20 20:23:48 +01:00
func ( t * DefaultAtomTranslator ) translateFeedUpdated ( atom * atom . Feed ) ( updated string ) {
return atom . Updated
}
func ( t * DefaultAtomTranslator ) translateFeedUpdatedParsed ( atom * atom . Feed ) ( updated * time . Time ) {
return atom . UpdatedParsed
}
func ( t * DefaultAtomTranslator ) translateFeedAuthor ( atom * atom . Feed ) ( author * Person ) {
a := t . firstPerson ( atom . Authors )
if a != nil {
feedAuthor := Person { }
feedAuthor . Name = a . Name
feedAuthor . Email = a . Email
author = & feedAuthor
}
return
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultAtomTranslator ) translateFeedAuthors ( atom * atom . Feed ) ( authors [ ] * Person ) {
if atom . Authors != nil {
authors = [ ] * Person { }
for _ , a := range atom . Authors {
authors = append ( authors , & Person {
Name : a . Name ,
Email : a . Email ,
} )
}
}
return
}
2019-02-20 20:23:48 +01:00
func ( t * DefaultAtomTranslator ) translateFeedLanguage ( atom * atom . Feed ) ( language string ) {
return atom . Language
}
func ( t * DefaultAtomTranslator ) translateFeedImage ( atom * atom . Feed ) ( image * Image ) {
if atom . Logo != "" {
feedImage := Image { }
feedImage . URL = atom . Logo
image = & feedImage
}
return
}
func ( t * DefaultAtomTranslator ) translateFeedCopyright ( atom * atom . Feed ) ( rights string ) {
return atom . Rights
}
func ( t * DefaultAtomTranslator ) translateFeedGenerator ( atom * atom . Feed ) ( generator string ) {
if atom . Generator != nil {
if atom . Generator . Value != "" {
generator += atom . Generator . Value
}
if atom . Generator . Version != "" {
generator += " v" + atom . Generator . Version
}
if atom . Generator . URI != "" {
generator += " " + atom . Generator . URI
}
generator = strings . TrimSpace ( generator )
}
return
}
func ( t * DefaultAtomTranslator ) translateFeedCategories ( atom * atom . Feed ) ( categories [ ] string ) {
if atom . Categories != nil {
categories = [ ] string { }
for _ , c := range atom . Categories {
categories = append ( categories , c . Term )
}
}
return
}
func ( t * DefaultAtomTranslator ) translateFeedItems ( atom * atom . Feed ) ( items [ ] * Item ) {
items = [ ] * Item { }
for _ , entry := range atom . Entries {
items = append ( items , t . translateFeedItem ( entry ) )
}
return
}
func ( t * DefaultAtomTranslator ) translateItemTitle ( entry * atom . Entry ) ( title string ) {
return entry . Title
}
func ( t * DefaultAtomTranslator ) translateItemDescription ( entry * atom . Entry ) ( desc string ) {
return entry . Summary
}
func ( t * DefaultAtomTranslator ) translateItemContent ( entry * atom . Entry ) ( content string ) {
if entry . Content != nil {
content = entry . Content . Value
}
return
}
func ( t * DefaultAtomTranslator ) translateItemLink ( entry * atom . Entry ) ( link string ) {
l := t . firstLinkWithType ( "alternate" , entry . Links )
if l != nil {
link = l . Href
}
return
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultAtomTranslator ) translateItemLinks ( entry * atom . Entry ) ( links [ ] string ) {
for _ , l := range entry . Links {
if l . Rel == "" || l . Rel == "alternate" || l . Rel == "self" {
links = append ( links , l . Href )
}
}
return
}
2019-02-20 20:23:48 +01:00
func ( t * DefaultAtomTranslator ) translateItemUpdated ( entry * atom . Entry ) ( updated string ) {
return entry . Updated
}
func ( t * DefaultAtomTranslator ) translateItemUpdatedParsed ( entry * atom . Entry ) ( updated * time . Time ) {
return entry . UpdatedParsed
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultAtomTranslator ) translateItemPublished ( entry * atom . Entry ) ( published string ) {
published = entry . Published
if published == "" {
published = entry . Updated
}
return
2019-02-20 20:23:48 +01:00
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultAtomTranslator ) translateItemPublishedParsed ( entry * atom . Entry ) ( published * time . Time ) {
published = entry . PublishedParsed
if published == nil {
published = entry . UpdatedParsed
}
return
2019-02-20 20:23:48 +01:00
}
func ( t * DefaultAtomTranslator ) translateItemAuthor ( entry * atom . Entry ) ( author * Person ) {
a := t . firstPerson ( entry . Authors )
if a != nil {
author = & Person { }
author . Name = a . Name
author . Email = a . Email
}
return
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultAtomTranslator ) translateItemAuthors ( entry * atom . Entry ) ( authors [ ] * Person ) {
if entry . Authors != nil {
authors = [ ] * Person { }
for _ , a := range entry . Authors {
authors = append ( authors , & Person {
Name : a . Name ,
Email : a . Email ,
} )
}
}
return
}
2019-02-20 20:23:48 +01:00
func ( t * DefaultAtomTranslator ) translateItemGUID ( entry * atom . Entry ) ( guid string ) {
return entry . ID
}
func ( t * DefaultAtomTranslator ) translateItemImage ( entry * atom . Entry ) ( image * Image ) {
return nil
}
func ( t * DefaultAtomTranslator ) translateItemCategories ( entry * atom . Entry ) ( categories [ ] string ) {
if entry . Categories != nil {
categories = [ ] string { }
for _ , c := range entry . Categories {
categories = append ( categories , c . Term )
}
}
return
}
func ( t * DefaultAtomTranslator ) translateItemEnclosures ( entry * atom . Entry ) ( enclosures [ ] * Enclosure ) {
if entry . Links != nil {
enclosures = [ ] * Enclosure { }
for _ , e := range entry . Links {
if e . Rel == "enclosure" {
enclosure := & Enclosure { }
enclosure . URL = e . Href
enclosure . Length = e . Length
enclosure . Type = e . Type
enclosures = append ( enclosures , enclosure )
}
}
if len ( enclosures ) == 0 {
enclosures = nil
}
}
return
}
func ( t * DefaultAtomTranslator ) firstLinkWithType ( linkType string , links [ ] * atom . Link ) * atom . Link {
if links == nil {
return nil
}
for _ , link := range links {
if link . Rel == linkType {
return link
}
}
return nil
}
func ( t * DefaultAtomTranslator ) firstPerson ( persons [ ] * atom . Person ) ( person * atom . Person ) {
if persons == nil || len ( persons ) == 0 {
return
}
person = persons [ 0 ]
return
}
2020-10-24 12:37:32 +02:00
// DefaultJSONTranslator converts an json.Feed struct
// into the generic Feed struct.
//
// This default implementation defines a set of
// mapping rules between json.Feed -> Feed
// for each of the fields in Feed.
type DefaultJSONTranslator struct { }
// Translate converts an JSON feed into the universal
// feed type.
func ( t * DefaultJSONTranslator ) Translate ( feed interface { } ) ( * Feed , error ) {
json , found := feed . ( * json . Feed )
if ! found {
return nil , fmt . Errorf ( "Feed did not match expected type of *json.Feed" )
}
result := & Feed { }
result . FeedVersion = json . Version
result . Title = t . translateFeedTitle ( json )
result . Link = t . translateFeedLink ( json )
result . FeedLink = t . translateFeedFeedLink ( json )
2021-12-13 10:35:45 +01:00
result . Links = t . translateFeedLinks ( json )
2020-10-24 12:37:32 +02:00
result . Description = t . translateFeedDescription ( json )
result . Image = t . translateFeedImage ( json )
result . Author = t . translateFeedAuthor ( json )
2021-12-13 10:35:45 +01:00
result . Authors = t . translateFeedAuthors ( json )
result . Language = t . translateFeedLanguage ( json )
2020-10-24 12:37:32 +02:00
result . Items = t . translateFeedItems ( json )
result . Updated = t . translateFeedUpdated ( json )
result . UpdatedParsed = t . translateFeedUpdatedParsed ( json )
result . Published = t . translateFeedPublished ( json )
result . PublishedParsed = t . translateFeedPublishedParsed ( json )
result . FeedType = "json"
// TODO UserComment is missing in global Feed
// TODO NextURL is missing in global Feed
// TODO Favicon is missing in global Feed
// TODO Exipred is missing in global Feed
// TODO Hubs is not supported in json.Feed
// TODO Extensions is not supported in json.Feed
return result , nil
}
func ( t * DefaultJSONTranslator ) translateFeedItem ( jsonItem * json . Item ) ( item * Item ) {
item = & Item { }
item . GUID = t . translateItemGUID ( jsonItem )
item . Link = t . translateItemLink ( jsonItem )
2021-12-13 10:35:45 +01:00
item . Links = t . translateItemLinks ( jsonItem )
2020-10-24 12:37:32 +02:00
item . Title = t . translateItemTitle ( jsonItem )
item . Content = t . translateItemContent ( jsonItem )
item . Description = t . translateItemDescription ( jsonItem )
item . Image = t . translateItemImage ( jsonItem )
item . Published = t . translateItemPublished ( jsonItem )
item . PublishedParsed = t . translateItemPublishedParsed ( jsonItem )
item . Updated = t . translateItemUpdated ( jsonItem )
item . UpdatedParsed = t . translateItemUpdatedParsed ( jsonItem )
item . Author = t . translateItemAuthor ( jsonItem )
2021-12-13 10:35:45 +01:00
item . Authors = t . translateItemAuthors ( jsonItem )
2020-10-24 12:37:32 +02:00
item . Categories = t . translateItemCategories ( jsonItem )
item . Enclosures = t . translateItemEnclosures ( jsonItem )
// TODO ExternalURL is missing in global Feed
// TODO BannerImage is missing in global Feed
return
}
func ( t * DefaultJSONTranslator ) translateFeedTitle ( json * json . Feed ) ( title string ) {
if json . Title != "" {
title = json . Title
}
return
}
func ( t * DefaultJSONTranslator ) translateFeedDescription ( json * json . Feed ) ( desc string ) {
return json . Description
}
func ( t * DefaultJSONTranslator ) translateFeedLink ( json * json . Feed ) ( link string ) {
if json . HomePageURL != "" {
link = json . HomePageURL
}
return
}
func ( t * DefaultJSONTranslator ) translateFeedFeedLink ( json * json . Feed ) ( link string ) {
if json . FeedURL != "" {
link = json . FeedURL
}
return
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultJSONTranslator ) translateFeedLinks ( json * json . Feed ) ( links [ ] string ) {
if json . HomePageURL != "" {
links = append ( links , json . HomePageURL )
}
if json . FeedURL != "" {
links = append ( links , json . FeedURL )
}
return
}
2020-10-24 12:37:32 +02:00
func ( t * DefaultJSONTranslator ) translateFeedUpdated ( json * json . Feed ) ( updated string ) {
if len ( json . Items ) > 0 {
updated = json . Items [ 0 ] . DateModified
}
return
}
func ( t * DefaultJSONTranslator ) translateFeedUpdatedParsed ( json * json . Feed ) ( updated * time . Time ) {
if len ( json . Items ) > 0 {
updateTime , err := shared . ParseDate ( json . Items [ 0 ] . DateModified )
if err == nil {
updated = & updateTime
}
}
return
}
func ( t * DefaultJSONTranslator ) translateFeedPublished ( json * json . Feed ) ( published string ) {
if len ( json . Items ) > 0 {
published = json . Items [ 0 ] . DatePublished
}
return
}
func ( t * DefaultJSONTranslator ) translateFeedPublishedParsed ( json * json . Feed ) ( published * time . Time ) {
if len ( json . Items ) > 0 {
publishTime , err := shared . ParseDate ( json . Items [ 0 ] . DatePublished )
if err == nil {
published = & publishTime
}
}
return
}
func ( t * DefaultJSONTranslator ) translateFeedAuthor ( json * json . Feed ) ( author * Person ) {
if json . Author != nil {
name , address := shared . ParseNameAddress ( json . Author . Name )
author = & Person { }
author . Name = name
author . Email = address
}
// Author.URL is missing in global feed
// Author.Avatar is missing in global feed
return
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultJSONTranslator ) translateFeedAuthors ( json * json . Feed ) ( authors [ ] * Person ) {
if json . Authors != nil {
authors = [ ] * Person { }
for _ , a := range json . Authors {
name , address := shared . ParseNameAddress ( a . Name )
author := & Person { }
author . Name = name
author . Email = address
authors = append ( authors , author )
}
} else if author := t . translateFeedAuthor ( json ) ; author != nil {
authors = [ ] * Person { author }
}
// Author.URL is missing in global feed
// Author.Avatar is missing in global feed
return
}
func ( t * DefaultJSONTranslator ) translateFeedLanguage ( json * json . Feed ) ( language string ) {
language = json . Language
return
}
2020-10-24 12:37:32 +02:00
func ( t * DefaultJSONTranslator ) translateFeedImage ( json * json . Feed ) ( image * Image ) {
// Using the Icon rather than the image
// icon (optional, string) is the URL of an image for the feed suitable to be used in a timeline. It should be square and relatively large — such as 512 x 512
if json . Icon != "" {
image = & Image { }
image . URL = json . Icon
}
return
}
func ( t * DefaultJSONTranslator ) translateFeedItems ( json * json . Feed ) ( items [ ] * Item ) {
items = [ ] * Item { }
for _ , i := range json . Items {
items = append ( items , t . translateFeedItem ( i ) )
}
return
}
func ( t * DefaultJSONTranslator ) translateItemTitle ( jsonItem * json . Item ) ( title string ) {
if jsonItem . Title != "" {
title = jsonItem . Title
}
return
}
func ( t * DefaultJSONTranslator ) translateItemDescription ( jsonItem * json . Item ) ( desc string ) {
if jsonItem . Summary != "" {
desc = jsonItem . Summary
}
return
}
func ( t * DefaultJSONTranslator ) translateItemContent ( jsonItem * json . Item ) ( content string ) {
if jsonItem . ContentHTML != "" {
content = jsonItem . ContentHTML
} else if jsonItem . ContentText != "" {
content = jsonItem . ContentText
}
return
}
func ( t * DefaultJSONTranslator ) translateItemLink ( jsonItem * json . Item ) ( link string ) {
return jsonItem . URL
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultJSONTranslator ) translateItemLinks ( jsonItem * json . Item ) ( links [ ] string ) {
if jsonItem . URL != "" {
links = append ( links , jsonItem . URL )
}
if jsonItem . ExternalURL != "" {
links = append ( links , jsonItem . ExternalURL )
}
return
}
2020-10-24 12:37:32 +02:00
func ( t * DefaultJSONTranslator ) translateItemUpdated ( jsonItem * json . Item ) ( updated string ) {
if jsonItem . DateModified != "" {
updated = jsonItem . DateModified
}
return updated
}
func ( t * DefaultJSONTranslator ) translateItemUpdatedParsed ( jsonItem * json . Item ) ( updated * time . Time ) {
if jsonItem . DateModified != "" {
updatedTime , err := shared . ParseDate ( jsonItem . DateModified )
if err == nil {
updated = & updatedTime
}
}
return
}
func ( t * DefaultJSONTranslator ) translateItemPublished ( jsonItem * json . Item ) ( pubDate string ) {
if jsonItem . DatePublished != "" {
pubDate = jsonItem . DatePublished
}
return
}
func ( t * DefaultJSONTranslator ) translateItemPublishedParsed ( jsonItem * json . Item ) ( pubDate * time . Time ) {
if jsonItem . DatePublished != "" {
publishTime , err := shared . ParseDate ( jsonItem . DatePublished )
if err == nil {
pubDate = & publishTime
}
}
return
}
func ( t * DefaultJSONTranslator ) translateItemAuthor ( jsonItem * json . Item ) ( author * Person ) {
if jsonItem . Author != nil {
name , address := shared . ParseNameAddress ( jsonItem . Author . Name )
author = & Person { }
author . Name = name
author . Email = address
}
// Author.URL is missing in global feed
// Author.Avatar is missing in global feed
return
}
2021-12-13 10:35:45 +01:00
func ( t * DefaultJSONTranslator ) translateItemAuthors ( jsonItem * json . Item ) ( authors [ ] * Person ) {
if jsonItem . Authors != nil {
authors = [ ] * Person { }
for _ , a := range jsonItem . Authors {
name , address := shared . ParseNameAddress ( a . Name )
author := & Person { }
author . Name = name
author . Email = address
authors = append ( authors , author )
}
} else if author := t . translateItemAuthor ( jsonItem ) ; author != nil {
authors = [ ] * Person { author }
}
// Author.URL is missing in global feed
// Author.Avatar is missing in global feed
return
}
2020-10-24 12:37:32 +02:00
func ( t * DefaultJSONTranslator ) translateItemGUID ( jsonItem * json . Item ) ( guid string ) {
if jsonItem . ID != "" {
guid = jsonItem . ID
}
return
}
func ( t * DefaultJSONTranslator ) translateItemImage ( jsonItem * json . Item ) ( image * Image ) {
if jsonItem . Image != "" {
image = & Image { }
image . URL = jsonItem . Image
} else if jsonItem . BannerImage != "" {
image = & Image { }
image . URL = jsonItem . BannerImage
}
return
}
func ( t * DefaultJSONTranslator ) translateItemCategories ( jsonItem * json . Item ) ( categories [ ] string ) {
if len ( jsonItem . Tags ) > 0 {
categories = jsonItem . Tags
}
return
}
func ( t * DefaultJSONTranslator ) translateItemEnclosures ( jsonItem * json . Item ) ( enclosures [ ] * Enclosure ) {
if jsonItem . Attachments != nil {
for _ , attachment := range * jsonItem . Attachments {
e := & Enclosure { }
e . URL = attachment . URL
e . Type = attachment . MimeType
e . Length = fmt . Sprintf ( "%d" , attachment . DurationInSeconds )
// Title is not defined in global enclosure
// SizeInBytes is not defined in global enclosure
enclosures = append ( enclosures , e )
}
}
return
}