From cedb7d95d03da21d73eed6a4768b15dccca1a843 Mon Sep 17 00:00:00 2001 From: Loweel Date: Sun, 4 May 2025 04:01:53 +0200 Subject: [PATCH] Cambio librerie --- go.mod | 5 +- go.sum | 24 +- pod.go | 6 - rss-xml.go | 76 +- .../github.com/eduncan911/podcast/.gitignore | 7 + vendor/github.com/eduncan911/podcast/LICENSE | 21 + vendor/github.com/eduncan911/podcast/Makefile | 17 + .../github.com/eduncan911/podcast/README.md | 1274 +++++++++++++++++ .../github.com/eduncan911/podcast/atomlink.go | 11 + .../github.com/eduncan911/podcast/author.go | 12 + vendor/github.com/eduncan911/podcast/doc.go | 157 ++ .../eduncan911/podcast/enclosure.go | 65 + vendor/github.com/eduncan911/podcast/fuzz.go | 297 ++++ vendor/github.com/eduncan911/podcast/image.go | 21 + vendor/github.com/eduncan911/podcast/item.go | 144 ++ .../github.com/eduncan911/podcast/itunes.go | 34 + .../github.com/eduncan911/podcast/podcast.go | 454 ++++++ .../eduncan911/podcast/textinput.go | 12 + vendor/github.com/google/uuid/CHANGELOG.md | 41 - vendor/github.com/google/uuid/CONTRIBUTING.md | 26 - vendor/github.com/google/uuid/CONTRIBUTORS | 9 - vendor/github.com/google/uuid/LICENSE | 27 - vendor/github.com/google/uuid/README.md | 21 - vendor/github.com/google/uuid/dce.go | 80 -- vendor/github.com/google/uuid/doc.go | 12 - vendor/github.com/google/uuid/hash.go | 59 - vendor/github.com/google/uuid/marshal.go | 38 - vendor/github.com/google/uuid/node.go | 90 -- vendor/github.com/google/uuid/node_js.go | 12 - vendor/github.com/google/uuid/node_net.go | 33 - vendor/github.com/google/uuid/null.go | 118 -- vendor/github.com/google/uuid/sql.go | 59 - vendor/github.com/google/uuid/time.go | 134 -- vendor/github.com/google/uuid/util.go | 43 - vendor/github.com/google/uuid/uuid.go | 365 ----- vendor/github.com/google/uuid/version1.go | 44 - vendor/github.com/google/uuid/version4.go | 76 - vendor/github.com/google/uuid/version6.go | 56 - vendor/github.com/google/uuid/version7.go | 104 -- vendor/github.com/gorilla/feeds/.editorconfig | 20 - vendor/github.com/gorilla/feeds/.gitignore | 1 - vendor/github.com/gorilla/feeds/LICENSE | 28 - vendor/github.com/gorilla/feeds/Makefile | 34 - vendor/github.com/gorilla/feeds/README.md | 198 --- vendor/github.com/gorilla/feeds/atom.go | 178 --- vendor/github.com/gorilla/feeds/doc.go | 73 - vendor/github.com/gorilla/feeds/feed.go | 146 -- vendor/github.com/gorilla/feeds/json.go | 190 --- vendor/github.com/gorilla/feeds/rss.go | 183 --- vendor/github.com/gorilla/feeds/test.atom | 92 -- vendor/github.com/gorilla/feeds/test.rss | 96 -- .../github.com/gorilla/feeds/to-implement.md | 20 - vendor/github.com/gorilla/feeds/uuid.go | 27 - vendor/github.com/pkg/errors/.gitignore | 24 + vendor/github.com/pkg/errors/.travis.yml | 10 + vendor/github.com/pkg/errors/LICENSE | 23 + vendor/github.com/pkg/errors/Makefile | 44 + vendor/github.com/pkg/errors/README.md | 59 + vendor/github.com/pkg/errors/appveyor.yml | 32 + vendor/github.com/pkg/errors/errors.go | 288 ++++ vendor/github.com/pkg/errors/go113.go | 38 + vendor/github.com/pkg/errors/stack.go | 177 +++ vendor/modules.txt | 10 +- 63 files changed, 3288 insertions(+), 2787 deletions(-) create mode 100644 vendor/github.com/eduncan911/podcast/.gitignore create mode 100644 vendor/github.com/eduncan911/podcast/LICENSE create mode 100644 vendor/github.com/eduncan911/podcast/Makefile create mode 100644 vendor/github.com/eduncan911/podcast/README.md create mode 100644 vendor/github.com/eduncan911/podcast/atomlink.go create mode 100644 vendor/github.com/eduncan911/podcast/author.go create mode 100644 vendor/github.com/eduncan911/podcast/doc.go create mode 100644 vendor/github.com/eduncan911/podcast/enclosure.go create mode 100644 vendor/github.com/eduncan911/podcast/fuzz.go create mode 100644 vendor/github.com/eduncan911/podcast/image.go create mode 100644 vendor/github.com/eduncan911/podcast/item.go create mode 100644 vendor/github.com/eduncan911/podcast/itunes.go create mode 100644 vendor/github.com/eduncan911/podcast/podcast.go create mode 100644 vendor/github.com/eduncan911/podcast/textinput.go delete mode 100644 vendor/github.com/google/uuid/CHANGELOG.md delete mode 100644 vendor/github.com/google/uuid/CONTRIBUTING.md delete mode 100644 vendor/github.com/google/uuid/CONTRIBUTORS delete mode 100644 vendor/github.com/google/uuid/LICENSE delete mode 100644 vendor/github.com/google/uuid/README.md delete mode 100644 vendor/github.com/google/uuid/dce.go delete mode 100644 vendor/github.com/google/uuid/doc.go delete mode 100644 vendor/github.com/google/uuid/hash.go delete mode 100644 vendor/github.com/google/uuid/marshal.go delete mode 100644 vendor/github.com/google/uuid/node.go delete mode 100644 vendor/github.com/google/uuid/node_js.go delete mode 100644 vendor/github.com/google/uuid/node_net.go delete mode 100644 vendor/github.com/google/uuid/null.go delete mode 100644 vendor/github.com/google/uuid/sql.go delete mode 100644 vendor/github.com/google/uuid/time.go delete mode 100644 vendor/github.com/google/uuid/util.go delete mode 100644 vendor/github.com/google/uuid/uuid.go delete mode 100644 vendor/github.com/google/uuid/version1.go delete mode 100644 vendor/github.com/google/uuid/version4.go delete mode 100644 vendor/github.com/google/uuid/version6.go delete mode 100644 vendor/github.com/google/uuid/version7.go delete mode 100644 vendor/github.com/gorilla/feeds/.editorconfig delete mode 100644 vendor/github.com/gorilla/feeds/.gitignore delete mode 100644 vendor/github.com/gorilla/feeds/LICENSE delete mode 100644 vendor/github.com/gorilla/feeds/Makefile delete mode 100644 vendor/github.com/gorilla/feeds/README.md delete mode 100644 vendor/github.com/gorilla/feeds/atom.go delete mode 100644 vendor/github.com/gorilla/feeds/doc.go delete mode 100644 vendor/github.com/gorilla/feeds/feed.go delete mode 100644 vendor/github.com/gorilla/feeds/json.go delete mode 100644 vendor/github.com/gorilla/feeds/rss.go delete mode 100644 vendor/github.com/gorilla/feeds/test.atom delete mode 100644 vendor/github.com/gorilla/feeds/test.rss delete mode 100644 vendor/github.com/gorilla/feeds/to-implement.md delete mode 100644 vendor/github.com/gorilla/feeds/uuid.go create mode 100644 vendor/github.com/pkg/errors/.gitignore create mode 100644 vendor/github.com/pkg/errors/.travis.yml create mode 100644 vendor/github.com/pkg/errors/LICENSE create mode 100644 vendor/github.com/pkg/errors/Makefile create mode 100644 vendor/github.com/pkg/errors/README.md create mode 100644 vendor/github.com/pkg/errors/appveyor.yml create mode 100644 vendor/github.com/pkg/errors/errors.go create mode 100644 vendor/github.com/pkg/errors/go113.go create mode 100644 vendor/github.com/pkg/errors/stack.go diff --git a/go.mod b/go.mod index 33572c2..7b24ecb 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.21.0 require ( github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8 - github.com/google/uuid v1.6.0 - github.com/gorilla/feeds v1.2.0 + github.com/eduncan911/podcast v1.4.2 ) + +require github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index aff7081..c032870 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,16 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8 h1:OtSeLS5y0Uy01jaKK4mA/WVIYtpzVm63vLVAPzJXigg= github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8/go.mod h1:apkPC/CR3s48O2D7Y++n1XWEpgPNNCjXYga3PPbJe2E= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/feeds v1.2.0 h1:O6pBiXJ5JHhPvqy53NsjKOThq+dNFm8+DFrxBEdzSCc= -github.com/gorilla/feeds v1.2.0/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/eduncan911/podcast v1.4.2 h1:S+fsUlbR2ULFou2Mc52G/MZI8JVJHedbxLQnoA+MY/w= +github.com/eduncan911/podcast v1.4.2/go.mod h1:mSxiK1z5KeNO0YFaQ3ElJlUZbbDV9dA7R9c1coeeXkc= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pod.go b/pod.go index cdaba77..857ef29 100644 --- a/pod.go +++ b/pod.go @@ -9,7 +9,6 @@ import ( "time" "github.com/dhowden/tag" - "github.com/google/uuid" ) type Episode struct { @@ -27,11 +26,6 @@ var ( rssLock sync.Mutex ) -func generateUUIDFromString(input string) uuid.UUID { - namespace := uuid.NameSpaceDNS // Namespace fisso per consistenza - return uuid.NewSHA1(namespace, []byte(input)) -} - func scanEpisodes() ([]Episode, error) { var episodes []Episode diff --git a/rss-xml.go b/rss-xml.go index 0ae8380..342ed83 100644 --- a/rss-xml.go +++ b/rss-xml.go @@ -1,12 +1,13 @@ package main import ( - "fmt" + "log" "os" "path/filepath" + "strings" "time" - "github.com/gorilla/feeds" + "github.com/eduncan911/podcast" ) func generateRSS() error { @@ -18,46 +19,59 @@ func generateRSS() error { return err } - // rss := fmt.Sprintf(` - // - // - // %s - // %s - // %s`, podTitle, podTitle, baseURL) + timeNow := time.Now() - feed := &feeds.Feed{ - Title: podTitle, - Link: &feeds.Link{Href: baseURL}, - Description: podDesc, - Author: &feeds.Author{Name: podAuthor}, - Created: time.Now(), - Copyright: podRights, - } + p := podcast.New( + podTitle, + baseURL, + podDesc, + &timeNow, &timeNow, + ) + + // 2. Aggiungi metadati globali + p.IAuthor = podAuthor + p.AddImage(podLogo) for _, ep := range episodes { epBaseUrl := baseURL + "/audio/" + filepath.Base(ep.File) - feed.Add(&feeds.Item{ + strip, found := strings.CutSuffix(epBaseUrl, ".mp3") + if !found { + log.Println("Seems the file is not mp3??????") + } + epBaseImg := baseURL + "/covers/" + strip + ".jpg" + + item := podcast.Item{ Title: ep.Title, - Link: &feeds.Link{Href: epBaseUrl}, Description: ep.Description, - Enclosure: &feeds.Enclosure{ - Url: epBaseUrl, - Length: fmt.Sprintf("%d", ep.Size), - Type: "audio/mpeg", + PubDate: &timeNow, + Enclosure: &podcast.Enclosure{ + URL: epBaseUrl, + Type: podcast.MP3, + Length: ep.Size, }, - Created: time.Now(), - }) + // Metadati specifici iTunes + IAuthor: ep.Artist, + IImage: &podcast.IImage{ + HREF: epBaseImg, // Campo corretto + }, + IExplicit: "no", + } + + if _, err := p.AddItem(item); err != nil { + log.Fatal("Errore nell'aggiunta dell'episodio: ", err) + } } - // Genera RSS - rss, _ := feed.ToRss() - return os.WriteFile("feed.xml", []byte(rss), 0644) + if err := p.Encode(os.Stdout); err != nil { + panic(err) + } + + // Opzionale: salva su file + file, _ := os.Create("feed.xml") + defer file.Close() + return p.Encode(file) } diff --git a/vendor/github.com/eduncan911/podcast/.gitignore b/vendor/github.com/eduncan911/podcast/.gitignore new file mode 100644 index 0000000..1b1053c --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/.gitignore @@ -0,0 +1,7 @@ +profile.out +README.md.tmp +corpus +crashers +suppressions +workdir +podcast-fuzz.zip diff --git a/vendor/github.com/eduncan911/podcast/LICENSE b/vendor/github.com/eduncan911/podcast/LICENSE new file mode 100644 index 0000000..06a51ca --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Eric Duncan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/eduncan911/podcast/Makefile b/vendor/github.com/eduncan911/podcast/Makefile new file mode 100644 index 0000000..1b8e97f --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/Makefile @@ -0,0 +1,17 @@ +SHELL = /bin/bash + +GITHUB_REPO:=eduncan911/podcast + +README: + godoc2ghmd -play -ex -verify_import_links=0 github.com/$(GITHUB_REPO) > README.md.tmp + echo "[![GoDoc](https://godoc.org/github.com/$(GITHUB_REPO)?status.svg)](https://godoc.org/github.com/$(GITHUB_REPO))" > README.md + echo "[![Build Status](https://github.com/$(GITHUB_REPO)/workflows/go-cicd/badge.svg)](https://github.com/$(GITHUB_REPO)/actions?workflow=go-cicd)" >> README.md + echo "[![Coverage Status](https://coveralls.io/repos/github/$(GITHUB_REPO)/badge.svg?branch=master)](https://coveralls.io/github/$(GITHUB_REPO)?branch=master)" >> README.md + echo "[![Go Report Card](https://goreportcard.com/badge/github.com/$(GITHUB_REPO))](https://goreportcard.com/report/github.com/$(GITHUB_REPO))" >> README.md + echo "[![MIT License](https://img.shields.io/npm/l/mediaelement.svg)](https://eduncan911.mit-license.org/)" >> README.md + echo >>README.md + cat README.md.tmp >> README.md + rm README.md.tmp + +clean: + rm -rf corpus crashers suppressions workdir podcast-fuzz.zip diff --git a/vendor/github.com/eduncan911/podcast/README.md b/vendor/github.com/eduncan911/podcast/README.md new file mode 100644 index 0000000..fded6c8 --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/README.md @@ -0,0 +1,1274 @@ +[![GoDoc](https://godoc.org/github.com/eduncan911/podcast?status.svg)](https://godoc.org/github.com/eduncan911/podcast) +[![Build Status](https://github.com/eduncan911/podcast/workflows/go-cicd/badge.svg)](https://github.com/eduncan911/podcast/actions?workflow=go-cicd) +[![Coverage Status](https://coveralls.io/repos/github/eduncan911/podcast/badge.svg?branch=master)](https://coveralls.io/github/eduncan911/podcast?branch=master) +[![Go Report Card](https://goreportcard.com/badge/github.com/eduncan911/podcast)](https://goreportcard.com/report/github.com/eduncan911/podcast) +[![MIT License](https://img.shields.io/npm/l/mediaelement.svg)](https://eduncan911.mit-license.org/) + +# podcast +Package podcast generates a fully compliant iTunes and RSS 2.0 podcast feed +for GoLang using a simple API. + +Full documentation with detailed examples located at https://godoc.org/github.com/eduncan911/podcast + +### Usage +To use, `go get` and `import` the package like your typical GoLang library. + + $ go get -u github.com/eduncan911/podcast + + import "github.com/eduncan911/podcast" + +The API exposes a number of method receivers on structs that implements the +logic required to comply with the specifications and ensure a compliant feed. +A number of overrides occur to help with iTunes visibility of your episodes. + +Notably, the `Podcast.AddItem` function performs most +of the heavy lifting by taking the `Item` input and performing +validation, overrides and duplicate setters through the feed. + +Full detailed Examples of the API are at https://godoc.org/github.com/eduncan911/podcast. + +### Go Modules +This library is supported on GoLang 1.7 and higher. + +We have implemented Go Modules support and the CI pipeline shows it working with +new installs, tested with Go 1.13. To keep 1.7 compatibility, we use +`go mod vendor` to maintain the `vendor/` folder for older 1.7 and later runtimes. + +If either runtime has an issue, please create an Issue and I will address. + +### Extensibility +For version 1.x, you are not restricted in having full control over your feeds. +You may choose to skip the API methods and instead use the structs directly. The +fields have been grouped by RSS 2.0 and iTunes fields with iTunes specific fields +all prefixed with the letter `I`. + +However, do note that the 2.x version currently in progress will break this +extensibility and enforce API methods going forward. This is to ensure that the feed +can both be marshalled, and unmarshalled back and forth (current 1.x branch can only +be unmarshalled - hence the work for 2.x). + +### Fuzzing Inputs +`go-fuzz` has been added in 1.4.1, covering all exported API methods. They have been +ran extensively and no issues have come out of them yet (most tests were ran overnight, +over about 11 hours with zero crashes). + +If you wish to help fuzz the inputs, with Go 1.13 or later you can run `go-fuzz` on any +of the inputs. + + go get -u github.com/dvyukov/go-fuzz/go-fuzz + go get -u github.com/dvyukov/go-fuzz/go-fuzz-build + go get -u github.com/eduncan911/podcast + cd $GOPATH/src/github.com/eduncan911/podcast + go-fuzz-build + go-fuzz -func FuzzPodcastAddItem + +To obtain a list of available funcs to pass, just run `go-fuzz` without any parameters: + + $ go-fuzz + 2020/02/13 07:27:32 -func flag not provided, but multiple fuzz functions available: + FuzzItemAddDuration, FuzzItemAddEnclosure, FuzzItemAddImage, FuzzItemAddPubDate, + FuzzItemAddSummary, FuzzPodcastAddAtomLink, FuzzPodcastAddAuthor, FuzzPodcastAddCategory, + FuzzPodcastAddImage, FuzzPodcastAddItem, FuzzPodcastAddLastBuildDate, FuzzPodcastAddPubDate, + FuzzPodcastAddSubTitle, FuzzPodcastAddSummary, FuzzPodcastBytes, FuzzPodcastEncode, + FuzzPodcastNew + +If you do find an issue, please raise an issue immediately and I will quickly address. + +### Roadmap +The 1.x branch is now mostly in maintenance mode, open to PRs. This means no +more planned features on the 1.x feature branch is expected. With the success of 6 +iTunes-accepted podcasts I have published with this library, and with the feedback from +the community, the 1.x releases are now considered stable. + +The 2.x branch's primary focus is to allow for bi-direction marshalling both ways. +Currently, the 1.x branch only allows unmarshalling to a serial feed. An attempt to marshall +a serialized feed back into a Podcast form will error or not work correctly. Note that while +the 2.x branch is targeted to remain backwards compatible, it is true if using the public +API funcs to set parameters only. Several of the underlying public fields are being removed +in order to accommodate the marshalling of serialized data. Therefore, a version 2.x is denoted +for this release. + +### Versioning +We use SemVer versioning schema. You can rest assured that pulling 1.x branches will +remain backwards compatible now and into the future. + +However, the new 2.x branch, while keeping the same API, is expected break those that +bypass the API methods and use the underlying public properties instead. + +### Release Notes +v1.4.2 + + * Slim down Go Modules for consumers (#32) + +v1.4.1 + + * Implement fuzz logic testing of exported funcs (#31) + * Upgrade CICD Pipeline Tooling (#31) + * Update documentation for 1.x and 2.3 (#31) + * Allow godoc2ghmd to run without network (#31) + +v1.4.0 + + * Add Go Modules, Update vendor folder (#26, #25) + * Add C.I. GitHub Actions (#25) + * Add additional error checks found by linters (#25) + * Go Fmt enclosure_test.go (#25) + +v1.3.2 + + * Correct count len of UTF8 strings (#9) + * Implement duration parser (#8) + * Fix Github and GoDocs Markdown (#14) + * Move podcast.go Private Methods to Respected Files (#12) + * Allow providing GUID on Podcast (#15) + +v1.3.1 + + * increased itunes compliance after feedback from Apple: + - specified what categories should be set with AddCategory(). + - enforced title and link as part of Image. + * added Podcast.AddAtomLink() for more broad compliance to readers. + +v1.3.0 + + * fixes Item.Duration being set incorrectly. + * changed Item.AddEnclosure() parameter definition (Bytes not Seconds!). + * added Item.AddDuration formatting and override. + * added more documentation surrounding Item.Enclosure{} + +v1.2.1 + + * added Podcast.AddSubTitle() and truncating to 64 chars. + * added a number of Guards to protect against empty fields. + +v1.2.0 + + * added Podcast.AddPubDate() and Podcast.AddLastBuildDate() overrides. + * added Item.AddImage() to mask some cumbersome addition of IImage. + * added Item.AddPubDate to simply datetime setters. + * added more examples (mostly around Item struct). + * tweaked some documentation. + +v1.1.0 + + * Enabling CDATA in ISummary fields for Podcast and Channel. + +v1.0.0 + + * Initial release. + * Full documentation, full examples and complete code coverage. + +### References +RSS 2.0: https://cyber.harvard.edu/rss/rss.html + +Podcasts: https://help.apple.com/itc/podcasts_connect/#/itca5b22233 + +#### Example: + +
+Click to expand code. + +```go +// ResponseWriter example using Podcast.Encode(w io.Writer). + // + httpHandler := func(w http.ResponseWriter, r *http.Request) { + + // instantiate a new Podcast + p := podcast.New( + "eduncan911 Podcasts", + "http://eduncan911.com/", + "An example Podcast", + &pubDate, &updatedDate, + ) + + // add some channel properties + p.AddAuthor("Jane Doe", "me@janedoe.com") + p.AddAtomLink("http://eduncan911.com/feed.rss") + p.AddImage("http://janedoe.com/i.jpg") + p.AddSummary(`link example.com`) + p.IExplicit = "no" + + for i := int64(1); i < 3; i++ { + n := strconv.FormatInt(i, 10) + d := pubDate.AddDate(0, 0, int(i)) + + // create an Item + item := podcast.Item{ + Title: "Episode " + n, + Link: "http://example.com/" + n + ".mp3", + Description: "Description for Episode " + n, + PubDate: &d, + } + item.AddImage("http://example.com/episode-" + n + ".png") + item.AddSummary(`item example.com`) + // add a Download to the Item + item.AddEnclosure("http://e.com/"+n+".mp3", podcast.MP3, 55*(i+1)) + + // add the Item and check for validation errors + if _, err := p.AddItem(item); err != nil { + fmt.Println(item.Title, ": error", err.Error()) + return + } + } + + // set the Content Type to that of XML + w.Header().Set("Content-Type", "application/xml") + + // finally, Encode and write the Podcast to the ResponseWriter. + // + // a simple pattern is to handle any errors within this check. + // alternatively if using middleware, you can just return + // the Podcast entity as it also implements the io.Writer interface + // that complies with several middleware packages. + if err := p.Encode(w); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + } + + rr := httptest.NewRecorder() + httpHandler(rr, nil) + os.Stdout.Write(rr.Body.Bytes()) + // Output: + // + // + // + // eduncan911 Podcasts + // http://eduncan911.com/ + // An example Podcast + // go podcast v1.3.1 (github.com/eduncan911/podcast) + // en-us + // Mon, 06 Feb 2017 08:21:52 +0000 + // me@janedoe.com (Jane Doe) + // Sat, 04 Feb 2017 08:21:52 +0000 + // + // http://janedoe.com/i.jpg + // eduncan911 Podcasts + // http://eduncan911.com/ + // + // + // me@janedoe.com (Jane Doe) + // example.com]]> + // + // no + // + // http://e.com/1.mp3 + // Episode 1 + // http://example.com/1.mp3 + // Description for Episode 1 + // Sun, 05 Feb 2017 08:21:52 +0000 + // + // me@janedoe.com (Jane Doe) + // example.com]]> + // + // + // + // http://e.com/2.mp3 + // Episode 2 + // http://example.com/2.mp3 + // Description for Episode 2 + // Mon, 06 Feb 2017 08:21:52 +0000 + // + // me@janedoe.com (Jane Doe) + // example.com]]> + // + // + // + // +``` + +
+ +#### Example: + +
+Click to expand code. + +```go +// instantiate a new Podcast + p := podcast.New( + "Sample Podcasts", + "http://example.com/", + "An example Podcast", + &createdDate, &updatedDate, + ) + + // add some channel properties + p.ISubtitle = "A simple Podcast" + p.AddSummary(`link example.com`) + p.AddImage("http://example.com/podcast.jpg") + p.AddAuthor("Jane Doe", "jane.doe@example.com") + p.AddAtomLink("http://example.com/atom.rss") + + for i := int64(9); i < 11; i++ { + n := strconv.FormatInt(i, 10) + d := pubDate.AddDate(0, 0, int(i)) + + // create an Item + item := podcast.Item{ + Title: "Episode " + n, + Description: "Description for Episode " + n, + ISubtitle: "A simple episode " + n, + PubDate: &d, + } + item.AddImage("http://example.com/episode-" + n + ".png") + item.AddSummary(`item k example.com`) + // add a Download to the Item + item.AddEnclosure("http://example.com/"+n+".mp3", podcast.MP3, 55*(i+1)) + + // add the Item and check for validation errors + if _, err := p.AddItem(item); err != nil { + os.Stderr.WriteString("item validation error: " + err.Error()) + } + } + + // Podcast.Encode writes to an io.Writer + if err := p.Encode(os.Stdout); err != nil { + fmt.Println("error writing to stdout:", err.Error()) + } + + // Output: + // + // + // + // Sample Podcasts + // http://example.com/ + // An example Podcast + // go podcast v1.3.1 (github.com/eduncan911/podcast) + // en-us + // Mon, 06 Feb 2017 08:21:52 +0000 + // jane.doe@example.com (Jane Doe) + // Wed, 01 Feb 2017 08:21:52 +0000 + // + // http://example.com/podcast.jpg + // Sample Podcasts + // http://example.com/ + // + // + // jane.doe@example.com (Jane Doe) + // A simple Podcast + // example.com]]> + // + // + // http://example.com/9.mp3 + // Episode 9 + // http://example.com/9.mp3 + // Description for Episode 9 + // Mon, 13 Feb 2017 08:21:52 +0000 + // + // jane.doe@example.com (Jane Doe) + // A simple episode 9 + // example.com]]> + // + // + // + // http://example.com/10.mp3 + // Episode 10 + // http://example.com/10.mp3 + // Description for Episode 10 + // Tue, 14 Feb 2017 08:21:52 +0000 + // + // jane.doe@example.com (Jane Doe) + // A simple episode 10 + // example.com]]> + // + // + // + // +``` + +
+ +## Table of Contents + +* [Imported Packages](#pkg-imports) +* [Index](#pkg-index) +* [Examples](#pkg-examples) + +## Imported Packages + +- [github.com/pkg/errors](https://godoc.org/github.com/pkg/errors) + +## Index +* [type AtomLink](#AtomLink) +* [type Author](#Author) +* [type Enclosure](#Enclosure) +* [type EnclosureType](#EnclosureType) + * [func (et EnclosureType) String() string](#EnclosureType.String) +* [type ICategory](#ICategory) +* [type IImage](#IImage) +* [type ISummary](#ISummary) +* [type Image](#Image) +* [type Item](#Item) + * [func (i \*Item) AddDuration(durationInSeconds int64)](#Item.AddDuration) + * [func (i \*Item) AddEnclosure(url string, enclosureType EnclosureType, lengthInBytes int64)](#Item.AddEnclosure) + * [func (i \*Item) AddImage(url string)](#Item.AddImage) + * [func (i \*Item) AddPubDate(datetime \*time.Time)](#Item.AddPubDate) + * [func (i \*Item) AddSummary(summary string)](#Item.AddSummary) +* [type Podcast](#Podcast) + * [func New(title, link, description string, pubDate, lastBuildDate \*time.Time) Podcast](#New) + * [func (p \*Podcast) AddAtomLink(href string)](#Podcast.AddAtomLink) + * [func (p \*Podcast) AddAuthor(name, email string)](#Podcast.AddAuthor) + * [func (p \*Podcast) AddCategory(category string, subCategories []string)](#Podcast.AddCategory) + * [func (p \*Podcast) AddImage(url string)](#Podcast.AddImage) + * [func (p \*Podcast) AddItem(i Item) (int, error)](#Podcast.AddItem) + * [func (p \*Podcast) AddLastBuildDate(datetime \*time.Time)](#Podcast.AddLastBuildDate) + * [func (p \*Podcast) AddPubDate(datetime \*time.Time)](#Podcast.AddPubDate) + * [func (p \*Podcast) AddSubTitle(subTitle string)](#Podcast.AddSubTitle) + * [func (p \*Podcast) AddSummary(summary string)](#Podcast.AddSummary) + * [func (p \*Podcast) Bytes() []byte](#Podcast.Bytes) + * [func (p \*Podcast) Encode(w io.Writer) error](#Podcast.Encode) + * [func (p \*Podcast) String() string](#Podcast.String) +* [type TextInput](#TextInput) + +#### Examples +* [Item.AddDuration](#example_Item_AddDuration) +* [Item.AddPubDate](#example_Item_AddPubDate) +* [New](#example_New) +* [Podcast.AddAuthor](#example_Podcast_AddAuthor) +* [Podcast.AddCategory](#example_Podcast_AddCategory) +* [Podcast.AddImage](#example_Podcast_AddImage) +* [Podcast.AddItem](#example_Podcast_AddItem) +* [Podcast.AddLastBuildDate](#example_Podcast_AddLastBuildDate) +* [Podcast.AddPubDate](#example_Podcast_AddPubDate) +* [Podcast.AddSummary](#example_Podcast_AddSummary) +* [Podcast.Bytes](#example_Podcast_Bytes) +* [Package (HttpHandlers)](#example__httpHandlers) +* [Package (IoWriter)](#example__ioWriter) + +#### Package files +[atomlink.go](./atomlink.go) [author.go](./author.go) [doc.go](./doc.go) [enclosure.go](./enclosure.go) [image.go](./image.go) [item.go](./item.go) [itunes.go](./itunes.go) [podcast.go](./podcast.go) [textinput.go](./textinput.go) + +## type [AtomLink](./atomlink.go#L6-L11) +``` go +type AtomLink struct { + XMLName xml.Name `xml:"atom:link"` + HREF string `xml:"href,attr"` + Rel string `xml:"rel,attr"` + Type string `xml:"type,attr"` +} +``` +AtomLink represents the Atom reference link. + +## type [Author](./author.go#L8-L12) +``` go +type Author struct { + XMLName xml.Name `xml:"itunes:owner"` + Name string `xml:"itunes:name"` + Email string `xml:"itunes:email"` +} +``` +Author represents a named author and email. + +For iTunes compliance, both Name and Email are required. + +## type [Enclosure](./enclosure.go#L46-L65) +``` go +type Enclosure struct { + XMLName xml.Name `xml:"enclosure"` + + // URL is the downloadable url for the content. (Required) + URL string `xml:"url,attr"` + + // Length is the size in Bytes of the download. (Required) + Length int64 `xml:"-"` + // LengthFormatted is the size in Bytes of the download. (Required) + // + // This field gets overwritten with the API when setting Length. + LengthFormatted string `xml:"length,attr"` + + // Type is MIME type encoding of the download. (Required) + Type EnclosureType `xml:"-"` + // TypeFormatted is MIME type encoding of the download. (Required) + // + // This field gets overwritten with the API when setting Type. + TypeFormatted string `xml:"type,attr"` +} +``` +Enclosure represents a download enclosure. + +## type [EnclosureType](./enclosure.go#L21) +``` go +type EnclosureType int +``` +EnclosureType specifies the type of the enclosure. + +``` go +const ( + M4A EnclosureType = iota + M4V + MP4 + MP3 + MOV + PDF + EPUB +) +``` +EnclosureType specifies the type of the enclosure. + +### func (EnclosureType) [String](./enclosure.go#L24) +``` go +func (et EnclosureType) String() string +``` +String returns the MIME type encoding of the specified EnclosureType. + +## type [ICategory](./itunes.go#L9-L13) +``` go +type ICategory struct { + XMLName xml.Name `xml:"itunes:category"` + Text string `xml:"text,attr"` + ICategories []*ICategory +} +``` +ICategory is a 2-tier classification system for iTunes. + +## type [IImage](./itunes.go#L23-L26) +``` go +type IImage struct { + XMLName xml.Name `xml:"itunes:image"` + HREF string `xml:"href,attr"` +} +``` +IImage represents an iTunes image. + +Podcast feeds contain artwork that is a minimum size of +1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, +72 dpi, in JPEG or PNG format with appropriate file +extensions (.jpg, .png), and in the RGB colorspace. To optimize +images for mobile devices, Apple recommends compressing your +image files. + +## type [ISummary](./itunes.go#L31-L34) +``` go +type ISummary struct { + XMLName xml.Name `xml:"itunes:summary"` + Text string `xml:",cdata"` +} +``` +ISummary is a 4000 character rich-text field for the itunes:summary tag. + +This is rendered as CDATA which allows for HTML tags such as ``. + +## type [Image](./image.go#L13-L21) +``` go +type Image struct { + XMLName xml.Name `xml:"image"` + URL string `xml:"url"` + Title string `xml:"title"` + Link string `xml:"link"` + Description string `xml:"description,omitempty"` + Width int `xml:"width,omitempty"` + Height int `xml:"height,omitempty"` +} +``` +Image represents an image. + +Podcast feeds contain artwork that is a minimum size of +1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, +72 dpi, in JPEG or PNG format with appropriate file +extensions (.jpg, .png), and in the RGB colorspace. To optimize +images for mobile devices, Apple recommends compressing your +image files. + +## type [Item](./item.go#L27-L51) +``` go +type Item struct { + XMLName xml.Name `xml:"item"` + GUID string `xml:"guid"` + Title string `xml:"title"` + Link string `xml:"link"` + Description string `xml:"description"` + Author *Author `xml:"-"` + AuthorFormatted string `xml:"author,omitempty"` + Category string `xml:"category,omitempty"` + Comments string `xml:"comments,omitempty"` + Source string `xml:"source,omitempty"` + PubDate *time.Time `xml:"-"` + PubDateFormatted string `xml:"pubDate,omitempty"` + Enclosure *Enclosure + + // https://help.apple.com/itc/podcasts_connect/#/itcb54353390 + IAuthor string `xml:"itunes:author,omitempty"` + ISubtitle string `xml:"itunes:subtitle,omitempty"` + ISummary *ISummary + IImage *IImage + IDuration string `xml:"itunes:duration,omitempty"` + IExplicit string `xml:"itunes:explicit,omitempty"` + IIsClosedCaptioned string `xml:"itunes:isClosedCaptioned,omitempty"` + IOrder string `xml:"itunes:order,omitempty"` +} +``` +Item represents a single entry in a podcast. + +Article minimal requirements are: +- Title +- Description +- Link + +Audio minimal requirements are: +- Title +- Description +- Enclosure (HREF, Type and Length all required) + +Recommendations: +- Setting the minimal fields sets most of other fields, including iTunes. +- Use the Published time.Time setting instead of PubDate. +- Always set an Enclosure.Length, to be nice to your downloaders. +- Use Enclosure.Type instead of setting TypeFormatted for valid extensions. + +### func (\*Item) [AddDuration](./item.go#L104) +``` go +func (i *Item) AddDuration(durationInSeconds int64) +``` +AddDuration adds the duration to the iTunes duration field. + +#### Example: + +
+Click to expand code. + +```go +i := podcast.Item{ + Title: "item title", + Description: "item desc", + Link: "item link", + } + d := int64(533) + + // add the Duration in Seconds + i.AddDuration(d) + + fmt.Println(i.IDuration) + // Output: + // 8:53 +``` + +
+ +### func (\*Item) [AddEnclosure](./item.go#L54-L55) +``` go +func (i *Item) AddEnclosure( + url string, enclosureType EnclosureType, lengthInBytes int64) +``` +AddEnclosure adds the downloadable asset to the podcast Item. + +### func (\*Item) [AddImage](./item.go#L72) +``` go +func (i *Item) AddImage(url string) +``` +AddImage adds the image as an iTunes-only IImage. RSS 2.0 does not have +the specification of Images at the Item level. + +Podcast feeds contain artwork that is a minimum size of +1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, +72 dpi, in JPEG or PNG format with appropriate file +extensions (.jpg, .png), and in the RGB colorspace. To optimize +images for mobile devices, Apple recommends compressing your +image files. + +### func (\*Item) [AddPubDate](./item.go#L81) +``` go +func (i *Item) AddPubDate(datetime *time.Time) +``` +AddPubDate adds the datetime as a parsed PubDate. + +UTC time is used by default. + +#### Example: + +
+Click to expand code. + +```go +p := podcast.New("title", "link", "description", nil, nil) + i := podcast.Item{ + Title: "item title", + Description: "item desc", + Link: "item link", + } + d := pubDate.AddDate(0, 0, -11) + + // add the pub date + i.AddPubDate(&d) + + // before adding + if i.PubDate != nil { + fmt.Println(i.PubDateFormatted, *i.PubDate) + } + + // this should not override with Podcast.PubDate + if _, err := p.AddItem(i); err != nil { + fmt.Println(err) + } + + // after adding item + fmt.Println(i.PubDateFormatted, *i.PubDate) + // Output: + // Tue, 24 Jan 2017 08:21:52 +0000 2017-01-24 08:21:52 +0000 UTC + // Tue, 24 Jan 2017 08:21:52 +0000 2017-01-24 08:21:52 +0000 UTC +``` + +
+ +### func (\*Item) [AddSummary](./item.go#L92) +``` go +func (i *Item) AddSummary(summary string) +``` +AddSummary adds the iTunes summary. + +Limit: 4000 characters + +Note that this field is a CDATA encoded field which allows for rich text +such as html links: `http://www.apple.com">Apple`. + +## type [Podcast](./podcast.go#L20-L59) +``` go +type Podcast struct { + XMLName xml.Name `xml:"channel"` + Title string `xml:"title"` + Link string `xml:"link"` + Description string `xml:"description"` + Category string `xml:"category,omitempty"` + Cloud string `xml:"cloud,omitempty"` + Copyright string `xml:"copyright,omitempty"` + Docs string `xml:"docs,omitempty"` + Generator string `xml:"generator,omitempty"` + Language string `xml:"language,omitempty"` + LastBuildDate string `xml:"lastBuildDate,omitempty"` + ManagingEditor string `xml:"managingEditor,omitempty"` + PubDate string `xml:"pubDate,omitempty"` + Rating string `xml:"rating,omitempty"` + SkipHours string `xml:"skipHours,omitempty"` + SkipDays string `xml:"skipDays,omitempty"` + TTL int `xml:"ttl,omitempty"` + WebMaster string `xml:"webMaster,omitempty"` + Image *Image + TextInput *TextInput + AtomLink *AtomLink + + // https://help.apple.com/itc/podcasts_connect/#/itcb54353390 + IAuthor string `xml:"itunes:author,omitempty"` + ISubtitle string `xml:"itunes:subtitle,omitempty"` + ISummary *ISummary + IBlock string `xml:"itunes:block,omitempty"` + IImage *IImage + IDuration string `xml:"itunes:duration,omitempty"` + IExplicit string `xml:"itunes:explicit,omitempty"` + IComplete string `xml:"itunes:complete,omitempty"` + INewFeedURL string `xml:"itunes:new-feed-url,omitempty"` + IOwner *Author // Author is formatted for itunes as-is + ICategories []*ICategory + + Items []*Item + // contains filtered or unexported fields +} +``` +Podcast represents a podcast. + +### func [New](./podcast.go#L65-L66) +``` go +func New(title, link, description string, + pubDate, lastBuildDate *time.Time) Podcast +``` +New instantiates a Podcast with required parameters. + +Nil-able fields are optional but recommended as they are formatted +to the expected proper formats. + +#### Example: + +
+Click to expand code. + +```go +ti, l, d := "title", "link", "description" + + // instantiate a new Podcast + p := podcast.New(ti, l, d, &pubDate, &updatedDate) + + fmt.Println(p.Title, p.Link, p.Description, p.Language) + fmt.Println(p.PubDate, p.LastBuildDate) + // Output: + // title link description en-us + // Sat, 04 Feb 2017 08:21:52 +0000 Mon, 06 Feb 2017 08:21:52 +0000 +``` + +
+ +### func (\*Podcast) [AddAtomLink](./podcast.go#L94) +``` go +func (p *Podcast) AddAtomLink(href string) +``` +AddAtomLink adds a FQDN reference to an atom feed. + +### func (\*Podcast) [AddAuthor](./podcast.go#L82) +``` go +func (p *Podcast) AddAuthor(name, email string) +``` +AddAuthor adds the specified Author to the podcast. + +#### Example: + +
+Click to expand code. + +```go +p := podcast.New("title", "link", "description", nil, nil) + + // add the Author + p.AddAuthor("the name", "me@test.com") + + fmt.Println(p.ManagingEditor) + fmt.Println(p.IAuthor) + // Output: + // me@test.com (the name) + // me@test.com (the name) +``` + +
+ +### func (\*Podcast) [AddCategory](./podcast.go#L183) +``` go +func (p *Podcast) AddCategory(category string, subCategories []string) +``` +AddCategory adds the category to the Podcast. + +ICategory can be listed multiple times. + +Calling this method multiple times will APPEND the category to the existing +list, if any, including ICategory. + +Note that Apple iTunes has a specific list of categories that only can be +used and will invalidate the feed if deviated from the list. That list is +as follows. + + * Arts + * Design + * Fashion & Beauty + * Food + * Literature + * Performing Arts + * Visual Arts + * Business + * Business News + * Careers + * Investing + * Management & Marketing + * Shopping + * Comedy + * Education + * Education Technology + * Higher Education + * K-12 + * Language Courses + * Training + * Games & Hobbies + * Automotive + * Aviation + * Hobbies + * Other Games + * Video Games + * Government & Organizations + * Local + * National + * Non-Profit + * Regional + * Health + * Alternative Health + * Fitness & Nutrition + * Self-Help + * Sexuality + * Kids & Family + * Music + * News & Politics + * Religion & Spirituality + * Buddhism + * Christianity + * Hinduism + * Islam + * Judaism + * Other + * Spirituality + * Science & Medicine + * Medicine + * Natural Sciences + * Social Sciences + * Society & Culture + * History + * Personal Journals + * Philosophy + * Places & Travel + * Sports & Recreation + * Amateur + * College & High School + * Outdoor + * Professional + * Technology + * Gadgets + * Podcasting + * Software How-To + * Tech News + * TV & Film + +#### Example: + +
+Click to expand code. + +```go +p := podcast.New("title", "link", "description", nil, nil) + + // add the Category + p.AddCategory("Bombay", nil) + p.AddCategory("American", []string{"Longhair", "Shorthair"}) + p.AddCategory("Siamese", nil) + + fmt.Println(len(p.ICategories), len(p.ICategories[1].ICategories)) + fmt.Println(p.Category) + // Output: + // 3 2 + // Bombay,American,Siamese +``` + +
+ +### func (\*Podcast) [AddImage](./podcast.go#L214) +``` go +func (p *Podcast) AddImage(url string) +``` +AddImage adds the specified Image to the Podcast. + +Podcast feeds contain artwork that is a minimum size of +1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, +72 dpi, in JPEG or PNG format with appropriate file +extensions (.jpg, .png), and in the RGB colorspace. To optimize +images for mobile devices, Apple recommends compressing your +image files. + +#### Example: + +
+Click to expand code. + +```go +p := podcast.New("title", "link", "description", nil, nil) + + // add the Image + p.AddImage("http://example.com/image.jpg") + + if p.Image != nil && p.IImage != nil { + fmt.Println(p.Image.URL) + fmt.Println(p.IImage.HREF) + } + // Output: + // http://example.com/image.jpg + // http://example.com/image.jpg +``` + +
+ +### func (\*Podcast) [AddItem](./podcast.go#L267) +``` go +func (p *Podcast) AddItem(i Item) (int, error) +``` +AddItem adds the podcast episode. It returns a count of Items added or any +errors in validation that may have occurred. + +This method takes the "itunes overrides" approach to populating +itunes tags according to the overrides rules in the specification. +This not only complies completely with iTunes parsing rules; but, it also +displays what is possible to be set on an individual episode level – if you +wish to have more fine grain control over your content. + +This method imposes strict validation of the Item being added to confirm +to Podcast and iTunes specifications. + +Article minimal requirements are: + + * Title + * Description + * Link + +Audio, Video and Downloads minimal requirements are: + + * Title + * Description + * Enclosure (HREF, Type and Length all required) + +The following fields are always overwritten (don't set them): + + * GUID + * PubDateFormatted + * AuthorFormatted + * Enclosure.TypeFormatted + * Enclosure.LengthFormatted + +Recommendations: + + * Just set the minimal fields: the rest get set for you. + * Always set an Enclosure.Length, to be nice to your downloaders. + * Follow Apple's best practices to enrich your podcasts: + https://help.apple.com/itc/podcasts_connect/#/itc2b3780e76 + * For specifications of itunes tags, see: + https://help.apple.com/itc/podcasts_connect/#/itcb54353390 + +#### Example: + +
+Click to expand code. + +```go +p := podcast.New("title", "link", "description", &pubDate, &updatedDate) + p.AddAuthor("the name", "me@test.com") + p.AddImage("http://example.com/image.jpg") + + // create an Item + date := pubDate.AddDate(0, 0, 77) + item := podcast.Item{ + Title: "Episode 1", + Description: "Description for Episode 1", + ISubtitle: "A simple episode 1", + PubDate: &date, + } + item.AddEnclosure( + "http://example.com/1.mp3", + podcast.MP3, + 183, + ) + item.AddSummary("See more at Here") + + // add the Item + if _, err := p.AddItem(item); err != nil { + fmt.Println("item validation error: " + err.Error()) + } + + if len(p.Items) != 1 { + fmt.Println("expected 1 item in the collection") + } + pp := p.Items[0] + fmt.Println( + pp.GUID, pp.Title, pp.Link, pp.Description, pp.Author, + pp.AuthorFormatted, pp.Category, pp.Comments, pp.Source, + pp.PubDate, pp.PubDateFormatted, *pp.Enclosure, + pp.IAuthor, pp.IDuration, pp.IExplicit, pp.IIsClosedCaptioned, + pp.IOrder, pp.ISubtitle, pp.ISummary) + // Output: + // http://example.com/1.mp3 Episode 1 http://example.com/1.mp3 Description for Episode 1 &{{ } me@test.com (the name)} 2017-04-22 08:21:52 +0000 UTC Sat, 22 Apr 2017 08:21:52 +0000 {{ } http://example.com/1.mp3 183 183 audio/mpeg audio/mpeg} me@test.com (the name) A simple episode 1 &{{ } See more at Here} +``` + +
+ +### func (\*Podcast) [AddLastBuildDate](./podcast.go#L344) +``` go +func (p *Podcast) AddLastBuildDate(datetime *time.Time) +``` +AddLastBuildDate adds the datetime as a parsed PubDate. + +UTC time is used by default. + +#### Example: + +
+Click to expand code. + +```go +p := podcast.New("title", "link", "description", nil, nil) + d := pubDate.AddDate(0, 0, -7) + + p.AddLastBuildDate(&d) + + fmt.Println(p.LastBuildDate) + // Output: + // Sat, 28 Jan 2017 08:21:52 +0000 +``` + +
+ +### func (\*Podcast) [AddPubDate](./podcast.go#L337) +``` go +func (p *Podcast) AddPubDate(datetime *time.Time) +``` +AddPubDate adds the datetime as a parsed PubDate. + +UTC time is used by default. + +#### Example: + +
+Click to expand code. + +```go +p := podcast.New("title", "link", "description", nil, nil) + d := pubDate.AddDate(0, 0, -5) + + p.AddPubDate(&d) + + fmt.Println(p.PubDate) + // Output: + // Mon, 30 Jan 2017 08:21:52 +0000 +``` + +
+ +### func (\*Podcast) [AddSubTitle](./podcast.go#L353) +``` go +func (p *Podcast) AddSubTitle(subTitle string) +``` +AddSubTitle adds the iTunes subtitle that is displayed with the title +in iTunes. + +Note that this field should be just a few words long according to Apple. +This method will truncate the string to 64 chars if too long with "..." + +### func (\*Podcast) [AddSummary](./podcast.go#L371) +``` go +func (p *Podcast) AddSummary(summary string) +``` +AddSummary adds the iTunes summary. + +Limit: 4000 characters + +Note that this field is a CDATA encoded field which allows for rich text +such as html links: `http://www.apple.com">Apple`. + +#### Example: + +
+Click to expand code. + +```go +p := podcast.New("title", "link", "description", nil, nil) + + // add a summary + p.AddSummary(`A very cool podcast with a long summary! + + See more at our website: example.com + `) + + if p.ISummary != nil { + fmt.Println(p.ISummary.Text) + } + // Output: + // A very cool podcast with a long summary! + // + // See more at our website: example.com +``` + +
+ +### func (\*Podcast) [Bytes](./podcast.go#L386) +``` go +func (p *Podcast) Bytes() []byte +``` +Bytes returns an encoded []byte slice. + +#### Example: + +
+Click to expand code. + +```go +p := podcast.New( + "eduncan911 Podcasts", + "http://eduncan911.com/", + "An example Podcast", + &pubDate, &updatedDate, + ) + p.AddAuthor("Jane Doe", "me@janedoe.com") + p.AddImage("http://janedoe.com/i.jpg") + p.AddSummary(`A very cool podcast with a long summary using Bytes()! + + See more at our website: example.com + `) + + for i := int64(5); i < 7; i++ { + n := strconv.FormatInt(i, 10) + d := pubDate.AddDate(0, 0, int(i+3)) + + item := podcast.Item{ + Title: "Episode " + n, + Link: "http://example.com/" + n + ".mp3", + Description: "Description for Episode " + n, + PubDate: &d, + } + if _, err := p.AddItem(item); err != nil { + fmt.Println(item.Title, ": error", err.Error()) + break + } + } + + // call Podcast.Bytes() to return a byte array + os.Stdout.Write(p.Bytes()) + + // Output: + // + // + // + // eduncan911 Podcasts + // http://eduncan911.com/ + // An example Podcast + // go podcast v1.3.1 (github.com/eduncan911/podcast) + // en-us + // Mon, 06 Feb 2017 08:21:52 +0000 + // me@janedoe.com (Jane Doe) + // Sat, 04 Feb 2017 08:21:52 +0000 + // + // http://janedoe.com/i.jpg + // eduncan911 Podcasts + // http://eduncan911.com/ + // + // me@janedoe.com (Jane Doe) + // example.com + // ]]> + // + // + // http://example.com/5.mp3 + // Episode 5 + // http://example.com/5.mp3 + // Description for Episode 5 + // Sun, 12 Feb 2017 08:21:52 +0000 + // me@janedoe.com (Jane Doe) + // + // + // + // http://example.com/6.mp3 + // Episode 6 + // http://example.com/6.mp3 + // Description for Episode 6 + // Mon, 13 Feb 2017 08:21:52 +0000 + // me@janedoe.com (Jane Doe) + // + // + // + // +``` + +
+ +### func (\*Podcast) [Encode](./podcast.go#L391) +``` go +func (p *Podcast) Encode(w io.Writer) error +``` +Encode writes the bytes to the io.Writer stream in RSS 2.0 specification. + +### func (\*Podcast) [String](./podcast.go#L410) +``` go +func (p *Podcast) String() string +``` +String encodes the Podcast state to a string. + +## type [TextInput](./textinput.go#L6-L12) +``` go +type TextInput struct { + XMLName xml.Name `xml:"textInput"` + Title string `xml:"title"` + Description string `xml:"description"` + Name string `xml:"name"` + Link string `xml:"link"` +} +``` +TextInput represents text inputs. + +- - - +Generated by [godoc2ghmd](https://github.com/eduncan911/godoc2ghmd) \ No newline at end of file diff --git a/vendor/github.com/eduncan911/podcast/atomlink.go b/vendor/github.com/eduncan911/podcast/atomlink.go new file mode 100644 index 0000000..0d9ec00 --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/atomlink.go @@ -0,0 +1,11 @@ +package podcast + +import "encoding/xml" + +// AtomLink represents the Atom reference link. +type AtomLink struct { + XMLName xml.Name `xml:"atom:link"` + HREF string `xml:"href,attr"` + Rel string `xml:"rel,attr"` + Type string `xml:"type,attr"` +} diff --git a/vendor/github.com/eduncan911/podcast/author.go b/vendor/github.com/eduncan911/podcast/author.go new file mode 100644 index 0000000..bb1fc0b --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/author.go @@ -0,0 +1,12 @@ +package podcast + +import "encoding/xml" + +// Author represents a named author and email. +// +// For iTunes compliance, both Name and Email are required. +type Author struct { + XMLName xml.Name `xml:"itunes:owner"` + Name string `xml:"itunes:name"` + Email string `xml:"itunes:email"` +} diff --git a/vendor/github.com/eduncan911/podcast/doc.go b/vendor/github.com/eduncan911/podcast/doc.go new file mode 100644 index 0000000..fc0f304 --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/doc.go @@ -0,0 +1,157 @@ +// Package podcast generates a fully compliant iTunes and RSS 2.0 podcast feed +// for GoLang using a simple API. +// +// Full documentation with detailed examples located at https://godoc.org/github.com/eduncan911/podcast +// +// Usage +// +// To use, `go get` and `import` the package like your typical GoLang library. +// +// $ go get -u github.com/eduncan911/podcast +// +// import "github.com/eduncan911/podcast" +// +// The API exposes a number of method receivers on structs that implements the +// logic required to comply with the specifications and ensure a compliant feed. +// A number of overrides occur to help with iTunes visibility of your episodes. +// +// Notably, the `Podcast.AddItem` function performs most +// of the heavy lifting by taking the `Item` input and performing +// validation, overrides and duplicate setters through the feed. +// +// Full detailed Examples of the API are at https://godoc.org/github.com/eduncan911/podcast. +// +// Go Modules +// +// This library is supported on GoLang 1.7 and higher. +// +// We have implemented Go Modules support and the CI pipeline shows it working with +// new installs, tested with Go 1.13. To keep 1.7 compatibility, we use +// `go mod vendor` to maintain the `vendor/` folder for older 1.7 and later runtimes. +// +// If either runtime has an issue, please create an Issue and I will address. +// +// Extensibility +// +// For version 1.x, you are not restricted in having full control over your feeds. +// You may choose to skip the API methods and instead use the structs directly. The +// fields have been grouped by RSS 2.0 and iTunes fields with iTunes specific fields +// all prefixed with the letter `I`. +// +// However, do note that the 2.x version currently in progress will break this +// extensibility and enforce API methods going forward. This is to ensure that the feed +// can both be marshalled, and unmarshalled back and forth (current 1.x branch can only +// be unmarshalled - hence the work for 2.x). +// +// Fuzzing Inputs +// +// `go-fuzz` has been added in 1.4.1, covering all exported API methods. They have been +// ran extensively and no issues have come out of them yet (most tests were ran overnight, +// over about 11 hours with zero crashes). +// +// If you wish to help fuzz the inputs, with Go 1.13 or later you can run `go-fuzz` on any +// of the inputs. +// +// go get -u github.com/dvyukov/go-fuzz/go-fuzz +// go get -u github.com/dvyukov/go-fuzz/go-fuzz-build +// go get -u github.com/eduncan911/podcast +// cd $GOPATH/src/github.com/eduncan911/podcast +// go-fuzz-build +// go-fuzz -func FuzzPodcastAddItem +// +// To obtain a list of available funcs to pass, just run `go-fuzz` without any parameters: +// +// $ go-fuzz +// 2020/02/13 07:27:32 -func flag not provided, but multiple fuzz functions available: +// FuzzItemAddDuration, FuzzItemAddEnclosure, FuzzItemAddImage, FuzzItemAddPubDate, +// FuzzItemAddSummary, FuzzPodcastAddAtomLink, FuzzPodcastAddAuthor, FuzzPodcastAddCategory, +// FuzzPodcastAddImage, FuzzPodcastAddItem, FuzzPodcastAddLastBuildDate, FuzzPodcastAddPubDate, +// FuzzPodcastAddSubTitle, FuzzPodcastAddSummary, FuzzPodcastBytes, FuzzPodcastEncode, +// FuzzPodcastNew +// +// If you do find an issue, please raise an issue immediately and I will quickly address. +// +// Roadmap +// +// The 1.x branch is now mostly in maintenance mode, open to PRs. This means no +// more planned features on the 1.x feature branch is expected. With the success of 6 +// iTunes-accepted podcasts I have published with this library, and with the feedback from +// the community, the 1.x releases are now considered stable. +// +// The 2.x branch's primary focus is to allow for bi-direction marshalling both ways. +// Currently, the 1.x branch only allows unmarshalling to a serial feed. An attempt to marshall +// a serialized feed back into a Podcast form will error or not work correctly. Note that while +// the 2.x branch is targeted to remain backwards compatible, it is true if using the public +// API funcs to set parameters only. Several of the underlying public fields are being removed +// in order to accommodate the marshalling of serialized data. Therefore, a version 2.x is denoted +// for this release. +// +// Versioning +// +// We use SemVer versioning schema. You can rest assured that pulling 1.x branches will +// remain backwards compatible now and into the future. +// +// However, the new 2.x branch, while keeping the same API, is expected break those that +// bypass the API methods and use the underlying public properties instead. +// +// Release Notes +// +// v1.4.2 +// * Slim down Go Modules for consumers (#32) +// +// v1.4.1 +// * Implement fuzz logic testing of exported funcs (#31) +// * Upgrade CICD Pipeline Tooling (#31) +// * Update documentation for 1.x and 2.3 (#31) +// * Allow godoc2ghmd to run without network (#31) +// +// v1.4.0 +// * Add Go Modules, Update vendor folder (#26, #25) +// * Add C.I. GitHub Actions (#25) +// * Add additional error checks found by linters (#25) +// * Go Fmt enclosure_test.go (#25) +// +// v1.3.2 +// * Correct count len of UTF8 strings (#9) +// * Implement duration parser (#8) +// * Fix Github and GoDocs Markdown (#14) +// * Move podcast.go Private Methods to Respected Files (#12) +// * Allow providing GUID on Podcast (#15) +// +// v1.3.1 +// * increased itunes compliance after feedback from Apple: +// - specified what categories should be set with AddCategory(). +// - enforced title and link as part of Image. +// * added Podcast.AddAtomLink() for more broad compliance to readers. +// +// v1.3.0 +// * fixes Item.Duration being set incorrectly. +// * changed Item.AddEnclosure() parameter definition (Bytes not Seconds!). +// * added Item.AddDuration formatting and override. +// * added more documentation surrounding Item.Enclosure{} +// +// v1.2.1 +// * added Podcast.AddSubTitle() and truncating to 64 chars. +// * added a number of Guards to protect against empty fields. +// +// v1.2.0 +// * added Podcast.AddPubDate() and Podcast.AddLastBuildDate() overrides. +// * added Item.AddImage() to mask some cumbersome addition of IImage. +// * added Item.AddPubDate to simply datetime setters. +// * added more examples (mostly around Item struct). +// * tweaked some documentation. +// +// v1.1.0 +// * Enabling CDATA in ISummary fields for Podcast and Channel. +// +// v1.0.0 +// * Initial release. +// * Full documentation, full examples and complete code coverage. +// +// References +// +// RSS 2.0: https://cyber.harvard.edu/rss/rss.html +// +// Podcasts: https://help.apple.com/itc/podcasts_connect/#/itca5b22233 +// +package podcast diff --git a/vendor/github.com/eduncan911/podcast/enclosure.go b/vendor/github.com/eduncan911/podcast/enclosure.go new file mode 100644 index 0000000..33b0b68 --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/enclosure.go @@ -0,0 +1,65 @@ +package podcast + +import "encoding/xml" + +// EnclosureType specifies the type of the enclosure. +const ( + M4A EnclosureType = iota + M4V + MP4 + MP3 + MOV + PDF + EPUB +) + +const ( + enclosureDefault = "application/octet-stream" +) + +// EnclosureType specifies the type of the enclosure. +type EnclosureType int + +// String returns the MIME type encoding of the specified EnclosureType. +func (et EnclosureType) String() string { + // https://help.apple.com/itc/podcasts_connect/#/itcb54353390 + switch et { + case M4A: + return "audio/x-m4a" + case M4V: + return "video/x-m4v" + case MP4: + return "video/mp4" + case MP3: + return "audio/mpeg" + case MOV: + return "video/quicktime" + case PDF: + return "application/pdf" + case EPUB: + return "document/x-epub" + } + return enclosureDefault +} + +// Enclosure represents a download enclosure. +type Enclosure struct { + XMLName xml.Name `xml:"enclosure"` + + // URL is the downloadable url for the content. (Required) + URL string `xml:"url,attr"` + + // Length is the size in Bytes of the download. (Required) + Length int64 `xml:"-"` + // LengthFormatted is the size in Bytes of the download. (Required) + // + // This field gets overwritten with the API when setting Length. + LengthFormatted string `xml:"length,attr"` + + // Type is MIME type encoding of the download. (Required) + Type EnclosureType `xml:"-"` + // TypeFormatted is MIME type encoding of the download. (Required) + // + // This field gets overwritten with the API when setting Type. + TypeFormatted string `xml:"type,attr"` +} diff --git a/vendor/github.com/eduncan911/podcast/fuzz.go b/vendor/github.com/eduncan911/podcast/fuzz.go new file mode 100644 index 0000000..27e9ece --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/fuzz.go @@ -0,0 +1,297 @@ +// +build gofuzz + +package podcast + +import ( + "bytes" + "encoding/binary" + "time" +) + +func FuzzItemAddDuration(data []byte) int { + input, read := binary.Varint(data) + if input <= 0 && read == 0 { + // error converting []byte into int64 + return 0 + } + i := newItem(data) + + i.AddDuration(input) + + p := newPodcast(data) + if _, err := p.AddItem(i); err != nil { + return 0 + } + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzItemAddEnclosure(data []byte) int { + url := string(data) + length, read := binary.Varint(data) + if length <= 0 && read == 0 { + // error converting []byte into int64 + return 0 + } + i := newItem(data) + + i.AddEnclosure(url, MP3, length) + + p := newPodcast(data) + if _, err := p.AddItem(i); err != nil { + return 0 + } + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzItemAddImage(data []byte) int { + i := newItem(data) + + i.AddImage(string(data)) + + p := newPodcast(data) + if _, err := p.AddItem(i); err != nil { + return 0 + } + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzItemAddPubDate(data []byte) int { + t := time.Time{} + if err := t.GobDecode(data); err != nil { + return 0 + } + i := newItem(data) + + i.AddPubDate(&t) + + p := newPodcast(data) + if _, err := p.AddItem(i); err != nil { + return 0 + } + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzItemAddSummary(data []byte) int { + i := newItem(data) + + i.AddSummary(string(data)) + + p := newPodcast(data) + if _, err := p.AddItem(i); err != nil { + return 0 + } + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastNew(data []byte) int { + p := newPodcast(data) + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastAddAtomLink(data []byte) int { + p := newPodcast(data) + + p.AddAtomLink(string(data)) + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastAddAuthor(data []byte) int { + p := newPodcast(data) + + p.AddAuthor(string(data), string(data)) + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastAddCategory(data []byte) int { + p := newPodcast(data) + + subs := make([]string, 3) + subs[0] = string(data) + subs[1] = string(data) + subs[2] = string(data) + p.AddCategory(string(data), subs) + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastAddImage(data []byte) int { + p := newPodcast(data) + + p.AddImage(string(data)) + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastAddItem(data []byte) int { + p := newPodcast(data) + i := newItem(data) + + if _, err := p.AddItem(i); err != nil { + return 0 + } + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastAddLastBuildDate(data []byte) int { + p := newPodcast(data) + t := time.Time{} + if err := t.GobDecode(data); err != nil { + return 0 + } + + p.AddLastBuildDate(&t) + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastAddPubDate(data []byte) int { + p := newPodcast(data) + t := time.Time{} + if err := t.GobDecode(data); err != nil { + return 0 + } + + p.AddPubDate(&t) + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastAddSubTitle(data []byte) int { + p := newPodcast(data) + + p.AddSubTitle(string(data)) + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastAddSummary(data []byte) int { + p := newPodcast(data) + + p.AddSummary(string(data)) + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func FuzzPodcastBytes(data []byte) int { + p := newPodcast(data) + + p.Bytes() + + return 1 +} + +func FuzzPodcastEncode(data []byte) int { + p := newPodcast(data) + + var buf bytes.Buffer + if err := p.Encode(&buf); err != nil { + return 0 + } + + return 1 +} + +func newPodcast(data []byte) Podcast { + return New( + string(data), + string(data), + string(data), + nil, nil) +} + +func newItem(data []byte) Item { + // Article minimal requirements are: + // - Title + // - Description + // - Link + // + // Audio minimal requirements are: + // - Title + // - Description + // - Enclosure (HREF, Type and Length all required) + // + return Item{ + Title: string(data), + Description: string(data), + Link: string(data), + } +} diff --git a/vendor/github.com/eduncan911/podcast/image.go b/vendor/github.com/eduncan911/podcast/image.go new file mode 100644 index 0000000..e6b4d61 --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/image.go @@ -0,0 +1,21 @@ +package podcast + +import "encoding/xml" + +// Image represents an image. +// +// Podcast feeds contain artwork that is a minimum size of +// 1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, +// 72 dpi, in JPEG or PNG format with appropriate file +// extensions (.jpg, .png), and in the RGB colorspace. To optimize +// images for mobile devices, Apple recommends compressing your +// image files. +type Image struct { + XMLName xml.Name `xml:"image"` + URL string `xml:"url"` + Title string `xml:"title"` + Link string `xml:"link"` + Description string `xml:"description,omitempty"` + Width int `xml:"width,omitempty"` + Height int `xml:"height,omitempty"` +} diff --git a/vendor/github.com/eduncan911/podcast/item.go b/vendor/github.com/eduncan911/podcast/item.go new file mode 100644 index 0000000..88294e5 --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/item.go @@ -0,0 +1,144 @@ +package podcast + +import ( + "encoding/xml" + "fmt" + "time" + "unicode/utf8" +) + +// Item represents a single entry in a podcast. +// +// Article minimal requirements are: +// - Title +// - Description +// - Link +// +// Audio minimal requirements are: +// - Title +// - Description +// - Enclosure (HREF, Type and Length all required) +// +// Recommendations: +// - Setting the minimal fields sets most of other fields, including iTunes. +// - Use the Published time.Time setting instead of PubDate. +// - Always set an Enclosure.Length, to be nice to your downloaders. +// - Use Enclosure.Type instead of setting TypeFormatted for valid extensions. +type Item struct { + XMLName xml.Name `xml:"item"` + GUID string `xml:"guid"` + Title string `xml:"title"` + Link string `xml:"link"` + Description string `xml:"description"` + Author *Author `xml:"-"` + AuthorFormatted string `xml:"author,omitempty"` + Category string `xml:"category,omitempty"` + Comments string `xml:"comments,omitempty"` + Source string `xml:"source,omitempty"` + PubDate *time.Time `xml:"-"` + PubDateFormatted string `xml:"pubDate,omitempty"` + Enclosure *Enclosure + + // https://help.apple.com/itc/podcasts_connect/#/itcb54353390 + IAuthor string `xml:"itunes:author,omitempty"` + ISubtitle string `xml:"itunes:subtitle,omitempty"` + ISummary *ISummary + IImage *IImage + IDuration string `xml:"itunes:duration,omitempty"` + IExplicit string `xml:"itunes:explicit,omitempty"` + IIsClosedCaptioned string `xml:"itunes:isClosedCaptioned,omitempty"` + IOrder string `xml:"itunes:order,omitempty"` +} + +// AddEnclosure adds the downloadable asset to the podcast Item. +func (i *Item) AddEnclosure( + url string, enclosureType EnclosureType, lengthInBytes int64) { + i.Enclosure = &Enclosure{ + URL: url, + Type: enclosureType, + Length: lengthInBytes, + } +} + +// AddImage adds the image as an iTunes-only IImage. RSS 2.0 does not have +// the specification of Images at the Item level. +// +// Podcast feeds contain artwork that is a minimum size of +// 1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, +// 72 dpi, in JPEG or PNG format with appropriate file +// extensions (.jpg, .png), and in the RGB colorspace. To optimize +// images for mobile devices, Apple recommends compressing your +// image files. +func (i *Item) AddImage(url string) { + if len(url) > 0 { + i.IImage = &IImage{HREF: url} + } +} + +// AddPubDate adds the datetime as a parsed PubDate. +// +// UTC time is used by default. +func (i *Item) AddPubDate(datetime *time.Time) { + i.PubDate = datetime + i.PubDateFormatted = parseDateRFC1123Z(i.PubDate) +} + +// AddSummary adds the iTunes summary. +// +// Limit: 4000 characters +// +// Note that this field is a CDATA encoded field which allows for rich text +// such as html links: `Apple`. +func (i *Item) AddSummary(summary string) { + count := utf8.RuneCountInString(summary) + if count > 4000 { + s := []rune(summary) + summary = string(s[0:4000]) + } + i.ISummary = &ISummary{ + Text: summary, + } +} + +// AddDuration adds the duration to the iTunes duration field. +func (i *Item) AddDuration(durationInSeconds int64) { + if durationInSeconds <= 0 { + return + } + i.IDuration = parseDuration(durationInSeconds) +} + +var parseDuration = func(duration int64) string { + h := duration / 3600 + duration = duration % 3600 + + m := duration / 60 + duration = duration % 60 + + s := duration + + // HH:MM:SS + if h > 9 { + return fmt.Sprintf("%02d:%02d:%02d", h, m, s) + } + + // H:MM:SS + if h > 0 { + return fmt.Sprintf("%d:%02d:%02d", h, m, s) + } + + // MM:SS + if m > 9 { + return fmt.Sprintf("%02d:%02d", m, s) + } + + // M:SS + return fmt.Sprintf("%d:%02d", m, s) +} + +var parseDateRFC1123Z = func(t *time.Time) string { + if t != nil && !t.IsZero() { + return t.Format(time.RFC1123Z) + } + return time.Now().UTC().Format(time.RFC1123Z) +} diff --git a/vendor/github.com/eduncan911/podcast/itunes.go b/vendor/github.com/eduncan911/podcast/itunes.go new file mode 100644 index 0000000..6ea7b6d --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/itunes.go @@ -0,0 +1,34 @@ +package podcast + +import "encoding/xml" + +// Specifications: https://help.apple.com/itc/podcasts_connect/#/itcb54353390 +// + +// ICategory is a 2-tier classification system for iTunes. +type ICategory struct { + XMLName xml.Name `xml:"itunes:category"` + Text string `xml:"text,attr"` + ICategories []*ICategory +} + +// IImage represents an iTunes image. +// +// Podcast feeds contain artwork that is a minimum size of +// 1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, +// 72 dpi, in JPEG or PNG format with appropriate file +// extensions (.jpg, .png), and in the RGB colorspace. To optimize +// images for mobile devices, Apple recommends compressing your +// image files. +type IImage struct { + XMLName xml.Name `xml:"itunes:image"` + HREF string `xml:"href,attr"` +} + +// ISummary is a 4000 character rich-text field for the itunes:summary tag. +// +// This is rendered as CDATA which allows for HTML tags such as ``. +type ISummary struct { + XMLName xml.Name `xml:"itunes:summary"` + Text string `xml:",cdata"` +} diff --git a/vendor/github.com/eduncan911/podcast/podcast.go b/vendor/github.com/eduncan911/podcast/podcast.go new file mode 100644 index 0000000..b71d5df --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/podcast.go @@ -0,0 +1,454 @@ +package podcast + +import ( + "bytes" + "encoding/xml" + "fmt" + "io" + "strconv" + "time" + "unicode/utf8" + + "github.com/pkg/errors" +) + +const ( + pVersion = "1.3.1" +) + +// Podcast represents a podcast. +type Podcast struct { + XMLName xml.Name `xml:"channel"` + Title string `xml:"title"` + Link string `xml:"link"` + Description string `xml:"description"` + Category string `xml:"category,omitempty"` + Cloud string `xml:"cloud,omitempty"` + Copyright string `xml:"copyright,omitempty"` + Docs string `xml:"docs,omitempty"` + Generator string `xml:"generator,omitempty"` + Language string `xml:"language,omitempty"` + LastBuildDate string `xml:"lastBuildDate,omitempty"` + ManagingEditor string `xml:"managingEditor,omitempty"` + PubDate string `xml:"pubDate,omitempty"` + Rating string `xml:"rating,omitempty"` + SkipHours string `xml:"skipHours,omitempty"` + SkipDays string `xml:"skipDays,omitempty"` + TTL int `xml:"ttl,omitempty"` + WebMaster string `xml:"webMaster,omitempty"` + Image *Image + TextInput *TextInput + AtomLink *AtomLink + + // https://help.apple.com/itc/podcasts_connect/#/itcb54353390 + IAuthor string `xml:"itunes:author,omitempty"` + ISubtitle string `xml:"itunes:subtitle,omitempty"` + ISummary *ISummary + IBlock string `xml:"itunes:block,omitempty"` + IImage *IImage + IDuration string `xml:"itunes:duration,omitempty"` + IExplicit string `xml:"itunes:explicit,omitempty"` + IComplete string `xml:"itunes:complete,omitempty"` + INewFeedURL string `xml:"itunes:new-feed-url,omitempty"` + IOwner *Author // Author is formatted for itunes as-is + ICategories []*ICategory + + Items []*Item + + encode func(w io.Writer, o interface{}) error +} + +// New instantiates a Podcast with required parameters. +// +// Nil-able fields are optional but recommended as they are formatted +// to the expected proper formats. +func New(title, link, description string, + pubDate, lastBuildDate *time.Time) Podcast { + return Podcast{ + Title: title, + Link: link, + Description: description, + Generator: fmt.Sprintf("go podcast v%s (github.com/eduncan911/podcast)", pVersion), + PubDate: parseDateRFC1123Z(pubDate), + LastBuildDate: parseDateRFC1123Z(lastBuildDate), + Language: "en-us", + + // setup dependency (could inject later) + encode: encoder, + } +} + +// AddAuthor adds the specified Author to the podcast. +func (p *Podcast) AddAuthor(name, email string) { + if len(email) == 0 { + return + } + p.ManagingEditor = parseAuthorNameEmail(&Author{ + Name: name, + Email: email, + }) + p.IAuthor = p.ManagingEditor +} + +// AddAtomLink adds a FQDN reference to an atom feed. +func (p *Podcast) AddAtomLink(href string) { + if len(href) == 0 { + return + } + p.AtomLink = &AtomLink{ + HREF: href, + Rel: "self", + Type: "application/rss+xml", + } +} + +// AddCategory adds the category to the Podcast. +// +// ICategory can be listed multiple times. +// +// Calling this method multiple times will APPEND the category to the existing +// list, if any, including ICategory. +// +// Note that Apple iTunes has a specific list of categories that only can be +// used and will invalidate the feed if deviated from the list. That list is +// as follows. +// +// * Arts +// * Design +// * Fashion & Beauty +// * Food +// * Literature +// * Performing Arts +// * Visual Arts +// * Business +// * Business News +// * Careers +// * Investing +// * Management & Marketing +// * Shopping +// * Comedy +// * Education +// * Education Technology +// * Higher Education +// * K-12 +// * Language Courses +// * Training +// * Games & Hobbies +// * Automotive +// * Aviation +// * Hobbies +// * Other Games +// * Video Games +// * Government & Organizations +// * Local +// * National +// * Non-Profit +// * Regional +// * Health +// * Alternative Health +// * Fitness & Nutrition +// * Self-Help +// * Sexuality +// * Kids & Family +// * Music +// * News & Politics +// * Religion & Spirituality +// * Buddhism +// * Christianity +// * Hinduism +// * Islam +// * Judaism +// * Other +// * Spirituality +// * Science & Medicine +// * Medicine +// * Natural Sciences +// * Social Sciences +// * Society & Culture +// * History +// * Personal Journals +// * Philosophy +// * Places & Travel +// * Sports & Recreation +// * Amateur +// * College & High School +// * Outdoor +// * Professional +// * Technology +// * Gadgets +// * Podcasting +// * Software How-To +// * Tech News +// * TV & Film +func (p *Podcast) AddCategory(category string, subCategories []string) { + if len(category) == 0 { + return + } + + // RSS 2.0 Category only supports 1-tier + if len(p.Category) > 0 { + p.Category = p.Category + "," + category + } else { + p.Category = category + } + + icat := ICategory{Text: category} + for _, c := range subCategories { + if len(c) == 0 { + continue + } + icat2 := ICategory{Text: c} + icat.ICategories = append(icat.ICategories, &icat2) + } + p.ICategories = append(p.ICategories, &icat) +} + +// AddImage adds the specified Image to the Podcast. +// +// Podcast feeds contain artwork that is a minimum size of +// 1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, +// 72 dpi, in JPEG or PNG format with appropriate file +// extensions (.jpg, .png), and in the RGB colorspace. To optimize +// images for mobile devices, Apple recommends compressing your +// image files. +func (p *Podcast) AddImage(url string) { + if len(url) == 0 { + return + } + p.Image = &Image{ + URL: url, + Title: p.Title, + Link: p.Link, + } + p.IImage = &IImage{HREF: url} +} + +// AddItem adds the podcast episode. It returns a count of Items added or any +// errors in validation that may have occurred. +// +// This method takes the "itunes overrides" approach to populating +// itunes tags according to the overrides rules in the specification. +// This not only complies completely with iTunes parsing rules; but, it also +// displays what is possible to be set on an individual episode level – if you +// wish to have more fine grain control over your content. +// +// This method imposes strict validation of the Item being added to confirm +// to Podcast and iTunes specifications. +// +// Article minimal requirements are: +// +// * Title +// * Description +// * Link +// +// Audio, Video and Downloads minimal requirements are: +// +// * Title +// * Description +// * Enclosure (HREF, Type and Length all required) +// +// The following fields are always overwritten (don't set them): +// +// * GUID +// * PubDateFormatted +// * AuthorFormatted +// * Enclosure.TypeFormatted +// * Enclosure.LengthFormatted +// +// Recommendations: +// +// * Just set the minimal fields: the rest get set for you. +// * Always set an Enclosure.Length, to be nice to your downloaders. +// * Follow Apple's best practices to enrich your podcasts: +// https://help.apple.com/itc/podcasts_connect/#/itc2b3780e76 +// * For specifications of itunes tags, see: +// https://help.apple.com/itc/podcasts_connect/#/itcb54353390 +// +func (p *Podcast) AddItem(i Item) (int, error) { + // initial guards for required fields + if len(i.Title) == 0 || len(i.Description) == 0 { + return len(p.Items), errors.New("Title and Description are required") + } + if i.Enclosure != nil { + if len(i.Enclosure.URL) == 0 { + return len(p.Items), + errors.New(i.Title + ": Enclosure.URL is required") + } + if i.Enclosure.Type.String() == enclosureDefault { + return len(p.Items), + errors.New(i.Title + ": Enclosure.Type is required") + } + } else if len(i.Link) == 0 { + return len(p.Items), + errors.New(i.Title + ": Link is required when not using Enclosure") + } + + // corrective actions and overrides + // + i.PubDateFormatted = parseDateRFC1123Z(i.PubDate) + i.AuthorFormatted = parseAuthorNameEmail(i.Author) + if i.Enclosure != nil { + if len(i.GUID) == 0 { + i.GUID = i.Enclosure.URL // yep, GUID is the Permlink URL + } + + if i.Enclosure.Length < 0 { + i.Enclosure.Length = 0 + } + i.Enclosure.LengthFormatted = strconv.FormatInt(i.Enclosure.Length, 10) + i.Enclosure.TypeFormatted = i.Enclosure.Type.String() + + // allow Link to be set for article references to Downloads, + // otherwise set it to the enclosurer's URL. + if len(i.Link) == 0 { + i.Link = i.Enclosure.URL + } + } else { + i.GUID = i.Link // yep, GUID is the Permlink URL + } + + // iTunes it + // + if len(i.IAuthor) == 0 { + switch { + case i.Author != nil: + i.IAuthor = i.Author.Email + case len(p.IAuthor) != 0: + i.Author = &Author{Email: p.IAuthor} + i.IAuthor = p.IAuthor + case len(p.ManagingEditor) != 0: + i.Author = &Author{Email: p.ManagingEditor} + i.IAuthor = p.ManagingEditor + } + } + if i.IImage == nil { + if p.Image != nil { + i.IImage = &IImage{HREF: p.Image.URL} + } + } + + p.Items = append(p.Items, &i) + return len(p.Items), nil +} + +// AddPubDate adds the datetime as a parsed PubDate. +// +// UTC time is used by default. +func (p *Podcast) AddPubDate(datetime *time.Time) { + p.PubDate = parseDateRFC1123Z(datetime) +} + +// AddLastBuildDate adds the datetime as a parsed PubDate. +// +// UTC time is used by default. +func (p *Podcast) AddLastBuildDate(datetime *time.Time) { + p.LastBuildDate = parseDateRFC1123Z(datetime) +} + +// AddSubTitle adds the iTunes subtitle that is displayed with the title +// in iTunes. +// +// Note that this field should be just a few words long according to Apple. +// This method will truncate the string to 64 chars if too long with "..." +func (p *Podcast) AddSubTitle(subTitle string) { + count := utf8.RuneCountInString(subTitle) + if count == 0 { + return + } + if count > 64 { + s := []rune(subTitle) + subTitle = string(s[0:61]) + "..." + } + p.ISubtitle = subTitle +} + +// AddSummary adds the iTunes summary. +// +// Limit: 4000 characters +// +// Note that this field is a CDATA encoded field which allows for rich text +// such as html links: `Apple`. +func (p *Podcast) AddSummary(summary string) { + count := utf8.RuneCountInString(summary) + if count == 0 { + return + } + if count > 4000 { + s := []rune(summary) + summary = string(s[0:4000]) + } + p.ISummary = &ISummary{ + Text: summary, + } +} + +// Bytes returns an encoded []byte slice. +func (p *Podcast) Bytes() []byte { + return []byte(p.String()) +} + +// Encode writes the bytes to the io.Writer stream in RSS 2.0 specification. +func (p *Podcast) Encode(w io.Writer) error { + if _, err := w.Write([]byte("\n")); err != nil { + return errors.Wrap(err, "podcast.Encode: w.Write return error") + } + + atomLink := "" + if p.AtomLink != nil { + atomLink = "http://www.w3.org/2005/Atom" + } + wrapped := podcastWrapper{ + ITUNESNS: "http://www.itunes.com/dtds/podcast-1.0.dtd", + ATOMNS: atomLink, + Version: "2.0", + Channel: p, + } + return p.encode(w, wrapped) +} + +// String encodes the Podcast state to a string. +func (p *Podcast) String() string { + b := new(bytes.Buffer) + if err := p.Encode(b); err != nil { + return "String: podcast.write returned the error: " + err.Error() + } + return b.String() +} + +// // Write implements the io.Writer interface to write an RSS 2.0 stream +// // that is compliant to the RSS 2.0 specification. +// func (p *Podcast) Write(b []byte) (n int, err error) { +// buf := bytes.NewBuffer(b) +// if err := p.Encode(buf); err != nil { +// return 0, errors.Wrap(err, "Write: podcast.encode returned error") +// } +// return buf.Len(), nil +// } + +type podcastWrapper struct { + XMLName xml.Name `xml:"rss"` + Version string `xml:"version,attr"` + ATOMNS string `xml:"xmlns:atom,attr,omitempty"` + ITUNESNS string `xml:"xmlns:itunes,attr"` + Channel *Podcast +} + +var encoder = func(w io.Writer, o interface{}) error { + e := xml.NewEncoder(w) + e.Indent("", " ") + if err := e.Encode(o); err != nil { + return errors.Wrap(err, "podcast.encoder: e.Encode returned error") + } + return nil +} + +var parseAuthorNameEmail = func(a *Author) string { + var author string + if a != nil { + author = a.Email + if len(a.Name) > 0 { + author = fmt.Sprintf("%s (%s)", a.Email, a.Name) + } + } + return author +} diff --git a/vendor/github.com/eduncan911/podcast/textinput.go b/vendor/github.com/eduncan911/podcast/textinput.go new file mode 100644 index 0000000..296f25e --- /dev/null +++ b/vendor/github.com/eduncan911/podcast/textinput.go @@ -0,0 +1,12 @@ +package podcast + +import "encoding/xml" + +// TextInput represents text inputs. +type TextInput struct { + XMLName xml.Name `xml:"textInput"` + Title string `xml:"title"` + Description string `xml:"description"` + Name string `xml:"name"` + Link string `xml:"link"` +} diff --git a/vendor/github.com/google/uuid/CHANGELOG.md b/vendor/github.com/google/uuid/CHANGELOG.md deleted file mode 100644 index 7ec5ac7..0000000 --- a/vendor/github.com/google/uuid/CHANGELOG.md +++ /dev/null @@ -1,41 +0,0 @@ -# Changelog - -## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16) - - -### Features - -* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3)) - - -### Bug Fixes - -* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06)) -* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6)) - -## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) - - -### Features - -* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29)) - -## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26) - - -### Features - -* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4)) - -### Fixes - -* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior) - -## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18) - - -### Bug Fixes - -* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0)) - -## Changelog diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md deleted file mode 100644 index a502fdc..0000000 --- a/vendor/github.com/google/uuid/CONTRIBUTING.md +++ /dev/null @@ -1,26 +0,0 @@ -# How to contribute - -We definitely welcome patches and contribution to this project! - -### Tips - -Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org). - -Always try to include a test case! If it is not possible or not necessary, -please explain why in the pull request description. - -### Releasing - -Commits that would precipitate a SemVer change, as described in the Conventional -Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action) -to create a release candidate pull request. Once submitted, `release-please` -will create a release. - -For tips on how to work with `release-please`, see its documentation. - -### Legal requirements - -In order to protect both you and ourselves, you will need to sign the -[Contributor License Agreement](https://cla.developers.google.com/clas). - -You may have already signed it for other Google projects. diff --git a/vendor/github.com/google/uuid/CONTRIBUTORS b/vendor/github.com/google/uuid/CONTRIBUTORS deleted file mode 100644 index b4bb97f..0000000 --- a/vendor/github.com/google/uuid/CONTRIBUTORS +++ /dev/null @@ -1,9 +0,0 @@ -Paul Borman -bmatsuo -shawnps -theory -jboverfelt -dsymonds -cd1 -wallclockbuilder -dansouza diff --git a/vendor/github.com/google/uuid/LICENSE b/vendor/github.com/google/uuid/LICENSE deleted file mode 100644 index 5dc6826..0000000 --- a/vendor/github.com/google/uuid/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009,2014 Google Inc. 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. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -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 -OWNER 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/google/uuid/README.md b/vendor/github.com/google/uuid/README.md deleted file mode 100644 index 3e9a618..0000000 --- a/vendor/github.com/google/uuid/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# uuid -The uuid package generates and inspects UUIDs based on -[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122) -and DCE 1.1: Authentication and Security Services. - -This package is based on the github.com/pborman/uuid package (previously named -code.google.com/p/go-uuid). It differs from these earlier packages in that -a UUID is a 16 byte array rather than a byte slice. One loss due to this -change is the ability to represent an invalid UUID (vs a NIL UUID). - -###### Install -```sh -go get github.com/google/uuid -``` - -###### Documentation -[![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid) - -Full `go doc` style documentation for the package can be viewed online without -installing this package by using the GoDoc site here: -http://pkg.go.dev/github.com/google/uuid diff --git a/vendor/github.com/google/uuid/dce.go b/vendor/github.com/google/uuid/dce.go deleted file mode 100644 index fa820b9..0000000 --- a/vendor/github.com/google/uuid/dce.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" - "fmt" - "os" -) - -// A Domain represents a Version 2 domain -type Domain byte - -// Domain constants for DCE Security (Version 2) UUIDs. -const ( - Person = Domain(0) - Group = Domain(1) - Org = Domain(2) -) - -// NewDCESecurity returns a DCE Security (Version 2) UUID. -// -// The domain should be one of Person, Group or Org. -// On a POSIX system the id should be the users UID for the Person -// domain and the users GID for the Group. The meaning of id for -// the domain Org or on non-POSIX systems is site defined. -// -// For a given domain/id pair the same token may be returned for up to -// 7 minutes and 10 seconds. -func NewDCESecurity(domain Domain, id uint32) (UUID, error) { - uuid, err := NewUUID() - if err == nil { - uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 - uuid[9] = byte(domain) - binary.BigEndian.PutUint32(uuid[0:], id) - } - return uuid, err -} - -// NewDCEPerson returns a DCE Security (Version 2) UUID in the person -// domain with the id returned by os.Getuid. -// -// NewDCESecurity(Person, uint32(os.Getuid())) -func NewDCEPerson() (UUID, error) { - return NewDCESecurity(Person, uint32(os.Getuid())) -} - -// NewDCEGroup returns a DCE Security (Version 2) UUID in the group -// domain with the id returned by os.Getgid. -// -// NewDCESecurity(Group, uint32(os.Getgid())) -func NewDCEGroup() (UUID, error) { - return NewDCESecurity(Group, uint32(os.Getgid())) -} - -// Domain returns the domain for a Version 2 UUID. Domains are only defined -// for Version 2 UUIDs. -func (uuid UUID) Domain() Domain { - return Domain(uuid[9]) -} - -// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2 -// UUIDs. -func (uuid UUID) ID() uint32 { - return binary.BigEndian.Uint32(uuid[0:4]) -} - -func (d Domain) String() string { - switch d { - case Person: - return "Person" - case Group: - return "Group" - case Org: - return "Org" - } - return fmt.Sprintf("Domain%d", int(d)) -} diff --git a/vendor/github.com/google/uuid/doc.go b/vendor/github.com/google/uuid/doc.go deleted file mode 100644 index 5b8a4b9..0000000 --- a/vendor/github.com/google/uuid/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package uuid generates and inspects UUIDs. -// -// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security -// Services. -// -// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to -// maps or compared directly. -package uuid diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go deleted file mode 100644 index dc60082..0000000 --- a/vendor/github.com/google/uuid/hash.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "crypto/md5" - "crypto/sha1" - "hash" -) - -// Well known namespace IDs and UUIDs -var ( - NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) - Nil UUID // empty UUID, all zeros - - // The Max UUID is special form of UUID that is specified to have all 128 bits set to 1. - Max = UUID{ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - } -) - -// NewHash returns a new UUID derived from the hash of space concatenated with -// data generated by h. The hash should be at least 16 byte in length. The -// first 16 bytes of the hash are used to form the UUID. The version of the -// UUID will be the lower 4 bits of version. NewHash is used to implement -// NewMD5 and NewSHA1. -func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { - h.Reset() - h.Write(space[:]) //nolint:errcheck - h.Write(data) //nolint:errcheck - s := h.Sum(nil) - var uuid UUID - copy(uuid[:], s) - uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) - uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant - return uuid -} - -// NewMD5 returns a new MD5 (Version 3) UUID based on the -// supplied name space and data. It is the same as calling: -// -// NewHash(md5.New(), space, data, 3) -func NewMD5(space UUID, data []byte) UUID { - return NewHash(md5.New(), space, data, 3) -} - -// NewSHA1 returns a new SHA1 (Version 5) UUID based on the -// supplied name space and data. It is the same as calling: -// -// NewHash(sha1.New(), space, data, 5) -func NewSHA1(space UUID, data []byte) UUID { - return NewHash(sha1.New(), space, data, 5) -} diff --git a/vendor/github.com/google/uuid/marshal.go b/vendor/github.com/google/uuid/marshal.go deleted file mode 100644 index 14bd340..0000000 --- a/vendor/github.com/google/uuid/marshal.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import "fmt" - -// MarshalText implements encoding.TextMarshaler. -func (uuid UUID) MarshalText() ([]byte, error) { - var js [36]byte - encodeHex(js[:], uuid) - return js[:], nil -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (uuid *UUID) UnmarshalText(data []byte) error { - id, err := ParseBytes(data) - if err != nil { - return err - } - *uuid = id - return nil -} - -// MarshalBinary implements encoding.BinaryMarshaler. -func (uuid UUID) MarshalBinary() ([]byte, error) { - return uuid[:], nil -} - -// UnmarshalBinary implements encoding.BinaryUnmarshaler. -func (uuid *UUID) UnmarshalBinary(data []byte) error { - if len(data) != 16 { - return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) - } - copy(uuid[:], data) - return nil -} diff --git a/vendor/github.com/google/uuid/node.go b/vendor/github.com/google/uuid/node.go deleted file mode 100644 index d651a2b..0000000 --- a/vendor/github.com/google/uuid/node.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "sync" -) - -var ( - nodeMu sync.Mutex - ifname string // name of interface being used - nodeID [6]byte // hardware for version 1 UUIDs - zeroID [6]byte // nodeID with only 0's -) - -// NodeInterface returns the name of the interface from which the NodeID was -// derived. The interface "user" is returned if the NodeID was set by -// SetNodeID. -func NodeInterface() string { - defer nodeMu.Unlock() - nodeMu.Lock() - return ifname -} - -// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. -// If name is "" then the first usable interface found will be used or a random -// Node ID will be generated. If a named interface cannot be found then false -// is returned. -// -// SetNodeInterface never fails when name is "". -func SetNodeInterface(name string) bool { - defer nodeMu.Unlock() - nodeMu.Lock() - return setNodeInterface(name) -} - -func setNodeInterface(name string) bool { - iname, addr := getHardwareInterface(name) // null implementation for js - if iname != "" && addr != nil { - ifname = iname - copy(nodeID[:], addr) - return true - } - - // We found no interfaces with a valid hardware address. If name - // does not specify a specific interface generate a random Node ID - // (section 4.1.6) - if name == "" { - ifname = "random" - randomBits(nodeID[:]) - return true - } - return false -} - -// NodeID returns a slice of a copy of the current Node ID, setting the Node ID -// if not already set. -func NodeID() []byte { - defer nodeMu.Unlock() - nodeMu.Lock() - if nodeID == zeroID { - setNodeInterface("") - } - nid := nodeID - return nid[:] -} - -// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes -// of id are used. If id is less than 6 bytes then false is returned and the -// Node ID is not set. -func SetNodeID(id []byte) bool { - if len(id) < 6 { - return false - } - defer nodeMu.Unlock() - nodeMu.Lock() - copy(nodeID[:], id) - ifname = "user" - return true -} - -// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is -// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. -func (uuid UUID) NodeID() []byte { - var node [6]byte - copy(node[:], uuid[10:]) - return node[:] -} diff --git a/vendor/github.com/google/uuid/node_js.go b/vendor/github.com/google/uuid/node_js.go deleted file mode 100644 index b2a0bc8..0000000 --- a/vendor/github.com/google/uuid/node_js.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build js - -package uuid - -// getHardwareInterface returns nil values for the JS version of the code. -// This removes the "net" dependency, because it is not used in the browser. -// Using the "net" library inflates the size of the transpiled JS code by 673k bytes. -func getHardwareInterface(name string) (string, []byte) { return "", nil } diff --git a/vendor/github.com/google/uuid/node_net.go b/vendor/github.com/google/uuid/node_net.go deleted file mode 100644 index 0cbbcdd..0000000 --- a/vendor/github.com/google/uuid/node_net.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2017 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !js - -package uuid - -import "net" - -var interfaces []net.Interface // cached list of interfaces - -// getHardwareInterface returns the name and hardware address of interface name. -// If name is "" then the name and hardware address of one of the system's -// interfaces is returned. If no interfaces are found (name does not exist or -// there are no interfaces) then "", nil is returned. -// -// Only addresses of at least 6 bytes are returned. -func getHardwareInterface(name string) (string, []byte) { - if interfaces == nil { - var err error - interfaces, err = net.Interfaces() - if err != nil { - return "", nil - } - } - for _, ifs := range interfaces { - if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { - return ifs.Name, ifs.HardwareAddr - } - } - return "", nil -} diff --git a/vendor/github.com/google/uuid/null.go b/vendor/github.com/google/uuid/null.go deleted file mode 100644 index d7fcbf2..0000000 --- a/vendor/github.com/google/uuid/null.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2021 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "bytes" - "database/sql/driver" - "encoding/json" - "fmt" -) - -var jsonNull = []byte("null") - -// NullUUID represents a UUID that may be null. -// NullUUID implements the SQL driver.Scanner interface so -// it can be used as a scan destination: -// -// var u uuid.NullUUID -// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u) -// ... -// if u.Valid { -// // use u.UUID -// } else { -// // NULL value -// } -// -type NullUUID struct { - UUID UUID - Valid bool // Valid is true if UUID is not NULL -} - -// Scan implements the SQL driver.Scanner interface. -func (nu *NullUUID) Scan(value interface{}) error { - if value == nil { - nu.UUID, nu.Valid = Nil, false - return nil - } - - err := nu.UUID.Scan(value) - if err != nil { - nu.Valid = false - return err - } - - nu.Valid = true - return nil -} - -// Value implements the driver Valuer interface. -func (nu NullUUID) Value() (driver.Value, error) { - if !nu.Valid { - return nil, nil - } - // Delegate to UUID Value function - return nu.UUID.Value() -} - -// MarshalBinary implements encoding.BinaryMarshaler. -func (nu NullUUID) MarshalBinary() ([]byte, error) { - if nu.Valid { - return nu.UUID[:], nil - } - - return []byte(nil), nil -} - -// UnmarshalBinary implements encoding.BinaryUnmarshaler. -func (nu *NullUUID) UnmarshalBinary(data []byte) error { - if len(data) != 16 { - return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) - } - copy(nu.UUID[:], data) - nu.Valid = true - return nil -} - -// MarshalText implements encoding.TextMarshaler. -func (nu NullUUID) MarshalText() ([]byte, error) { - if nu.Valid { - return nu.UUID.MarshalText() - } - - return jsonNull, nil -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (nu *NullUUID) UnmarshalText(data []byte) error { - id, err := ParseBytes(data) - if err != nil { - nu.Valid = false - return err - } - nu.UUID = id - nu.Valid = true - return nil -} - -// MarshalJSON implements json.Marshaler. -func (nu NullUUID) MarshalJSON() ([]byte, error) { - if nu.Valid { - return json.Marshal(nu.UUID) - } - - return jsonNull, nil -} - -// UnmarshalJSON implements json.Unmarshaler. -func (nu *NullUUID) UnmarshalJSON(data []byte) error { - if bytes.Equal(data, jsonNull) { - *nu = NullUUID{} - return nil // valid null UUID - } - err := json.Unmarshal(data, &nu.UUID) - nu.Valid = err == nil - return err -} diff --git a/vendor/github.com/google/uuid/sql.go b/vendor/github.com/google/uuid/sql.go deleted file mode 100644 index 2e02ec0..0000000 --- a/vendor/github.com/google/uuid/sql.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "database/sql/driver" - "fmt" -) - -// Scan implements sql.Scanner so UUIDs can be read from databases transparently. -// Currently, database types that map to string and []byte are supported. Please -// consult database-specific driver documentation for matching types. -func (uuid *UUID) Scan(src interface{}) error { - switch src := src.(type) { - case nil: - return nil - - case string: - // if an empty UUID comes from a table, we return a null UUID - if src == "" { - return nil - } - - // see Parse for required string format - u, err := Parse(src) - if err != nil { - return fmt.Errorf("Scan: %v", err) - } - - *uuid = u - - case []byte: - // if an empty UUID comes from a table, we return a null UUID - if len(src) == 0 { - return nil - } - - // assumes a simple slice of bytes if 16 bytes - // otherwise attempts to parse - if len(src) != 16 { - return uuid.Scan(string(src)) - } - copy((*uuid)[:], src) - - default: - return fmt.Errorf("Scan: unable to scan type %T into UUID", src) - } - - return nil -} - -// Value implements sql.Valuer so that UUIDs can be written to databases -// transparently. Currently, UUIDs map to strings. Please consult -// database-specific driver documentation for matching types. -func (uuid UUID) Value() (driver.Value, error) { - return uuid.String(), nil -} diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go deleted file mode 100644 index c351129..0000000 --- a/vendor/github.com/google/uuid/time.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" - "sync" - "time" -) - -// A Time represents a time as the number of 100's of nanoseconds since 15 Oct -// 1582. -type Time int64 - -const ( - lillian = 2299160 // Julian day of 15 Oct 1582 - unix = 2440587 // Julian day of 1 Jan 1970 - epoch = unix - lillian // Days between epochs - g1582 = epoch * 86400 // seconds between epochs - g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs -) - -var ( - timeMu sync.Mutex - lasttime uint64 // last time we returned - clockSeq uint16 // clock sequence for this run - - timeNow = time.Now // for testing -) - -// UnixTime converts t the number of seconds and nanoseconds using the Unix -// epoch of 1 Jan 1970. -func (t Time) UnixTime() (sec, nsec int64) { - sec = int64(t - g1582ns100) - nsec = (sec % 10000000) * 100 - sec /= 10000000 - return sec, nsec -} - -// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and -// clock sequence as well as adjusting the clock sequence as needed. An error -// is returned if the current time cannot be determined. -func GetTime() (Time, uint16, error) { - defer timeMu.Unlock() - timeMu.Lock() - return getTime() -} - -func getTime() (Time, uint16, error) { - t := timeNow() - - // If we don't have a clock sequence already, set one. - if clockSeq == 0 { - setClockSequence(-1) - } - now := uint64(t.UnixNano()/100) + g1582ns100 - - // If time has gone backwards with this clock sequence then we - // increment the clock sequence - if now <= lasttime { - clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000 - } - lasttime = now - return Time(now), clockSeq, nil -} - -// ClockSequence returns the current clock sequence, generating one if not -// already set. The clock sequence is only used for Version 1 UUIDs. -// -// The uuid package does not use global static storage for the clock sequence or -// the last time a UUID was generated. Unless SetClockSequence is used, a new -// random clock sequence is generated the first time a clock sequence is -// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) -func ClockSequence() int { - defer timeMu.Unlock() - timeMu.Lock() - return clockSequence() -} - -func clockSequence() int { - if clockSeq == 0 { - setClockSequence(-1) - } - return int(clockSeq & 0x3fff) -} - -// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to -// -1 causes a new sequence to be generated. -func SetClockSequence(seq int) { - defer timeMu.Unlock() - timeMu.Lock() - setClockSequence(seq) -} - -func setClockSequence(seq int) { - if seq == -1 { - var b [2]byte - randomBits(b[:]) // clock sequence - seq = int(b[0])<<8 | int(b[1]) - } - oldSeq := clockSeq - clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant - if oldSeq != clockSeq { - lasttime = 0 - } -} - -// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in -// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs. -func (uuid UUID) Time() Time { - var t Time - switch uuid.Version() { - case 6: - time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110 - t = Time(time) - case 7: - time := binary.BigEndian.Uint64(uuid[:8]) - t = Time((time>>16)*10000 + g1582ns100) - default: // forward compatible - time := int64(binary.BigEndian.Uint32(uuid[0:4])) - time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 - time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 - t = Time(time) - } - return t -} - -// ClockSequence returns the clock sequence encoded in uuid. -// The clock sequence is only well defined for version 1 and 2 UUIDs. -func (uuid UUID) ClockSequence() int { - return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff -} diff --git a/vendor/github.com/google/uuid/util.go b/vendor/github.com/google/uuid/util.go deleted file mode 100644 index 5ea6c73..0000000 --- a/vendor/github.com/google/uuid/util.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "io" -) - -// randomBits completely fills slice b with random data. -func randomBits(b []byte) { - if _, err := io.ReadFull(rander, b); err != nil { - panic(err.Error()) // rand should never fail - } -} - -// xvalues returns the value of a byte as a hexadecimal digit or 255. -var xvalues = [256]byte{ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -} - -// xtob converts hex characters x1 and x2 into a byte. -func xtob(x1, x2 byte) (byte, bool) { - b1 := xvalues[x1] - b2 := xvalues[x2] - return (b1 << 4) | b2, b1 != 255 && b2 != 255 -} diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go deleted file mode 100644 index 5232b48..0000000 --- a/vendor/github.com/google/uuid/uuid.go +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright 2018 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "bytes" - "crypto/rand" - "encoding/hex" - "errors" - "fmt" - "io" - "strings" - "sync" -) - -// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC -// 4122. -type UUID [16]byte - -// A Version represents a UUID's version. -type Version byte - -// A Variant represents a UUID's variant. -type Variant byte - -// Constants returned by Variant. -const ( - Invalid = Variant(iota) // Invalid UUID - RFC4122 // The variant specified in RFC4122 - Reserved // Reserved, NCS backward compatibility. - Microsoft // Reserved, Microsoft Corporation backward compatibility. - Future // Reserved for future definition. -) - -const randPoolSize = 16 * 16 - -var ( - rander = rand.Reader // random function - poolEnabled = false - poolMu sync.Mutex - poolPos = randPoolSize // protected with poolMu - pool [randPoolSize]byte // protected with poolMu -) - -type invalidLengthError struct{ len int } - -func (err invalidLengthError) Error() string { - return fmt.Sprintf("invalid UUID length: %d", err.len) -} - -// IsInvalidLengthError is matcher function for custom error invalidLengthError -func IsInvalidLengthError(err error) bool { - _, ok := err.(invalidLengthError) - return ok -} - -// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both -// the standard UUID forms defined in RFC 4122 -// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition, -// Parse accepts non-standard strings such as the raw hex encoding -// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings, -// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are -// examined in the latter case. Parse should not be used to validate strings as -// it parses non-standard encodings as indicated above. -func Parse(s string) (UUID, error) { - var uuid UUID - switch len(s) { - // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36: - - // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36 + 9: - if !strings.EqualFold(s[:9], "urn:uuid:") { - return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) - } - s = s[9:] - - // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} - case 36 + 2: - s = s[1:] - - // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - case 32: - var ok bool - for i := range uuid { - uuid[i], ok = xtob(s[i*2], s[i*2+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - } - return uuid, nil - default: - return uuid, invalidLengthError{len(s)} - } - // s is now at least 36 bytes long - // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { - return uuid, errors.New("invalid UUID format") - } - for i, x := range [16]int{ - 0, 2, 4, 6, - 9, 11, - 14, 16, - 19, 21, - 24, 26, 28, 30, 32, 34, - } { - v, ok := xtob(s[x], s[x+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - uuid[i] = v - } - return uuid, nil -} - -// ParseBytes is like Parse, except it parses a byte slice instead of a string. -func ParseBytes(b []byte) (UUID, error) { - var uuid UUID - switch len(b) { - case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) { - return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) - } - b = b[9:] - case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} - b = b[1:] - case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - var ok bool - for i := 0; i < 32; i += 2 { - uuid[i/2], ok = xtob(b[i], b[i+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - } - return uuid, nil - default: - return uuid, invalidLengthError{len(b)} - } - // s is now at least 36 bytes long - // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { - return uuid, errors.New("invalid UUID format") - } - for i, x := range [16]int{ - 0, 2, 4, 6, - 9, 11, - 14, 16, - 19, 21, - 24, 26, 28, 30, 32, 34, - } { - v, ok := xtob(b[x], b[x+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - uuid[i] = v - } - return uuid, nil -} - -// MustParse is like Parse but panics if the string cannot be parsed. -// It simplifies safe initialization of global variables holding compiled UUIDs. -func MustParse(s string) UUID { - uuid, err := Parse(s) - if err != nil { - panic(`uuid: Parse(` + s + `): ` + err.Error()) - } - return uuid -} - -// FromBytes creates a new UUID from a byte slice. Returns an error if the slice -// does not have a length of 16. The bytes are copied from the slice. -func FromBytes(b []byte) (uuid UUID, err error) { - err = uuid.UnmarshalBinary(b) - return uuid, err -} - -// Must returns uuid if err is nil and panics otherwise. -func Must(uuid UUID, err error) UUID { - if err != nil { - panic(err) - } - return uuid -} - -// Validate returns an error if s is not a properly formatted UUID in one of the following formats: -// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} -// It returns an error if the format is invalid, otherwise nil. -func Validate(s string) error { - switch len(s) { - // Standard UUID format - case 36: - - // UUID with "urn:uuid:" prefix - case 36 + 9: - if !strings.EqualFold(s[:9], "urn:uuid:") { - return fmt.Errorf("invalid urn prefix: %q", s[:9]) - } - s = s[9:] - - // UUID enclosed in braces - case 36 + 2: - if s[0] != '{' || s[len(s)-1] != '}' { - return fmt.Errorf("invalid bracketed UUID format") - } - s = s[1 : len(s)-1] - - // UUID without hyphens - case 32: - for i := 0; i < len(s); i += 2 { - _, ok := xtob(s[i], s[i+1]) - if !ok { - return errors.New("invalid UUID format") - } - } - - default: - return invalidLengthError{len(s)} - } - - // Check for standard UUID format - if len(s) == 36 { - if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { - return errors.New("invalid UUID format") - } - for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} { - if _, ok := xtob(s[x], s[x+1]); !ok { - return errors.New("invalid UUID format") - } - } - } - - return nil -} - -// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -// , or "" if uuid is invalid. -func (uuid UUID) String() string { - var buf [36]byte - encodeHex(buf[:], uuid) - return string(buf[:]) -} - -// URN returns the RFC 2141 URN form of uuid, -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. -func (uuid UUID) URN() string { - var buf [36 + 9]byte - copy(buf[:], "urn:uuid:") - encodeHex(buf[9:], uuid) - return string(buf[:]) -} - -func encodeHex(dst []byte, uuid UUID) { - hex.Encode(dst, uuid[:4]) - dst[8] = '-' - hex.Encode(dst[9:13], uuid[4:6]) - dst[13] = '-' - hex.Encode(dst[14:18], uuid[6:8]) - dst[18] = '-' - hex.Encode(dst[19:23], uuid[8:10]) - dst[23] = '-' - hex.Encode(dst[24:], uuid[10:]) -} - -// Variant returns the variant encoded in uuid. -func (uuid UUID) Variant() Variant { - switch { - case (uuid[8] & 0xc0) == 0x80: - return RFC4122 - case (uuid[8] & 0xe0) == 0xc0: - return Microsoft - case (uuid[8] & 0xe0) == 0xe0: - return Future - default: - return Reserved - } -} - -// Version returns the version of uuid. -func (uuid UUID) Version() Version { - return Version(uuid[6] >> 4) -} - -func (v Version) String() string { - if v > 15 { - return fmt.Sprintf("BAD_VERSION_%d", v) - } - return fmt.Sprintf("VERSION_%d", v) -} - -func (v Variant) String() string { - switch v { - case RFC4122: - return "RFC4122" - case Reserved: - return "Reserved" - case Microsoft: - return "Microsoft" - case Future: - return "Future" - case Invalid: - return "Invalid" - } - return fmt.Sprintf("BadVariant%d", int(v)) -} - -// SetRand sets the random number generator to r, which implements io.Reader. -// If r.Read returns an error when the package requests random data then -// a panic will be issued. -// -// Calling SetRand with nil sets the random number generator to the default -// generator. -func SetRand(r io.Reader) { - if r == nil { - rander = rand.Reader - return - } - rander = r -} - -// EnableRandPool enables internal randomness pool used for Random -// (Version 4) UUID generation. The pool contains random bytes read from -// the random number generator on demand in batches. Enabling the pool -// may improve the UUID generation throughput significantly. -// -// Since the pool is stored on the Go heap, this feature may be a bad fit -// for security sensitive applications. -// -// Both EnableRandPool and DisableRandPool are not thread-safe and should -// only be called when there is no possibility that New or any other -// UUID Version 4 generation function will be called concurrently. -func EnableRandPool() { - poolEnabled = true -} - -// DisableRandPool disables the randomness pool if it was previously -// enabled with EnableRandPool. -// -// Both EnableRandPool and DisableRandPool are not thread-safe and should -// only be called when there is no possibility that New or any other -// UUID Version 4 generation function will be called concurrently. -func DisableRandPool() { - poolEnabled = false - defer poolMu.Unlock() - poolMu.Lock() - poolPos = randPoolSize -} - -// UUIDs is a slice of UUID types. -type UUIDs []UUID - -// Strings returns a string slice containing the string form of each UUID in uuids. -func (uuids UUIDs) Strings() []string { - var uuidStrs = make([]string, len(uuids)) - for i, uuid := range uuids { - uuidStrs[i] = uuid.String() - } - return uuidStrs -} diff --git a/vendor/github.com/google/uuid/version1.go b/vendor/github.com/google/uuid/version1.go deleted file mode 100644 index 4631096..0000000 --- a/vendor/github.com/google/uuid/version1.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" -) - -// NewUUID returns a Version 1 UUID based on the current NodeID and clock -// sequence, and the current time. If the NodeID has not been set by SetNodeID -// or SetNodeInterface then it will be set automatically. If the NodeID cannot -// be set NewUUID returns nil. If clock sequence has not been set by -// SetClockSequence then it will be set automatically. If GetTime fails to -// return the current NewUUID returns nil and an error. -// -// In most cases, New should be used. -func NewUUID() (UUID, error) { - var uuid UUID - now, seq, err := GetTime() - if err != nil { - return uuid, err - } - - timeLow := uint32(now & 0xffffffff) - timeMid := uint16((now >> 32) & 0xffff) - timeHi := uint16((now >> 48) & 0x0fff) - timeHi |= 0x1000 // Version 1 - - binary.BigEndian.PutUint32(uuid[0:], timeLow) - binary.BigEndian.PutUint16(uuid[4:], timeMid) - binary.BigEndian.PutUint16(uuid[6:], timeHi) - binary.BigEndian.PutUint16(uuid[8:], seq) - - nodeMu.Lock() - if nodeID == zeroID { - setNodeInterface("") - } - copy(uuid[10:], nodeID[:]) - nodeMu.Unlock() - - return uuid, nil -} diff --git a/vendor/github.com/google/uuid/version4.go b/vendor/github.com/google/uuid/version4.go deleted file mode 100644 index 7697802..0000000 --- a/vendor/github.com/google/uuid/version4.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import "io" - -// New creates a new random UUID or panics. New is equivalent to -// the expression -// -// uuid.Must(uuid.NewRandom()) -func New() UUID { - return Must(NewRandom()) -} - -// NewString creates a new random UUID and returns it as a string or panics. -// NewString is equivalent to the expression -// -// uuid.New().String() -func NewString() string { - return Must(NewRandom()).String() -} - -// NewRandom returns a Random (Version 4) UUID. -// -// The strength of the UUIDs is based on the strength of the crypto/rand -// package. -// -// Uses the randomness pool if it was enabled with EnableRandPool. -// -// A note about uniqueness derived from the UUID Wikipedia entry: -// -// Randomly generated UUIDs have 122 random bits. One's annual risk of being -// hit by a meteorite is estimated to be one chance in 17 billion, that -// means the probability is about 0.00000000006 (6 × 10−11), -// equivalent to the odds of creating a few tens of trillions of UUIDs in a -// year and having one duplicate. -func NewRandom() (UUID, error) { - if !poolEnabled { - return NewRandomFromReader(rander) - } - return newRandomFromPool() -} - -// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader. -func NewRandomFromReader(r io.Reader) (UUID, error) { - var uuid UUID - _, err := io.ReadFull(r, uuid[:]) - if err != nil { - return Nil, err - } - uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 - uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 - return uuid, nil -} - -func newRandomFromPool() (UUID, error) { - var uuid UUID - poolMu.Lock() - if poolPos == randPoolSize { - _, err := io.ReadFull(rander, pool[:]) - if err != nil { - poolMu.Unlock() - return Nil, err - } - poolPos = 0 - } - copy(uuid[:], pool[poolPos:(poolPos+16)]) - poolPos += 16 - poolMu.Unlock() - - uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 - uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 - return uuid, nil -} diff --git a/vendor/github.com/google/uuid/version6.go b/vendor/github.com/google/uuid/version6.go deleted file mode 100644 index 339a959..0000000 --- a/vendor/github.com/google/uuid/version6.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2023 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import "encoding/binary" - -// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. -// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. -// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead. -// -// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6 -// -// NewV6 returns a Version 6 UUID based on the current NodeID and clock -// sequence, and the current time. If the NodeID has not been set by SetNodeID -// or SetNodeInterface then it will be set automatically. If the NodeID cannot -// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by -// SetClockSequence then it will be set automatically. If GetTime fails to -// return the current NewV6 returns Nil and an error. -func NewV6() (UUID, error) { - var uuid UUID - now, seq, err := GetTime() - if err != nil { - return uuid, err - } - - /* - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | time_high | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | time_mid | time_low_and_version | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |clk_seq_hi_res | clk_seq_low | node (0-1) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | node (2-5) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - - binary.BigEndian.PutUint64(uuid[0:], uint64(now)) - binary.BigEndian.PutUint16(uuid[8:], seq) - - uuid[6] = 0x60 | (uuid[6] & 0x0F) - uuid[8] = 0x80 | (uuid[8] & 0x3F) - - nodeMu.Lock() - if nodeID == zeroID { - setNodeInterface("") - } - copy(uuid[10:], nodeID[:]) - nodeMu.Unlock() - - return uuid, nil -} diff --git a/vendor/github.com/google/uuid/version7.go b/vendor/github.com/google/uuid/version7.go deleted file mode 100644 index 3167b64..0000000 --- a/vendor/github.com/google/uuid/version7.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2023 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "io" -) - -// UUID version 7 features a time-ordered value field derived from the widely -// implemented and well known Unix Epoch timestamp source, -// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. -// As well as improved entropy characteristics over versions 1 or 6. -// -// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7 -// -// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible. -// -// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch). -// Uses the randomness pool if it was enabled with EnableRandPool. -// On error, NewV7 returns Nil and an error -func NewV7() (UUID, error) { - uuid, err := NewRandom() - if err != nil { - return uuid, err - } - makeV7(uuid[:]) - return uuid, nil -} - -// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch). -// it use NewRandomFromReader fill random bits. -// On error, NewV7FromReader returns Nil and an error. -func NewV7FromReader(r io.Reader) (UUID, error) { - uuid, err := NewRandomFromReader(r) - if err != nil { - return uuid, err - } - - makeV7(uuid[:]) - return uuid, nil -} - -// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6]) -// uuid[8] already has the right version number (Variant is 10) -// see function NewV7 and NewV7FromReader -func makeV7(uuid []byte) { - /* - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | unix_ts_ms | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | unix_ts_ms | ver | rand_a (12 bit seq) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |var| rand_b | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | rand_b | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - _ = uuid[15] // bounds check - - t, s := getV7Time() - - uuid[0] = byte(t >> 40) - uuid[1] = byte(t >> 32) - uuid[2] = byte(t >> 24) - uuid[3] = byte(t >> 16) - uuid[4] = byte(t >> 8) - uuid[5] = byte(t) - - uuid[6] = 0x70 | (0x0F & byte(s>>8)) - uuid[7] = byte(s) -} - -// lastV7time is the last time we returned stored as: -// -// 52 bits of time in milliseconds since epoch -// 12 bits of (fractional nanoseconds) >> 8 -var lastV7time int64 - -const nanoPerMilli = 1000000 - -// getV7Time returns the time in milliseconds and nanoseconds / 256. -// The returned (milli << 12 + seq) is guarenteed to be greater than -// (milli << 12 + seq) returned by any previous call to getV7Time. -func getV7Time() (milli, seq int64) { - timeMu.Lock() - defer timeMu.Unlock() - - nano := timeNow().UnixNano() - milli = nano / nanoPerMilli - // Sequence number is between 0 and 3906 (nanoPerMilli>>8) - seq = (nano - milli*nanoPerMilli) >> 8 - now := milli<<12 + seq - if now <= lastV7time { - now = lastV7time + 1 - milli = now >> 12 - seq = now & 0xfff - } - lastV7time = now - return milli, seq -} diff --git a/vendor/github.com/gorilla/feeds/.editorconfig b/vendor/github.com/gorilla/feeds/.editorconfig deleted file mode 100644 index 2940ec9..0000000 --- a/vendor/github.com/gorilla/feeds/.editorconfig +++ /dev/null @@ -1,20 +0,0 @@ -; https://editorconfig.org/ - -root = true - -[*] -insert_final_newline = true -charset = utf-8 -trim_trailing_whitespace = true -indent_style = space -indent_size = 2 - -[{Makefile,go.mod,go.sum,*.go,.gitmodules}] -indent_style = tab -indent_size = 4 - -[*.md] -indent_size = 4 -trim_trailing_whitespace = false - -eclint_indent_style = unset diff --git a/vendor/github.com/gorilla/feeds/.gitignore b/vendor/github.com/gorilla/feeds/.gitignore deleted file mode 100644 index 84039fe..0000000 --- a/vendor/github.com/gorilla/feeds/.gitignore +++ /dev/null @@ -1 +0,0 @@ -coverage.coverprofile diff --git a/vendor/github.com/gorilla/feeds/LICENSE b/vendor/github.com/gorilla/feeds/LICENSE deleted file mode 100644 index ee0d53c..0000000 --- a/vendor/github.com/gorilla/feeds/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2023 The Gorilla 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. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -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 -OWNER 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/Makefile b/vendor/github.com/gorilla/feeds/Makefile deleted file mode 100644 index ac37ffd..0000000 --- a/vendor/github.com/gorilla/feeds/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '') -GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest - -GO_SEC=$(shell which gosec 2> /dev/null || echo '') -GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest - -GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '') -GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest - -.PHONY: golangci-lint -golangci-lint: - $(if $(GO_LINT), ,go install $(GO_LINT_URI)) - @echo "##### Running golangci-lint" - golangci-lint run -v - -.PHONY: gosec -gosec: - $(if $(GO_SEC), ,go install $(GO_SEC_URI)) - @echo "##### Running gosec" - gosec ./... - -.PHONY: govulncheck -govulncheck: - $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI)) - @echo "##### Running govulncheck" - govulncheck ./... - -.PHONY: verify -verify: golangci-lint gosec govulncheck - -.PHONY: test -test: - @echo "##### Running tests" - go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./... diff --git a/vendor/github.com/gorilla/feeds/README.md b/vendor/github.com/gorilla/feeds/README.md deleted file mode 100644 index 7d7137b..0000000 --- a/vendor/github.com/gorilla/feeds/README.md +++ /dev/null @@ -1,198 +0,0 @@ -## gorilla/feeds -![testing](https://github.com/gorilla/feeds/actions/workflows/test.yml/badge.svg) -[![codecov](https://codecov.io/github/gorilla/feeds/branch/main/graph/badge.svg)](https://codecov.io/github/gorilla/feeds) -[![godoc](https://godoc.org/github.com/gorilla/feeds?status.svg)](https://godoc.org/github.com/gorilla/feeds) -[![sourcegraph](https://sourcegraph.com/github.com/gorilla/feeds/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/feeds?badge) - -![Gorilla Logo](https://github.com/gorilla/.github/assets/53367916/d92caabf-98e0-473e-bfbf-ab554ba435e5) - -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.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 effectively", - 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 - - - jmoiron.net blog - - http://jmoiron.net/blog - 2013-01-16T03:26:01-05:00 - discussion about tech, footie, photos - - Limiting Concurrency in Go - - 2013-01-16T03:26:01-05:00 - tag:jmoiron.net,2013-01-16:/blog/limiting-concurrency-in-go/ - A discussion on controlled parallelism in golang - - Jason Moiron - jmoiron@jmoiron.net - - - - Logic-less Template Redux - - 2013-01-16T03:26:01-05:00 - tag:jmoiron.net,2013-01-16:/blog/logicless-template-redux/ - More thoughts on logicless templates - - - - Idiomatic Code Reuse in Go - - 2013-01-16T03:26:01-05:00 - tag:jmoiron.net,2013-01-16:/blog/idiomatic-code-reuse-in-go/ - How to use interfaces <em>effectively</em> - - - - - - - - jmoiron.net blog - http://jmoiron.net/blog - discussion about tech, footie, photos - jmoiron@jmoiron.net (Jason Moiron) - 2013-01-16T03:22:24-05:00 - - Limiting Concurrency in Go - http://jmoiron.net/blog/limiting-concurrency-in-go/ - A discussion on controlled parallelism in golang - 2013-01-16T03:22:24-05:00 - - - Logic-less Template Redux - http://jmoiron.net/blog/logicless-template-redux/ - More thoughts on logicless templates - 2013-01-16T03:22:24-05:00 - - - Idiomatic Code Reuse in Go - http://jmoiron.net/blog/idiomatic-code-reuse-in-go/ - How to use interfaces <em>effectively</em> - 2013-01-16T03:22:24-05:00 - - - - -{ - "version": "https://jsonfeed.org/version/1.1", - "title": "jmoiron.net blog", - "home_page_url": "http://jmoiron.net/blog", - "description": "discussion about tech, footie, photos", - "author": { - "name": "Jason Moiron" - }, - "authors": [ - { - "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" - }, - "authors": [ - { - "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 deleted file mode 100644 index 73de995..0000000 --- a/vendor/github.com/gorilla/feeds/atom.go +++ /dev/null @@ -1,178 +0,0 @@ -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 - 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 - link := i.Link - if link == nil { - link = &Link{} - } - if len(id) == 0 { - // if there's no id set, try to create one, either from data or just a uuid - if len(link.Href) > 0 && (!i.Created.IsZero() || !i.Updated.IsZero()) { - dateStr := anyTimeFormat("2006-01-02", i.Updated, i.Created) - host, path := link.Href, "/invalid.html" - if url, err := url.Parse(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 := link.Rel - if link_rel == "" { - link_rel = "alternate" - } - x := &AtomEntry{ - Title: i.Title, - Links: []AtomLink{{Href: link.Href, Rel: link_rel, Type: link.Type}}, - Id: id, - Updated: anyTimeFormat(time.RFC3339, i.Updated, i.Created), - } - - // if there's a description, assume it's html - if len(i.Description) > 0 { - x.Summary = &AtomSummary{Content: i.Description, Type: "html"} - } - - // 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) - link := a.Link - if link == nil { - link = &Link{} - } - feed := &AtomFeed{ - Xmlns: ns, - Title: a.Title, - Link: &AtomLink{Href: link.Href, Rel: link.Rel}, - Subtitle: a.Description, - Id: 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 deleted file mode 100644 index 4e0759c..0000000 --- a/vendor/github.com/gorilla/feeds/doc.go +++ /dev/null @@ -1,73 +0,0 @@ -/* -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 effectively", - 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 deleted file mode 100644 index 929c226..0000000 --- a/vendor/github.com/gorilla/feeds/feed.go +++ /dev/null @@ -1,146 +0,0 @@ -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 - IsPermaLink string // an optional parameter for guid in rss - 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 deleted file mode 100644 index ae5deb7..0000000 --- a/vendor/github.com/gorilla/feeds/json.go +++ /dev/null @@ -1,190 +0,0 @@ -package feeds - -import ( - "encoding/json" - "strings" - "time" -) - -const jsonFeedVersion = "https://jsonfeed.org/version/1.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"` // deprecated in JSON Feed v1.1, keeping for backwards compatibility - Authors []*JSONAuthor `json:"authors,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"` - Language string `json:"language,omitempty"` - 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"` // deprecated in JSON Feed v1.1, keeping for backwards compatibility - Authors []*JSONAuthor `json:"authors,omitempty"` - Expired *bool `json:"expired,omitempty"` - Hubs []*JSONHub `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 { - author := &JSONAuthor{ - Name: f.Author.Name, - } - feed.Author = author - feed.Authors = []*JSONAuthor{author} - } - 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 { - author := &JSONAuthor{ - Name: i.Author.Name, - } - item.Author = author - item.Authors = []*JSONAuthor{author} - } - 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 deleted file mode 100644 index 9326cef..0000000 --- a/vendor/github.com/gorilla/feeds/rss.go +++ /dev/null @@ -1,183 +0,0 @@ -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 .. 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 *RssGuid // Id used - PubDate string `xml:"pubDate,omitempty"` // created or updated - Source string `xml:"source,omitempty"` -} - -type RssEnclosure struct { - //RSS 2.0 - XMLName xml.Name `xml:"enclosure"` - Url string `xml:"url,attr"` - Length string `xml:"length,attr"` - Type string `xml:"type,attr"` -} - -type RssGuid struct { - //RSS 2.0 http://inessential.com/2002/09/01.php#a2 - XMLName xml.Name `xml:"guid"` - Id string `xml:",chardata"` - IsPermaLink string `xml:"isPermaLink,attr,omitempty"` // "true", "false", or an empty string -} - -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, - Description: i.Description, - PubDate: anyTimeFormat(time.RFC1123Z, i.Created, i.Updated), - } - if i.Id != "" { - item.Guid = &RssGuid{Id: i.Id, IsPermaLink: i.IsPermaLink} - } - if i.Link != nil { - item.Link = i.Link.Href - } - 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} - } - - var href string - if r.Link != nil { - href = r.Link.Href - } - channel := &RssFeed{ - Title: r.Title, - 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 deleted file mode 100644 index aa15214..0000000 --- a/vendor/github.com/gorilla/feeds/test.atom +++ /dev/null @@ -1,92 +0,0 @@ - - - <![CDATA[Lorem ipsum feed for an interval of 1 minutes]]> - - http://example.com/ - RSS for Node - Tue, 30 Oct 2018 23:22:37 GMT - - Tue, 30 Oct 2018 23:22:00 GMT - - 60 - - <![CDATA[Lorem ipsum 2018-10-30T23:22:00+00:00]]> - - http://example.com/test/1540941720 - http://example.com/test/1540941720 - - Tue, 30 Oct 2018 23:22:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:21:00+00:00]]> - - http://example.com/test/1540941660 - http://example.com/test/1540941660 - - Tue, 30 Oct 2018 23:21:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:20:00+00:00]]> - - http://example.com/test/1540941600 - http://example.com/test/1540941600 - - Tue, 30 Oct 2018 23:20:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:19:00+00:00]]> - - http://example.com/test/1540941540 - http://example.com/test/1540941540 - - Tue, 30 Oct 2018 23:19:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:18:00+00:00]]> - - http://example.com/test/1540941480 - http://example.com/test/1540941480 - - Tue, 30 Oct 2018 23:18:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:17:00+00:00]]> - - http://example.com/test/1540941420 - http://example.com/test/1540941420 - - Tue, 30 Oct 2018 23:17:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:16:00+00:00]]> - - http://example.com/test/1540941360 - http://example.com/test/1540941360 - - Tue, 30 Oct 2018 23:16:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:15:00+00:00]]> - - http://example.com/test/1540941300 - http://example.com/test/1540941300 - - Tue, 30 Oct 2018 23:15:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:14:00+00:00]]> - - http://example.com/test/1540941240 - http://example.com/test/1540941240 - - Tue, 30 Oct 2018 23:14:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:13:00+00:00]]> - - http://example.com/test/1540941180 - http://example.com/test/1540941180 - - Tue, 30 Oct 2018 23:13:00 GMT - - \ No newline at end of file diff --git a/vendor/github.com/gorilla/feeds/test.rss b/vendor/github.com/gorilla/feeds/test.rss deleted file mode 100644 index 8d912ab..0000000 --- a/vendor/github.com/gorilla/feeds/test.rss +++ /dev/null @@ -1,96 +0,0 @@ - - - - <![CDATA[Lorem ipsum feed for an interval of 1 minutes]]> - - http://example.com/ - RSS for Node - Tue, 30 Oct 2018 23:22:37 GMT - - Tue, 30 Oct 2018 23:22:00 GMT - - 60 - - <![CDATA[Lorem ipsum 2018-10-30T23:22:00+00:00]]> - - http://example.com/test/1540941720 - http://example.com/test/1540941720 - - Tue, 30 Oct 2018 23:22:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:21:00+00:00]]> - - http://example.com/test/1540941660 - http://example.com/test/1540941660 - - Tue, 30 Oct 2018 23:21:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:20:00+00:00]]> - - http://example.com/test/1540941600 - http://example.com/test/1540941600 - - Tue, 30 Oct 2018 23:20:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:19:00+00:00]]> - - http://example.com/test/1540941540 - http://example.com/test/1540941540 - - Tue, 30 Oct 2018 23:19:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:18:00+00:00]]> - - http://example.com/test/1540941480 - http://example.com/test/1540941480 - - Tue, 30 Oct 2018 23:18:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:17:00+00:00]]> - - http://example.com/test/1540941420 - http://example.com/test/1540941420 - - Tue, 30 Oct 2018 23:17:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:16:00+00:00]]> - - http://example.com/test/1540941360 - http://example.com/test/1540941360 - - Tue, 30 Oct 2018 23:16:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:15:00+00:00]]> - - http://example.com/test/1540941300 - http://example.com/test/1540941300 - - Tue, 30 Oct 2018 23:15:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:14:00+00:00]]> - - http://example.com/test/1540941240 - http://example.com/test/1540941240 - - Tue, 30 Oct 2018 23:14:00 GMT - - - <![CDATA[Lorem ipsum 2018-10-30T23:13:00+00:00]]> - - http://example.com/test/1540941180 - http://example.com/test/1540941180 - - Tue, 30 Oct 2018 23:13:00 GMT - - - \ 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 deleted file mode 100644 index 45fd1e7..0000000 --- a/vendor/github.com/gorilla/feeds/to-implement.md +++ /dev/null @@ -1,20 +0,0 @@ -[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) - -``` - - - - - - - - - - - - - - -``` \ No newline at end of file diff --git a/vendor/github.com/gorilla/feeds/uuid.go b/vendor/github.com/gorilla/feeds/uuid.go deleted file mode 100644 index 51bbafe..0000000 --- a/vendor/github.com/gorilla/feeds/uuid.go +++ /dev/null @@ -1,27 +0,0 @@ -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:]) -} diff --git a/vendor/github.com/pkg/errors/.gitignore b/vendor/github.com/pkg/errors/.gitignore new file mode 100644 index 0000000..daf913b --- /dev/null +++ b/vendor/github.com/pkg/errors/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/pkg/errors/.travis.yml b/vendor/github.com/pkg/errors/.travis.yml new file mode 100644 index 0000000..9159de0 --- /dev/null +++ b/vendor/github.com/pkg/errors/.travis.yml @@ -0,0 +1,10 @@ +language: go +go_import_path: github.com/pkg/errors +go: + - 1.11.x + - 1.12.x + - 1.13.x + - tip + +script: + - make check diff --git a/vendor/github.com/pkg/errors/LICENSE b/vendor/github.com/pkg/errors/LICENSE new file mode 100644 index 0000000..835ba3e --- /dev/null +++ b/vendor/github.com/pkg/errors/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2015, Dave Cheney +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/pkg/errors/Makefile b/vendor/github.com/pkg/errors/Makefile new file mode 100644 index 0000000..ce9d7cd --- /dev/null +++ b/vendor/github.com/pkg/errors/Makefile @@ -0,0 +1,44 @@ +PKGS := github.com/pkg/errors +SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS)) +GO := go + +check: test vet gofmt misspell unconvert staticcheck ineffassign unparam + +test: + $(GO) test $(PKGS) + +vet: | test + $(GO) vet $(PKGS) + +staticcheck: + $(GO) get honnef.co/go/tools/cmd/staticcheck + staticcheck -checks all $(PKGS) + +misspell: + $(GO) get github.com/client9/misspell/cmd/misspell + misspell \ + -locale GB \ + -error \ + *.md *.go + +unconvert: + $(GO) get github.com/mdempsky/unconvert + unconvert -v $(PKGS) + +ineffassign: + $(GO) get github.com/gordonklaus/ineffassign + find $(SRCDIRS) -name '*.go' | xargs ineffassign + +pedantic: check errcheck + +unparam: + $(GO) get mvdan.cc/unparam + unparam ./... + +errcheck: + $(GO) get github.com/kisielk/errcheck + errcheck $(PKGS) + +gofmt: + @echo Checking code is gofmted + @test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)" diff --git a/vendor/github.com/pkg/errors/README.md b/vendor/github.com/pkg/errors/README.md new file mode 100644 index 0000000..54dfdcb --- /dev/null +++ b/vendor/github.com/pkg/errors/README.md @@ -0,0 +1,59 @@ +# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge) + +Package errors provides simple error handling primitives. + +`go get github.com/pkg/errors` + +The traditional error handling idiom in Go is roughly akin to +```go +if err != nil { + return err +} +``` +which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error. + +## Adding context to an error + +The errors.Wrap function returns a new error that adds context to the original error. For example +```go +_, err := ioutil.ReadAll(r) +if err != nil { + return errors.Wrap(err, "read failed") +} +``` +## Retrieving the cause of an error + +Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`. +```go +type causer interface { + Cause() error +} +``` +`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example: +```go +switch err := errors.Cause(err).(type) { +case *MyError: + // handle specifically +default: + // unknown error +} +``` + +[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). + +## Roadmap + +With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows: + +- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible) +- 1.0. Final release. + +## Contributing + +Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports. + +Before sending a PR, please discuss your change by raising an issue. + +## License + +BSD-2-Clause diff --git a/vendor/github.com/pkg/errors/appveyor.yml b/vendor/github.com/pkg/errors/appveyor.yml new file mode 100644 index 0000000..a932ead --- /dev/null +++ b/vendor/github.com/pkg/errors/appveyor.yml @@ -0,0 +1,32 @@ +version: build-{build}.{branch} + +clone_folder: C:\gopath\src\github.com\pkg\errors +shallow_clone: true # for startup speed + +environment: + GOPATH: C:\gopath + +platform: + - x64 + +# http://www.appveyor.com/docs/installed-software +install: + # some helpful output for debugging builds + - go version + - go env + # pre-installed MinGW at C:\MinGW is 32bit only + # but MSYS2 at C:\msys64 has mingw64 + - set PATH=C:\msys64\mingw64\bin;%PATH% + - gcc --version + - g++ --version + +build_script: + - go install -v ./... + +test_script: + - set PATH=C:\gopath\bin;%PATH% + - go test -v ./... + +#artifacts: +# - path: '%GOPATH%\bin\*.exe' +deploy: off diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go new file mode 100644 index 0000000..161aea2 --- /dev/null +++ b/vendor/github.com/pkg/errors/errors.go @@ -0,0 +1,288 @@ +// Package errors provides simple error handling primitives. +// +// The traditional error handling idiom in Go is roughly akin to +// +// if err != nil { +// return err +// } +// +// which when applied recursively up the call stack results in error reports +// without context or debugging information. The errors package allows +// programmers to add context to the failure path in their code in a way +// that does not destroy the original value of the error. +// +// Adding context to an error +// +// The errors.Wrap function returns a new error that adds context to the +// original error by recording a stack trace at the point Wrap is called, +// together with the supplied message. For example +// +// _, err := ioutil.ReadAll(r) +// if err != nil { +// return errors.Wrap(err, "read failed") +// } +// +// If additional control is required, the errors.WithStack and +// errors.WithMessage functions destructure errors.Wrap into its component +// operations: annotating an error with a stack trace and with a message, +// respectively. +// +// Retrieving the cause of an error +// +// Using errors.Wrap constructs a stack of errors, adding context to the +// preceding error. Depending on the nature of the error it may be necessary +// to reverse the operation of errors.Wrap to retrieve the original error +// for inspection. Any error value which implements this interface +// +// type causer interface { +// Cause() error +// } +// +// can be inspected by errors.Cause. errors.Cause will recursively retrieve +// the topmost error that does not implement causer, which is assumed to be +// the original cause. For example: +// +// switch err := errors.Cause(err).(type) { +// case *MyError: +// // handle specifically +// default: +// // unknown error +// } +// +// Although the causer interface is not exported by this package, it is +// considered a part of its stable public interface. +// +// Formatted printing of errors +// +// All error values returned from this package implement fmt.Formatter and can +// be formatted by the fmt package. The following verbs are supported: +// +// %s print the error. If the error has a Cause it will be +// printed recursively. +// %v see %s +// %+v extended format. Each Frame of the error's StackTrace will +// be printed in detail. +// +// Retrieving the stack trace of an error or wrapper +// +// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are +// invoked. This information can be retrieved with the following interface: +// +// type stackTracer interface { +// StackTrace() errors.StackTrace +// } +// +// The returned errors.StackTrace type is defined as +// +// type StackTrace []Frame +// +// The Frame type represents a call site in the stack trace. Frame supports +// the fmt.Formatter interface that can be used for printing information about +// the stack trace of this error. For example: +// +// if err, ok := err.(stackTracer); ok { +// for _, f := range err.StackTrace() { +// fmt.Printf("%+s:%d\n", f, f) +// } +// } +// +// Although the stackTracer interface is not exported by this package, it is +// considered a part of its stable public interface. +// +// See the documentation for Frame.Format for more details. +package errors + +import ( + "fmt" + "io" +) + +// New returns an error with the supplied message. +// New also records the stack trace at the point it was called. +func New(message string) error { + return &fundamental{ + msg: message, + stack: callers(), + } +} + +// Errorf formats according to a format specifier and returns the string +// as a value that satisfies error. +// Errorf also records the stack trace at the point it was called. +func Errorf(format string, args ...interface{}) error { + return &fundamental{ + msg: fmt.Sprintf(format, args...), + stack: callers(), + } +} + +// fundamental is an error that has a message and a stack, but no caller. +type fundamental struct { + msg string + *stack +} + +func (f *fundamental) Error() string { return f.msg } + +func (f *fundamental) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + io.WriteString(s, f.msg) + f.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, f.msg) + case 'q': + fmt.Fprintf(s, "%q", f.msg) + } +} + +// WithStack annotates err with a stack trace at the point WithStack was called. +// If err is nil, WithStack returns nil. +func WithStack(err error) error { + if err == nil { + return nil + } + return &withStack{ + err, + callers(), + } +} + +type withStack struct { + error + *stack +} + +func (w *withStack) Cause() error { return w.error } + +// Unwrap provides compatibility for Go 1.13 error chains. +func (w *withStack) Unwrap() error { return w.error } + +func (w *withStack) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v", w.Cause()) + w.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, w.Error()) + case 'q': + fmt.Fprintf(s, "%q", w.Error()) + } +} + +// Wrap returns an error annotating err with a stack trace +// at the point Wrap is called, and the supplied message. +// If err is nil, Wrap returns nil. +func Wrap(err error, message string) error { + if err == nil { + return nil + } + err = &withMessage{ + cause: err, + msg: message, + } + return &withStack{ + err, + callers(), + } +} + +// Wrapf returns an error annotating err with a stack trace +// at the point Wrapf is called, and the format specifier. +// If err is nil, Wrapf returns nil. +func Wrapf(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + err = &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } + return &withStack{ + err, + callers(), + } +} + +// WithMessage annotates err with a new message. +// If err is nil, WithMessage returns nil. +func WithMessage(err error, message string) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: message, + } +} + +// WithMessagef annotates err with the format specifier. +// If err is nil, WithMessagef returns nil. +func WithMessagef(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } +} + +type withMessage struct { + cause error + msg string +} + +func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } +func (w *withMessage) Cause() error { return w.cause } + +// Unwrap provides compatibility for Go 1.13 error chains. +func (w *withMessage) Unwrap() error { return w.cause } + +func (w *withMessage) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v\n", w.Cause()) + io.WriteString(s, w.msg) + return + } + fallthrough + case 's', 'q': + io.WriteString(s, w.Error()) + } +} + +// Cause returns the underlying cause of the error, if possible. +// An error value has a cause if it implements the following +// interface: +// +// type causer interface { +// Cause() error +// } +// +// If the error does not implement Cause, the original error will +// be returned. If the error is nil, nil will be returned without further +// investigation. +func Cause(err error) error { + type causer interface { + Cause() error + } + + for err != nil { + cause, ok := err.(causer) + if !ok { + break + } + err = cause.Cause() + } + return err +} diff --git a/vendor/github.com/pkg/errors/go113.go b/vendor/github.com/pkg/errors/go113.go new file mode 100644 index 0000000..be0d10d --- /dev/null +++ b/vendor/github.com/pkg/errors/go113.go @@ -0,0 +1,38 @@ +// +build go1.13 + +package errors + +import ( + stderrors "errors" +) + +// Is reports whether any error in err's chain matches target. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error is considered to match a target if it is equal to that target or if +// it implements a method Is(error) bool such that Is(target) returns true. +func Is(err, target error) bool { return stderrors.Is(err, target) } + +// As finds the first error in err's chain that matches target, and if so, sets +// target to that error value and returns true. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error matches target if the error's concrete value is assignable to the value +// pointed to by target, or if the error has a method As(interface{}) bool such that +// As(target) returns true. In the latter case, the As method is responsible for +// setting target. +// +// As will panic if target is not a non-nil pointer to either a type that implements +// error, or to any interface type. As returns false if err is nil. +func As(err error, target interface{}) bool { return stderrors.As(err, target) } + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +func Unwrap(err error) error { + return stderrors.Unwrap(err) +} diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go new file mode 100644 index 0000000..779a834 --- /dev/null +++ b/vendor/github.com/pkg/errors/stack.go @@ -0,0 +1,177 @@ +package errors + +import ( + "fmt" + "io" + "path" + "runtime" + "strconv" + "strings" +) + +// Frame represents a program counter inside a stack frame. +// For historical reasons if Frame is interpreted as a uintptr +// its value represents the program counter + 1. +type Frame uintptr + +// pc returns the program counter for this frame; +// multiple frames may have the same PC value. +func (f Frame) pc() uintptr { return uintptr(f) - 1 } + +// file returns the full path to the file that contains the +// function for this Frame's pc. +func (f Frame) file() string { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return "unknown" + } + file, _ := fn.FileLine(f.pc()) + return file +} + +// line returns the line number of source code of the +// function for this Frame's pc. +func (f Frame) line() int { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return 0 + } + _, line := fn.FileLine(f.pc()) + return line +} + +// name returns the name of this function, if known. +func (f Frame) name() string { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return "unknown" + } + return fn.Name() +} + +// Format formats the frame according to the fmt.Formatter interface. +// +// %s source file +// %d source line +// %n function name +// %v equivalent to %s:%d +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+s function name and path of source file relative to the compile time +// GOPATH separated by \n\t (\n\t) +// %+v equivalent to %+s:%d +func (f Frame) Format(s fmt.State, verb rune) { + switch verb { + case 's': + switch { + case s.Flag('+'): + io.WriteString(s, f.name()) + io.WriteString(s, "\n\t") + io.WriteString(s, f.file()) + default: + io.WriteString(s, path.Base(f.file())) + } + case 'd': + io.WriteString(s, strconv.Itoa(f.line())) + case 'n': + io.WriteString(s, funcname(f.name())) + case 'v': + f.Format(s, 's') + io.WriteString(s, ":") + f.Format(s, 'd') + } +} + +// MarshalText formats a stacktrace Frame as a text string. The output is the +// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs. +func (f Frame) MarshalText() ([]byte, error) { + name := f.name() + if name == "unknown" { + return []byte(name), nil + } + return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil +} + +// StackTrace is stack of Frames from innermost (newest) to outermost (oldest). +type StackTrace []Frame + +// Format formats the stack of Frames according to the fmt.Formatter interface. +// +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+v Prints filename, function, and line number for each Frame in the stack. +func (st StackTrace) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case s.Flag('+'): + for _, f := range st { + io.WriteString(s, "\n") + f.Format(s, verb) + } + case s.Flag('#'): + fmt.Fprintf(s, "%#v", []Frame(st)) + default: + st.formatSlice(s, verb) + } + case 's': + st.formatSlice(s, verb) + } +} + +// formatSlice will format this StackTrace into the given buffer as a slice of +// Frame, only valid when called with '%s' or '%v'. +func (st StackTrace) formatSlice(s fmt.State, verb rune) { + io.WriteString(s, "[") + for i, f := range st { + if i > 0 { + io.WriteString(s, " ") + } + f.Format(s, verb) + } + io.WriteString(s, "]") +} + +// stack represents a stack of program counters. +type stack []uintptr + +func (s *stack) Format(st fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case st.Flag('+'): + for _, pc := range *s { + f := Frame(pc) + fmt.Fprintf(st, "\n%+v", f) + } + } + } +} + +func (s *stack) StackTrace() StackTrace { + f := make([]Frame, len(*s)) + for i := 0; i < len(f); i++ { + f[i] = Frame((*s)[i]) + } + return f +} + +func callers() *stack { + const depth = 32 + var pcs [depth]uintptr + n := runtime.Callers(3, pcs[:]) + var st stack = pcs[0:n] + return &st +} + +// funcname removes the path prefix component of a function's name reported by func.Name(). +func funcname(name string) string { + i := strings.LastIndex(name, "/") + name = name[i+1:] + i = strings.Index(name, ".") + return name[i+1:] +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 8c9b6dd..f650064 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,9 +1,9 @@ # github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8 ## explicit; go 1.20 github.com/dhowden/tag -# github.com/google/uuid v1.6.0 +# github.com/eduncan911/podcast v1.4.2 +## explicit; go 1.13 +github.com/eduncan911/podcast +# github.com/pkg/errors v0.9.1 ## explicit -github.com/google/uuid -# github.com/gorilla/feeds v1.2.0 -## explicit; go 1.20 -github.com/gorilla/feeds +github.com/pkg/errors