Basic OPDS support
This commit is contained in:
parent
078b210392
commit
b0a0b68561
6 changed files with 175 additions and 0 deletions
|
@ -34,6 +34,7 @@ const (
|
||||||
IMG_PATH = "img/"
|
IMG_PATH = "img/"
|
||||||
ROBOTS_PATH = "robots.txt"
|
ROBOTS_PATH = "robots.txt"
|
||||||
DESCRIPTION_PATH = "description.json"
|
DESCRIPTION_PATH = "description.json"
|
||||||
|
OPENSEARCH_PATH = "opensearch.xml"
|
||||||
LOGGER_CONFIG = "logger.xml"
|
LOGGER_CONFIG = "logger.xml"
|
||||||
|
|
||||||
IMG_WIDTH_BIG = 300
|
IMG_WIDTH_BIG = 300
|
||||||
|
|
11
opensearch.xml
Normal file
11
opensearch.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
|
<ShortName>Imperial Library of Trantor</ShortName>
|
||||||
|
<Description>Book search in the library.</Description>
|
||||||
|
<InputEncoding>UTF-8</InputEncoding>
|
||||||
|
<OutputEncoding>UTF-8</OutputEncoding>
|
||||||
|
<Tags>books epub</Tags>
|
||||||
|
<Image type="image/x-icon" width="16" height="16">/img/favicon.ico</Image>
|
||||||
|
<Contact>zenow@riseup.net</Contact>
|
||||||
|
<Url type="application/atom+xml" template="/search/?fmt=opds&q={searchTerms}"/>
|
||||||
|
</OpenSearchDescription>
|
10
template.go
10
template.go
|
@ -9,6 +9,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.gitorious.org/trantor/trantor.git/database"
|
"git.gitorious.org/trantor/trantor.git/database"
|
||||||
)
|
)
|
||||||
|
@ -20,6 +21,7 @@ type Status struct {
|
||||||
User string
|
User string
|
||||||
IsAdmin bool
|
IsAdmin bool
|
||||||
Notif []Notification
|
Notif []Notification
|
||||||
|
Updated string
|
||||||
Home bool
|
Home bool
|
||||||
About bool
|
About bool
|
||||||
News bool
|
News bool
|
||||||
|
@ -36,6 +38,7 @@ func GetStatus(h handler) Status {
|
||||||
s.User = h.sess.User
|
s.User = h.sess.User
|
||||||
s.IsAdmin = h.sess.IsAdmin()
|
s.IsAdmin = h.sess.IsAdmin()
|
||||||
s.Notif = h.sess.GetNotif()
|
s.Notif = h.sess.GetNotif()
|
||||||
|
s.Updated = time.Now().UTC().Format("2006-01-02T15:04:05Z")
|
||||||
h.sess.Save(h.w, h.r)
|
h.sess.Save(h.w, h.r)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -66,12 +69,19 @@ var tmpl_rss = txt_tmpl.Must(txt_tmpl.ParseFiles(
|
||||||
TEMPLATE_PATH+"news.rss",
|
TEMPLATE_PATH+"news.rss",
|
||||||
))
|
))
|
||||||
|
|
||||||
|
var tmpl_opds = txt_tmpl.Must(txt_tmpl.ParseFiles(
|
||||||
|
TEMPLATE_PATH+"index.opds",
|
||||||
|
TEMPLATE_PATH+"search.opds",
|
||||||
|
))
|
||||||
|
|
||||||
func loadTemplate(h handler, tmpl string, data interface{}) {
|
func loadTemplate(h handler, tmpl string, data interface{}) {
|
||||||
var err error
|
var err error
|
||||||
fmt := h.r.FormValue("fmt")
|
fmt := h.r.FormValue("fmt")
|
||||||
switch fmt {
|
switch fmt {
|
||||||
case "rss":
|
case "rss":
|
||||||
err = tmpl_rss.ExecuteTemplate(h.w, tmpl+".rss", data)
|
err = tmpl_rss.ExecuteTemplate(h.w, tmpl+".rss", data)
|
||||||
|
case "opds":
|
||||||
|
err = tmpl_opds.ExecuteTemplate(h.w, tmpl+".opds", data)
|
||||||
case "json":
|
case "json":
|
||||||
err = loadJson(h.w, tmpl, data)
|
err = loadJson(h.w, tmpl, data)
|
||||||
default:
|
default:
|
||||||
|
|
52
templates/index.opds
Normal file
52
templates/index.opds
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<feed xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:odl="http://opds-spec.org/odl"
|
||||||
|
xml:lang="en"
|
||||||
|
xmlns="http://www.w3.org/2005/Atom"
|
||||||
|
xmlns:dcterms="http://purl.org/dc/terms/"
|
||||||
|
xmlns:app="http://www.w3.org/2007/app"
|
||||||
|
xmlns:opds="http://opds-spec.org/2010/catalog"
|
||||||
|
xmlns:thr="http://purl.org/syndication/thread/1.0"
|
||||||
|
xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
|
<id>{{.S.BaseURL}}</id>
|
||||||
|
<link rel="self"
|
||||||
|
href="/?fmt=opds"
|
||||||
|
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
|
||||||
|
<link rel="start"
|
||||||
|
href="/?fmt=opds"
|
||||||
|
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
|
||||||
|
<link rel="search"
|
||||||
|
href="/opensearch.xml"
|
||||||
|
type="application/opensearchdescription+xml"/>
|
||||||
|
|
||||||
|
<title>The Imperial Libary of Trantor</title>
|
||||||
|
<author>
|
||||||
|
<name>The Imperial Library of Trantor</name>
|
||||||
|
<uri>{{.S.BaseURL}}</uri>
|
||||||
|
<email>zenow@riseup.net</email>
|
||||||
|
</author>
|
||||||
|
<updated>{{.S.Updated}}</updated>
|
||||||
|
<icon>{{.S.BaseURL}}/img/favicon.ico</icon>
|
||||||
|
|
||||||
|
<entry>
|
||||||
|
<title>Last books added</title>
|
||||||
|
<link rel="http://opds-spec.org/sort/new"
|
||||||
|
href="/search/?fmt=opds"
|
||||||
|
type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
|
||||||
|
<updated>{{.S.Updated}}</updated>
|
||||||
|
<id>{{.S.BaseURL}}/search/</id>
|
||||||
|
</entry>
|
||||||
|
{{$updated := .S.Updated}}
|
||||||
|
{{$baseurl := .S.BaseURL}}
|
||||||
|
{{range .Tags}}
|
||||||
|
<entry>
|
||||||
|
<title>{{html .}}</title>
|
||||||
|
<link rel="http://opds-spec.org/facet"
|
||||||
|
href="/search/?q=subject:{{urlquery .}}&fmt=opds"
|
||||||
|
title="{{html .}}"
|
||||||
|
type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
|
||||||
|
<updated>{{$updated}}</updated>
|
||||||
|
<id>{{$baseurl}}/search/?subject:{{urlquery .}}</id>
|
||||||
|
</entry>
|
||||||
|
{{end}}
|
||||||
|
</feed>
|
100
templates/search.opds
Normal file
100
templates/search.opds
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<feed xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:odl="http://opds-spec.org/odl"
|
||||||
|
xml:lang="en"
|
||||||
|
xmlns="http://www.w3.org/2005/Atom"
|
||||||
|
xmlns:dcterms="http://purl.org/dc/terms/"
|
||||||
|
xmlns:app="http://www.w3.org/2007/app"
|
||||||
|
xmlns:opds="http://opds-spec.org/2010/catalog"
|
||||||
|
xmlns:thr="http://purl.org/syndication/thread/1.0"
|
||||||
|
xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
|
<id>{{.S.BaseURL}}/search/?q={{.S.Search}}</id>
|
||||||
|
<icon>{{.S.BaseURL}}/img/favicon.ico</icon>
|
||||||
|
|
||||||
|
<link rel="self"
|
||||||
|
href="/search/?q={{.S.Search}}&p={{.Page}}&fmt=opds"
|
||||||
|
type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
|
||||||
|
<link rel="start"
|
||||||
|
href="/?fmt=opds"
|
||||||
|
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
|
||||||
|
<link rel="up"
|
||||||
|
href="/?fmt=opds"
|
||||||
|
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
|
||||||
|
{{if .Prev}}
|
||||||
|
<link rel="first"
|
||||||
|
href="/search/?q={{.S.Search}}&fmt=opds"
|
||||||
|
type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
|
||||||
|
<link rel="previous"
|
||||||
|
href="{{html .Prev}}&fmt=opds"
|
||||||
|
type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
|
||||||
|
{{end}}
|
||||||
|
{{if .Next}}
|
||||||
|
<link rel="next"
|
||||||
|
href="{{html .Next}}&fmt=opds"
|
||||||
|
type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
|
||||||
|
{{end}}
|
||||||
|
<link rel="search"
|
||||||
|
title="Search The Imperial Libary of Trantor"
|
||||||
|
href="/search/?q={searchTerms}&fmt=opds"
|
||||||
|
type="application/atom+xml"/>
|
||||||
|
<link rel="search"
|
||||||
|
href="opensearch.xml"
|
||||||
|
type="application/opensearchdescription+xml"/>
|
||||||
|
|
||||||
|
<opensearch:totalResults>{{.Found}}</opensearch:totalResults>
|
||||||
|
<opensearch:itemsPerPage>{{.ItemsPage}}</opensearch:itemsPerPage>
|
||||||
|
|
||||||
|
<title>search {{.S.Search}}</title>
|
||||||
|
<author>
|
||||||
|
<name>The Imperial Library of Trantor</name>
|
||||||
|
<uri>{{.S.BaseURL}}</uri>
|
||||||
|
<email>zenow@riseup.net</email>
|
||||||
|
</author>
|
||||||
|
<updated>{{.S.Updated}}</updated>
|
||||||
|
|
||||||
|
|
||||||
|
{{$updated := .S.Updated}}
|
||||||
|
{{$baseurl := .S.BaseURL}}
|
||||||
|
{{range .Books}}
|
||||||
|
<entry>
|
||||||
|
<title>{{html .Title}}</title>
|
||||||
|
<id>{{$baseurl}}/book/{{.Id}}</id>
|
||||||
|
<updated>{{$updated}}</updated>
|
||||||
|
|
||||||
|
{{range .Author}}
|
||||||
|
<author>
|
||||||
|
<name>{{html .}}</name>
|
||||||
|
</author>
|
||||||
|
{{end}}
|
||||||
|
{{if .Contributor}}
|
||||||
|
<contributor>
|
||||||
|
<name>{{html .Contributor}}</name>
|
||||||
|
</contributor>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .Isbn}}
|
||||||
|
<dcterms:identifier>urn:isbn:{{.Isbn}}</dcterms:identifier>
|
||||||
|
{{end}}
|
||||||
|
<dcterms:publisher>{{html .Publisher}}</dcterms:publisher>
|
||||||
|
{{if .Date}}
|
||||||
|
<dcterms:issued>{{.Date}}</dcterms:issued>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{range .Lang}}
|
||||||
|
<dcterms:language>{{.}}</dcterms:language>
|
||||||
|
{{end}}
|
||||||
|
{{range .Subject}}
|
||||||
|
<category term="{{html .}}"
|
||||||
|
label="{{html .}}"/>
|
||||||
|
{{end}}
|
||||||
|
<summary>{{html .Description}}</summary>
|
||||||
|
|
||||||
|
<link type="image/jpeg" href="/cover/{{.Id}}/big/cover.jpg" rel="http://opds-spec.org/image"/>
|
||||||
|
<link type="image/jpg" href="/cover/{{.Id}}/small/thumbnail.jpg" rel="http://opds-spec.org/image/thumbnail" />
|
||||||
|
|
||||||
|
<link rel="http://opds-spec.org/acquisition"
|
||||||
|
href="/download/{{.Id}}/{{urlquery .Title}}.epub"
|
||||||
|
type="application/epub+zip" />
|
||||||
|
</entry>
|
||||||
|
{{end}}
|
||||||
|
</feed>
|
|
@ -187,6 +187,7 @@ func initRouter(db *database.DB, sg *StatsGatherer) {
|
||||||
r.HandleFunc("/", sg.Gather(indexHandler))
|
r.HandleFunc("/", sg.Gather(indexHandler))
|
||||||
r.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, ROBOTS_PATH) })
|
r.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, ROBOTS_PATH) })
|
||||||
r.HandleFunc("/description.json", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, DESCRIPTION_PATH) })
|
r.HandleFunc("/description.json", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, DESCRIPTION_PATH) })
|
||||||
|
r.HandleFunc("/opensearch.xml", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, OPENSEARCH_PATH) })
|
||||||
|
|
||||||
r.HandleFunc("/book/{id:"+id_pattern+"}", sg.Gather(bookHandler))
|
r.HandleFunc("/book/{id:"+id_pattern+"}", sg.Gather(bookHandler))
|
||||||
r.HandleFunc("/search/", sg.Gather(searchHandler))
|
r.HandleFunc("/search/", sg.Gather(searchHandler))
|
||||||
|
|
Reference in a new issue