Renamed feed to opds for better compatibility with some readers

added clickable links to feed (should hopefully solve #79)
updated readme
pull/90/head
OzzieIsaacs 8 years ago
parent e744ccc20e
commit 157a2e6e4a

@ -61,23 +61,25 @@
{% for author in authors %}
<entry>
<title>{{author.name}}</title>
<!--content type="text">{{author.name}}</content-->
<id>{{ url_for('feed_author', name=author.name) }}</id>
<link href="{{ url_for('feed_author', name=author.name)}}" type="application/atom+xml;profile=opds-catalog;kind=navigation" rel="subsection"/>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_author', name=author.name)}}" />
<link type="application/atom+xml" href="{{url_for('feed_author', name=author.name)}}" rel="subsection"/>
</entry>
{% endfor %}
{% for entry in categorys %}
<entry>
<title>{{entry.name}}</title>
<id>{{ url_for('feed_category', name=entry.name) }}</id>
<link href="{{ url_for('feed_category', name=entry.name)}}" type="application/atom+xml;profile=opds-catalog;kind=navigation" rel="subsection"/>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_category', name=entry.name)}}" />
<link type="application/atom+xml" href="{{url_for('feed_category', name=entry.name)}}" rel="subsection"/>
</entry>
{% endfor %}
{% for entry in series %}
<entry>
<title>{{entry.name}}</title>
<id>{{ url_for('feed_series', name=entry.name) }}</id>
<link href="{{ url_for('feed_series', name=entry.name)}}" type="application/atom+xml;profile=opds-catalog;kind=navigation" rel="subsection"/>
</entry>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_series', name=entry.name)}}" />
<link type="application/atom+xml" href="{{url_for('feed_series', name=entry.name)}}" rel="subsection"/>
</entry>
{% endfor %}
</feed>

@ -21,51 +21,55 @@
<entry>
<title>{{_('Hot Books')}}</title>
<link rel="http://opds-spec.org/sort/popular"
href="{{url_for('feed_hot')}}"
type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_hot')}}" />
<link type="application/atom+xml" href="{{url_for('feed_hot')}}" rel="http://opds-spec.org/sort/popular"/>
<id>{{url_for('feed_hot')}}</id>
<content type="text">{{_('Popular publications from this catalog based on Rating.')}}</content>
</entry>
<entry>
<title>{{_('New Books')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_new')}}" />
<link rel="http://opds-spec.org/sort/new"
href="{{url_for('feed_new')}}"
type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition"/>
<id>{{url_for('feed_new')}}</id>
<content type="text">{{_('The latest Books')}}</content>
</entry>
<entry>
<title>{{_('Random Books')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_discover')}}" />
<link rel="http://opds-spec.org/featured"
href="{{url_for('feed_discover')}}"
type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition"/>
<id>{{url_for('feed_discover')}}</id>
<content type="text">{{_('Show Random Books')}}</content>
</entry>
<entry>
<title>{{_('Authors')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_authorindex')}}" />
<link rel="subsection"
href="{{url_for('feed_authorindex')}}"
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
<id>{{url_for('feed_authorindex')}}</id>
<content type="text">{{_('Books ordered by Author')}}</content>
</entry>
<entry>
<title>{{_('Category list')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_categoryindex')}}" />
<link rel="subsection"
href="{{url_for('feed_categoryindex')}}"
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
<id>{{url_for('feed_categoryindex')}}</id>
<content type="text">{{_('Books ordered by category')}}</content>
</entry>
<entry>
<title>{{_('Series list')}}</title>
<link type="application/atom+xml;profile=opds-catalog;type=feed;kind=acquisition" href="{{url_for('feed_seriesindex')}}" />
<link rel="subsection"
href="{{url_for('feed_seriesindex')}}"
type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/>
<id>{{url_for('feed_seriesindex')}}</id>
<content type="text">{{_('Books ordered by series')}}</content>
</entry>

@ -13,21 +13,6 @@
<Url type="application/atom+xml"
template="{{url_for('feed_search')}}?query={searchTerms}"/>
<Url type="application/x-suggestions+json"
rel="suggestions"
template="http://www.gutenberg.org/ebooks/suggest/?query={searchTerms}"/>
<!--
<Url type="application/rss+xml"
template="http://example.com/?q={searchTerms}&amp;pw={startPage?}&amp;format=rss"/>
<Image height="64" width="64" type="image/png">http://example.com/websearch.png</Image>
<Image height="16" width="16" type="image/vnd.microsoft.icon">http://example.com/websearch.ico</Image>
-->
<!--Query role="example" searchTerms="shakespeare hamlet" />
<Query role="example" searchTerms="doyle detective" />
<Query role="example" searchTerms="love stories" /-->
<Attribution>Search Data Copyright 1971-2012, Project Gutenberg, All Rights Reserved.</Attribution>
<SyndicationRight>open</SyndicationRight>
<Language>de-DE</Language>
<OutputEncoding>UTF-8</OutputEncoding>

@ -13,17 +13,6 @@
<Url type="application/atom+xml"
template="{{url_for('feed_search')}}?query={searchTerms}"/>
<!--
<Url type="application/rss+xml"
template="http://example.com/?q={searchTerms}&amp;pw={startPage?}&amp;format=rss"/>
<Image height="64" width="64" type="image/png">http://example.com/websearch.png</Image>
<Image height="16" width="16" type="image/vnd.microsoft.icon">http://example.com/websearch.ico</Image>
-->
<Query role="example" searchTerms="shakespeare hamlet" />
<Query role="example" searchTerms="doyle detective" />
<Query role="example" searchTerms="love stories" />
<SyndicationRight>open</SyndicationRight>
<Language>de-DE</Language>
<OutputEncoding>UTF-8</OutputEncoding>

@ -416,7 +416,7 @@ def before_request():
g.allow_upload = config.UPLOADING
@app.route("/feed")
@app.route("/opds")
@requires_basic_auth_if_no_ano
def feed_index():
if current_user.filter_language() != "all":
@ -429,7 +429,7 @@ def feed_index():
return response
@app.route("/feed/osd")
@app.route("/opds/osd")
@requires_basic_auth_if_no_ano
def feed_osd():
xml = render_template('osd.xml')
@ -438,7 +438,7 @@ def feed_osd():
return response
@app.route("/feed/search", methods=["GET"])
@app.route("/opds/search", methods=["GET"])
@requires_basic_auth_if_no_ano
def feed_search():
term = request.args.get("query").strip()
@ -459,7 +459,7 @@ def feed_search():
return response
@app.route("/feed/new")
@app.route("/opds/new")
@requires_basic_auth_if_no_ano
def feed_new():
off = request.args.get("start_index")
@ -472,13 +472,13 @@ def feed_new():
entries = db.session.query(db.Books).filter(filter).order_by(db.Books.timestamp.desc()).offset(off).limit(
config.NEWEST_BOOKS)
xml = render_template('feed.xml', entries=entries,
next_url="/feed/new?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
next_url="/opds/new?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
response = make_response(xml)
response.headers["Content-Type"] = "application/xml"
return response
@app.route("/feed/discover")
@app.route("/opds/discover")
@requires_basic_auth_if_no_ano
def feed_discover():
off = request.args.get("start_index")
@ -490,13 +490,13 @@ def feed_discover():
off = 0
entries = db.session.query(db.Books).filter(filter).order_by(func.random()).offset(off).limit(config.NEWEST_BOOKS)
xml = render_template('feed.xml', entries=entries,
next_url="/feed/discover?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
next_url="/opds/discover?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
response = make_response(xml)
response.headers["Content-Type"] = "application/xml"
return response
@app.route("/feed/hot")
@app.route("/opds/hot")
@requires_basic_auth_if_no_ano
def feed_hot():
off = request.args.get("start_index")
@ -510,13 +510,13 @@ def feed_hot():
off).limit(config.NEWEST_BOOKS)
xml = render_template('feed.xml', entries=entries,
next_url="/feed/hot?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
next_url="/opds/hot?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
response = make_response(xml)
response.headers["Content-Type"] = "application/xml"
return response
@app.route("/feed/author")
@app.route("/opds/author")
@requires_basic_auth_if_no_ano
def feed_authorindex():
off = request.args.get("start_index")
@ -528,13 +528,13 @@ def feed_authorindex():
off = 0
authors = db.session.query(db.Authors).order_by(db.Authors.sort).offset(off).limit(config.NEWEST_BOOKS)
xml = render_template('feed.xml', authors=authors,
next_url="/feed/author?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
next_url="/opds/author?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
response = make_response(xml)
response.headers["Content-Type"] = "application/xml"
return response
@app.route("/feed/author/<name>")
@app.route("/opds/author/<name>")
@requires_basic_auth_if_no_ano
def feed_author(name):
off = request.args.get("start_index")
@ -547,13 +547,13 @@ def feed_author(name):
entries = db.session.query(db.Books).filter(db.Books.authors.any(db.Authors.name.like("%" + name + "%"))).filter(
filter).offset(off).limit(config.NEWEST_BOOKS)
xml = render_template('feed.xml', entries=entries,
next_url="/feed/author?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
next_url="/opds/author?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
response = make_response(xml)
response.headers["Content-Type"] = "application/xml"
return response
@app.route("/feed/category")
@app.route("/opds/category")
@requires_basic_auth_if_no_ano
def feed_categoryindex():
off = request.args.get("start_index")
@ -561,13 +561,13 @@ def feed_categoryindex():
off = 0
entries = db.session.query(db.Tags).order_by(db.Tags.name).offset(off).limit(config.NEWEST_BOOKS)
xml = render_template('feed.xml', categorys=entries,
next_url="/feed/category?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
next_url="/opds/category?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
response = make_response(xml)
response.headers["Content-Type"] = "application/xml"
return response
@app.route("/feed/category/<name>")
@app.route("/opds/category/<name>")
@requires_basic_auth_if_no_ano
def feed_category(name):
off = request.args.get("start_index")
@ -580,13 +580,13 @@ def feed_category(name):
entries = db.session.query(db.Books).filter(db.Books.tags.any(db.Tags.name.like("%" + name + "%"))).order_by(
db.Books.timestamp.desc()).filter(filter).offset(off).limit(config.NEWEST_BOOKS)
xml = render_template('feed.xml', entries=entries,
next_url="/feed/category?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
next_url="/opds/category?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
response = make_response(xml)
response.headers["Content-Type"] = "application/xml"
return response
@app.route("/feed/series")
@app.route("/opds/series")
@requires_basic_auth_if_no_ano
def feed_seriesindex():
off = request.args.get("start_index")
@ -594,13 +594,13 @@ def feed_seriesindex():
off = 0
entries = db.session.query(db.Series).order_by(db.Series.name).offset(off).limit(config.NEWEST_BOOKS)
xml = render_template('feed.xml', series=entries,
next_url="/feed/series?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
next_url="/opds/series?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
response = make_response(xml)
response.headers["Content-Type"] = "application/xml"
return response
@app.route("/feed/series/<name>")
@app.route("/opds/series/<name>")
@requires_basic_auth_if_no_ano
def feed_series(name):
off = request.args.get("start_index")
@ -613,13 +613,13 @@ def feed_series(name):
entries = db.session.query(db.Books).filter(db.Books.series.any(db.Series.name.like("%" + name + "%"))).order_by(
db.Books.timestamp.desc()).filter(filter).offset(off).limit(config.NEWEST_BOOKS)
xml = render_template('feed.xml', entries=entries,
next_url="/feed/series?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
next_url="/opds/series?start_index=%d" % (int(config.NEWEST_BOOKS) + int(off)))
response = make_response(xml)
response.headers["Content-Type"] = "application/xml"
return response
@app.route("/feed/download/<int:book_id>/<format>")
@app.route("/opds/download/<int:book_id>/<format>")
@requires_basic_auth_if_no_ano
@download_required
def get_opds_download_link(book_id, format):
@ -1036,7 +1036,7 @@ def get_cover(cover_path):
return send_from_directory(os.path.join(config.DB_ROOT, cover_path), "cover.jpg")
@app.route("/feed/cover/<path:cover_path>")
@app.route("/opds/cover/<path:cover_path>")
@requires_basic_auth_if_no_ano
def feed_get_cover(cover_path):
return send_from_directory(os.path.join(config.DB_ROOT, cover_path), "cover.jpg")

@ -10,6 +10,7 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d
- Bootstrap 3 HTML5 interface
- User management
- Admin interface
- User Interface in english, german and french
- OPDS feed for eBook reader apps
- Filter and search by titles, authors, tags, series and language
- Create custom book collection (shelves)
@ -18,7 +19,7 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d
- Restrict eBook download to logged-in users
- Support for public user registration
- Send eBooks to Kindle devices with the click of a button
- Support for reading eBooks directly in the browser
- Support for reading eBooks directly in the browser (.txt, .epub, .pdf)
- Upload new books in PDF format
- Support for Calibre custom columns
- Fine grained per-user permissions
@ -27,7 +28,7 @@ Calibre Web is a web app providing a clean interface for browsing, reading and d
1. Rename `config.ini.example` to `config.ini` and set `DB_ROOT` to the path of the folder where your Calibre library (metadata.db) lives
2. Execute the command: `python cps.py`
3. Point your browser to `http://localhost:8083` or `http://localhost:8083/feed` for the OPDS catalog
3. Point your browser to `http://localhost:8083` or `http://localhost:8083/opds` for the OPDS catalog
**Default admin login:**
*Username:* admin

Loading…
Cancel
Save