Commit Graph
67 Commits
Author SHA1 Message Date
tim b73b2808ca Search the library in the import section
The search shows the matches from a story site that Bindery does not track yet. The button that lists every such book stays.
2026-10-04 02:04:16 +02:00
tim d28f69d93a Show the story sort headings as chips on narrow screens v0.6 2026-10-03 11:53:47 +02:00
tim 60424e8e74 Name the publishing site in the README
"The site" could mean the publishing site of a story or the Bindery
site. Name the publishing site, its publisher and its published text.
2026-10-03 11:23:28 +02:00
tim 5ac56de09d Document the OPDS catalog
Cover the catalog, its logins in each mode, and the paths that the
proxy must let through.
2026-10-03 11:23:28 +02:00
tim 3662372c38 Add the OPDS settings to the settings page
The Book Downloads card has an "Enable OPDS" box. In the proxy mode, it
also shows the user name for the reader and a field to set the OPDS
password. The field is grey until the box is checked. Disabled text
fields now look grey.
2026-10-03 11:23:28 +02:00
tim 28cd0dcde9 Add an OPDS catalog
A reader app can browse the stored books by title, author and last
change, search them, and download them. The download and cover
routes share their code with the story page.

An admin turns the catalog on in the settings. The login follows
AUTH_METHOD: none needs no login, local and cwa take the account
login, and proxy takes the user name from the proxy with an OPDS
password that each user sets. The API key does not open the catalog.
2026-10-03 11:23:28 +02:00
tim ece59c2558 Add {series_sort} to the download template
It gives the series with a leading article at the end, as Calibre's default does for {series}.
v0.5
2026-10-03 08:09:41 +02:00
tim dcdd8e4ac7 Keep the article in {title} and {series}
The default template is now {title_sort} - {authors}. It gives the same name as Calibre's default.
2026-10-03 08:09:41 +02:00
tim 42e7287389 Fold each group of settings into an open card
The long help for the download template and the date format now folds shut.
2026-10-03 08:09:41 +02:00
tim e38c8d655a Add a date format for download names
The new setting gives the strftime format of {pubdate}, {timestamp} and {last_modified}.
The default is Calibre's "%b, %Y".
2026-10-03 08:09:41 +02:00
tim 2c8a1bb187 Use {title} - {authors} as the default download template
This is Calibre's default. An empty template now restores the default.
2026-10-03 08:09:41 +02:00
tim 323bec3c04 Name no template fields that Bindery does not have 2026-10-03 08:09:41 +02:00
tim 3e29ab6bf0 Name downloaded books with a template
The new "Book Downloads" group in Settings holds a Calibre template for the file name of a
direct download. Without a template, the name stays the title. The name is also the title if
the template fails or gives no name for a book.
2026-10-03 08:09:41 +02:00
tim 9e7a488b50 Add Calibre's file name templates
The module prepares the metadata of a book and expands a template as Calibre 9.2.1 does with
its default tweaks. It takes fields, formats, indexes, and text before and after a field. It
refuses template functions and the program modes.
2026-10-03 08:09:41 +02:00
tim ccd3b18791 Share the folder setup of the configuration tests v0.4 2026-10-03 08:09:41 +02:00
tim 6a1c92bc62 Remove duplicates in the web interface
The settings page has one Save button helper. The story list sorts by
the sort key that the server sends, so the rule for a leading article
exists once. The story page takes its list of download modes from the
mode hints.
2026-10-03 08:09:41 +02:00
tim 2ce3de6b58 Remove unused store and CWA client code
The two functions that add chapters share one insert. Nothing used
Store.current_revisions and CwaClient.check.
2026-10-03 08:09:41 +02:00
tim 5f682d209b Remove small duplicates in the settings, the logins and the names
One function reads a true or false value. The download name uses the
file name cleaning of the ingest folder. The login code reads the login
mode from the configuration, and has one lockout message. The title
helper of FanFicFare is now unescape_title, because cwa.py has another
plain_title.
2026-10-03 08:09:41 +02:00
tim 96cf1e4f03 Split the site job into smaller functions
A new story, the chapter list of the site and the choice of chapters to
download each have a function. One helper downloads a chapter for both
loops.
2026-10-03 08:09:41 +02:00
tim 2ada3b3d7e Share the checks and the job builders of the orchestrator
One function checks a whole number of a request, and one checks the
metadata field names. save_settings takes the settings by name. A rebuild
job and a story from an epub each have one builder.
2026-10-03 08:09:41 +02:00
tim 89709f875a Give a library book one form in the API
A book from the search, from the list of library candidates and from a
lookup now has the same fields, with the authors as a list.
2026-10-03 08:09:41 +02:00
tim 22478c3a56 Simplify the upload state and the story page data
The pause of the user and a missing ingest folder are separate checks.
One function gives the upload state to the settings and the story page.
A route that returns only a story no longer loads its chapters or asks
CWA for its book. The story page data loses the values that no page reads.
2026-10-03 08:09:41 +02:00
tim 2b1a26d1da Name Bindery alone in the default personal.ini 2026-10-03 08:09:41 +02:00
tim 05ef1dbfad Add CWA_ENABLED to run Bindery without CWA
With CWA_ENABLED=false, Bindery ignores the CWA settings, makes no request
to CWA, and shows nothing about CWA in the log and the web interface. A
set INGEST_DIR still gets each changed book as a plain epub.

