translator.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. package gofeed
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. "github.com/mmcdole/gofeed/atom"
  7. "github.com/mmcdole/gofeed/extensions"
  8. "github.com/mmcdole/gofeed/internal/shared"
  9. "github.com/mmcdole/gofeed/rss"
  10. )
  11. // Translator converts a particular feed (atom.Feed or rss.Feed)
  12. // into the generic Feed struct
  13. type Translator interface {
  14. Translate(feed interface{}) (*Feed, error)
  15. }
  16. // DefaultRSSTranslator converts an rss.Feed struct
  17. // into the generic Feed struct.
  18. //
  19. // This default implementation defines a set of
  20. // mapping rules between rss.Feed -> Feed
  21. // for each of the fields in Feed.
  22. type DefaultRSSTranslator struct{}
  23. // Translate converts an RSS feed into the universal
  24. // feed type.
  25. func (t *DefaultRSSTranslator) Translate(feed interface{}) (*Feed, error) {
  26. rss, found := feed.(*rss.Feed)
  27. if !found {
  28. return nil, fmt.Errorf("Feed did not match expected type of *rss.Feed")
  29. }
  30. result := &Feed{}
  31. result.Title = t.translateFeedTitle(rss)
  32. result.Description = t.translateFeedDescription(rss)
  33. result.Link = t.translateFeedLink(rss)
  34. result.FeedLink = t.translateFeedFeedLink(rss)
  35. result.Updated = t.translateFeedUpdated(rss)
  36. result.UpdatedParsed = t.translateFeedUpdatedParsed(rss)
  37. result.Published = t.translateFeedPublished(rss)
  38. result.PublishedParsed = t.translateFeedPublishedParsed(rss)
  39. result.Author = t.translateFeedAuthor(rss)
  40. result.Language = t.translateFeedLanguage(rss)
  41. result.Image = t.translateFeedImage(rss)
  42. result.Copyright = t.translateFeedCopyright(rss)
  43. result.Generator = t.translateFeedGenerator(rss)
  44. result.Categories = t.translateFeedCategories(rss)
  45. result.Items = t.translateFeedItems(rss)
  46. result.ITunesExt = rss.ITunesExt
  47. result.DublinCoreExt = rss.DublinCoreExt
  48. result.Extensions = rss.Extensions
  49. result.FeedVersion = rss.Version
  50. result.FeedType = "rss"
  51. return result, nil
  52. }
  53. func (t *DefaultRSSTranslator) translateFeedItem(rssItem *rss.Item) (item *Item) {
  54. item = &Item{}
  55. item.Title = t.translateItemTitle(rssItem)
  56. item.Description = t.translateItemDescription(rssItem)
  57. item.Content = t.translateItemContent(rssItem)
  58. item.Link = t.translateItemLink(rssItem)
  59. item.Published = t.translateItemPublished(rssItem)
  60. item.PublishedParsed = t.translateItemPublishedParsed(rssItem)
  61. item.Author = t.translateItemAuthor(rssItem)
  62. item.GUID = t.translateItemGUID(rssItem)
  63. item.Image = t.translateItemImage(rssItem)
  64. item.Categories = t.translateItemCategories(rssItem)
  65. item.Enclosures = t.translateItemEnclosures(rssItem)
  66. item.DublinCoreExt = rssItem.DublinCoreExt
  67. item.ITunesExt = rssItem.ITunesExt
  68. item.Extensions = rssItem.Extensions
  69. return
  70. }
  71. func (t *DefaultRSSTranslator) translateFeedTitle(rss *rss.Feed) (title string) {
  72. if rss.Title != "" {
  73. title = rss.Title
  74. } else if rss.DublinCoreExt != nil && rss.DublinCoreExt.Title != nil {
  75. title = t.firstEntry(rss.DublinCoreExt.Title)
  76. }
  77. return
  78. }
  79. func (t *DefaultRSSTranslator) translateFeedDescription(rss *rss.Feed) (desc string) {
  80. return rss.Description
  81. }
  82. func (t *DefaultRSSTranslator) translateFeedLink(rss *rss.Feed) (link string) {
  83. if rss.Link != "" {
  84. link = rss.Link
  85. } else if rss.ITunesExt != nil && rss.ITunesExt.Subtitle != "" {
  86. link = rss.ITunesExt.Subtitle
  87. }
  88. return
  89. }
  90. func (t *DefaultRSSTranslator) translateFeedFeedLink(rss *rss.Feed) (link string) {
  91. atomExtensions := t.extensionsForKeys([]string{"atom", "atom10", "atom03"}, rss.Extensions)
  92. for _, ex := range atomExtensions {
  93. if links, ok := ex["link"]; ok {
  94. for _, l := range links {
  95. if l.Attrs["Rel"] == "self" {
  96. link = l.Value
  97. }
  98. }
  99. }
  100. }
  101. return
  102. }
  103. func (t *DefaultRSSTranslator) translateFeedUpdated(rss *rss.Feed) (updated string) {
  104. if rss.LastBuildDate != "" {
  105. updated = rss.LastBuildDate
  106. } else if rss.DublinCoreExt != nil && rss.DublinCoreExt.Date != nil {
  107. updated = t.firstEntry(rss.DublinCoreExt.Date)
  108. }
  109. return
  110. }
  111. func (t *DefaultRSSTranslator) translateFeedUpdatedParsed(rss *rss.Feed) (updated *time.Time) {
  112. if rss.LastBuildDateParsed != nil {
  113. updated = rss.LastBuildDateParsed
  114. } else if rss.DublinCoreExt != nil && rss.DublinCoreExt.Date != nil {
  115. dateText := t.firstEntry(rss.DublinCoreExt.Date)
  116. date, err := shared.ParseDate(dateText)
  117. if err == nil {
  118. updated = &date
  119. }
  120. }
  121. return
  122. }
  123. func (t *DefaultRSSTranslator) translateFeedPublished(rss *rss.Feed) (published string) {
  124. return rss.PubDate
  125. }
  126. func (t *DefaultRSSTranslator) translateFeedPublishedParsed(rss *rss.Feed) (published *time.Time) {
  127. return rss.PubDateParsed
  128. }
  129. func (t *DefaultRSSTranslator) translateFeedAuthor(rss *rss.Feed) (author *Person) {
  130. if rss.ManagingEditor != "" {
  131. name, address := shared.ParseNameAddress(rss.ManagingEditor)
  132. author = &Person{}
  133. author.Name = name
  134. author.Email = address
  135. } else if rss.WebMaster != "" {
  136. name, address := shared.ParseNameAddress(rss.WebMaster)
  137. author = &Person{}
  138. author.Name = name
  139. author.Email = address
  140. } else if rss.DublinCoreExt != nil && rss.DublinCoreExt.Author != nil {
  141. dcAuthor := t.firstEntry(rss.DublinCoreExt.Author)
  142. name, address := shared.ParseNameAddress(dcAuthor)
  143. author = &Person{}
  144. author.Name = name
  145. author.Email = address
  146. } else if rss.DublinCoreExt != nil && rss.DublinCoreExt.Creator != nil {
  147. dcCreator := t.firstEntry(rss.DublinCoreExt.Creator)
  148. name, address := shared.ParseNameAddress(dcCreator)
  149. author = &Person{}
  150. author.Name = name
  151. author.Email = address
  152. } else if rss.ITunesExt != nil && rss.ITunesExt.Author != "" {
  153. name, address := shared.ParseNameAddress(rss.ITunesExt.Author)
  154. author = &Person{}
  155. author.Name = name
  156. author.Email = address
  157. }
  158. return
  159. }
  160. func (t *DefaultRSSTranslator) translateFeedLanguage(rss *rss.Feed) (language string) {
  161. if rss.Language != "" {
  162. language = rss.Language
  163. } else if rss.DublinCoreExt != nil && rss.DublinCoreExt.Language != nil {
  164. language = t.firstEntry(rss.DublinCoreExt.Language)
  165. }
  166. return
  167. }
  168. func (t *DefaultRSSTranslator) translateFeedImage(rss *rss.Feed) (image *Image) {
  169. if rss.Image != nil {
  170. image = &Image{}
  171. image.Title = rss.Image.Title
  172. image.URL = rss.Image.URL
  173. } else if rss.ITunesExt != nil && rss.ITunesExt.Image != "" {
  174. image = &Image{}
  175. image.URL = rss.ITunesExt.Image
  176. }
  177. return
  178. }
  179. func (t *DefaultRSSTranslator) translateFeedCopyright(rss *rss.Feed) (rights string) {
  180. if rss.Copyright != "" {
  181. rights = rss.Copyright
  182. } else if rss.DublinCoreExt != nil && rss.DublinCoreExt.Rights != nil {
  183. rights = t.firstEntry(rss.DublinCoreExt.Rights)
  184. }
  185. return
  186. }
  187. func (t *DefaultRSSTranslator) translateFeedGenerator(rss *rss.Feed) (generator string) {
  188. return rss.Generator
  189. }
  190. func (t *DefaultRSSTranslator) translateFeedCategories(rss *rss.Feed) (categories []string) {
  191. cats := []string{}
  192. if rss.Categories != nil {
  193. for _, c := range rss.Categories {
  194. cats = append(cats, c.Value)
  195. }
  196. }
  197. if rss.ITunesExt != nil && rss.ITunesExt.Keywords != "" {
  198. keywords := strings.Split(rss.ITunesExt.Keywords, ",")
  199. for _, k := range keywords {
  200. cats = append(cats, k)
  201. }
  202. }
  203. if rss.ITunesExt != nil && rss.ITunesExt.Categories != nil {
  204. for _, c := range rss.ITunesExt.Categories {
  205. cats = append(cats, c.Text)
  206. if c.Subcategory != nil {
  207. cats = append(cats, c.Subcategory.Text)
  208. }
  209. }
  210. }
  211. if rss.DublinCoreExt != nil && rss.DublinCoreExt.Subject != nil {
  212. for _, c := range rss.DublinCoreExt.Subject {
  213. cats = append(cats, c)
  214. }
  215. }
  216. if len(cats) > 0 {
  217. categories = cats
  218. }
  219. return
  220. }
  221. func (t *DefaultRSSTranslator) translateFeedItems(rss *rss.Feed) (items []*Item) {
  222. items = []*Item{}
  223. for _, i := range rss.Items {
  224. items = append(items, t.translateFeedItem(i))
  225. }
  226. return
  227. }
  228. func (t *DefaultRSSTranslator) translateItemTitle(rssItem *rss.Item) (title string) {
  229. if rssItem.Title != "" {
  230. title = rssItem.Title
  231. } else if rssItem.DublinCoreExt != nil && rssItem.DublinCoreExt.Title != nil {
  232. title = t.firstEntry(rssItem.DublinCoreExt.Title)
  233. }
  234. return
  235. }
  236. func (t *DefaultRSSTranslator) translateItemDescription(rssItem *rss.Item) (desc string) {
  237. if rssItem.Description != "" {
  238. desc = rssItem.Description
  239. } else if rssItem.DublinCoreExt != nil && rssItem.DublinCoreExt.Description != nil {
  240. desc = t.firstEntry(rssItem.DublinCoreExt.Description)
  241. }
  242. return
  243. }
  244. func (t *DefaultRSSTranslator) translateItemContent(rssItem *rss.Item) (content string) {
  245. return rssItem.Content
  246. }
  247. func (t *DefaultRSSTranslator) translateItemLink(rssItem *rss.Item) (link string) {
  248. return rssItem.Link
  249. }
  250. func (t *DefaultRSSTranslator) translateItemUpdated(rssItem *rss.Item) (updated string) {
  251. if rssItem.DublinCoreExt != nil && rssItem.DublinCoreExt.Date != nil {
  252. updated = t.firstEntry(rssItem.DublinCoreExt.Date)
  253. }
  254. return updated
  255. }
  256. func (t *DefaultRSSTranslator) translateItemUpdatedParsed(rssItem *rss.Item) (updated *time.Time) {
  257. if rssItem.DublinCoreExt != nil && rssItem.DublinCoreExt.Date != nil {
  258. updatedText := t.firstEntry(rssItem.DublinCoreExt.Date)
  259. updatedDate, err := shared.ParseDate(updatedText)
  260. if err == nil {
  261. updated = &updatedDate
  262. }
  263. }
  264. return
  265. }
  266. func (t *DefaultRSSTranslator) translateItemPublished(rssItem *rss.Item) (pubDate string) {
  267. if rssItem.PubDate != "" {
  268. return rssItem.PubDate
  269. } else if rssItem.DublinCoreExt != nil && rssItem.DublinCoreExt.Date != nil {
  270. return t.firstEntry(rssItem.DublinCoreExt.Date)
  271. }
  272. return
  273. }
  274. func (t *DefaultRSSTranslator) translateItemPublishedParsed(rssItem *rss.Item) (pubDate *time.Time) {
  275. if rssItem.PubDateParsed != nil {
  276. return rssItem.PubDateParsed
  277. } else if rssItem.DublinCoreExt != nil && rssItem.DublinCoreExt.Date != nil {
  278. pubDateText := t.firstEntry(rssItem.DublinCoreExt.Date)
  279. pubDateParsed, err := shared.ParseDate(pubDateText)
  280. if err == nil {
  281. pubDate = &pubDateParsed
  282. }
  283. }
  284. return
  285. }
  286. func (t *DefaultRSSTranslator) translateItemAuthor(rssItem *rss.Item) (author *Person) {
  287. if rssItem.Author != "" {
  288. name, address := shared.ParseNameAddress(rssItem.Author)
  289. author = &Person{}
  290. author.Name = name
  291. author.Email = address
  292. } else if rssItem.DublinCoreExt != nil && rssItem.DublinCoreExt.Author != nil {
  293. dcAuthor := t.firstEntry(rssItem.DublinCoreExt.Author)
  294. name, address := shared.ParseNameAddress(dcAuthor)
  295. author = &Person{}
  296. author.Name = name
  297. author.Email = address
  298. } else if rssItem.DublinCoreExt != nil && rssItem.DublinCoreExt.Creator != nil {
  299. dcCreator := t.firstEntry(rssItem.DublinCoreExt.Creator)
  300. name, address := shared.ParseNameAddress(dcCreator)
  301. author = &Person{}
  302. author.Name = name
  303. author.Email = address
  304. } else if rssItem.ITunesExt != nil && rssItem.ITunesExt.Author != "" {
  305. name, address := shared.ParseNameAddress(rssItem.ITunesExt.Author)
  306. author = &Person{}
  307. author.Name = name
  308. author.Email = address
  309. }
  310. return
  311. }
  312. func (t *DefaultRSSTranslator) translateItemGUID(rssItem *rss.Item) (guid string) {
  313. if rssItem.GUID != nil {
  314. guid = rssItem.GUID.Value
  315. }
  316. return
  317. }
  318. func (t *DefaultRSSTranslator) translateItemImage(rssItem *rss.Item) (image *Image) {
  319. if rssItem.ITunesExt != nil && rssItem.ITunesExt.Image != "" {
  320. image = &Image{}
  321. image.URL = rssItem.ITunesExt.Image
  322. }
  323. return
  324. }
  325. func (t *DefaultRSSTranslator) translateItemCategories(rssItem *rss.Item) (categories []string) {
  326. cats := []string{}
  327. if rssItem.Categories != nil {
  328. for _, c := range rssItem.Categories {
  329. cats = append(cats, c.Value)
  330. }
  331. }
  332. if rssItem.ITunesExt != nil && rssItem.ITunesExt.Keywords != "" {
  333. keywords := strings.Split(rssItem.ITunesExt.Keywords, ",")
  334. for _, k := range keywords {
  335. cats = append(cats, k)
  336. }
  337. }
  338. if rssItem.DublinCoreExt != nil && rssItem.DublinCoreExt.Subject != nil {
  339. for _, c := range rssItem.DublinCoreExt.Subject {
  340. cats = append(cats, c)
  341. }
  342. }
  343. if len(cats) > 0 {
  344. categories = cats
  345. }
  346. return
  347. }
  348. func (t *DefaultRSSTranslator) translateItemEnclosures(rssItem *rss.Item) (enclosures []*Enclosure) {
  349. if rssItem.Enclosure != nil {
  350. e := &Enclosure{}
  351. e.URL = rssItem.Enclosure.URL
  352. e.Type = rssItem.Enclosure.Type
  353. e.Length = rssItem.Enclosure.Length
  354. enclosures = []*Enclosure{e}
  355. }
  356. return
  357. }
  358. func (t *DefaultRSSTranslator) extensionsForKeys(keys []string, extensions ext.Extensions) (matches []map[string][]ext.Extension) {
  359. matches = []map[string][]ext.Extension{}
  360. if extensions == nil {
  361. return
  362. }
  363. for _, key := range keys {
  364. if match, ok := extensions[key]; ok {
  365. matches = append(matches, match)
  366. }
  367. }
  368. return
  369. }
  370. func (t *DefaultRSSTranslator) firstEntry(entries []string) (value string) {
  371. if entries == nil {
  372. return
  373. }
  374. if len(entries) == 0 {
  375. return
  376. }
  377. return entries[0]
  378. }
  379. // DefaultAtomTranslator converts an atom.Feed struct
  380. // into the generic Feed struct.
  381. //
  382. // This default implementation defines a set of
  383. // mapping rules between atom.Feed -> Feed
  384. // for each of the fields in Feed.
  385. type DefaultAtomTranslator struct{}
  386. // Translate converts an Atom feed into the universal
  387. // feed type.
  388. func (t *DefaultAtomTranslator) Translate(feed interface{}) (*Feed, error) {
  389. atom, found := feed.(*atom.Feed)
  390. if !found {
  391. return nil, fmt.Errorf("Feed did not match expected type of *atom.Feed")
  392. }
  393. result := &Feed{}
  394. result.Title = t.translateFeedTitle(atom)
  395. result.Description = t.translateFeedDescription(atom)
  396. result.Link = t.translateFeedLink(atom)
  397. result.FeedLink = t.translateFeedFeedLink(atom)
  398. result.Updated = t.translateFeedUpdated(atom)
  399. result.UpdatedParsed = t.translateFeedUpdatedParsed(atom)
  400. result.Author = t.translateFeedAuthor(atom)
  401. result.Language = t.translateFeedLanguage(atom)
  402. result.Image = t.translateFeedImage(atom)
  403. result.Copyright = t.translateFeedCopyright(atom)
  404. result.Categories = t.translateFeedCategories(atom)
  405. result.Generator = t.translateFeedGenerator(atom)
  406. result.Items = t.translateFeedItems(atom)
  407. result.Extensions = atom.Extensions
  408. result.FeedVersion = atom.Version
  409. result.FeedType = "atom"
  410. return result, nil
  411. }
  412. func (t *DefaultAtomTranslator) translateFeedItem(entry *atom.Entry) (item *Item) {
  413. item = &Item{}
  414. item.Title = t.translateItemTitle(entry)
  415. item.Description = t.translateItemDescription(entry)
  416. item.Content = t.translateItemContent(entry)
  417. item.Link = t.translateItemLink(entry)
  418. item.Updated = t.translateItemUpdated(entry)
  419. item.UpdatedParsed = t.translateItemUpdatedParsed(entry)
  420. item.Published = t.translateItemPublished(entry)
  421. item.PublishedParsed = t.translateItemPublishedParsed(entry)
  422. item.Author = t.translateItemAuthor(entry)
  423. item.GUID = t.translateItemGUID(entry)
  424. item.Image = t.translateItemImage(entry)
  425. item.Categories = t.translateItemCategories(entry)
  426. item.Enclosures = t.translateItemEnclosures(entry)
  427. item.Extensions = entry.Extensions
  428. return
  429. }
  430. func (t *DefaultAtomTranslator) translateFeedTitle(atom *atom.Feed) (title string) {
  431. return atom.Title
  432. }
  433. func (t *DefaultAtomTranslator) translateFeedDescription(atom *atom.Feed) (desc string) {
  434. return atom.Subtitle
  435. }
  436. func (t *DefaultAtomTranslator) translateFeedLink(atom *atom.Feed) (link string) {
  437. l := t.firstLinkWithType("alternate", atom.Links)
  438. if l != nil {
  439. link = l.Href
  440. }
  441. return
  442. }
  443. func (t *DefaultAtomTranslator) translateFeedFeedLink(atom *atom.Feed) (link string) {
  444. feedLink := t.firstLinkWithType("self", atom.Links)
  445. if feedLink != nil {
  446. link = feedLink.Href
  447. }
  448. return
  449. }
  450. func (t *DefaultAtomTranslator) translateFeedUpdated(atom *atom.Feed) (updated string) {
  451. return atom.Updated
  452. }
  453. func (t *DefaultAtomTranslator) translateFeedUpdatedParsed(atom *atom.Feed) (updated *time.Time) {
  454. return atom.UpdatedParsed
  455. }
  456. func (t *DefaultAtomTranslator) translateFeedAuthor(atom *atom.Feed) (author *Person) {
  457. a := t.firstPerson(atom.Authors)
  458. if a != nil {
  459. feedAuthor := Person{}
  460. feedAuthor.Name = a.Name
  461. feedAuthor.Email = a.Email
  462. author = &feedAuthor
  463. }
  464. return
  465. }
  466. func (t *DefaultAtomTranslator) translateFeedLanguage(atom *atom.Feed) (language string) {
  467. return atom.Language
  468. }
  469. func (t *DefaultAtomTranslator) translateFeedImage(atom *atom.Feed) (image *Image) {
  470. if atom.Logo != "" {
  471. feedImage := Image{}
  472. feedImage.URL = atom.Logo
  473. image = &feedImage
  474. }
  475. return
  476. }
  477. func (t *DefaultAtomTranslator) translateFeedCopyright(atom *atom.Feed) (rights string) {
  478. return atom.Rights
  479. }
  480. func (t *DefaultAtomTranslator) translateFeedGenerator(atom *atom.Feed) (generator string) {
  481. if atom.Generator != nil {
  482. if atom.Generator.Value != "" {
  483. generator += atom.Generator.Value
  484. }
  485. if atom.Generator.Version != "" {
  486. generator += " v" + atom.Generator.Version
  487. }
  488. if atom.Generator.URI != "" {
  489. generator += " " + atom.Generator.URI
  490. }
  491. generator = strings.TrimSpace(generator)
  492. }
  493. return
  494. }
  495. func (t *DefaultAtomTranslator) translateFeedCategories(atom *atom.Feed) (categories []string) {
  496. if atom.Categories != nil {
  497. categories = []string{}
  498. for _, c := range atom.Categories {
  499. categories = append(categories, c.Term)
  500. }
  501. }
  502. return
  503. }
  504. func (t *DefaultAtomTranslator) translateFeedItems(atom *atom.Feed) (items []*Item) {
  505. items = []*Item{}
  506. for _, entry := range atom.Entries {
  507. items = append(items, t.translateFeedItem(entry))
  508. }
  509. return
  510. }
  511. func (t *DefaultAtomTranslator) translateItemTitle(entry *atom.Entry) (title string) {
  512. return entry.Title
  513. }
  514. func (t *DefaultAtomTranslator) translateItemDescription(entry *atom.Entry) (desc string) {
  515. return entry.Summary
  516. }
  517. func (t *DefaultAtomTranslator) translateItemContent(entry *atom.Entry) (content string) {
  518. if entry.Content != nil {
  519. content = entry.Content.Value
  520. }
  521. return
  522. }
  523. func (t *DefaultAtomTranslator) translateItemLink(entry *atom.Entry) (link string) {
  524. l := t.firstLinkWithType("alternate", entry.Links)
  525. if l != nil {
  526. link = l.Href
  527. }
  528. return
  529. }
  530. func (t *DefaultAtomTranslator) translateItemUpdated(entry *atom.Entry) (updated string) {
  531. return entry.Updated
  532. }
  533. func (t *DefaultAtomTranslator) translateItemUpdatedParsed(entry *atom.Entry) (updated *time.Time) {
  534. return entry.UpdatedParsed
  535. }
  536. func (t *DefaultAtomTranslator) translateItemPublished(entry *atom.Entry) (updated string) {
  537. return entry.Published
  538. }
  539. func (t *DefaultAtomTranslator) translateItemPublishedParsed(entry *atom.Entry) (updated *time.Time) {
  540. return entry.PublishedParsed
  541. }
  542. func (t *DefaultAtomTranslator) translateItemAuthor(entry *atom.Entry) (author *Person) {
  543. a := t.firstPerson(entry.Authors)
  544. if a != nil {
  545. author = &Person{}
  546. author.Name = a.Name
  547. author.Email = a.Email
  548. }
  549. return
  550. }
  551. func (t *DefaultAtomTranslator) translateItemGUID(entry *atom.Entry) (guid string) {
  552. return entry.ID
  553. }
  554. func (t *DefaultAtomTranslator) translateItemImage(entry *atom.Entry) (image *Image) {
  555. return nil
  556. }
  557. func (t *DefaultAtomTranslator) translateItemCategories(entry *atom.Entry) (categories []string) {
  558. if entry.Categories != nil {
  559. categories = []string{}
  560. for _, c := range entry.Categories {
  561. categories = append(categories, c.Term)
  562. }
  563. }
  564. return
  565. }
  566. func (t *DefaultAtomTranslator) translateItemEnclosures(entry *atom.Entry) (enclosures []*Enclosure) {
  567. if entry.Links != nil {
  568. enclosures = []*Enclosure{}
  569. for _, e := range entry.Links {
  570. if e.Rel == "enclosure" {
  571. enclosure := &Enclosure{}
  572. enclosure.URL = e.Href
  573. enclosure.Length = e.Length
  574. enclosure.Type = e.Type
  575. enclosures = append(enclosures, enclosure)
  576. }
  577. }
  578. if len(enclosures) == 0 {
  579. enclosures = nil
  580. }
  581. }
  582. return
  583. }
  584. func (t *DefaultAtomTranslator) firstLinkWithType(linkType string, links []*atom.Link) *atom.Link {
  585. if links == nil {
  586. return nil
  587. }
  588. for _, link := range links {
  589. if link.Rel == linkType {
  590. return link
  591. }
  592. }
  593. return nil
  594. }
  595. func (t *DefaultAtomTranslator) firstPerson(persons []*atom.Person) (person *atom.Person) {
  596. if persons == nil || len(persons) == 0 {
  597. return
  598. }
  599. person = persons[0]
  600. return
  601. }