diff --git a/Gopkg.lock b/Gopkg.lock
index 0ed0867..f373c4c 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -13,6 +13,12 @@
   revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
   version = "v1.4.7"
 
+[[projects]]
+  name = "github.com/gorilla/feeds"
+  packages = ["."]
+  revision = "2079b9bbce59c062ad62eecb771e3ed3a772b8e4"
+  version = "v1.1.1"
+
 [[projects]]
   name = "github.com/gorilla/mux"
   packages = ["."]
@@ -28,6 +34,6 @@
 [solve-meta]
   analyzer-name = "dep"
   analyzer-version = 1
-  inputs-digest = "285ed2d6bee95c3e1cadd6853e7a996552cf6ee36c52dc53c4a1c3d8d9f6deb7"
+  inputs-digest = "099e9b3cae85abca10bb0623f45e324b7230301ecc5a021b3c5a5f45f28f2f93"
   solver-name = "gps-cdcl"
   solver-version = 1
diff --git a/config.json b/config.json
index 0240b07..76ba6cd 100644
--- a/config.json
+++ b/config.json
@@ -3,5 +3,16 @@
     "server": {
         "host": "127.0.0.1",
         "port": 0
+    },
+    "feed": {
+        "external_url": "http://your-url.example",
+        "title": "Feed Title",
+        "link": "http://your-url.example/about",
+        "description": "Feed Description",
+        "author": {
+            "name": "Author Name",
+            "email": "author@somewhere.example"
+        },
+        "copyright": "Copyright Text"
     }
 }
diff --git a/pkg/app/app.go b/pkg/app/app.go
index 665b602..d13a888 100644
--- a/pkg/app/app.go
+++ b/pkg/app/app.go
@@ -5,8 +5,12 @@ import (
 	"log"
 	"net"
 	"net/http"
+	"net/url"
+	"path"
+	"time"
 
 	"github.com/fsnotify/fsnotify"
+	"github.com/gorilla/feeds"
 	"github.com/gorilla/mux"
 	"github.com/wybiral/tube/pkg/media"
 )
