[add] opds search, [fix] opds urls, [add] log level env var
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -163,11 +163,12 @@ func (api *API) registerOPDSRoutes(apiGroup *gin.RouterGroup) {
|
||||
opdsGroup := apiGroup.Group("/opds")
|
||||
|
||||
// OPDS Routes
|
||||
opdsGroup.GET("", api.authOPDSMiddleware, api.opdsDocuments)
|
||||
opdsGroup.GET("/", api.authOPDSMiddleware, api.opdsDocuments)
|
||||
opdsGroup.GET("", api.authOPDSMiddleware, api.opdsEntry)
|
||||
opdsGroup.GET("/", api.authOPDSMiddleware, api.opdsEntry)
|
||||
opdsGroup.GET("/search.xml", api.authOPDSMiddleware, api.opdsSearchDescription)
|
||||
opdsGroup.GET("/documents", api.authOPDSMiddleware, api.opdsDocuments)
|
||||
opdsGroup.GET("/documents/:document/cover", api.authOPDSMiddleware, api.getDocumentCover)
|
||||
opdsGroup.GET("/documents/:document/file", api.authOPDSMiddleware, api.downloadDocument)
|
||||
opdsGroup.GET("/search.xml", api.authOPDSMiddleware, api.opdsSearchDescription)
|
||||
}
|
||||
|
||||
func generateToken(n int) ([]byte, error) {
|
||||
|
||||
@@ -32,8 +32,8 @@ type queryParams struct {
|
||||
}
|
||||
|
||||
type searchParams struct {
|
||||
Query *string `form:"query"`
|
||||
BookType *string `form:"book_type"`
|
||||
Query *string `form:"query"`
|
||||
Source *search.Source `form:"source"`
|
||||
}
|
||||
|
||||
type requestDocumentUpload struct {
|
||||
@@ -64,10 +64,10 @@ type requestSettingsEdit struct {
|
||||
}
|
||||
|
||||
type requestDocumentAdd struct {
|
||||
ID *string `form:"id"`
|
||||
Title *string `form:"title"`
|
||||
Author *string `form:"author"`
|
||||
BookType *string `form:"book_type"`
|
||||
ID string `form:"id"`
|
||||
Title *string `form:"title"`
|
||||
Author *string `form:"author"`
|
||||
Source search.Source `form:"source"`
|
||||
}
|
||||
|
||||
func (api *API) webManifest(c *gin.Context) {
|
||||
@@ -240,25 +240,18 @@ func (api *API) createAppResourcesRoute(routeName string, args ...map[string]any
|
||||
c.BindQuery(&sParams)
|
||||
|
||||
// Only Handle Query
|
||||
if sParams.BookType != nil && !slices.Contains([]string{"NON_FICTION", "FICTION"}, *sParams.BookType) {
|
||||
templateVars["SearchErrorMessage"] = "Invalid Book Type"
|
||||
} else if sParams.Query != nil && *sParams.Query == "" {
|
||||
templateVars["SearchErrorMessage"] = "Invalid Query"
|
||||
} else if sParams.BookType != nil && sParams.Query != nil {
|
||||
var bType search.BookType = search.BOOK_FICTION
|
||||
if *sParams.BookType == "NON_FICTION" {
|
||||
bType = search.BOOK_NON_FICTION
|
||||
}
|
||||
|
||||
if sParams.Query != nil && sParams.Source != nil {
|
||||
// Search
|
||||
searchResults, err := search.SearchBook(*sParams.Query, bType)
|
||||
searchResults, err := search.SearchBook(*sParams.Query, *sParams.Source)
|
||||
if err != nil {
|
||||
errorPage(c, http.StatusInternalServerError, fmt.Sprintf("Search Error: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
templateVars["Data"] = searchResults
|
||||
templateVars["BookType"] = *sParams.BookType
|
||||
templateVars["Source"] = *sParams.Source
|
||||
} else if sParams.Query != nil || sParams.Source != nil {
|
||||
templateVars["SearchErrorMessage"] = "Invalid Query"
|
||||
}
|
||||
} else if routeName == "login" {
|
||||
templateVars["RegistrationEnabled"] = api.Config.RegistrationEnabled
|
||||
@@ -762,23 +755,8 @@ func (api *API) saveNewDocument(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Validate Form Exists
|
||||
if rDocAdd.ID == nil ||
|
||||
rDocAdd.BookType == nil ||
|
||||
rDocAdd.Title == nil ||
|
||||
rDocAdd.Author == nil {
|
||||
log.Error("[saveNewDocument] Missing Form Values")
|
||||
errorPage(c, http.StatusBadRequest, "Invalid or missing form values.")
|
||||
return
|
||||
}
|
||||
|
||||
var bType search.BookType = search.BOOK_FICTION
|
||||
if *rDocAdd.BookType == "NON_FICTION" {
|
||||
bType = search.BOOK_NON_FICTION
|
||||
}
|
||||
|
||||
// Save Book
|
||||
tempFilePath, err := search.SaveBook(*rDocAdd.ID, bType)
|
||||
tempFilePath, err := search.SaveBook(rDocAdd.ID, rDocAdd.Source)
|
||||
if err != nil {
|
||||
log.Warn("[saveNewDocument] Temp File Error: ", err)
|
||||
errorPage(c, http.StatusInternalServerError, "Unable to save file.")
|
||||
|
||||
@@ -26,6 +26,40 @@ var mimeMapping map[string]string = map[string]string{
|
||||
"lit": "application/x-ms-reader",
|
||||
}
|
||||
|
||||
func (api *API) opdsEntry(c *gin.Context) {
|
||||
// Build & Return XML
|
||||
mainFeed := &opds.Feed{
|
||||
Title: "AnthoLume OPDS Server",
|
||||
Updated: time.Now().UTC(),
|
||||
Links: []opds.Link{
|
||||
{
|
||||
Title: "Search AnthoLume",
|
||||
Rel: "search",
|
||||
TypeLink: "application/opensearchdescription+xml",
|
||||
Href: "/api/opds/search.xml",
|
||||
},
|
||||
},
|
||||
|
||||
Entries: []opds.Entry{
|
||||
{
|
||||
Title: "AnthoLume - All Documents",
|
||||
Content: &opds.Content{
|
||||
Content: "AnthoLume - All Documents",
|
||||
ContentType: "text",
|
||||
},
|
||||
Links: []opds.Link{
|
||||
{
|
||||
Href: "/api/opds/documents?limit=100",
|
||||
TypeLink: "application/atom+xml;type=feed;profile=opds-catalog",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
c.XML(http.StatusOK, mainFeed)
|
||||
}
|
||||
|
||||
func (api *API) opdsDocuments(c *gin.Context) {
|
||||
var userID string
|
||||
if rUser, _ := c.Get("AuthorizedUser"); rUser != nil {
|
||||
@@ -35,9 +69,17 @@ func (api *API) opdsDocuments(c *gin.Context) {
|
||||
// Potential URL Parameters
|
||||
qParams := bindQueryParams(c)
|
||||
|
||||
// Possible Query
|
||||
var query *string
|
||||
if qParams.Search != nil && *qParams.Search != "" {
|
||||
search := "%" + *qParams.Search + "%"
|
||||
query = &search
|
||||
}
|
||||
|
||||
// Get Documents
|
||||
documents, err := api.DB.Queries.GetDocumentsWithStats(api.DB.Ctx, database.GetDocumentsWithStatsParams{
|
||||
UserID: userID,
|
||||
Query: query,
|
||||
Offset: (*qParams.Page - 1) * *qParams.Limit,
|
||||
Limit: *qParams.Limit,
|
||||
})
|
||||
@@ -71,7 +113,7 @@ func (api *API) opdsDocuments(c *gin.Context) {
|
||||
}
|
||||
|
||||
item := opds.Entry{
|
||||
Title: fmt.Sprintf("[%3d%%] %s", int(doc.Percentage), title),
|
||||
Title: title,
|
||||
Author: []opds.Author{
|
||||
{
|
||||
Name: author,
|
||||
@@ -84,12 +126,12 @@ func (api *API) opdsDocuments(c *gin.Context) {
|
||||
Links: []opds.Link{
|
||||
{
|
||||
Rel: "http://opds-spec.org/acquisition",
|
||||
Href: fmt.Sprintf("./documents/%s/file", doc.ID),
|
||||
Href: fmt.Sprintf("/api/opds/documents/%s/file", doc.ID),
|
||||
TypeLink: mimeMapping[fileType],
|
||||
},
|
||||
{
|
||||
Rel: "http://opds-spec.org/image",
|
||||
Href: fmt.Sprintf("./documents/%s/cover", doc.ID),
|
||||
Href: fmt.Sprintf("/api/opds/documents/%s/cover", doc.ID),
|
||||
TypeLink: "image/jpeg",
|
||||
},
|
||||
},
|
||||
@@ -99,19 +141,15 @@ func (api *API) opdsDocuments(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
feedTitle := "All Documents"
|
||||
if query != nil {
|
||||
feedTitle = "Search Results"
|
||||
}
|
||||
|
||||
// Build & Return XML
|
||||
searchFeed := &opds.Feed{
|
||||
Title: "All Documents",
|
||||
Title: feedTitle,
|
||||
Updated: time.Now().UTC(),
|
||||
// TODO
|
||||
// Links: []opds.Link{
|
||||
// {
|
||||
// Title: "Search AnthoLume",
|
||||
// Rel: "search",
|
||||
// TypeLink: "application/opensearchdescription+xml",
|
||||
// Href: "search.xml",
|
||||
// },
|
||||
// },
|
||||
Entries: allEntries,
|
||||
}
|
||||
|
||||
@@ -122,7 +160,7 @@ func (api *API) opdsSearchDescription(c *gin.Context) {
|
||||
rawXML := `<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||
<ShortName>Search AnthoLume</ShortName>
|
||||
<Description>Search AnthoLume</Description>
|
||||
<Url type="application/atom+xml;profile=opds-catalog;kind=acquisition" template="./search?query={searchTerms}"/>
|
||||
<Url type="application/atom+xml;profile=opds-catalog;kind=acquisition" template="/api/opds/documents?limit=100&search={searchTerms}"/>
|
||||
</OpenSearchDescription>`
|
||||
c.Data(http.StatusOK, "application/xml", []byte(rawXML))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user