-
Notifications
You must be signed in to change notification settings - Fork 5
OPDS For Library Patrons
Unlike electronic bookstores and open-access repositories, public libraries often license ebooks for their patrons under terms that impose an artificial scarcity. Any of these scenarios may apply to a public library trying to get an ebook to one of its patrons:
- The library has licensed a certain number of 'copies' of a book, and all the 'copies' are currently out on loan.
- The library has a daily budget for loaning out books, which has been exceeded. No more titles from this vendor may be loaned out today.
- The library may only deliver a book to a patron as a time-limited loan. After the loan expires, the patron is obliged to erase their local copy of the book.
As a response to the first scenario (not enough 'copies'), some electronic libraries have introduced the concept of holds from the physical world of branch libraries. A hold is a promise from library to patron that the patron will get a chance to borrow a book eventually, once other patrons in the 'hold queue' get a chance to read the book.
This specification documents OPDS extensions that allow public
libraries to communicate these scenarios of artificial scarcity --
availability, holds queues, loan durations -- to OPDS clients. It also
sets out guidelines for how an OPDS client should process the standard
http://opds-spec.org/acquisition/borrow link relation.
OPDS operates on the background assumption that a book with an OPDS entry is available right now and will always be available. In a public library environment, this is generally not true:
- The patron might have a time-limited loan for a book. It's available now, but soon it won't be.
- The patron might be in the middle of a hold queue. The book is not available now, but it will be eventually.
- The patron might be at the front of a hold queue. The book is available now, but if the patron doesn't borrow it soon, they will lose their opportunity and have to go to the back of the queue.
Even in online bookstores, the 'now and always available' assumption does not necessarily hold. Two possible scenarios:
- A book may be available for pre-order. The user can buy the book now, but the purchase will not be fulfillable until a certain date.
- A book may be not be available after a certain date due to an expiring license, analogous to how films leave Netflix.
The opds:availability element conveys a title's current availability. It
goes inside an atom:link element and communicates the current
availability of the resource at the other end of the link.
Inserting availability information into the link allows a server to provide the client with a 'next step' towards availability, even if a title is not currently available. It also allows for the possibility that a title might be available through one mechanism but not another.
Three attributes are defined for the opds:availability element:
| Attribute | Semantics | Values | Default |
|---|---|---|---|
| status | The current availability status of the resource. | Four values for this attribute are defined below: available, unavailable, reserved, and ready. |
available |
| since | Date when the availability status changed to the current status. | ISO 8601 date | No value |
| until | Date when the availability status is expected to change again. | ISO 8601 date | No value |
The opds:availability element is OPTIONAL. If it's not present, an OPDS
client MUST assume that the resource at the other end of the
atom:link is currently available.
The opds:status attribute is REQUIRED for an opds:availability element.
These values are defined for opds:status:
-
available: The resource is available right now. If the user is authenticated, this means the resource is available to that user -- it might not be available generally. If the user is not authenticated, this means that any authenticated user can expect to be able to obtain the resource.This is not a binding promise. When the user follows the link, the resource may turn out not to be available after all.
-
unavailable: The resource is not currently available. The user can still follow the acquisition link, but this will result in some intermediate step, such as a preorder or a hold, rather than the immediate acquisition of the resource.This is not a binding promise. When the user follows the link, the resource may turn out to be available after all.
-
reserved: The authenticated user will get the resource eventually, but it's not available now. This generally means the authenticated user has placed a hold on the resource and is waiting in a holds queue.This is not a binding promise. When the user follows the link, it may turn out that the resource is in fact now available to them.
-
ready: The resource is ready for the authenticated user, but not for the general public. The user can acquire the resource now, but if they don't act soon, they will lose the opportunity.This is not a binding promise. When the user follows the link, it may turn out that the reservation has expired and the resource is now unavailable.
NOTE: When this extension is ported to OPDS 2, "status" should be renamed to "state".
The date attributes are OPTIONAL in an opds:status element. They are
used to help the patron plan for the future.
-
If
opds:statusisavailable, thenopds:sinceis the time at which the resource became available, andopds:untilis the time at which the resource will no longer be available.For example, if the patron has a resource on loan,
opds:sinceis the loan's start date andopds:untilis the expiration date. -
If
opds:statusisunavailable, thenopds:sinceis the last time at which the resource was available (probably not useful) andopds:untilis the estimated time at which the resource will become available. Theopds:untiltime may be conditional on the user taking some immediate action, such as putting a hold on the resource. -
If
opds:statusisreserved, thenopds:sinceis the time at which the authenticated user placed their hold, andopds:untilis the estimated time at which the resource will become available (probably by moving into thereadystatus). This estimate can't be exact because it depends on the behavior of people further up in the hold queue.If the patron does not have an active loan, then
opds:untilfor anunavailableresource may indicate the estimated time at which the resource will become available if the patron joins the hold queue now, -
If
opds:statusisready, thenopds:sinceis the time at which the resource became ready to the authenticated user, andopds:untilis the time at which the resource will revert to its default availability (probablyunavailable).
The opds:copies element describes the number of licenses the server owns
for a resource. Although this is intended to describe electronic
licenses for virtual resources, it may also be used to represent
physical books in a bookstore or branch library.
Like opds:availability, opds:copies goes inside an atom:link element
and describes the resource at the other end of the link. If multiple
links give access to the same resource (e.g. in different formats),
each link SHOULD provide the same information in its opds:copies.
opds:copies has two optional attributes, opds:total and
opds:available. Both have a numeric value.
-
opds:totalis the total number of licenses available to the server. -
opds:availableis the number of those licenses that are available to patrons right now (e.g. not disabled or on loan to specific patrons).
If the opds:status is unavailable, then opds:available SHOULD be 0.
The opds:holds element describes the people waiting in line for access
to a resource.
Like opds:availability, opds:holds goes inside an atom:link element
and describes the resource at the other end of the link. If multiple
links give access to the same resource (e.g. in different formats),
each link SHOULD provide the same information in its opds:holds.
opds:holds has two optional attributes, opds:total and
opds:position. Both have a numeric value.
-
opds:totalIs the total number of people waiting for access to this resource. -
opds:positionis the position in that queue of the currently authenticated user.
If the opds:status is available, then opds:total SHOULD be 0.
With the combination of opds:status and acquisition relations, a book can generally fall in to one of 6 states:
-
Open Access: The book can be downloaded immediately via open-access links without any loan or auth requirements.
- Condition: Presence of link(s) with
http://opds-spec.org/acquisition/open-accessrel.
- Condition: Presence of link(s) with
-
Available to borrow: There is no queue and the book can be borrowed immediately by a patron.
- Condition:
opds:statusisavailableandhttp://opds-spec.org/acquisition/borrowlink is present.
- Condition:
-
Available to reserve: The book cannot be borrowed right now, but the patron can join the queue to borrow it.
- Condition:
opds:statusisunavailableandhttp://opds-spec.org/acquisition/borrowis present.
- Condition:
-
Reserved: The patron is currently in the queue to borrow.
- Condition:
opds:statusisreserved.
- Condition:
-
Ready to borrow: The patron has waited through the queue and now has a hold on the book. They must borrow it before their hold expires, or they lose their spot in line.
- Condition:
opds:statusisreadyandhttp://opds-spec.org/acquisition/borrowis present.
- Condition:
-
Available to access: The patron may access the book (download, read in app, etc) either directly or indirectly immediately.
- Condition:
opds:statusisavailableand link(s) withhttp://opds-spec.org/acquisitionrel are present.
- Condition:
This example shows a book which is not currently available, but which
can be put on hold (the first link, with the relation
http://opds-spec.org/acquisition/borrow) or pre-ordered (the second
link, with the relation http://opds-spec.org/acquisition/buy).
<entry>
<link type="application/atom+xml;type=entry;profile=opds-catalog" rel="http://opds-spec.org/acquisition/borrow" href="http://example.org/hold/1">
<opds:availability status="unavailable" until="2019-09-07"/>
<opds:indirectAcquisition type="application/vnd.adobe.adept+xml">
<opds:indirectAcquisition type="application/epub+zip"/>
</opds:indirectAcquisition>
</link>
<link type="text/html" rel="http://opds-spec.org/acquisition/buy" href="http://example.org/buy/1">
<opds:price currency="EUR">10.99</opds:price>
<opds:availability status="unavailable" until="2019-09-07"/>
<opds:indirectAcquisition type="application/vnd.adobe.adept+xml">
<opds:indirectAcquisition type="application/epub+zip"/>
</opds:indirectAcquisition>
</link>
</entry>
In this example, there are 100 people in the hold queue, 20 copies in
total (none of them available) and the user has yet to place a hold
for the book. The availability status is unavailable and the opds:until
attribute is an estimate of how long the user will be waiting in the
hold queue.
<link ...>
<opds:availability status="unavailable" until="2019-09-07"/>
<opds:indirectAcquisition type="application/epub+zip"/>
<opds:holds total="100"/>
<opds:copies total="20" available="0"/>
</link>
In this example, there are 93 people in the hold queue for a book, and
87 of those people are ahead of the authenticated user. The
availability status is reserved and the opds:until attribute gives
the estimated time at which the book will be available to this user.
<link ...>
<opds:availability status="reserved" until="2015-09-07"/>
<opds:indirectAcquisition type="application/epub+zip"/>
<opds:holds total="93" position="88"/>
<opds:copies total="19" available="0"/>
</link>
In this example, the authenticated user is at the front of the hold
queue but has not yet acquired a loan. The opds:position element is
missing from opds:holds. The opds:availability element indicates
that the user can get the book now (opds:status is ready) but that
if they don't act, they eventually lose their opportunity and have to
place a new hold (opds:until gives the time at which this will
happen).
<link ...>
<opds:availability status="ready" since="2018-09-07" until="2018-09-10"/>
<opds:holds total="59"/>
<opds:copies total="19" available="0"/>
</link>
In this example, the user has acquired a loan for the book. Here the
opds:availability element is most important. Its opds:status
attribute is availabile. The opds:since attribute shows the time
at which the loan was created, and the opds:until attribute shows
the time at which the loan will expire.
<link ...>
<opds:availability status="available" since="2018-09-09" until="2018-10-09"/>
<opds:holds total="58"/>
<opds:copies total="19" available="0"/>
</link>
An online bookstore typically does not allow someone who buys a book to renounce their purchase. However, a public library allows someone with a book on loan to return the book before their loan expires, freeing it up for someone else. A library also allows someone with a hold on a book to abandon their place in the holds queue, perhaps because they're tired of waiting or they gave up and bought their own copy.
If an opds:entry for a title includes an atom:link element with
the relation http://librarysimplified.org/terms/rel/revoke, it means
the authenticated user can make a POST or DELETE requst to the link
target (the atom:href) to abandon their active loan or hold on that
title. The server is expected to act as though the user had never
borrowed this title or put it on hold.
With some DRM systems (such as with Adobe ACS) early return is entirely the responsibility of the DRM library, and triggering a link with this relation will do nothing. But when there is no DRM, triggering the link should be all that's necessary to abandon an active loan.
The link relation http://opds-spec.org/acquisition/borrow is defined
in the core OPDS 1.2 spec like so: "Indicates that the complete
representation of the content Resource may be retrieved as part of a
lending transaction."
OPDS For Library Patrons offers additional details about how this state transition is expected to work, based on the needs of public libraries.
There are two basic things to keep in mind.
-
"Borrowing" and "fulfillment" are two different steps. To "borrow" is to create a loan. To "fulfill" is to download a copy of a book for which you have an active loan. You can borrow a book once and then fulfill it on several reading devices.
This specification uses the link relation
http://opds-spec.org/acquisition/borrowto talk about the "borrow" step and the generic link relationhttp://opds-spec.org/acquisitionto talk about the "fulfill" step. -
When you trigger a
http://opds-spec.org/acquisition/borrowstate transition, you may end up with a hold, rather than a loan. Theopds:availabilityelement will guide you as to whether following a link will get you a loan or a hold, but theopds:availabilitymight be wrong -- someone else may have checked out the last copy of a book just before you did.On the other hand, you may trigger the state transition expecting to get a hold, and end up with a loan -- someone returned their copy of the book in between the time you downloaded the OPDS feed and the time you followed the link.
So, here are the specific semantics for the
http://opds-spec.org/acquisition/borrow link relation:
-
A server that publishes a link with the relation
http://opds-spec.org/acquisition/borrowSHOULD setatom:typeto the media type of an OPDS Catalog Entry Document Resource (i.e. "application/atom+xml;type=entry;profile=opds-catalog")Example:
<link href="https://borrow-me/" rel="http://opds-spec.org/acquisition/borrow"
type="application/atom+xml;type=entry;profile=opds-catalog">
<opds:indirectAcquisition type="application/vnd.adobe.adept+xml">
<opds:indirectAcquisition type="application/epub+zip"/>
</opds:indirectAcquisition>
</link>
We suggest sending an OPDS Entry instead of the actual title for two reasons. First, borrowing is different from fulfillment. If a book is fulfillable in multiple formats, the client should be given a choice of formats at fulfillment time, not at borrow time. That choice of formats is given in an OPDS entry (as per item 3 below).
Second, the client may not actually end up with a loan! If the client asks to borrow a title, but the server can only put it on hold, the appropriate response is an OPDS entry explaining the conditions of the hold.
-
A client may trigger a link with the relation
http://opds-spec.org/acquisition/borrowby sending a POST request to the target URL. No specific entity-body is required, but client authentication MUST be provided if known. -
When sending an OPDS entry to an authenticated user who has a title on loan, a server MUST use the relation
http://opds-spec.org/acquisitionfor links that will lead to digital a copy of the title.Example:
<link href="http://download/book.pdf"
rel="http://opds-spec.org/acquisition"
type="application/pdf"/>
</link>
<link href="http://acs-server/a-book.acsm"
rel="http://opds-spec.org/acquisition"
type="application/vnd.adobe.adept+xml"/>
<opds:indirectAcquisition type="application/epub+zip"/>
</link>
The first link is saying there's a PDF document at the other end of
http://download/book.pdf. The second link is saying that there's
an Adobe ACSM document at the other end of
http://acs-server/a-book.acsm, which can be processed to obtain
an EPUB document.
So, here's what a client might do and see when the user expresses the intention to borrow a book:
- Send a POST request to the target of a
http://opds-spec.org/acquisition/borrowlink. - Parse the resulting OPDS entry.
- If there are
http://opds-spec.org/acquisition/links, you have an active loan and can proceed to download the book. You should see anopds:availabilityelement explaining the terms of your loan. - If there are no such links, you are in the hold queue. You should see an
opds:availabilityexplaining where you are in the hold queue.