122 lines
2.7 KiB
Go
122 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
|
|
"embed"
|
|
|
|
"github.com/PuerkitoBio/goquery"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/mmcdole/gofeed"
|
|
)
|
|
|
|
//go:embed index.html
|
|
|
|
var content embed.FS
|
|
|
|
func main() {
|
|
port, ok := os.LookupEnv("PORT")
|
|
if !ok {
|
|
port = "8080"
|
|
}
|
|
|
|
app := fiber.New(fiber.Config{})
|
|
|
|
app.Get("/", func(c *fiber.Ctx) error {
|
|
feedUrl := c.Query("url")
|
|
if feedUrl == "" {
|
|
c.Type("html", "UTF8")
|
|
body, _ := content.ReadFile("index.html")
|
|
return c.Send(body)
|
|
}
|
|
|
|
feeds, statusCode := getFeeds(feedUrl)
|
|
|
|
if c.Is("json") {
|
|
if statusCode >= 400 || statusCode == 300 {
|
|
c.Status(statusCode)
|
|
}
|
|
return c.JSON(feeds)
|
|
} else {
|
|
c.Status(statusCode)
|
|
c.Location(feeds[0])
|
|
|
|
if len(feeds) > 1 {
|
|
responseBody := "Multiple Choices\n\n"
|
|
for _, feed := range feeds {
|
|
responseBody += feed + "\n"
|
|
}
|
|
return c.SendString(responseBody)
|
|
}
|
|
|
|
return c.Send(nil)
|
|
}
|
|
})
|
|
|
|
fmt.Println(app.Listen(fmt.Sprintf(":%s", port)))
|
|
}
|
|
|
|
func absoluteUrl(requestUrl, foundUrl string) string {
|
|
if !strings.HasPrefix(foundUrl, "http") {
|
|
parsedUrl, _ := url.Parse(requestUrl)
|
|
foundUrl = fmt.Sprintf("%s://%s%s", parsedUrl.Scheme, parsedUrl.Host, foundUrl)
|
|
}
|
|
|
|
return foundUrl
|
|
}
|
|
|
|
func getFeeds(requestURL string) ([]string, int) {
|
|
feeds := []string{}
|
|
|
|
fp := gofeed.NewParser()
|
|
_, err := fp.ParseURL(requestURL)
|
|
if err == nil {
|
|
feeds = []string{requestURL}
|
|
} else if err != nil && err == gofeed.ErrFeedTypeNotDetected {
|
|
res, err := http.Get(requestURL)
|
|
if err != nil {
|
|
fmt.Printf("Failed to fetch URL %s", requestURL)
|
|
return feeds, fiber.StatusInternalServerError
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
if res.StatusCode >= 400 {
|
|
fmt.Println("Provided URL returned an error status code")
|
|
return feeds, res.StatusCode
|
|
}
|
|
|
|
doc, err := goquery.NewDocumentFromReader(res.Body)
|
|
if err != nil {
|
|
fmt.Println("Failed to parse response body")
|
|
return feeds, fiber.StatusInternalServerError
|
|
}
|
|
|
|
matches := doc.Find(`[rel="alternate"][type="application/rss+xml"],[rel="alternate"][type="application/atom+xml"]`)
|
|
if matches.Length() == 0 {
|
|
fmt.Printf("No RSS feeds found on page %s\n", requestURL)
|
|
return feeds, fiber.StatusNotFound
|
|
}
|
|
|
|
matches.Each(func(i int, s *goquery.Selection) {
|
|
feeds = append(feeds, absoluteUrl(requestURL, s.AttrOr("href", "")))
|
|
})
|
|
|
|
if matches.Length() > 1 {
|
|
fmt.Printf("Multiple RSS feed found on page %s\n", requestURL)
|
|
return feeds, fiber.StatusMultipleChoices
|
|
} else {
|
|
fmt.Printf("Single RSS feed found on page %s\n", requestURL)
|
|
return feeds, fiber.StatusTemporaryRedirect
|
|
}
|
|
} else if err != nil {
|
|
fmt.Println("Failed while attempting to parse feed")
|
|
return feeds, fiber.StatusInternalServerError
|
|
}
|
|
|
|
return feeds, 200
|
|
}
|