Without it, the log names each CWA function that a missing setting turns
off.
2026-10-02 23:39:58 +02:00
tim bb6c87cdd5 Let only admins change the global settings
BINDERY_ADMIN_USERS lists the admins of the cwa and proxy modes. Only an
admin can change the global settings and the global rules, and read or
change personal.ini. Without a list, each user is an admin.
2026-10-02 23:37:33 +02:00
tim 751b52da77 Answer only to the host names of Bindery
Without a login, a web page that the user visits could reach Bindery
under a name of its own that points at the address of Bindery, and read
and change everything. The "none" mode now answers only to addresses
and to names of a private network. ALLOWED_HOSTS sets the names for
each mode.
2026-10-02 23:37:33 +02:00
tim 2d9796d77c Accept the proxy user header only from trusted addresses
In proxy mode, each client that reached the port could send the user
header. PROXY_AUTH_TRUSTED_IPS now lists the addresses and networks that
can send it. The default is the loopback and private addresses, so a
request that comes straight from the internet cannot log in.
2026-10-02 23:37:33 +02:00
tim 9196dd75a8 Refuse OPDS logins when CWA accepts every password
A CWA with anonymous browsing can answer an OPDS request whatever the
password, so each password logged a user in to Bindery. Bindery now
tests CWA with a login that cannot exist, and refuses OPDS logins if
CWA accepts it. A login check no longer shares the session of the
account of Bindery. The CWA account stays optional for a CWA that asks
for no login, and a missing account now gets its own message.
2026-10-02 23:37:33 +02:00
tim 869e56eaf0 Do not make the ingest folder
A folder that Bindery made hid a missing volume mount. The books went
to a folder inside the container, and CWA never saw them. A missing
folder is now an error in the log at the start, and each upload fails
with a message that names the mount.
2026-10-02 23:37:33 +02:00
tim 679c1ede9f Serve a download from the built book, and delete stale uploads
A download built the book again each time. It now sends the kept build,
and builds only if the book changed after it. Stop tracking deletes the
built book. A cancelled import deletes its uploaded file, and the start
deletes the uploads that no job needs.
2026-10-02 23:37:33 +02:00
tim ff2fa0bf90 Keep a move or a delete of chapters that the user makes during a job
A job placed each new chapter with the chapter order from its start, so
a move by hand during the job went back. The store now places a new
chapter against the order that the story has at that moment, in one
transaction. A recheck of a chapter that the user deleted no longer
stops the job.
2026-10-02 23:37:33 +02:00
tim 81efc03b75 Keep the job thread alive after an error of the queue
An error outside a job, such as a full disk, stopped the thread, and no
job ran until a restart. The health check now answers 503 when a job
thread stopped.
2026-10-02 23:37:33 +02:00
tim c0504135b2 Follow the writing rules in the README and two messages
Remove "should" from the README and the semicolons from two messages.
Correct the note about a local run without CWA.
2026-10-02 23:37:33 +02:00
tim 9c9c5b7dac Load a job record that holds unknown fields
A downgrade of Bindery no longer stops at the start.
2026-10-02 23:37:33 +02:00
tim 98c4a66da1 Answer 400 for a request value of the wrong type
A value such as chapter_ids that is not a list of numbers gave a 500.
2026-10-02 23:37:33 +02:00
tim 90457610f6 Wait only 5 seconds for CWA on the story page
A job still waits for the full timeout.
2026-10-02 23:37:33 +02:00
tim e196d1688e Keep server details out of API answers
An unexpected error now sends a general message, and the log keeps the
text. A job no longer shows the path of its uploaded file. A cover is
cached only by the browser of the user.
2026-10-02 23:37:33 +02:00
tim 0edfa1308c Stop the start with a clear message for a bad setting
A bad UPDATE_INTERVAL_HOURS or LOG_LEVEL no longer ends in a traceback.
Warn about a CWA_PASSWORD without a CWA_USERNAME.
2026-10-02 23:37:33 +02:00
tim 0506086533 Check every setting before the first one is stored
A bad value in a settings request no longer leaves the other values of
that request saved.
2026-10-02 23:37:33 +02:00
tim 7a36e26751 Build and send a book only when it changed
A key of the chapters, rules and metadata of a story tells if its book
changed. A check without a change no longer builds the book again, also
for a book that waits for an upload. A held book goes out without a new
build. The Rebuild button still builds and sends in each case.
2026-10-02 23:37:33 +02:00
tim f961e4781e Warn when the ingest folder has no library to match
Without CWA_URL and CALIBRE_DB_PATH, each update goes to CWA as a new book.
2026-10-02 21:04:49 +02:00
tim c188795852 Make CWA linking and uploads optional 2026-10-02 20:25:45 +02:00
tim 34ff432aac Remember story sorting in local storage v0.3 2026-10-01 16:08:46 +02:00
tim e4a17029c1 Sort stories through column headings 2026-10-01 16:08:42 +02:00
tim b536a1f116 Show story change times and compact list details 2026-10-01 15:42:48 +02:00
timandClaude Sonnet 5 13d7360f60 Show last update time on the story page
The story page already showed last check time. Add last update time
next to it, from the existing last_changed field.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 21:28:48 +02:00
tim 8faab2463b Move and delete chapters by hand in the chapter list
The merge cannot always tell where new chapters go. For example, a site
can list an announcement before the chapters of an old book. You can now
select chapters and move them, in their order, to after another chapter
or to the start. You can also delete them with their revisions. A story
keeps at least one chapter. The book is then rebuilt. A deleted chapter
that the site still lists comes back with the next download.

