2 Commits
Author SHA1 Message Date
misko903andClaude Opus 5.5 d50440f6c2 fix(webshare): clear the "Resolving" status once the download starts (#1575)
## What

A Webshare.cz download shows "Resolving Webshare link" for its entire
duration, so a large download (e.g. a 1.3 GB audiobook archive) looks
stuck.

## Why

After the link was resolved, the handler called
`status_callback("downloading", None)`. `update_download_status` treats
a `None` message as "keep the current message", so the "Resolving
Webshare link" detail stayed in the activity panel. The HTTP handler
sends `""` for exactly this reason.

## How

- Report `downloading` with an empty message, which clears the resolving
text.
- When the download response has no `Content-Length`, use the release's
size (`task.size`, parsed with `parse_size_string`) as the total for
progress. Without it, progress never moved, and stall detection would
flag a healthy long download after 5 minutes.

## Testing

- New tests in `tests/webshare/test_handler.py`: the downloading status
clears the message, and progress is computed from the release size when
there is no Content-Length.
- `uv run pytest tests/webshare` is green (34 passed), and `ruff check`
and `ruff format --check` are clean.

Follow-up to #1543.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 11:00:15 -04:00
2007384058 feat(sources): add Webshare.cz as a release source (#1543)
## What

Adds [Webshare.cz](https://webshare.cz), the Czech file host, as a
release source for ebooks and audiobooks. It follows the Libgen source:
disabled by default, with a settings tab for credentials and a **Test
Login** button that reports whether the account is VIP.

## Why

Webshare is one of the main places Czech and Slovak ebooks and
audiobooks are shared, and none of the existing sources reach it.
Together with the Databáze knih metadata provider (#1479), this lets
Universal mode find Czech and Slovak titles end to end.

## How

- **API client** (`webshare/api.py`): Webshare's XML API (`POST
/api/<endpoint>/`). Login is the salted exchange the API documents:
fetch the salt, send `SHA1(MD5_CRYPT(password, salt))` plus an MD5
digest. Python dropped the `crypt` module in 3.13, so md5-crypt is a
small pure-Python port, checked against `openssl passwd -1`. The session
token is cached per account and refreshed once when an authenticated
call fails. File-level errors (`FILE_LINK_FATAL_*`) are not retried. XML
is parsed with `defusedxml`.
- **Search** (`webshare/source.py`): Webshare matches file names only,
so the file name becomes the release title and its extension the format.
Queries are title + author, then title only, or the manual query.
Results are filtered to the configured `SUPPORTED_FORMATS` /
`SUPPORTED_AUDIOBOOK_FORMATS`, plus `zip`/`rar` for audiobooks, since
they are usually uploaded as archives. Password-protected files are
skipped. The language is guessed from tags in the name (`CZ`, `SK`,
`ENG`, ...), and the vote balance is a sortable column. API failures
raise `SourceUnavailableError`.
- **Download** (`webshare/handler.py`): resolves a time-limited link per
attempt with `file_link`, then streams it into `TMP_DIR` with progress
and cancel support. Large audiobook archives are not buffered in memory.
- **Settings**: `WEBSHARE_ENABLED`, `WEBSHARE_USERNAME`,
`WEBSHARE_PASSWORD` (a `PasswordField`, already covered by the
`_PASSWORD` redaction in `genDebug.sh`), and `WEBSHARE_MAX_RESULTS`. The
`docs/environment-variables.md` section was added.

## Testing

- `tests/webshare/`: 31 offline tests. They cover md5-crypt vectors,
password hashing, XML parsing, token reuse and re-login, non-retried
file errors, availability gating, format filtering, query fallback,
release mapping, language guessing, and the handler's streaming,
small-file rejection, link errors and cancel.
- `ruff check` and `ruff format --check` are clean. The rest of the unit
suite fails the same way with and without this change: Windows-only
tests on my machine.
- Verified live against webshare.cz: search parsing and the salt
endpoint's error path.
- Still a draft: I haven't yet verified login and download with a real
account.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-22 20:30:01 -04:00