forked from Ivasoft/opds-proxy
refactor: cleanup
naming and other things
This commit is contained in:
@@ -2,7 +2,7 @@ package convert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -46,13 +46,21 @@ func (mc *MobiConverter) Convert(input string) (string, error) {
|
||||
cmd.Stderr = &stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
isError := true
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
if exiterr.ExitCode() != 1 {
|
||||
fmt.Println(fmt.Sprint(err) + ": " + out.String() + ":" + stderr.String())
|
||||
return "", err
|
||||
// Sometimes warnings cause a 1 exit-code, but the file is still created
|
||||
slog.Info("Exit code", slog.Any("code", exiterr.ExitCode()))
|
||||
if exiterr.ExitCode() == 1 {
|
||||
isError = false
|
||||
}
|
||||
} else {
|
||||
fmt.Println(fmt.Sprint(err) + ": " + out.String() + ":" + stderr.String())
|
||||
}
|
||||
|
||||
if isError {
|
||||
slog.Error("Error converting file",
|
||||
slog.Any("error", err),
|
||||
slog.String("stdout", out.String()),
|
||||
slog.String("stderr", stderr.String()),
|
||||
)
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
4
go.mod
4
go.mod
@@ -8,14 +8,14 @@ require (
|
||||
github.com/knadh/koanf/v2 v2.1.1
|
||||
)
|
||||
|
||||
require github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
require github.com/gorilla/securecookie v1.1.2
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
|
||||
github.com/knadh/koanf/maps v0.1.1 // indirect
|
||||
github.com/knadh/koanf/providers/basicflag v1.0.0
|
||||
github.com/knadh/koanf/providers/confmap v0.1.0
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
|
||||
10
go.sum
10
go.sum
@@ -6,14 +6,16 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||
github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
|
||||
github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
||||
github.com/knadh/koanf/parsers/yaml v0.1.0 h1:ZZ8/iGfRLvKSaMEECEBPM1HQslrZADk8fP1XFUxVI5w=
|
||||
github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY=
|
||||
github.com/knadh/koanf/providers/basicflag v1.0.0 h1:qB0es/9fYsLuYnrKazxNCuWtkv3JFX1lI1druUsDDvY=
|
||||
github.com/knadh/koanf/providers/basicflag v1.0.0/go.mod h1:n0NlnaxXUCER/WIzRroT9q3Np+FiZ9pSjrC6A/OozI8=
|
||||
github.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPghxRVp7JbIvdvqzU=
|
||||
github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC7+fyHFdQkd697K4MdLnIU=
|
||||
github.com/knadh/koanf/providers/file v1.0.0 h1:DtPvSQBeF+N0QLPMz0yf2bx0nFSxUcncpqQvzCxfCyk=
|
||||
github.com/knadh/koanf/providers/file v1.0.0/go.mod h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI=
|
||||
github.com/knadh/koanf/v2 v2.1.1 h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM=
|
||||
@@ -24,8 +26,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
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/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
|
||||
@@ -92,6 +92,7 @@ func constructLink(url string, entry opds.Entry) LinkViewModel {
|
||||
|
||||
return vm
|
||||
}
|
||||
|
||||
func resolveHref(feedUrl string, relativePath string) string {
|
||||
baseUrl, err := url.Parse(feedUrl)
|
||||
if err != nil {
|
||||
|
||||
23
html/html.go
23
html/html.go
@@ -39,11 +39,8 @@ type LoginParams struct {
|
||||
ReturnURL string
|
||||
}
|
||||
|
||||
func Login(w io.Writer, p LoginParams, partial string) error {
|
||||
if partial == "" {
|
||||
partial = "layout.html"
|
||||
}
|
||||
return login.ExecuteTemplate(w, partial, p)
|
||||
func Login(w io.Writer, p LoginParams) error {
|
||||
return login.Execute(w, p)
|
||||
}
|
||||
|
||||
type FeedParams struct {
|
||||
@@ -51,14 +48,9 @@ type FeedParams struct {
|
||||
Feed *opds.Feed
|
||||
}
|
||||
|
||||
func Feed(w io.Writer, p FeedParams, partial string) error {
|
||||
if partial == "" {
|
||||
partial = "layout.html"
|
||||
}
|
||||
|
||||
func Feed(w io.Writer, p FeedParams) error {
|
||||
vm := convertFeed(&p)
|
||||
|
||||
return feed.ExecuteTemplate(w, partial, vm)
|
||||
return feed.Execute(w, vm)
|
||||
}
|
||||
|
||||
type FeedInfo struct {
|
||||
@@ -66,11 +58,8 @@ type FeedInfo struct {
|
||||
URL string
|
||||
}
|
||||
|
||||
func Home(w io.Writer, vm []FeedInfo, partial string) error {
|
||||
if partial == "" {
|
||||
partial = "layout.html"
|
||||
}
|
||||
return home.ExecuteTemplate(w, partial, vm)
|
||||
func Home(w io.Writer, vm []FeedInfo) error {
|
||||
return home.Execute(w, vm)
|
||||
}
|
||||
|
||||
func StaticFiles() embed.FS {
|
||||
|
||||
38
main.go
38
main.go
@@ -5,44 +5,41 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/securecookie"
|
||||
"github.com/knadh/koanf/parsers/yaml"
|
||||
"github.com/knadh/koanf/providers/basicflag"
|
||||
"github.com/knadh/koanf/providers/confmap"
|
||||
"github.com/knadh/koanf/providers/file"
|
||||
"github.com/knadh/koanf/v2"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
type ProxyConfig struct {
|
||||
Port string `koanf:"port"`
|
||||
Auth auth `koanf:"auth"`
|
||||
Feeds []feedConfig `koanf:"feeds" `
|
||||
Auth AuthConfig `koanf:"auth"`
|
||||
Feeds []FeedConfig `koanf:"feeds" `
|
||||
}
|
||||
|
||||
type auth struct {
|
||||
type AuthConfig struct {
|
||||
HashKey string `koanf:"hash_key"`
|
||||
BlockKey string `koanf:"block_key"`
|
||||
}
|
||||
|
||||
type feedConfig struct {
|
||||
type FeedConfig struct {
|
||||
Name string `koanf:"name"`
|
||||
Url string `koanf:"url"`
|
||||
Username string `koanf:"username"`
|
||||
Password string `koanf:"password"`
|
||||
}
|
||||
|
||||
func (f feedConfig) HasCredentials() bool {
|
||||
return f.Username != "" && f.Password != ""
|
||||
}
|
||||
|
||||
var k = koanf.New(".")
|
||||
|
||||
func main() {
|
||||
fs := flag.NewFlagSet("", flag.ContinueOnError)
|
||||
fs.String("port", "8080", "port to listen on")
|
||||
// These aren't mapped to the config file.
|
||||
configPath := fs.String("config", "config.yml", "config file to load")
|
||||
generateKeys := fs.Bool("generate-keys", false, "generate cookie signing keys and exit")
|
||||
|
||||
port := fs.String("port", "8080", "port to listen on")
|
||||
if err := fs.Parse(os.Args[1:]); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -52,18 +49,22 @@ func main() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
var k = koanf.New(".")
|
||||
|
||||
// Load config file from disk.
|
||||
// Feed options must be defined here.
|
||||
if err := k.Load(file.Provider(*configPath), yaml.Parser()); err != nil && !os.IsNotExist(err) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Flags take precedence over config file.
|
||||
if err := k.Load(basicflag.Provider(fs, "."), nil); err != nil {
|
||||
// Selectively add command line options to the config. Overriding the config file.
|
||||
if err := k.Load(confmap.Provider(map[string]interface{}{
|
||||
"port": *port,
|
||||
}, "."), nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
config := config{}
|
||||
config := ProxyConfig{}
|
||||
k.Unmarshal("", &config)
|
||||
|
||||
if len(config.Feeds) == 0 {
|
||||
@@ -82,7 +83,10 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
server.Serve()
|
||||
|
||||
if err = server.Serve(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func displayKeys() (string, string) {
|
||||
|
||||
34
server.go
34
server.go
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"log/slog"
|
||||
"mime"
|
||||
"net/http"
|
||||
@@ -43,7 +42,7 @@ type Credentials struct {
|
||||
Password string
|
||||
}
|
||||
|
||||
func NewServer(config *config) (*Server, error) {
|
||||
func NewServer(config *ProxyConfig) (*Server, error) {
|
||||
hashKey, err := hex.DecodeString(config.Auth.HashKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -68,12 +67,12 @@ func NewServer(config *config) (*Server, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) Serve() {
|
||||
func (s *Server) Serve() error {
|
||||
slog.Info("Starting server", slog.String("port", s.addr))
|
||||
log.Fatal(http.ListenAndServe(s.addr, s.router))
|
||||
return http.ListenAndServe(s.addr, s.router)
|
||||
}
|
||||
|
||||
func handleHome(feeds []feedConfig) http.HandlerFunc {
|
||||
func handleHome(feeds []FeedConfig) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vmFeeds := make([]html.FeedInfo, len(feeds))
|
||||
for i, feed := range feeds {
|
||||
@@ -83,11 +82,11 @@ func handleHome(feeds []feedConfig) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
html.Home(w, vmFeeds, partial(r))
|
||||
html.Home(w, vmFeeds)
|
||||
}
|
||||
}
|
||||
|
||||
func handleFeed(outputDir string, feeds []feedConfig, s *securecookie.SecureCookie) http.HandlerFunc {
|
||||
func handleFeed(outputDir string, feeds []FeedConfig, s *securecookie.SecureCookie) http.HandlerFunc {
|
||||
kepubConverter := &convert.KepubConverter{}
|
||||
mobiConverter := &convert.MobiConverter{}
|
||||
|
||||
@@ -107,7 +106,7 @@ func handleFeed(outputDir string, feeds []feedConfig, s *securecookie.SecureCook
|
||||
|
||||
searchTerm := r.URL.Query().Get("search")
|
||||
if searchTerm != "" {
|
||||
queryURL = replaceSearchPlaceHolder(queryURL, searchTerm)
|
||||
queryURL = strings.Replace(queryURL, "{searchTerms}", searchTerm, 1)
|
||||
}
|
||||
|
||||
resp, err := fetchFromUrl(queryURL, getCredentials(r, feeds, s))
|
||||
@@ -122,8 +121,7 @@ func handleFeed(outputDir string, feeds []feedConfig, s *securecookie.SecureCook
|
||||
return
|
||||
}
|
||||
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
mimeType, _, err := mime.ParseMediaType(contentType)
|
||||
mimeType, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
handleError(r, w, "Failed to parse content type", err)
|
||||
}
|
||||
@@ -140,7 +138,7 @@ func handleFeed(outputDir string, feeds []feedConfig, s *securecookie.SecureCook
|
||||
Feed: feed,
|
||||
}
|
||||
|
||||
if err = html.Feed(w, feedParams, partial(r)); err != nil {
|
||||
if err = html.Feed(w, feedParams); err != nil {
|
||||
handleError(r, w, "Failed to render feed", err)
|
||||
return
|
||||
}
|
||||
@@ -187,7 +185,7 @@ func handleAuth(s *securecookie.SecureCookie) http.HandlerFunc {
|
||||
}
|
||||
|
||||
if r.Method == "GET" {
|
||||
html.Login(w, html.LoginParams{ReturnURL: returnUrl}, partial(r))
|
||||
html.Login(w, html.LoginParams{ReturnURL: returnUrl})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -231,7 +229,7 @@ func handleAuth(s *securecookie.SecureCookie) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func getCredentials(r *http.Request, feeds []feedConfig, s *securecookie.SecureCookie) *Credentials {
|
||||
func getCredentials(r *http.Request, feeds []FeedConfig, s *securecookie.SecureCookie) *Credentials {
|
||||
if !r.URL.Query().Has("q") {
|
||||
return nil
|
||||
}
|
||||
@@ -243,7 +241,7 @@ func getCredentials(r *http.Request, feeds []feedConfig, s *securecookie.SecureC
|
||||
|
||||
// Try to get credentials from the config first
|
||||
for _, feed := range feeds {
|
||||
if !feed.HasCredentials() {
|
||||
if feed.Username == "" || feed.Password == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -293,14 +291,6 @@ func handleError(r *http.Request, w http.ResponseWriter, message string, err err
|
||||
http.Error(w, "An unexpected error occurred", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func replaceSearchPlaceHolder(url string, searchTerm string) string {
|
||||
return strings.Replace(url, "{searchTerms}", searchTerm, 1)
|
||||
}
|
||||
|
||||
func partial(req *http.Request) string {
|
||||
return req.URL.Query().Get("partial")
|
||||
}
|
||||
|
||||
func downloadFile(path string, resp *http.Response) error {
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user