mirror of
https://github.com/rwinkhart/backtone.git
synced 2026-08-27 20:36:32 -04:00
122 lines
4.6 KiB
Go
122 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/xml"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/gorilla/feeds"
|
|
"github.com/rwinkhart/backtone/atom"
|
|
"github.com/rwinkhart/backtone/websrc"
|
|
"github.com/rwinkhart/go-boilerplate/other"
|
|
)
|
|
|
|
const cfgPath = "/etc/backtone.xml"
|
|
|
|
// feedFieldInfo provides the string value for a given field in the parent feed
|
|
// and specifies which index in the regex capture group to extract the same field
|
|
// from per individual news item.
|
|
// An index of -1 can be used to use the same value as the parent feed.
|
|
// An index of -2 can be used to use a default (placeholder) value.
|
|
type feedFieldInfoT struct {
|
|
Parent string `xml:"parent,omitempty"`
|
|
CaptureGroupConnector []string `xml:"captureGroupConnector,omitempty"`
|
|
CaptureGroupIndex []int8 `xml:"captureGroupIndex,omitempty"`
|
|
}
|
|
type feedT struct {
|
|
Title feedFieldInfoT `xml:"title"`
|
|
Link feedFieldInfoT `xml:"link"`
|
|
Description feedFieldInfoT `xml:"description"`
|
|
AuthorName feedFieldInfoT `xml:"authorName"`
|
|
AuthorEmail feedFieldInfoT `xml:"authorEmail"`
|
|
}
|
|
type inputT struct {
|
|
FlareSolverrEndpoint string `xml:"flareSolverrEndpoint,omitempty"`
|
|
APIMethodEndpointPayload string `xml:"apiMethodEndpointPayload,omitempty"`
|
|
Regex string `xml:"regex"`
|
|
LoadSeconds float32 `xml:"loadSeconds"`
|
|
MaxFeedItems int `xml:"maxFeedItems"`
|
|
Feed feedT `xml:"feed"`
|
|
}
|
|
|
|
func main() {
|
|
// handle input argument (XML)
|
|
if len(os.Args) < 2 {
|
|
demoInputBytes, _ := xml.MarshalIndent(
|
|
inputT{
|
|
FlareSolverrEndpoint: "http://127.0.0.1:8191",
|
|
Regex: "PLACEHOLDER",
|
|
LoadSeconds: 2.5,
|
|
MaxFeedItems: 10,
|
|
Feed: feedT{
|
|
Title: feedFieldInfoT{Parent: "Demo Title", CaptureGroupIndex: []int8{0}},
|
|
Link: feedFieldInfoT{Parent: "https://example.com/", CaptureGroupIndex: []int8{1}},
|
|
Description: feedFieldInfoT{Parent: "Demo description", CaptureGroupConnector: []string{"Prefix - ", " - Middle - ", " - Suffix"}, CaptureGroupIndex: []int8{1, 3}},
|
|
AuthorName: feedFieldInfoT{Parent: "John Doe", CaptureGroupIndex: []int8{3}},
|
|
AuthorEmail: feedFieldInfoT{Parent: "johndoe@example.com", CaptureGroupIndex: []int8{4}},
|
|
},
|
|
},
|
|
"",
|
|
" ",
|
|
)
|
|
other.PrintError(os.Args[0]+" must be called with valid base64-encoded XML input using the following schema:\n\n"+string(demoInputBytes), 1)
|
|
}
|
|
|
|
// decode base64 input XML
|
|
decodedXML, err := base64.StdEncoding.DecodeString(os.Args[1])
|
|
if err != nil {
|
|
other.PrintError("Failed to decode base64 input XML: "+err.Error(), 1)
|
|
}
|
|
|
|
var inputInfo inputT
|
|
if err := xml.Unmarshal(decodedXML, &inputInfo); err != nil {
|
|
other.PrintError("Failed to unmarshal input XML: "+err.Error(), 1)
|
|
}
|
|
|
|
var rawString string
|
|
if inputInfo.FlareSolverrEndpoint != "" {
|
|
rawString, err = websrc.GetByScrape(inputInfo.FlareSolverrEndpoint, inputInfo.Feed.Link.Parent, inputInfo.LoadSeconds)
|
|
if err != nil {
|
|
other.PrintError("Failed to scrape HTML content: "+err.Error(), 1)
|
|
}
|
|
} else if inputInfo.APIMethodEndpointPayload != "" {
|
|
apiInfoSplit := strings.Split(inputInfo.APIMethodEndpointPayload, "@")
|
|
rawString, err = websrc.GetByAPIJson(apiInfoSplit[0], apiInfoSplit[1], []byte(apiInfoSplit[2]))
|
|
if err != nil {
|
|
other.PrintError("Failed to get API response: "+err.Error(), 1)
|
|
}
|
|
} else {
|
|
other.PrintError("Either FlareSolverrEndpoint or APIMethodPayload must be specified", 1)
|
|
}
|
|
|
|
atomXML, err := atom.GetFromString(
|
|
&feeds.Feed{
|
|
Title: inputInfo.Feed.Title.Parent,
|
|
Link: &feeds.Link{Href: inputInfo.Feed.Link.Parent},
|
|
Description: inputInfo.Feed.Description.Parent,
|
|
Author: &feeds.Author{Name: inputInfo.Feed.AuthorName.Parent, Email: inputInfo.Feed.AuthorEmail.Parent},
|
|
},
|
|
&rawString,
|
|
inputInfo.Regex,
|
|
atom.IndicesT{
|
|
TitleC: inputInfo.Feed.Title.CaptureGroupConnector,
|
|
TitleI: inputInfo.Feed.Title.CaptureGroupIndex,
|
|
LinkC: inputInfo.Feed.Link.CaptureGroupConnector,
|
|
LinkI: inputInfo.Feed.Link.CaptureGroupIndex,
|
|
DescriptionC: inputInfo.Feed.Description.CaptureGroupConnector,
|
|
DescriptionI: inputInfo.Feed.Description.CaptureGroupIndex,
|
|
AuthorNameC: inputInfo.Feed.AuthorName.CaptureGroupConnector,
|
|
AuthorNameI: inputInfo.Feed.AuthorName.CaptureGroupIndex,
|
|
AuthorEmailC: inputInfo.Feed.AuthorEmail.CaptureGroupConnector,
|
|
AuthorEmailI: inputInfo.Feed.AuthorEmail.CaptureGroupIndex,
|
|
},
|
|
inputInfo.MaxFeedItems,
|
|
)
|
|
if err != nil {
|
|
other.PrintError("Failed to generate Atom RSS feed from HTML:\n\n"+rawString+"\n\n"+err.Error(), 1)
|
|
}
|
|
fmt.Println(*atomXML)
|
|
}
|