@@ -44,6 +48,7 @@ func NewApp(cfg *Config) (*App, error) {
 	r.HandleFunc("/v/{id}.mp4", a.videoHandler).Methods("GET")
 	r.HandleFunc("/t/{id}", a.thumbHandler).Methods("GET")
 	r.HandleFunc("/v/{id}", a.pageHandler).Methods("GET")
+	r.HandleFunc("/feed.xml", a.rssHandler).Methods("GET")
 	fsHandler := http.StripPrefix(
 		"/static/",
 		http.FileServer(http.Dir("./static/")),
@@ -159,3 +164,41 @@ func (a *App) thumbHandler(w http.ResponseWriter, r *http.Request) {
 		w.Write(m.Thumb)
 	}
 }
+
+func (a *App) rssHandler(w http.ResponseWriter, r *http.Request) {
+	cfg := a.Config.Feed
+	now := time.Now()
+	f := &feeds.Feed{
+		Title:       cfg.Title,
+		Link:        &feeds.Link{Href: cfg.Link},
+		Description: cfg.Description,
+		Author: &feeds.Author{
+			Name:  cfg.Author.Name,
+			Email: cfg.Author.Email,
+		},
+		Created:   now,
+		Copyright: cfg.Copyright,
+	}
+	for _, v := range a.Library.Playlist() {
+		u, err := url.Parse(cfg.ExternalURL)
+		if err != nil {
+			return
+		}
+		u.Path = path.Join(u.Path, "v", v.ID)
+		id := u.String()
+		f.Items = append(f.Items, &feeds.Item{
+			Id:          id,
+			Title:       v.Title,
+			Link:        &feeds.Link{Href: id},
+			Description: v.Description,
+			Author: &feeds.Author{
+				Name:  cfg.Author.Name,
+				Email: cfg.Author.Email,
+			},
+			Created: v.Timestamp,
+		})
+	}
+	w.Header().Set("Cache-Control", "public, max-age=7776000")
+	w.Header().Set("Content-Type", "text/xml")
+	f.WriteRss(w)
+}
diff --git a/pkg/app/config.go b/pkg/app/config.go
index c4ea170..12cf21d 100644
--- a/pkg/app/config.go
+++ b/pkg/app/config.go
@@ -8,6 +8,7 @@ import (
 type Config struct {
 	LibraryPath string        `json:"library"`
 	Server      *ServerConfig `json:"server"`
+	Feed        *FeedConfig   `json:"feed"`
 }
 
 type ServerConfig struct {
@@ -15,6 +16,18 @@ type ServerConfig struct {
 	Port int    `json:"port"`
 }
 
+type FeedConfig struct {
+	ExternalURL string `json:"external_url"`
+	Title       string `json:"title"`
+	Link        string `json:"link"`
+	Description string `json:"description"`
+	Author      struct {
+		Name  string `json:"name"`
+		Email string `json:"email"`
+	} `json:"author"`
+	Copyright string `json:"copyright"`
+}
+
 func DefaultConfig() *Config {
 	return &Config{
 		LibraryPath: "videos",
@@ -22,6 +35,9 @@ func DefaultConfig() *Config {
 			Host: "127.0.0.1",
 			Port: 0,
 		},
+		Feed: &FeedConfig{
+			ExternalURL: "http://localhost",
+		},
 	}
 }
 
diff --git a/pkg/media/playlist.go b/pkg/media/playlist.go
index ed22f27..86dcb76 100644
--- a/pkg/media/playlist.go
+++ b/pkg/media/playlist.go
@@ -11,5 +11,5 @@ func (p Playlist) Swap(i, j int) {
 }
 
 func (p Playlist) Less(i, j int) bool {
-	return p[i].ID < p[j].ID
+	return p[i].Timestamp.After(p[j].Timestamp)
 }
diff --git a/pkg/media/video.go b/pkg/media/video.go
index f79ab44..7fddbee 100644
--- a/pkg/media/video.go
+++ b/pkg/media/video.go
@@ -3,6 +3,7 @@ package media
 import (
 	"os"
 	"strings"
+	"time"
 
 	"github.com/dhowden/tag"
 )
@@ -15,6 +16,7 @@ type Video struct {
 	Thumb       []byte
 	ThumbType   string
 	Modified    string
+	Timestamp   time.Time
 }
 
 func ParseVideo(path string) (*Video, error) {
@@ -26,7 +28,8 @@ func ParseVideo(path string) (*Video, error) {
 	if err != nil {
 		return nil, err
 	}
-	modified := info.ModTime().Format("2006-01-02")
+	timestamp := info.ModTime()
+	modified := timestamp.Format("2006-01-02 03:04 PM")
 	name := info.Name()
 	// ID is name without extension
 	idx := strings.LastIndex(name, ".")
@@ -49,6 +52,7 @@ func ParseVideo(path string) (*Video, error) {
 		Album:       m.Album(),
 		Description: m.Comment(),
 		Modified:    modified,
+		Timestamp:   timestamp,
 	}
 	// Add thumbnail (if exists)
 	p := m.Picture()
diff --git a/vendor/github.com/gorilla/feeds/.travis.yml b/vendor/github.com/gorilla/feeds/.travis.yml
new file mode 100644
index 0000000..7939a21
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/.travis.yml
@@ -0,0 +1,16 @@
+language: go
+sudo: false
+matrix:
+  include:
+    - go: 1.8
+    - go: 1.9
+    - go: "1.10"
+    - go: 1.x
+    - go: tip
+  allow_failures:
+    - go: tip
+script:
+  - go get -t -v ./...
+  - diff -u <(echo -n) <(gofmt -d -s .)
+  - go vet .
+  - go test -v -race ./...
diff --git a/vendor/github.com/gorilla/feeds/AUTHORS b/vendor/github.com/gorilla/feeds/AUTHORS
new file mode 100644
index 0000000..2c28cf9
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/AUTHORS
@@ -0,0 +1,29 @@
+# This is the official list of gorilla/feeds authors for copyright purposes.
+# Please keep the list sorted.
+
+Dmitry Chestnykh <dmitry@codingrobots.com>
+Eddie Scholtz <eascholtz@gmail.com>
+Gabriel Simmer <bladesimmer@gmail.com>
+Google LLC (https://opensource.google.com/)
+honky <honky@defendtheplanet.net>
+James Gregory <james@jagregory.com>
+Jason Hall <imjasonh@gmail.com>
+Jason Moiron <jmoiron@jmoiron.net>
+Kamil Kisiel <kamil@kamilkisiel.net>
+Kevin Stock <kevinstock@tantalic.com>
+Markus Zimmermann <markus.zimmermann@nethead.at>
+Matt Silverlock <matt@eatsleeprepeat.net>
+Matthew Dawson <matthew@mjdsystems.ca>
+Milan Aleksic <milanaleksic@gmail.com>
+Milan Aleksić <milanaleksic@gmail.com>
+nlimpid <jshuangzl@gmail.com>
+Paul Petring <paul@defendtheplanet.net>
+Sean Enck <enckse@users.noreply.github.com>
+Sue Spence <virtuallysue@gmail.com>
+Supermighty <ukiah@faction.com>
+Toru Fukui <fukuimone@gmail.com>
+Vabd <vabd@anon.acme>
+Volker <lists.volker@gmail.com>
+ZhiFeng Hu <hufeng1987@gmail.com>
+weberc2 <weberc2@gmail.com>
+
diff --git a/vendor/github.com/gorilla/feeds/LICENSE b/vendor/github.com/gorilla/feeds/LICENSE
new file mode 100644
index 0000000..e24412d
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2013-2018 The Gorilla Feeds Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+  Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/gorilla/feeds/README.md b/vendor/github.com/gorilla/feeds/README.md
new file mode 100644
index 0000000..4d733cf
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/README.md
@@ -0,0 +1,185 @@
+## gorilla/feeds
+[![GoDoc](https://godoc.org/github.com/gorilla/feeds?status.svg)](https://godoc.org/github.com/gorilla/feeds)
+[![Build Status](https://travis-ci.org/gorilla/feeds.svg?branch=master)](https://travis-ci.org/gorilla/feeds)
+
+feeds is a web feed generator library for generating RSS, Atom and JSON feeds from Go
+applications.
+
+### Goals
+
+ * Provide a simple interface to create both Atom & RSS 2.0 feeds
+ * Full support for [Atom][atom], [RSS 2.0][rss], and [JSON Feed Version 1][jsonfeed] spec elements
+ * Ability to modify particulars for each spec
+
+[atom]: https://tools.ietf.org/html/rfc4287
+[rss]: http://www.rssboard.org/rss-specification
+[jsonfeed]: https://jsonfeed.org/version/1
+
+### Usage
+
+```go
+package main
+
+import (
+    "fmt"
+    "log"
+    "time"
+    "github.com/gorilla/feeds"
+)
+
+func main() {
+    now := time.Now()
+    feed := &feeds.Feed{
+        Title:       "jmoiron.net blog",
+        Link:        &feeds.Link{Href: "http://jmoiron.net/blog"},
+        Description: "discussion about tech, footie, photos",
+        Author:      &feeds.Author{Name: "Jason Moiron", Email: "jmoiron@jmoiron.net"},
+        Created:     now,
+    }
+
+    feed.Items = []*feeds.Item{
+        &feeds.Item{
+            Title:       "Limiting Concurrency in Go",
+            Link:        &feeds.Link{Href: "http://jmoiron.net/blog/limiting-concurrency-in-go/"},
+            Description: "A discussion on controlled parallelism in golang",
+            Author:      &feeds.Author{Name: "Jason Moiron", Email: "jmoiron@jmoiron.net"},
+            Created:     now,
+        },
+        &feeds.Item{
+            Title:       "Logic-less Template Redux",
+            Link:        &feeds.Link{Href: "http://jmoiron.net/blog/logicless-template-redux/"},
+            Description: "More thoughts on logicless templates",
+            Created:     now,
+        },
+        &feeds.Item{
+            Title:       "Idiomatic Code Reuse in Go",
+            Link:        &feeds.Link{Href: "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"},
+            Description: "How to use interfaces <em>effectively</em>",
+            Created:     now,
+        },
+    }
+
+    atom, err := feed.ToAtom()
+    if err != nil {
+        log.Fatal(err)
+    }
+
+    rss, err := feed.ToRss()
+    if err != nil {
+        log.Fatal(err)
+    }
+
+    json, err := feed.ToJSON()
+    if err != nil {
+        log.Fatal(err)
+    }
+
+    fmt.Println(atom, "\n", rss, "\n", json)
+}
+```
+
+Outputs:
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+  <title>jmoiron.net blog</title>
+  <link href="http://jmoiron.net/blog"></link>
+  <id>http://jmoiron.net/blog</id>
+  <updated>2013-01-16T03:26:01-05:00</updated>
+  <summary>discussion about tech, footie, photos</summary>
+  <entry>
+    <title>Limiting Concurrency in Go</title>
+    <link href="http://jmoiron.net/blog/limiting-concurrency-in-go/"></link>
+    <updated>2013-01-16T03:26:01-05:00</updated>
+    <id>tag:jmoiron.net,2013-01-16:/blog/limiting-concurrency-in-go/</id>
+    <summary type="html">A discussion on controlled parallelism in golang</summary>
+    <author>
+      <name>Jason Moiron</name>
+      <email>jmoiron@jmoiron.net</email>
+    </author>
+  </entry>
+  <entry>
+    <title>Logic-less Template Redux</title>
+    <link href="http://jmoiron.net/blog/logicless-template-redux/"></link>
+    <updated>2013-01-16T03:26:01-05:00</updated>
+    <id>tag:jmoiron.net,2013-01-16:/blog/logicless-template-redux/</id>
+    <summary type="html">More thoughts on logicless templates</summary>
+    <author></author>
+  </entry>
+  <entry>
+    <title>Idiomatic Code Reuse in Go</title>
+    <link href="http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"></link>
+    <updated>2013-01-16T03:26:01-05:00</updated>
+    <id>tag:jmoiron.net,2013-01-16:/blog/idiomatic-code-reuse-in-go/</id>
+    <summary type="html">How to use interfaces &lt;em&gt;effectively&lt;/em&gt;</summary>
+    <author></author>
+  </entry>
+</feed>
+
+<?xml version="1.0" encoding="UTF-8"?>
+<rss version="2.0">
+  <channel>
+    <title>jmoiron.net blog</title>
+    <link>http://jmoiron.net/blog</link>
+    <description>discussion about tech, footie, photos</description>
+    <managingEditor>jmoiron@jmoiron.net (Jason Moiron)</managingEditor>
+    <pubDate>2013-01-16T03:22:24-05:00</pubDate>
+    <item>
+      <title>Limiting Concurrency in Go</title>
+      <link>http://jmoiron.net/blog/limiting-concurrency-in-go/</link>
+      <description>A discussion on controlled parallelism in golang</description>
+      <pubDate>2013-01-16T03:22:24-05:00</pubDate>
+    </item>
+    <item>
+      <title>Logic-less Template Redux</title>
+      <link>http://jmoiron.net/blog/logicless-template-redux/</link>
+      <description>More thoughts on logicless templates</description>
+      <pubDate>2013-01-16T03:22:24-05:00</pubDate>
+    </item>
+    <item>
+      <title>Idiomatic Code Reuse in Go</title>
+      <link>http://jmoiron.net/blog/idiomatic-code-reuse-in-go/</link>
+      <description>How to use interfaces &lt;em&gt;effectively&lt;/em&gt;</description>
+      <pubDate>2013-01-16T03:22:24-05:00</pubDate>
+    </item>
+  </channel>
+</rss>
+
+{
+  "version": "https://jsonfeed.org/version/1",
+  "title": "jmoiron.net blog",
+  "home_page_url": "http://jmoiron.net/blog",
+  "description": "discussion about tech, footie, photos",
+  "author": {
+    "name": "Jason Moiron"
+  },
+  "items": [
+    {
+      "id": "",
+      "url": "http://jmoiron.net/blog/limiting-concurrency-in-go/",
+      "title": "Limiting Concurrency in Go",
+      "summary": "A discussion on controlled parallelism in golang",
+      "date_published": "2013-01-16T03:22:24.530817846-05:00",
+      "author": {
+        "name": "Jason Moiron"
+      }
+    },
+    {
+      "id": "",
+      "url": "http://jmoiron.net/blog/logicless-template-redux/",
+      "title": "Logic-less Template Redux",
+      "summary": "More thoughts on logicless templates",
+      "date_published": "2013-01-16T03:22:24.530817846-05:00"
+    },
+    {
+      "id": "",
+      "url": "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/",
+      "title": "Idiomatic Code Reuse in Go",
+      "summary": "How to use interfaces \u003cem\u003eeffectively\u003c/em\u003e",
+      "date_published": "2013-01-16T03:22:24.530817846-05:00"
+    }
+  ]
+}
+```
+
diff --git a/vendor/github.com/gorilla/feeds/atom.go b/vendor/github.com/gorilla/feeds/atom.go
new file mode 100644
index 0000000..7196f47
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/atom.go
@@ -0,0 +1,169 @@
+package feeds
+
+import (
+	"encoding/xml"
+	"fmt"
+	"net/url"
+	"time"
+)
+
+// Generates Atom feed as XML
+
+const ns = "http://www.w3.org/2005/Atom"
+
+type AtomPerson struct {
+	Name  string `xml:"name,omitempty"`
+	Uri   string `xml:"uri,omitempty"`
+	Email string `xml:"email,omitempty"`
+}
+
+type AtomSummary struct {
+	XMLName xml.Name `xml:"summary"`
+	Content string   `xml:",chardata"`
+	Type    string   `xml:"type,attr"`
+}
+
+type AtomContent struct {
+	XMLName xml.Name `xml:"content"`
+	Content string   `xml:",chardata"`
+	Type    string   `xml:"type,attr"`
+}
+
+type AtomAuthor struct {
+	XMLName xml.Name `xml:"author"`
+	AtomPerson
+}
+
+type AtomContributor struct {
+	XMLName xml.Name `xml:"contributor"`
+	AtomPerson
+}
+
+type AtomEntry struct {
+	XMLName     xml.Name `xml:"entry"`
+	Xmlns       string   `xml:"xmlns,attr,omitempty"`
+	Title       string   `xml:"title"`   // required
+	Updated     string   `xml:"updated"` // required
+	Id          string   `xml:"id"`      // required
+	Category    string   `xml:"category,omitempty"`
+	Content     *AtomContent
+	Rights      string `xml:"rights,omitempty"`
+	Source      string `xml:"source,omitempty"`
+	Published   string `xml:"published,omitempty"`
+	Contributor *AtomContributor
+	Links       []AtomLink   // required if no child 'content' elements
+	Summary     *AtomSummary // required if content has src or content is base64
+	Author      *AtomAuthor  // required if feed lacks an author
+}
+
+// Multiple links with different rel can coexist
+type AtomLink struct {
+	//Atom 1.0 <link rel="enclosure" type="audio/mpeg" title="MP3" href="http://www.example.org/myaudiofile.mp3" length="1234" />
+	XMLName xml.Name `xml:"link"`
+	Href    string   `xml:"href,attr"`
+	Rel     string   `xml:"rel,attr,omitempty"`
+	Type    string   `xml:"type,attr,omitempty"`
+	Length  string   `xml:"length,attr,omitempty"`
+}
+
+type AtomFeed struct {
+	XMLName     xml.Name `xml:"feed"`
+	Xmlns       string   `xml:"xmlns,attr"`
+	Title       string   `xml:"title"`   // required
+	Id          string   `xml:"id"`      // required
+	Updated     string   `xml:"updated"` // required
+	Category    string   `xml:"category,omitempty"`
+	Icon        string   `xml:"icon,omitempty"`
+	Logo        string   `xml:"logo,omitempty"`
+	Rights      string   `xml:"rights,omitempty"` // copyright used
+	Subtitle    string   `xml:"subtitle,omitempty"`
+	Link        *AtomLink
+	Author      *AtomAuthor `xml:"author,omitempty"`
+	Contributor *AtomContributor
+	Entries     []*AtomEntry `xml:"entry"`
+}
+
+type Atom struct {
+	*Feed
+}
+
+func newAtomEntry(i *Item) *AtomEntry {
+	id := i.Id
+	// assume the description is html
+	s := &AtomSummary{Content: i.Description, Type: "html"}
+
+	if len(id) == 0 {
+		// if there's no id set, try to create one, either from data or just a uuid
+		if len(i.Link.Href) > 0 && (!i.Created.IsZero() || !i.Updated.IsZero()) {
+			dateStr := anyTimeFormat("2006-01-02", i.Updated, i.Created)
+			host, path := i.Link.Href, "/invalid.html"
+			if url, err := url.Parse(i.Link.Href); err == nil {
+				host, path = url.Host, url.Path
+			}
+			id = fmt.Sprintf("tag:%s,%s:%s", host, dateStr, path)
+		} else {
+			id = "urn:uuid:" + NewUUID().String()
+		}
+	}
+	var name, email string
+	if i.Author != nil {
+		name, email = i.Author.Name, i.Author.Email
+	}
+
+	link_rel := i.Link.Rel
+	if link_rel == "" {
+		link_rel = "alternate"
+	}
+	x := &AtomEntry{
+		Title:   i.Title,
+		Links:   []AtomLink{{Href: i.Link.Href, Rel: link_rel, Type: i.Link.Type}},
+		Id:      id,
+		Updated: anyTimeFormat(time.RFC3339, i.Updated, i.Created),
+		Summary: s,
+	}
+
+	// if there's a content, assume it's html
+	if len(i.Content) > 0 {
+		x.Content = &AtomContent{Content: i.Content, Type: "html"}
+	}
+
+	if i.Enclosure != nil && link_rel != "enclosure" {
+		x.Links = append(x.Links, AtomLink{Href: i.Enclosure.Url, Rel: "enclosure", Type: i.Enclosure.Type, Length: i.Enclosure.Length})
+	}
+
+	if len(name) > 0 || len(email) > 0 {
+		x.Author = &AtomAuthor{AtomPerson: AtomPerson{Name: name, Email: email}}
+	}
+	return x
+}
+
+// create a new AtomFeed with a generic Feed struct's data
+func (a *Atom) AtomFeed() *AtomFeed {
+	updated := anyTimeFormat(time.RFC3339, a.Updated, a.Created)
+	feed := &AtomFeed{
+		Xmlns:    ns,
+		Title:    a.Title,
+		Link:     &AtomLink{Href: a.Link.Href, Rel: a.Link.Rel},
+		Subtitle: a.Description,
+		Id:       a.Link.Href,
+		Updated:  updated,
+		Rights:   a.Copyright,
+	}
+	if a.Author != nil {
+		feed.Author = &AtomAuthor{AtomPerson: AtomPerson{Name: a.Author.Name, Email: a.Author.Email}}
+	}
+	for _, e := range a.Items {
+		feed.Entries = append(feed.Entries, newAtomEntry(e))
+	}
+	return feed
+}
+
+// FeedXml returns an XML-Ready object for an Atom object
+func (a *Atom) FeedXml() interface{} {
+	return a.AtomFeed()
+}
+
+// FeedXml returns an XML-ready object for an AtomFeed object
+func (a *AtomFeed) FeedXml() interface{} {
+	return a
+}
diff --git a/vendor/github.com/gorilla/feeds/doc.go b/vendor/github.com/gorilla/feeds/doc.go
new file mode 100644
index 0000000..4e0759c
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/doc.go
@@ -0,0 +1,73 @@
+/*
+Syndication (feed) generator library for golang.
+
+Installing
+
+	go get github.com/gorilla/feeds
+
+Feeds provides a simple, generic Feed interface with a generic Item object as well as RSS, Atom and JSON Feed specific RssFeed, AtomFeed and JSONFeed objects which allow access to all of each spec's defined elements.
+
+Examples
+
+Create a Feed and some Items in that feed using the generic interfaces:
+
+	import (
+		"time"
+		. "github.com/gorilla/feeds"
+	)
+
+	now = time.Now()
+
+	feed := &Feed{
+		Title:       "jmoiron.net blog",
+		Link:        &Link{Href: "http://jmoiron.net/blog"},
+		Description: "discussion about tech, footie, photos",
+		Author:      &Author{Name: "Jason Moiron", Email: "jmoiron@jmoiron.net"},
+		Created:     now,
+		Copyright:   "This work is copyright © Benjamin Button",
+	}
+
+	feed.Items = []*Item{
+		&Item{
+			Title:       "Limiting Concurrency in Go",
+			Link:        &Link{Href: "http://jmoiron.net/blog/limiting-concurrency-in-go/"},
+			Description: "A discussion on controlled parallelism in golang",
+			Author:      &Author{Name: "Jason Moiron", Email: "jmoiron@jmoiron.net"},
+			Created:     now,
+		},
+		&Item{
+			Title:       "Logic-less Template Redux",
+			Link:        &Link{Href: "http://jmoiron.net/blog/logicless-template-redux/"},
+			Description: "More thoughts on logicless templates",
+			Created:     now,
+		},
+		&Item{
+			Title:       "Idiomatic Code Reuse in Go",
+			Link:        &Link{Href: "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"},
+			Description: "How to use interfaces <em>effectively</em>",
+			Created:     now,
+		},
+	}
+
+From here, you can output Atom, RSS, or JSON Feed versions of this feed easily
+
+	atom, err := feed.ToAtom()
+	rss, err := feed.ToRss()
+	json, err := feed.ToJSON()
+
+You can also get access to the underlying objects that feeds uses to export its XML
+
+	atomFeed := (&Atom{Feed: feed}).AtomFeed()
+	rssFeed := (&Rss{Feed: feed}).RssFeed()
+	jsonFeed := (&JSON{Feed: feed}).JSONFeed()
+
+From here, you can modify or add each syndication's specific fields before outputting
+
+	atomFeed.Subtitle = "plays the blues"
+	atom, err := ToXML(atomFeed)
+	rssFeed.Generator = "gorilla/feeds v1.0 (github.com/gorilla/feeds)"
+	rss, err := ToXML(rssFeed)
+	jsonFeed.NextUrl = "https://www.example.com/feed.json?page=2"
+	json, err := jsonFeed.ToJSON()
+*/
+package feeds
diff --git a/vendor/github.com/gorilla/feeds/feed.go b/vendor/github.com/gorilla/feeds/feed.go
new file mode 100644
index 0000000..790a1b6
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/feed.go
@@ -0,0 +1,145 @@
+package feeds
+
+import (
+	"encoding/json"
+	"encoding/xml"
+	"io"
+	"sort"
+	"time"
+)
+
+type Link struct {
+	Href, Rel, Type, Length string
+}
+
+type Author struct {
+	Name, Email string
+}
+
+type Image struct {
+	Url, Title, Link string
+	Width, Height    int
+}
+
+type Enclosure struct {
+	Url, Length, Type string
+}
+
+type Item struct {
+	Title       string
+	Link        *Link
+	Source      *Link
+	Author      *Author
+	Description string // used as description in rss, summary in atom
+	Id          string // used as guid in rss, id in atom
+	Updated     time.Time
+	Created     time.Time
+	Enclosure   *Enclosure
+	Content     string
+}
+
+type Feed struct {
+	Title       string
+	Link        *Link
+	Description string
+	Author      *Author
+	Updated     time.Time
+	Created     time.Time
+	Id          string
+	Subtitle    string
+	Items       []*Item
+	Copyright   string
+	Image       *Image
+}
+
+// add a new Item to a Feed
+func (f *Feed) Add(item *Item) {
+	f.Items = append(f.Items, item)
+}
+
+// returns the first non-zero time formatted as a string or ""
+func anyTimeFormat(format string, times ...time.Time) string {
+	for _, t := range times {
+		if !t.IsZero() {
+			return t.Format(format)
+		}
+	}
+	return ""
+}
+
+// interface used by ToXML to get a object suitable for exporting XML.
+type XmlFeed interface {
+	FeedXml() interface{}
+}
+
+// turn a feed object (either a Feed, AtomFeed, or RssFeed) into xml
+// returns an error if xml marshaling fails
+func ToXML(feed XmlFeed) (string, error) {
+	x := feed.FeedXml()
+	data, err := xml.MarshalIndent(x, "", "  ")
+	if err != nil {
+		return "", err
+	}
+	// strip empty line from default xml header
+	s := xml.Header[:len(xml.Header)-1] + string(data)
+	return s, nil
+}
+
+// WriteXML writes a feed object (either a Feed, AtomFeed, or RssFeed) as XML into
+// the writer. Returns an error if XML marshaling fails.
+func WriteXML(feed XmlFeed, w io.Writer) error {
+	x := feed.FeedXml()
+	// write default xml header, without the newline
+	if _, err := w.Write([]byte(xml.Header[:len(xml.Header)-1])); err != nil {
+		return err
+	}
+	e := xml.NewEncoder(w)
+	e.Indent("", "  ")
+	return e.Encode(x)
+}
+
+// creates an Atom representation of this feed
+func (f *Feed) ToAtom() (string, error) {
+	a := &Atom{f}
+	return ToXML(a)
+}
+
+// WriteAtom writes an Atom representation of this feed to the writer.
+func (f *Feed) WriteAtom(w io.Writer) error {
+	return WriteXML(&Atom{f}, w)
+}
+
+// creates an Rss representation of this feed
+func (f *Feed) ToRss() (string, error) {
+	r := &Rss{f}
+	return ToXML(r)
+}
+
+// WriteRss writes an RSS representation of this feed to the writer.
+func (f *Feed) WriteRss(w io.Writer) error {
+	return WriteXML(&Rss{f}, w)
+}
+
+// ToJSON creates a JSON Feed representation of this feed
+func (f *Feed) ToJSON() (string, error) {
+	j := &JSON{f}
+	return j.ToJSON()
+}
+
+// WriteJSON writes an JSON representation of this feed to the writer.
+func (f *Feed) WriteJSON(w io.Writer) error {
+	j := &JSON{f}
+	feed := j.JSONFeed()
+
+	e := json.NewEncoder(w)
+	e.SetIndent("", "  ")
+	return e.Encode(feed)
+}
+
+// Sort sorts the Items in the feed with the given less function.
+func (f *Feed) Sort(less func(a, b *Item) bool) {
+	lessFunc := func(i, j int) bool {
+		return less(f.Items[i], f.Items[j])
+	}
+	sort.SliceStable(f.Items, lessFunc)
+}
diff --git a/vendor/github.com/gorilla/feeds/json.go b/vendor/github.com/gorilla/feeds/json.go
new file mode 100644
index 0000000..75a82fd
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/json.go
@@ -0,0 +1,183 @@
+package feeds
+
+import (
+	"encoding/json"
+	"strings"
+	"time"
+)
+
+const jsonFeedVersion = "https://jsonfeed.org/version/1"
+
+// JSONAuthor represents the author of the feed or of an individual item
+// in the feed
+type JSONAuthor struct {
+	Name   string `json:"name,omitempty"`
+	Url    string `json:"url,omitempty"`
+	Avatar string `json:"avatar,omitempty"`
+}
+
+// JSONAttachment represents a related resource. Podcasts, for instance, would
+// include an attachment that’s an audio or video file.
+type JSONAttachment struct {
+	Url      string        `json:"url,omitempty"`
+	MIMEType string        `json:"mime_type,omitempty"`
+	Title    string        `json:"title,omitempty"`
+	Size     int32         `json:"size,omitempty"`
+	Duration time.Duration `json:"duration_in_seconds,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+// The Duration field is marshaled in seconds, all other fields are marshaled
+// based upon the definitions in struct tags.
+func (a *JSONAttachment) MarshalJSON() ([]byte, error) {
+	type EmbeddedJSONAttachment JSONAttachment
+	return json.Marshal(&struct {
+		Duration float64 `json:"duration_in_seconds,omitempty"`
+		*EmbeddedJSONAttachment
+	}{
+		EmbeddedJSONAttachment: (*EmbeddedJSONAttachment)(a),
+		Duration:               a.Duration.Seconds(),
+	})
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+// The Duration field is expected to be in seconds, all other field types
+// match the struct definition.
+func (a *JSONAttachment) UnmarshalJSON(data []byte) error {
+	type EmbeddedJSONAttachment JSONAttachment
+	var raw struct {
+		Duration float64 `json:"duration_in_seconds,omitempty"`
+		*EmbeddedJSONAttachment
+	}
+	raw.EmbeddedJSONAttachment = (*EmbeddedJSONAttachment)(a)
+
+	err := json.Unmarshal(data, &raw)
+	if err != nil {
+		return err
+	}
+
+	if raw.Duration > 0 {
+		nsec := int64(raw.Duration * float64(time.Second))
+		raw.EmbeddedJSONAttachment.Duration = time.Duration(nsec)
+	}
+
+	return nil
+}
+
+// JSONItem represents a single entry/post for the feed.
+type JSONItem struct {
+	Id            string           `json:"id"`
+	Url           string           `json:"url,omitempty"`
+	ExternalUrl   string           `json:"external_url,omitempty"`
+	Title         string           `json:"title,omitempty"`
+	ContentHTML   string           `json:"content_html,omitempty"`
+	ContentText   string           `json:"content_text,omitempty"`
+	Summary       string           `json:"summary,omitempty"`
+	Image         string           `json:"image,omitempty"`
+	BannerImage   string           `json:"banner_,omitempty"`
+	PublishedDate *time.Time       `json:"date_published,omitempty"`
+	ModifiedDate  *time.Time       `json:"date_modified,omitempty"`
+	Author        *JSONAuthor      `json:"author,omitempty"`
+	Tags          []string         `json:"tags,omitempty"`
+	Attachments   []JSONAttachment `json:"attachments,omitempty"`
+}
+
+// JSONHub describes an endpoint that can be used to subscribe to real-time
+// notifications from the publisher of this feed.
+type JSONHub struct {
+	Type string `json:"type"`
+	Url  string `json:"url"`
+}
+
+// JSONFeed represents a syndication feed in the JSON Feed Version 1 format.
+// Matching the specification found here: https://jsonfeed.org/version/1.
+type JSONFeed struct {
+	Version     string      `json:"version"`
+	Title       string      `json:"title"`
+	HomePageUrl string      `json:"home_page_url,omitempty"`
+	FeedUrl     string      `json:"feed_url,omitempty"`
+	Description string      `json:"description,omitempty"`
+	UserComment string      `json:"user_comment,omitempty"`
+	NextUrl     string      `json:"next_url,omitempty"`
+	Icon        string      `json:"icon,omitempty"`
+	Favicon     string      `json:"favicon,omitempty"`
+	Author      *JSONAuthor `json:"author,omitempty"`
+	Expired     *bool       `json:"expired,omitempty"`
+	Hubs        []*JSONItem `json:"hubs,omitempty"`
+	Items       []*JSONItem `json:"items,omitempty"`
+}
+
+// JSON is used to convert a generic Feed to a JSONFeed.
+type JSON struct {
+	*Feed
+}
+
+// ToJSON encodes f into a JSON string. Returns an error if marshalling fails.
+func (f *JSON) ToJSON() (string, error) {
+	return f.JSONFeed().ToJSON()
+}
+
+// ToJSON encodes f into a JSON string. Returns an error if marshalling fails.
+func (f *JSONFeed) ToJSON() (string, error) {
+	data, err := json.MarshalIndent(f, "", "  ")
+	if err != nil {
+		return "", err
+	}
+
+	return string(data), nil
+}
+
+// JSONFeed creates a new JSONFeed with a generic Feed struct's data.
+func (f *JSON) JSONFeed() *JSONFeed {
+	feed := &JSONFeed{
+		Version:     jsonFeedVersion,
+		Title:       f.Title,
+		Description: f.Description,
+	}
+
+	if f.Link != nil {
+		feed.HomePageUrl = f.Link.Href
+	}
+	if f.Author != nil {
+		feed.Author = &JSONAuthor{
+			Name: f.Author.Name,
+		}
+	}
+	for _, e := range f.Items {
+		feed.Items = append(feed.Items, newJSONItem(e))
+	}
+	return feed
+}
+
+func newJSONItem(i *Item) *JSONItem {
+	item := &JSONItem{
+		Id:      i.Id,
+		Title:   i.Title,
+		Summary: i.Description,
+
+		ContentHTML: i.Content,
+	}
+
+	if i.Link != nil {
+		item.Url = i.Link.Href
+	}
+	if i.Source != nil {
+		item.ExternalUrl = i.Source.Href
+	}
+	if i.Author != nil {
+		item.Author = &JSONAuthor{
+			Name: i.Author.Name,
+		}
+	}
+	if !i.Created.IsZero() {
+		item.PublishedDate = &i.Created
+	}
+	if !i.Updated.IsZero() {
+		item.ModifiedDate = &i.Updated
+	}
+	if i.Enclosure != nil && strings.HasPrefix(i.Enclosure.Type, "image/") {
+		item.Image = i.Enclosure.Url
+	}
+
+	return item
+}
diff --git a/vendor/github.com/gorilla/feeds/rss.go b/vendor/github.com/gorilla/feeds/rss.go
new file mode 100644
index 0000000..09179df
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/rss.go
@@ -0,0 +1,168 @@
+package feeds
+
+// rss support
+// validation done according to spec here:
+//    http://cyber.law.harvard.edu/rss/rss.html
+
+import (
+	"encoding/xml"
+	"fmt"
+	"time"
+)
+
+// private wrapper around the RssFeed which gives us the <rss>..</rss> xml
+type RssFeedXml struct {
+	XMLName          xml.Name `xml:"rss"`
+	Version          string   `xml:"version,attr"`
+	ContentNamespace string   `xml:"xmlns:content,attr"`
+	Channel          *RssFeed
+}
+
+type RssContent struct {
+	XMLName xml.Name `xml:"content:encoded"`
+	Content string   `xml:",cdata"`
+}
+
+type RssImage struct {
+	XMLName xml.Name `xml:"image"`
+	Url     string   `xml:"url"`
+	Title   string   `xml:"title"`
+	Link    string   `xml:"link"`
+	Width   int      `xml:"width,omitempty"`
+	Height  int      `xml:"height,omitempty"`
+}
+
+type RssTextInput struct {
+	XMLName     xml.Name `xml:"textInput"`
+	Title       string   `xml:"title"`
+	Description string   `xml:"description"`
+	Name        string   `xml:"name"`
+	Link        string   `xml:"link"`
+}
+
+type RssFeed struct {
+	XMLName        xml.Name `xml:"channel"`
+	Title          string   `xml:"title"`       // required
+	Link           string   `xml:"link"`        // required
+	Description    string   `xml:"description"` // required
+	Language       string   `xml:"language,omitempty"`
+	Copyright      string   `xml:"copyright,omitempty"`
+	ManagingEditor string   `xml:"managingEditor,omitempty"` // Author used
+	WebMaster      string   `xml:"webMaster,omitempty"`
+	PubDate        string   `xml:"pubDate,omitempty"`       // created or updated
+	LastBuildDate  string   `xml:"lastBuildDate,omitempty"` // updated used
+	Category       string   `xml:"category,omitempty"`
+	Generator      string   `xml:"generator,omitempty"`
+	Docs           string   `xml:"docs,omitempty"`
+	Cloud          string   `xml:"cloud,omitempty"`
+	Ttl            int      `xml:"ttl,omitempty"`
+	Rating         string   `xml:"rating,omitempty"`
+	SkipHours      string   `xml:"skipHours,omitempty"`
+	SkipDays       string   `xml:"skipDays,omitempty"`
+	Image          *RssImage
+	TextInput      *RssTextInput
+	Items          []*RssItem `xml:"item"`
+}
+
+type RssItem struct {
+	XMLName     xml.Name `xml:"item"`
+	Title       string   `xml:"title"`       // required
+	Link        string   `xml:"link"`        // required
+	Description string   `xml:"description"` // required
+	Content     *RssContent
+	Author      string `xml:"author,omitempty"`
+	Category    string `xml:"category,omitempty"`
+	Comments    string `xml:"comments,omitempty"`
+	Enclosure   *RssEnclosure
+	Guid        string `xml:"guid,omitempty"`    // Id used
+	PubDate     string `xml:"pubDate,omitempty"` // created or updated
+	Source      string `xml:"source,omitempty"`
+}
+
+type RssEnclosure struct {
+	//RSS 2.0 <enclosure url="http://example.com/file.mp3" length="123456789" type="audio/mpeg" />
+	XMLName xml.Name `xml:"enclosure"`
+	Url     string   `xml:"url,attr"`
+	Length  string   `xml:"length,attr"`
+	Type    string   `xml:"type,attr"`
+}
+
+type Rss struct {
+	*Feed
+}
+
+// create a new RssItem with a generic Item struct's data
+func newRssItem(i *Item) *RssItem {
+	item := &RssItem{
+		Title:       i.Title,
+		Link:        i.Link.Href,
+		Description: i.Description,
+		Guid:        i.Id,
+		PubDate:     anyTimeFormat(time.RFC1123Z, i.Created, i.Updated),
+	}
+	if len(i.Content) > 0 {
+		item.Content = &RssContent{Content: i.Content}
+	}
+	if i.Source != nil {
+		item.Source = i.Source.Href
+	}
+
+	// Define a closure
+	if i.Enclosure != nil && i.Enclosure.Type != "" && i.Enclosure.Length != "" {
+		item.Enclosure = &RssEnclosure{Url: i.Enclosure.Url, Type: i.Enclosure.Type, Length: i.Enclosure.Length}
+	}
+
+	if i.Author != nil {
+		item.Author = i.Author.Name
+	}
+	return item
+}
+
+// create a new RssFeed with a generic Feed struct's data
+func (r *Rss) RssFeed() *RssFeed {
+	pub := anyTimeFormat(time.RFC1123Z, r.Created, r.Updated)
+	build := anyTimeFormat(time.RFC1123Z, r.Updated)
+	author := ""
+	if r.Author != nil {
+		author = r.Author.Email
+		if len(r.Author.Name) > 0 {
+			author = fmt.Sprintf("%s (%s)", r.Author.Email, r.Author.Name)
+		}
+	}
+
+	var image *RssImage
+	if r.Image != nil {
+		image = &RssImage{Url: r.Image.Url, Title: r.Image.Title, Link: r.Image.Link, Width: r.Image.Width, Height: r.Image.Height}
+	}
+
+	channel := &RssFeed{
+		Title:          r.Title,
+		Link:           r.Link.Href,
+		Description:    r.Description,
+		ManagingEditor: author,
+		PubDate:        pub,
+		LastBuildDate:  build,
+		Copyright:      r.Copyright,
+		Image:          image,
+	}
+	for _, i := range r.Items {
+		channel.Items = append(channel.Items, newRssItem(i))
+	}
+	return channel
+}
+
+// FeedXml returns an XML-Ready object for an Rss object
+func (r *Rss) FeedXml() interface{} {
+	// only generate version 2.0 feeds for now
+	return r.RssFeed().FeedXml()
+
+}
+
+// FeedXml returns an XML-ready object for an RssFeed object
+func (r *RssFeed) FeedXml() interface{} {
+	return &RssFeedXml{
+		Version:          "2.0",
+		Channel:          r,
+		ContentNamespace: "http://purl.org/rss/1.0/modules/content/",
+	}
+}
diff --git a/vendor/github.com/gorilla/feeds/test.atom b/vendor/github.com/gorilla/feeds/test.atom
new file mode 100644
index 0000000..aa15214
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/test.atom
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feed xmlns:atom="http://www.w3.org/2005/Atom">
+        <title><![CDATA[Lorem ipsum feed for an interval of 1 minutes]]></title>
+        <description><![CDATA[This is a constantly updating lorem ipsum feed]]></description>
+        <link>http://example.com/</link>
+        <generator>RSS for Node</generator>
+        <lastBuildDate>Tue, 30 Oct 2018 23:22:37 GMT</lastBuildDate>
+        <author><![CDATA[John Smith]]></author>
+        <pubDate>Tue, 30 Oct 2018 23:22:00 GMT</pubDate>
+        <copyright><![CDATA[Michael Bertolacci, licensed under a Creative Commons Attribution 3.0 Unported License.]]></copyright>
+        <ttl>60</ttl>
+        <entry>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:22:00+00:00]]></title>
+            <description><![CDATA[Exercitation ut Lorem sint proident.]]></description>
+            <link>http://example.com/test/1540941720</link>
+            <guid isPermaLink="true">http://example.com/test/1540941720</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:22:00 GMT</pubDate>
+        </entry>
+        <entry>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:21:00+00:00]]></title>
+            <description><![CDATA[Ea est do quis fugiat exercitation.]]></description>
+            <link>http://example.com/test/1540941660</link>
+            <guid isPermaLink="true">http://example.com/test/1540941660</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:21:00 GMT</pubDate>
+        </entry>
+        <entry>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:20:00+00:00]]></title>
+            <description><![CDATA[Ipsum velit cillum ad laborum sit nulla exercitation consequat sint veniam culpa veniam voluptate incididunt.]]></description>
+            <link>http://example.com/test/1540941600</link>
+            <guid isPermaLink="true">http://example.com/test/1540941600</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:20:00 GMT</pubDate>
+        </entry>
+        <entry>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:19:00+00:00]]></title>
+            <description><![CDATA[Ullamco pariatur aliqua consequat ea veniam id qui incididunt laborum.]]></description>
+            <link>http://example.com/test/1540941540</link>
+            <guid isPermaLink="true">http://example.com/test/1540941540</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:19:00 GMT</pubDate>
+        </entry>
+        <entry>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:18:00+00:00]]></title>
+            <description><![CDATA[Velit proident aliquip aliquip anim mollit voluptate laboris voluptate et occaecat occaecat laboris ea nulla.]]></description>
+            <link>http://example.com/test/1540941480</link>
+            <guid isPermaLink="true">http://example.com/test/1540941480</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:18:00 GMT</pubDate>
+        </entry>
+        <entry>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:17:00+00:00]]></title>
+            <description><![CDATA[Do in quis mollit consequat id in minim laborum sint exercitation laborum elit officia.]]></description>
+            <link>http://example.com/test/1540941420</link>
+            <guid isPermaLink="true">http://example.com/test/1540941420</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:17:00 GMT</pubDate>
+        </entry>
+        <entry>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:16:00+00:00]]></title>
+            <description><![CDATA[Irure id sint ullamco Lorem magna consectetur officia adipisicing duis incididunt.]]></description>
+            <link>http://example.com/test/1540941360</link>
+            <guid isPermaLink="true">http://example.com/test/1540941360</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:16:00 GMT</pubDate>
+        </entry>
+        <entry>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:15:00+00:00]]></title>
+            <description><![CDATA[Sunt anim excepteur esse nisi commodo culpa laborum exercitation ad anim ex elit.]]></description>
+            <link>http://example.com/test/1540941300</link>
+            <guid isPermaLink="true">http://example.com/test/1540941300</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:15:00 GMT</pubDate>
+        </entry>
+        <entry>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:14:00+00:00]]></title>
+            <description><![CDATA[Excepteur aliquip fugiat ex labore nisi.]]></description>
+            <link>http://example.com/test/1540941240</link>
+            <guid isPermaLink="true">http://example.com/test/1540941240</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:14:00 GMT</pubDate>
+        </entry>
+        <entry>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:13:00+00:00]]></title>
+            <description><![CDATA[Id proident adipisicing proident pariatur aute pariatur pariatur dolor dolor in voluptate dolor.]]></description>
+            <link>http://example.com/test/1540941180</link>
+            <guid isPermaLink="true">http://example.com/test/1540941180</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:13:00 GMT</pubDate>
+        </entry>
+</feed>
\ No newline at end of file
diff --git a/vendor/github.com/gorilla/feeds/test.rss b/vendor/github.com/gorilla/feeds/test.rss
new file mode 100644
index 0000000..8d912ab
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/test.rss
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rss xmlns:dc="http://purl.org/dc/elements/1.1/" 
+    xmlns:content="http://purl.org/rss/1.0/modules/content/" 
+    xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
+    <channel>
+        <title><![CDATA[Lorem ipsum feed for an interval of 1 minutes]]></title>
+        <description><![CDATA[This is a constantly updating lorem ipsum feed]]></description>
+        <link>http://example.com/</link>
+        <generator>RSS for Node</generator>
+        <lastBuildDate>Tue, 30 Oct 2018 23:22:37 GMT</lastBuildDate>
+        <author><![CDATA[John Smith]]></author>
+        <pubDate>Tue, 30 Oct 2018 23:22:00 GMT</pubDate>
+        <copyright><![CDATA[Michael Bertolacci, licensed under a Creative Commons Attribution 3.0 Unported License.]]></copyright>
+        <ttl>60</ttl>
+        <item>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:22:00+00:00]]></title>
+            <description><![CDATA[Exercitation ut Lorem sint proident.]]></description>
+            <link>http://example.com/test/1540941720</link>
+            <guid isPermaLink="true">http://example.com/test/1540941720</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:22:00 GMT</pubDate>
+        </item>
+        <item>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:21:00+00:00]]></title>
+            <description><![CDATA[Ea est do quis fugiat exercitation.]]></description>
+            <link>http://example.com/test/1540941660</link>
+            <guid isPermaLink="true">http://example.com/test/1540941660</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:21:00 GMT</pubDate>
+        </item>
+        <item>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:20:00+00:00]]></title>
+            <description><![CDATA[Ipsum velit cillum ad laborum sit nulla exercitation consequat sint veniam culpa veniam voluptate incididunt.]]></description>
+            <link>http://example.com/test/1540941600</link>
+            <guid isPermaLink="true">http://example.com/test/1540941600</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:20:00 GMT</pubDate>
+        </item>
+        <item>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:19:00+00:00]]></title>
+            <description><![CDATA[Ullamco pariatur aliqua consequat ea veniam id qui incididunt laborum.]]></description>
+            <link>http://example.com/test/1540941540</link>
+            <guid isPermaLink="true">http://example.com/test/1540941540</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:19:00 GMT</pubDate>
+        </item>
+        <item>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:18:00+00:00]]></title>
+            <description><![CDATA[Velit proident aliquip aliquip anim mollit voluptate laboris voluptate et occaecat occaecat laboris ea nulla.]]></description>
+            <link>http://example.com/test/1540941480</link>
+            <guid isPermaLink="true">http://example.com/test/1540941480</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:18:00 GMT</pubDate>
+        </item>
+        <item>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:17:00+00:00]]></title>
+            <description><![CDATA[Do in quis mollit consequat id in minim laborum sint exercitation laborum elit officia.]]></description>
+            <link>http://example.com/test/1540941420</link>
+            <guid isPermaLink="true">http://example.com/test/1540941420</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:17:00 GMT</pubDate>
+        </item>
+        <item>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:16:00+00:00]]></title>
+            <description><![CDATA[Irure id sint ullamco Lorem magna consectetur officia adipisicing duis incididunt.]]></description>
+            <link>http://example.com/test/1540941360</link>
+            <guid isPermaLink="true">http://example.com/test/1540941360</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:16:00 GMT</pubDate>
+        </item>
+        <item>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:15:00+00:00]]></title>
+            <description><![CDATA[Sunt anim excepteur esse nisi commodo culpa laborum exercitation ad anim ex elit.]]></description>
+            <link>http://example.com/test/1540941300</link>
+            <guid isPermaLink="true">http://example.com/test/1540941300</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:15:00 GMT</pubDate>
+        </item>
+        <item>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:14:00+00:00]]></title>
+            <description><![CDATA[Excepteur aliquip fugiat ex labore nisi.]]></description>
+            <link>http://example.com/test/1540941240</link>
+            <guid isPermaLink="true">http://example.com/test/1540941240</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:14:00 GMT</pubDate>
+        </item>
+        <item>
+            <title><![CDATA[Lorem ipsum 2018-10-30T23:13:00+00:00]]></title>
+            <description><![CDATA[Id proident adipisicing proident pariatur aute pariatur pariatur dolor dolor in voluptate dolor.]]></description>
+            <link>http://example.com/test/1540941180</link>
+            <guid isPermaLink="true">http://example.com/test/1540941180</guid>
+            <dc:creator><![CDATA[John Smith]]></dc:creator>
+            <pubDate>Tue, 30 Oct 2018 23:13:00 GMT</pubDate>
+        </item>
+    </channel>
+</rss>
\ No newline at end of file
diff --git a/vendor/github.com/gorilla/feeds/to-implement.md b/vendor/github.com/gorilla/feeds/to-implement.md
new file mode 100644
index 0000000..45fd1e7
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/to-implement.md
@@ -0,0 +1,20 @@
+[Full iTunes list](https://help.apple.com/itc/podcasts_connect/#/itcb54353390)
+
+[Example of ideal iTunes RSS feed](https://help.apple.com/itc/podcasts_connect/#/itcbaf351599)
+
+```
+<itunes:author>
+<itunes:block>
+<itunes:catergory>
+<itunes:image>
+<itunes:duration>
+<itunes:explicit>
+<itunes:isClosedCaptioned>
+<itunes:order>
+<itunes:complete>
+<itunes:new-feed-url>
+<itunes:owner>
+<itunes:subtitle>
+<itunes:summary>
+<language>
+```
\ No newline at end of file
diff --git a/vendor/github.com/gorilla/feeds/uuid.go b/vendor/github.com/gorilla/feeds/uuid.go
new file mode 100644
index 0000000..51bbafe
--- /dev/null
+++ b/vendor/github.com/gorilla/feeds/uuid.go
@@ -0,0 +1,27 @@
+package feeds
+
+// relevant bits from https://github.com/abneptis/GoUUID/blob/master/uuid.go
+
+import (
+	"crypto/rand"
+	"fmt"
+)
+
+type UUID [16]byte
+
+// create a new uuid v4
+func NewUUID() *UUID {
+	u := &UUID{}
+	_, err := rand.Read(u[:16])
+	if err != nil {
+		panic(err)
+	}
+
+	u[8] = (u[8] | 0x80) & 0xBf
+	u[6] = (u[6] | 0x40) & 0x4f
+	return u
+}
+
+func (u *UUID) String() string {
+	return fmt.Sprintf("%x-%x-%x-%x-%x", u[:4], u[4:6], u[6:8], u[8:10], u[10:])
+}