diff --git a/cmd/podsync/updater.go b/cmd/podsync/updater.go index 26d48b9..d17ad91 100644 --- a/cmd/podsync/updater.go +++ b/cmd/podsync/updater.go @@ -63,7 +63,7 @@ func (u *Updater) Update(ctx context.Context, feedConfig *config.Feed) error { return err } - if err := u.buildOPML(ctx, feedConfig); err != nil { + if err := u.buildOPML(ctx); err != nil { return err } @@ -251,7 +251,7 @@ func (u *Updater) buildXML(ctx context.Context, feedConfig *config.Feed) error { return nil } -func (u *Updater) buildOPML(ctx context.Context, feedConfig *config.Feed) error { +func (u *Updater) buildOPML(ctx context.Context) error { // Build OPML with data received from builder log.Debug("building podcast OPML") diff --git a/go.mod b/go.mod index e60c533..253370e 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,8 @@ require ( github.com/BurntSushi/toml v0.3.1 github.com/dgraph-io/badger v1.6.0 github.com/eduncan911/podcast v1.3.0 + github.com/gilliek/go-opml v1.0.0 + github.com/golang/mock v1.4.3 github.com/hashicorp/go-multierror v1.0.0 github.com/jessevdk/go-flags v1.4.0 github.com/pkg/errors v0.8.1 @@ -14,7 +16,7 @@ require ( github.com/stretchr/testify v1.3.0 golang.org/x/net v0.0.0-20190620200207-3b0461eec859 golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd - golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 + golang.org/x/sync v0.0.0-20190423024810-112230192c58 google.golang.org/api v0.0.0-20180718221112-efcb5f25ac56 google.golang.org/appengine v1.1.0 // indirect ) diff --git a/go.sum b/go.sum index 3577209..c6d2af4 100644 --- a/go.sum +++ b/go.sum @@ -21,6 +21,10 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/eduncan911/podcast v1.3.0 h1:lVCar1J39mMNWR2SbGzPjeUbCKEkQ6/pt/7beQqK6fk= github.com/eduncan911/podcast v1.3.0/go.mod h1:C7Q04QZtv7LW/1X67mc1zwsktpZ68kbxsUS3CYWniJg= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/gilliek/go-opml v1.0.0 h1:X8xVjtySRXU/x6KvaiXkn7OV3a4DHqxY8Rpv6U/JvCY= +github.com/gilliek/go-opml v1.0.0/go.mod h1:fOxmtlzyBvUjU6bjpdjyxCGlWz+pgtAHrHf/xRZl3lk= +github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -67,22 +71,28 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd h1:QQhib242ErYDSMitlBm8V7wYCm/1a25hV8qMadIKLPA= golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/api v0.0.0-20180718221112-efcb5f25ac56 h1:iDRbkenn0VZEo05mHiCtN6/EfbZj7x1Rg+tPjB5HiQc= google.golang.org/api v0.0.0-20180718221112-efcb5f25ac56/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/pkg/feed/build.go b/pkg/feed/build.go index ace0bb8..93d1c92 100644 --- a/pkg/feed/build.go +++ b/pkg/feed/build.go @@ -13,10 +13,6 @@ import ( "github.com/mxpv/podsync/pkg/model" ) -type urlProvider interface { - URL(ctx context.Context, ns string, fileName string) (string, error) -} - func Build(ctx context.Context, feed *model.Feed, cfg *config.Feed, provider urlProvider) (*itunes.Podcast, error) { const ( podsyncGenerator = "Podsync generator (support us at https://github.com/mxpv/podsync)" diff --git a/pkg/feed/common.go b/pkg/feed/common.go index 58729a2..c8823c0 100644 --- a/pkg/feed/common.go +++ b/pkg/feed/common.go @@ -41,3 +41,11 @@ func New(ctx context.Context, cfg *config.Feed, tokens config.Tokens) (Builder, return provider, err } + +type feedProvider interface { + GetFeed(ctx context.Context, feedID string) (*model.Feed, error) +} + +type urlProvider interface { + URL(ctx context.Context, ns string, fileName string) (string, error) +} diff --git a/pkg/feed/opml.go b/pkg/feed/opml.go index dfa9883..ac77224 100644 --- a/pkg/feed/opml.go +++ b/pkg/feed/opml.go @@ -4,64 +4,44 @@ import ( "context" "fmt" - "encoding/xml" + "github.com/gilliek/go-opml/opml" + "github.com/pkg/errors" "github.com/mxpv/podsync/pkg/config" - "github.com/mxpv/podsync/pkg/db" - "github.com/mxpv/podsync/pkg/fs" - "github.com/pkg/errors" ) -type opml struct { - XMLName xml.Name `xml:"opml"` - Version string `xml:"version,attr"` - Head head - Body body -} - -type head struct { - XMLName xml.Name `xml:"head"` - Title string `xml:"title"` -} - -type body struct { - XMLName xml.Name `xml:"body"` - Outlines []outline `xml:"outline"` -} - -type outline struct { - Text string `xml:"text,attr"` - Title string `xml:"title,attr"` - Type string `xml:"type,attr"` - XMLURL string `xml:"xmlUrl,attr"` -} - -func BuildOPML(ctx context.Context, config *config.Config, db db.Storage, fs fs.Storage) (string, error) { - - ou := make([]outline, 0) +func BuildOPML(ctx context.Context, config *config.Config, db feedProvider, provider urlProvider) (string, error) { + doc := opml.OPML{Version: "1.0"} + doc.Head = opml.Head{Title: "Podsync feeds"} + doc.Body = opml.Body{} for _, feed := range config.Feeds { - f, err := db.GetFeed(ctx, feed.ID) if err != nil { return "", err } if feed.OPML { - downloadURL, err := fs.URL(ctx, "", fmt.Sprintf("%s.xml", feed.ID)) + downloadURL, err := provider.URL(ctx, "", fmt.Sprintf("%s.xml", feed.ID)) if err != nil { - return "", errors.Wrapf(err, "failed to: obtain download URL for feed") + return "", errors.Wrapf(err, "failed to get feed URL for %q", feed.ID) } - ou = append(ou, outline{Title: f.Title, Text: f.Title, Type: "rss", XMLURL: downloadURL}) + + outline := opml.Outline{ + Title: f.Title, + Text: f.Description, + Type: "rss", + XMLURL: downloadURL, + } + + doc.Body.Outlines = append(doc.Body.Outlines, outline) } } - op := opml{Version: "1.0"} - op.Head = head{Title: "PodSync feeds"} - op.Body = body{Outlines: ou} - - out, _ := xml.MarshalIndent(op, " ", " ") - - return xml.Header + string(out), nil + out, err := doc.XML() + if err != nil { + return "", errors.Wrap(err, "failed to marshal OPML") + } + return out, nil }