The Move… and Delete… buttons open a dialog that names the selected
chapters before anything changes. A shift-click selects a range of
chapters.

The Select all checkbox moves into the first heading of the chapter
list. On a phone, that heading shows with the text "Select all".
v0.2
2026-09-27 23:38:28 +02:00
tim ee611cd283 Sort the story list without a leading The, A or An 2026-09-27 23:38:28 +02:00
tim df9959a078 Add a script that cleans up smart punctuation in chapter revisions
Some revisions differ from others only by curly quotes, curly
apostrophes and the ellipsis. The script deletes those revisions and
keeps the one with the least smart punctuation. In revisions with other
text changes, it makes the punctuation straight and stores the new text
hash. It does not change the newest revision if it came from the site.

The script uses only the Python standard library, so you can run it on
the host against bindery.db. It is a dry run unless you give --apply,
and --apply makes a backup first.
2026-09-27 23:38:28 +02:00
tim 5df2806694 Add a script that fills a gap in a story from an ePub without chapter links
A FanFicFare ePub records the site address of each chapter, so Bindery
can import it. Other ePubs, such as the author's own ebook of a story,
have no chapter links. The script asks which stored chapters come before
and after the gap, and which ePub chapters match them. It suggests
matches by title and puts the suggestion on the input line. It then adds
the ePub chapters between the matches, with their images, in the order
of the ePub.

Each added chapter gets a stable URL with the #bindery-import- marker
and the revision source "epub-import". A second run with the same ePub
does not add the same chapters again. --remove deletes the chapters that
the script added.
2026-09-27 23:38:28 +02:00