This tool lets you borrow, download and return (audio)books from Libby (OverDrive). You can download audiobooks without the extra step of getting the ODM file first.
You can use pipenv, first install the stuff in the Pipfile (you only need to do this the first time):
pipenv install
Then run PyLibby like this
pipenv run python pylibby.py -h
CLI for Libby options: -h, --help show this help message and exit -id path, --id-file path Path to id JSON (which you get from '--code'. Defaults to ./config/id.json). -c 12345678, --code 12345678 Login with code. -o path, --output path Output dir, will output to current dir if omitted. -s "search query", --search "search query" Search for book in your libraries. -sa "search query", --search-audiobook "search query" Search for audiobook in your libraries. -se "search query", --search-ebook "search query" Search for ebook in your libraries. -ls, --list-loans List your current loans. -lsc, --list-cards List your current cards. -lsh, --list-holds List your current holds. -b id, --borrow-book id Borrow book from the first library where it's available. -r id, --return-book id Return book. If the same book is borrowed in multiple libraries this will only return the first one. -ho id, --hold-book id Hold book from the library with the shortest wait. -ch id, --cancel-hold id Cancel hold. If the same book is held in multiple libraries this will only return the first one. -dl id, --download id Download book or audiobook by title id. You need to have borrowed the book. -f id, --format id Which format to download with -dl. -dla format, --download-all format Download all loans with the specified format. Does not consider -f. -odm Download the ODM instead of directly downloading mp3's for 'audiobook-mp3'. -si, --save-info Save information about downloaded book. -i id, --info id Print media info (JSON). -a path, --archive path Path to archive file. The archive keeps track of what is already downloaded. Defaults to ./config/archive.json -j, --json Output verbose JSON instead of tables. -e, --embed-metadata Embeds metadata in MP3 files, including chapter markers. -opf, --create-opf Create an OPF file with metadata when downloading a book. -dlo id, --download-opf id Generate an OPF file by title id. -ofs string, --output-format-string string Format string specifying output folder(s), default is "%a/%y - %t". %a = Author(s). %n = Narrator(s). %i = ISBN. %o = Overdrive ID. %p = Publisher. %s = Series. %s{STRING} = Will place STRING in folder name if book is in series, else nothing. %S = Subtitle. %S{STRING} = Will place STRING in folder name if book has a subtitle, else nothing. %t = Title. %v = Volume (book in series). %y = Year published. -rs, --replace-space Replace spaces in folder path with underscores. -t TIMEOUT, --timeout TIMEOUT Download timeout interval (seconds). --retry {0,1,2,3,4,5} Maximum download retry attempts. -v, --version Print version.
Alternatively you can run PyLibby without pipenv, but make sure you have installed the requirements, "requests", "tabulate", "dicttoxml" and "mutagen". Minimum Python version is 3.10.
You need to log in before you can start using PyLibby. You can do this by logging in to Libby on any device and going to Settings->Copy To Another Device. You will get a code there which you can use like this:
python pylibby.py -c 12345678
To check if you are logged in you can try listing your loans like this:
python pylibby.py -ls
+--------+-----------+---------------------+-----------+----------+--------------+--------------+---------------+ | Id | Type | Formats | Library | CardId | Authors | Title | Narrators | +========+===========+=====================+===========+==========+==============+==============+===============+ | 123456 | ebook | ebook-overdrive | name1 | 87654321 | Mary Shelley | Frankenstein | | | | | ebook-epub-adobe | | | | | | | | | ebook-epub-open | | | | | | +--------+-----------+---------------------+-----------+----------+--------------+--------------+---------------+ | 654321 | audiobook | audiobook-overdrive | name2 | 12345678 | Bram Stoker | Dracula | Tavia Gilbert | | | | audiobook-mp3 | | | | | J. P. Guimont | +--------+-----------+---------------------+-----------+----------+--------------+--------------+---------------+
To download a book you need to specify the format and output path. For audiobooks the format will always be "audiobook-mp3".
python pylibby.py -dl 654321 -f audiobook-mp3 -o /home/username/books
When downloading a book, you can specify the output format using a custom format string. Substitutions include:
%t - title
%a - author
%s - series
%S - subtitle
%v - volume (book in series)
%p - publisher
%y - year published
%n - narrator
%i - ISBN
%o - Overdrive ID
Additionally, you can include text, but make it conditional on if the book is in a series. To do so, simply include:
%s{/}
Which will render to / if there is a series, but if the book is not in a series, will just disappear.
This similarly works on subtitle existence with %S{STRING}
Use -rs to change spaces in folder names to "_".
Thus, an example is:
python pylibby.py -dl 654321 -f audiobook-mp3 -ofs "%a/%t"
Which will result in a folder structure like:
Jane Austen/Pride and Prejudice/file.mp3
You can search for books like this:
python pylibby.py -s "moby dick"
+---------+-----------+---------------------+------------------------+-----------------+-----------+------------------+ | Id | Type | Formats | Libraries | Authors | Title | Narrators | +=========+===========+=====================+========================+=================+===========+==================+ | 1234567 | audiobook | audiobook-overdrive | name3: available | Herman Melville | Moby Dick | Pete Cross | | | | audiobook-mp3 | | | | | +---------+-----------+---------------------+------------------------+-----------------+-----------+------------------+ | 654321 | ebook | ebook-overdrive | name1: available | Herman Melville | Moby Dick | | | | | ebook-epub-adobe | name2: unavailable | | | | | | | ebook-epub-open | name3: unavailable | | | | | | | ebook-pdf-adobe | name4: available | | | | | | | ebook-pdf-open | | | | | +---------+-----------+---------------------+------------------------+-----------------+-----------+------------------+ | 1111111 | ebook | ebook-kindle | name1: available | Herman Melville | Moby Dick | | | | | ebook-overdrive | | | | | | | | ebook-epub-adobe | | | | | | | | ebook-kobo | | | | | +---------+-----------+---------------------+------------------------+-----------------+-----------+------------------+
You can chain together multiple arguments like this:
python pylibby.py -b 87654321 -b 12345678 -ls -dl 12345678 -f audiobook-mp3 -r 12345678 -ls
PyLibby can take some environment variables. These are:
- CODE - code that you get from the Libby app
- DOWNLOAD_ALL - format
- SAVE_INFO - save json information about downloaded books, value can be anything
- EMBED_METADATA - embed metadata in mp3 files, value can be anything
- CREATE_OPF - create metadata opf when downloading, value can be anything
- OUTPUT_FORMAT_STRING - output format string
- ARCHIVE - path to archive.json
- ID - path to id.json
- OUTPUT - output path
- RETRY - maximum download retry attempts (max 5, anything over = 0)
- TIMEOUT - download timeout in seconds
These can be used like this:
CODE=12345678 DOWNLOAD_ALL=audiobook-mp3 EMBED_METADATA=yes CREATE_OPF=yes ARCHIVE="./config/archive.json" OUTPUT="./Books" python pylibby.py
You can schedule --download-all with cron so that you always have your books ready. To make this easier you can use the provided docker-compose file. Open docker-compose.yml in any text editor and edit it to suit your needs. When you are done, go into the Libby app on your phone or in the browser and get a new code. Enter the code where it says CODE=00000000 in the file, then quickly(!) run:
docker-compose up -d
You have to be fast or else the code will expire.
As I mainly use Libby for audiobooks this tool is focused on that. If you want to download ebooks your best bet is to try the "ebook-epub-adobe"-format and use something like Knock. Unfortunately it was removed from GitHub, but you can still download it here. Most other formats will just print out a link you can open in your browser.
This tool has only been tested on Linux and macOS (thanks dhnyny).
You can try --timeout and --retry if you're having connection issues.
- There's a swagger API with documentation here, but I couldn't get everything to work.
- "ebook-overdrive"-format (Libby web reader) is mostly a regular epub. The book is base64encoded in .xhtml files which we can get. I think most of the toc.ncx file can be reconstructed from openbook.json. Every book could in theory be downloaded this way, then we wouldn't need to bother with acsm's and so on.
- "ebook-kobo"-format is often/always listed as available even if it isn't...? I don't have a device I can test with and I don't know how it works.
- You can still get an ODM file by using
-odm
- Overdrive for their service.
- The Norwegian libraries that are a part of Overdrive.
- Naleo Hyde
- ping
This program is not authorized by Overdrive/Libby. It does not intentionally circumvent any restrictions in Overdrive's or Libby's services, but instead works in the same way as their own software. This means that you will need a valid library card and also a license for each book you download (you need to have "borrowed" them). PyLibby does not remove DRM from files it downloads.
Copyright © 2022 Raymond Olsen.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/
If this software was helpful to you, you may donate any amount here.
Thank you!