CHANGELOG.md
Rama main · réplica de lectura del repositorio original.
# Changelog
All notable changes are recorded here. Format loosely follows
[Keep a Changelog](https://keepachangelog.com/), versions follow
[SemVer](https://semver.org/).
## [Unreleased]
### Added
- #255 Pushes and pull requests to `main` run CI: a lint for syntax
errors and undefined names, a check that the sdist and wheel build,
pass `twine check` and start, the whole test suite on Linux with
Python 3.12 in four parallel parts, and the non-GUI unit tests on
Python 3.11 and 3.13 and on Windows; macOS runs them on pushes to
`main` and releases. The live scraper probes run weekly and upload
`health.json`.
- Part of #317: a tag's GitHub Release, with the desktop downloads, is
created only when that CI and the dependency check below pass on the
tag; the release builds run alongside them. The Docker image is not
gated yet: its own workflow still builds and publishes it for every
tag, whatever the tests show, until this is coordinated with the
Docker workflow changes in #477.
- Part of #285: the GitHub Release text is the version's section of
this changelog, followed by GitHub's list of merged pull requests. A
tag whose version has no section here fails within seconds, before
the tests and release builds start. Publishing to PyPI and syncing the
`cli` branch are not automated yet.
- Part of #385: the pinned dependencies in `requirements/` are checked
against known vulnerabilities when they change, weekly and before
every GitHub Release; a known vulnerability fails the check unless it
is listed with a reason in `.github/osv-scanner.toml`. This covers the
Python packages of the Docker image too, not its operating system
packages, which are not scanned yet. Dependabot proposes updates of the
GitHub Actions the workflows use.
- #217 `memanga setup` prepares a first run after `pip install`, which
itself still sets nothing up. It creates `config.yaml` with the default
settings when there is none (an existing file is never changed) and
the download folder, checks both are writable, and checks that the
Playwright Firefox and Chromium builds are installed and start
headless. Missing builds are downloaded only after a yes on a terminal
or with `--install-browsers`; without a terminal nothing is downloaded,
and `--no-install-browsers` never downloads. Missing system libraries
are reported with the command that installs them; setup never runs
sudo or a package manager. It can be run again at any time and exits
1 while something still needs the user. A scraper whose browser build
is missing now says to run `memanga setup` instead of showing
Playwright's install banner, and `doctor` points there too.
- #359 A small, supported Python API: `memanga.api.Library` reads the
tracked manga of a config directory (title, status, sources, last,
downloaded and failed chapters) as read-only objects, without printing,
locking or writing anything. Every other module is internal; checks,
downloads and edits are done with the CLI. See "Python API" in the
README.
- #380 Release downloads and the Docker image ship third-party notices.
Desktop builds list every component PyInstaller bundled (Python
packages, the Python runtime, the Qt runtime from PySide6, the
PyInstaller bootloader and native libraries from the build system) with
the license and notice files each one ships, plus the LGPL/GPL texts
for the PySide6 wheels, which ship none. Every release asset gets a
matching `<asset>-THIRD_PARTY_NOTICES.txt`; the file is also inside
`MeManga.app`, next to the binary in the Linux `.tar.gz` and embedded
in the binary. The Docker image has the notices for its Python packages,
Python runtime and Playwright browser builds in
`/usr/share/doc/memanga/`. Builds fail when a component has no license
text. A desktop build's native library that no Python package or system
package owns needs an entry in `packaging/third_party_overrides.json`,
which ships that component's own license text (OpenSSL, libffi and the
Visual C++ runtime for the Windows build). Attributions for the
third-party code inside Qt and the browser builds are not reproduced;
the file says where they are published.
- #345 Turning on email delivery asks which manga to send: only the
manga you turn on, or every manga. The desktop app's Settings and the
`config` wizard propose "only manga I choose", so a library is never
sent in full unasked; `config set delivery.mode email` and switching
from local to email in `config edit` take that choice when none was
made and say how to change it. The choice is the
new `email.kindle_scope` setting (`selected` or `all`), shown by
`config email`. A manga's own Kindle toggle always wins, and a config
that already used email delivery without the setting keeps sending
every manga as before.
- #366 Email can be sent over implicit TLS (port 465) as well as
STARTTLS (port 587). The new `email.smtp_tls` setting is `auto` by
default (implicit TLS on port 465, STARTTLS on any other port), or
`starttls` / `implicit` to choose. Both check the server certificate
and need TLS 1.2 or later, and there is still no unencrypted mode. Delivery, `config email
--test` / `--send-test`, `doctor --smtp` and the desktop app's email
tests all use it; `config email` and `status --json` show it. A
connection that fails because the encryption doesn't match the port
now says which setting to change, instead of only timing out. The
guide lists SMTP settings for Gmail, iCloud Mail, Fastmail, Microsoft
365 and Outlook.com, including the Microsoft accounts that can't use a
password.
- #355 `memanga send TARGET CHAPTER...` sends downloaded chapters to the
Kindle again from their saved files, with the configured email
settings and `delivery.delete_after_send`. Every chapter is checked
before anything is sent. Files are taken from the manga's download
folder, never through a symlink (a chapter still on the `--pending`
list uses its recorded file, as `send --pending` does), and nothing is
downloaded. A file whose name could also belong to another downloaded
chapter is only used when the download history says it is this
chapter's. A missing or unclear file, or a format the Kindle doesn't
accept, is reported per chapter while the others are still sent (exit
`3`). A failed email puts the chapter on the `--pending` list, keeping
the parts of a split PDF that were already accepted. Several chapters
ask first unless `--yes`, and `--dry-run` shows what would be sent.
- #360 A chapter that was saved but could not be sent to the Kindle is
no longer only a log line. It stays downloaded, its file is kept and it
is recorded as not sent until a send succeeds. `memanga send --pending
[TARGET]` sends those chapters again (`--list` only lists them,
`--clear` forgets the records; the files stay), and the desktop app
shows "Not sent to Kindle" with a Send button in the manga's chapter
list. `delivery.delete_after_send` still only deletes a file once it
was sent. `check` and `failed retry` now report such chapters and exit
`3`, like other incomplete runs.
- #343 Settings in the desktop app has an About page with the MeManga
version, install type (packaged app or not), Python, OS, Qt and
Playwright versions, whether the Playwright browsers are installed and
which keyring stores the app password. "Copy diagnostics" copies the
same list for a bug report; it holds no folder paths, user names,
e-mail addresses or passwords.
- #247 The app password can come from `MEMANGA_SMTP_PASSWORD_FILE` (a
file such as a Docker secret) or `MEMANGA_SMTP_PASSWORD`, ahead of the
keyring and `config.yaml`, and is then never saved. Setting both, or a
file that cannot be read, leaves no app password (a stored one is not
used instead) and `memanga doctor` says why. Saving the password
without a usable keyring now warns, in the command line and in the
desktop app's Settings, that it is in plain text in `config.yaml`, with
the file's path; a keyring that silently drops secrets counts as
unusable. `config show` also hides email addresses (`***@domain`);
`config get KEY` still prints one value in full.
- #409 `config.yaml` and `state.json` carry a `schema_version`. Files
from older releases load as before and are upgraded on their next
save, with the previous file kept as the `.bak` copy; future layout
changes run as step-by-step migrations. A file from a newer MeManga
is refused and left as it is instead of being overwritten: commands
exit 1 with an update hint, the desktop app shows an error and
`memanga doctor` reports it.
- #357 `memanga path TARGET` prints the download folder of a tracked manga
(only the absolute path, so `cd "$(memanga path TARGET)"` works) and
`memanga open TARGET` opens it in the system file manager. A manga with
nothing downloaded yet, or a missing file opener such as `xdg-open`, is
reported on stderr with the folder path and exits 1; nothing is created.
- #356 `memanga read TARGET CHAPTER...` and `memanga unread TARGET
CHAPTER...` mark chapters read or unread in the same read state the
desktop reader, Library and chapter list use. `read --all` marks every
downloaded chapter; `unread --all` clears the manga's read chapters.
Every chapter is checked before anything changes, and files and download
history are never touched.
- #248 `memanga --version` (also `-V`) prints the installed version, and
`memanga completion bash` prints a bash completion script.
Help and error messages always name the program `memanga`, also under
`python -m memanga`. `check` takes its target as a positional argument
like `edit` and `remove` (`check "Blue Lock"`); `-t TITLE`
still works.
- #354 `memanga export -` writes the backup JSON to stdout and
`memanga import -` reads it from stdin. `import --dry-run` checks the
backup and lists what would be added or skipped without changing
anything. File paths work as before.
- #353 `memanga config` gains `show [--json]`, `get KEY`, `set KEY VALUE`,
`path`, `edit` and `email [--test]` for scripts, Docker and support.
`get` prints only the value, `set` checks the key and value before
saving, and the app password stays masked; it is set with
`config set email.app_password -` from stdin, never from the command
line. `config path` and `config edit` also work when config.yaml cannot
be loaded. The existing `config` flags and the interactive editor are
unchanged.
- #400 MangaDex chapters credit MangaDex and the scanlation group in the
built-in reader and in saved chapters (EPUB/PDF metadata, ComicInfo
`Translator`, or `Source.txt`). Chapters from groups that asked for
removal are skipped; `config --mangadex-remove-group GROUP_ID` adds a
group locally.
- #400 MangaDex image quality can be set to data saver for smaller
e-reader downloads (`config --mangadex-quality data-saver` or Settings →
General). Original quality stays the default.
- #400 MangaDex@Home image loads are reported to MangaDex, and a failed
page is retried on a newly assigned image server.
- #250 `memanga doctor` checks the config and state files, download
directory, email and keyring setup, the scheduled-check entry, cached
source health and the Playwright browser installs in one report. It
exits 1 when a check fails (`--strict` also fails on warnings). The
SMTP login test (`--smtp`) and headless browser launch
(`--launch-browsers`) only run when asked.
- #262 `memanga doctor` adds a `runtime` check that reports the Python
version and executable, platform, MeManga version, package path and
install mode (editable, source, installed, frozen or unknown). It warns when
the package metadata for the imported code has a different version;
unrelated metadata, such as an older install shadowed by a source
checkout, is reported but ignored.
- #250 `list`, `status` and `failed` accept `--json` for scripts. The
output is plain JSON with a `schema_version` field, and
`status --json` never includes the app password.
- #351 `memanga check --download` is the explicit way to download new
chapters without prompting. `-a`/`--auto` and `-y`/`--yes` are aliases
and keep working without warnings, so existing cron lines are
unchanged. `check --help`, the README and the guide describe the
check-only (`--dry-run`), download and ask modes and the exit codes,
including exit 0 for no new chapters and for a withheld suspicious
batch.
- #352 `memanga failed` has explicit actions: `failed list`, `failed
retry` and `failed clear`, each with an optional TARGET (a title or
`#N`). Plain `failed` still lists, and `--retry`/`--clear` keep working
as aliases of `retry`/`clear`.
- #327 `memanga watch` keeps scheduled checks running without cron, for
Docker and NAS setups. It runs `check --auto --quiet` right away and
then every `--every` interval (default 6h, at least 15m) plus up to
`--jitter` random delay. Checks run one at a time, each as its own
process that locks the config directory only while it works; a failed
check is reported and the schedule continues. On SIGTERM a running
check saves its state before the watcher exits 143. `compose.yaml` has
a `scheduler` service for it (`docker compose up -d scheduler`) with
`restart: unless-stopped`, `init: true` and a one-minute stop grace
period; the `memanga` service for one-off commands is unchanged.
### Changed
- #405 Chapter counts in search results can be turned off: **Show
chapter counts in search results** in **Settings → Advanced → Network
& Privacy** (`gui.search_chapter_counts` for `memanga config set`,
on by default; desktop app only). Each count loads the result's
chapter list from its source, which can take several requests (long
lists come in pages, and failed requests may be retried); the README
now says so, and the `memanga search --no-chips` help mentions it. The
app and `memanga search` now fetch at most 4 counts at a time instead
of 6, which is easier on slow connections.
- #376 More neutral wording in help, command output and docs. Help text
no longer cites issue numbers, source notes in `memanga sources` and
the source lists describe the site instead of making size or speed
claims or describing how the scraper works, and messages such as
"Configuration saved." end without exclamation marks. The desktop
app's Check Login now reports "Signed in". Options, exit codes and
JSON keys are unchanged; only the text of `note` changes for some
sources.
- #316 Release builds install `requirements/build.txt` with
`--require-hashes`, wheels only (`--only-binary :all:`) and
`--force-reinstall`, so nothing is built from source with unpinned
build tools and every package is downloaded and hash-checked even if
the runner already had it; the macOS legs no longer install Homebrew's
qpdf for that. The release workflow no longer upgrades pip from the
index, builds only after the full lock check passes on the tag (every
lock generated again from its `pyproject.toml` and compared row for
row), and fails before building when the build environment holds a
package the lock does not pin, another version of one it does, more
than one copy of one, or one installed from a URL or path
(`python scripts/lock_dependencies.py --check-installed build`).
- #315 `pyproject.toml` is the only place dependencies are declared. The
pinned installs in `requirements/` (`cli.txt`, `gui.txt`, `dev.txt`,
`build.txt`) are generated from it by `scripts/lock_dependencies.py`,
with hashes, for every supported platform and Python version. Which
versions they pin is set there too, as the state of PyPI at recorded
times, so the locks can be regenerated exactly, and a check fails pull
requests whose files differ from that in any way. They replace
`requirements.txt`, `requirements-docker.txt`, `requirements-lock.txt`,
`requirements-docker-constraints.txt` and `tests/requirements-test.txt`.
The Docker image installs `requirements/cli.txt` with hash checking;
the dev and release builds and the release workflow install
`requirements/build.txt`, which now also pins PyInstaller; the
bootstrap and Linux setup scripts install `requirements/gui.txt`. The
pinned versions are unchanged. The `urllib3>=2.8.0` floor, which only
the Docker set had, is now a package dependency, and the `dev` extra
has all the test tools.
- #314 The Docker image installs the package unmodified: it keeps the
`memanga-gui` launcher instead of deleting it after the install, and
the build fails if the pinned dependencies do not satisfy the package
(`pip check`). In the image, `memanga-gui` and `python -m memanga.gui`
exit with status 1 and the same "not available in this image" error
as `memanga --gui`.
- #219 PySide6 is no longer a default dependency. `pip install` gives the
CLI only, for servers, containers and scheduled checks; the desktop app
needs the new `gui` extra (`memanga[gui]`). The `dev` and `build` extras
include it. Without it, `memanga --gui`, `memanga-gui` and
`python -m memanga.gui` exit with status 1 and print the install
command instead of a traceback. Release downloads, the Docker image,
`requirements.txt` and the bootstrap script are unchanged.
- #215 The version is set in one place, `__version__` in
`memanga/__init__.py`; `pyproject.toml` reads it at build time and the
release tag check reads it from there. The package metadata now has an
SPDX license expression with the license file, author, keywords,
classifiers and project links. Building needs setuptools 77 or newer.
- #393 "Remove chapters after reading" moves a finished chapter's
download to the system trash (Recycle Bin on Windows, Trash on macOS and
Linux) instead of deleting it for good, so a chapter finished by
accident can be restored. A notification says where it went. If the
trash can't take it, the download is kept and stays downloaded.
- #392 Removing a manga in the desktop app asks the same question from the
Library right-click menu and from the manga's page. It says what
happens: read progress and download history are kept unless you tick
"Also delete progress and history", and downloaded files
always stay in the download folder. Adding the manga again picks up its
kept progress. Both used to delete the history, and only one said so.
The Library header counts only tracked manga, so kept history no longer
inflates the manga and chapter counts. Deleting the history also clears
the manga's Downloads History rows. Renaming a manga now moves its
History rows to the new title; rows from a rename made with an older
version keep the old title and are not deleted, and the dialog says it
deletes the history saved under the manga's current title. A rename in
the app or with `edit --title` is refused when the new title is already
in the library (the app did not check this before) or still has history
from an earlier manga, so a rename never mixes two manga's history.
`remove --purge-history` also clears the manga's Downloads History rows.
- #386 Page images are held to one explicit pixel limit, 2,048 x 65,535
pixels (about 134 megapixels), checked against the image header before
anything is decoded, by the downloader and by the desktop reader. Tall
webtoon strips up to the tallest possible JPEG fit; the desktop reader
used to refuse colour strips over about 67 megapixels that downloaded
fine. A downloaded page over the limit is not retried, and the
chapter's "Incomplete download" error names the page, its size and the
limit (with partial chapters allowed, it counts as a missing page). The
reader shows such a page as "Page N is too large to show (W x H
pixels)." instead of "couldn't be loaded".
- #381 The Windows and Linux desktop downloads are a folder instead of a
single self-extracting file, and no release build is UPX-compressed, so
the LGPL components (Qt, PySide6, Shiboken6, img2pdf) stay separate files
under `_internal` that users can replace; their Python parts ship as
`.py` source. Windows now downloads as `MeManga-windows-x64.zip` (run
`MeManga.exe` from the extracted folder) and the Linux tarball extracts
to a `MeManga-linux-x64/` folder (run `./MeManga-linux-x64/MeManga`).
The macOS app keeps its single executable. The notices file now opens
with an LGPL section: the exact source archives of the shipped Qt for
Python, Qt and img2pdf versions, where MeManga's own source and build
files are, and how to use a modified component (replace the files, or
rebuild from source on macOS with the new `python build_app.py
--no-install`, which builds from the installed packages instead of
reinstalling the pinned ones over the modified component). A release
fails when its tag is not `v` plus the project version, so
the tag the notices name is the one the download was built from.
Builds drop Qt Virtual Keyboard (GPL or
commercial only) and Python's `readline` module (it links GNU Readline,
GPL), which the app never uses, and fail if either is still bundled; the release checks the extracted Windows and
Linux archives keep the LGPL files separate and unpacked.
- #329 The guide shows how to pass the app password to the Docker image
as a secret file, with Compose (`compose.override.yaml`) or
`docker run`, and how to check it with `memanga doctor`.
- #402 Browsers are replaced during long runs without `--safe`: a
source's headless browser is replaced with a fresh one after it has
served 20 searches, chapter lists or chapter pages (100 tokens for
MangaFire's token browser). The replacement happens between two of
those steps, never in the middle of one, and is only logged at debug
level. `--safe` still restarts every browser after every 3 downloaded
chapters, for machines with very little memory.
- #253 Commands start faster: scraper modules are loaded when a source
is used instead of all of them on every run. `memanga --version` and
`--help` load no scraper, and checking or downloading a manga loads
only the scrapers for its sources.
- #254 A source's scraper is reused instead of rebuilt on every lookup,
so repeated searches, checks and retries against one site keep its
connection and cookies. Each worker thread, including the ones that
download a chapter's pages, uses its own scraper and connection, but
the pause between requests to a site is now shared by all of them, so
parallel searches, chapter counts and downloads no longer hit one site
faster than its limit. Finding the scraper for a subdomain checks only
that host's parent domains instead of every supported site.
- #372 The plain summary line of `memanga check` ends with the next
step when there is one: `next: run 'memanga failed' for details` after
failed chapters, or `next: rerun with --download` when chapters needed
confirmation. It shows even with `memanga -q`, which hides the
separate warning.
- #226 Output and logging work the same everywhere. Scrapers, the
downloader, email delivery and the desktop app report through logging
instead of printing to stdout, so stdout only carries command results
and `--json` stays clean. Diagnostics go to stderr: warnings and errors
by default, more with `memanga -v` (progress) or `-vv` (debug), only
errors with `memanga -q`, or any level through `MEMANGA_LOG_LEVEL`;
this covers the warnings and errors `check` and `failed retry` report
themselves. When stdout is not a terminal (pipes, files, cron), or
with `--plain`, output is plain text without colour, emoji, borders or
line wrapping, and `check` prints a single summary line;
`NO_COLOR` turns colour off. Log lines on a redirected stderr or in a
log file, traceback lines included, carry a timestamp and level. `memanga --log-file`
also writes a rotating `diagnostics.log` in the config folder. The
desktop app keeps the last three `runtime.log` files instead of
overwriting it at every start. Passwords and tokens
are masked in log output, and redirected output on Windows is written
as UTF-8.
- #249 Config and state live in the platform config folder:
`%APPDATA%\memanga` on Windows, `~/Library/Application Support/memanga`
on macOS and `$XDG_CONFIG_HOME/memanga` (default `~/.config/memanga`) on
Linux. The CLI and the desktop app pick the same folder. An existing
`~/.config/memanga` is moved there once, as a single rename under the
config lock, and a `MOVED.txt` note stays behind so scheduled checks
installed earlier keep running. When the move is not safe (another
MeManga is running, the new folder is not empty, settings point inside
the old folder, or the rename fails) the old folder stays in use
unchanged. `--config-dir` and `MEMANGA_CONFIG_DIR` still win and never
move anything, and now apply to the desktop app too:
`memanga --config-dir DIR --gui` opens the app on DIR (it was refused
before), the app started on its own honours `MEMANGA_CONFIG_DIR`, and
the daily check set up in its Settings keeps the chosen directory.
- #348 `edit` is the command for changing a tracked manga, including its
status (`memanga edit "One Piece" --status on-hold`); `update` stays an
alias. Help and the bash completion list `edit (update)`.
- #354 `import --replace` asks for confirmation before replacing the
library and download state. Non-interactive runs and stdin imports must
pass `--yes` (`-y`); without it they exit 1 and change nothing.
- #354 `import` checks the whole backup before writing: invalid JSON, a
`manga` value that is not a list, entries without a title and
non-object state entries are rejected (exit 1) instead of crashing
midway or being written to config.yaml as-is.
- #352 `failed` targets (TARGET or `-t`) are matched like `check -t`: `#N`
from `memanga list`, an exact title, then a unique part of a title. A
target that matches nothing or several manga is now an error (exit 1)
and changes nothing; it used to act on every title containing the
text, or exit 0 with nothing found.
- #352 `failed retry` (and `--retry`) downloads through the same chapter
steps as `check --download`: it now also emails chapters saved from the
backup source, honors delete-after-send, page retries and the
partial-chapter settings, and clears backup-delay clocks. A chapter
saved as a partial again keeps its record and counts as not recovered
(exit 3).
- #222 `failed retry` reads each manga's chapter list from the primary
source once per run, instead of once for every failed chapter of that
manga. `check` and `failed retry` now process chapters through one
shared module, so their download, backup, partial, delivery and state
handling stay the same.
- #295 GUI downloads now go through the same chapter steps as
`check --download` and `failed retry`. The Detail and Downloads pages
honor "Delete after sending to Kindle", image folders are no longer
emailed, the backup source is searched with the same group filters as
the command line, and a backup-delay clock is cleared once the chapter
is saved. Chapters the reader fetches ahead of time are never deleted
after sending.
- #296 Kindle email settings (addresses, SMTP server, port, timeout and
app password) are read from config in one place for the desktop app's
Downloads, Detail and Reader pages and for `check`, `failed retry`,
`send --pending`, `config email` and `status --json`, so their defaults
and when a manga is sent to the Kindle cannot drift apart. Behavior is
unchanged.
- #297 `memanga cron` and the desktop app's Settings install, remove and
check the daily scheduled check through one shared module, so cron and
Windows Task Scheduler behave the same from both. Remove in Settings on
Windows no longer reports success and turns the setting off when the
task was not deleted. Status and Remove now say when the crontab or the
Windows task list could not be read instead of reporting that no check
is set up, and change nothing. `cron install` rejects times outside
00:00-23:59, as Settings already did. A missing `crontab` or `schtasks`,
or output that is not readable text, is reported as an error instead of
a crash, and each scheduler call that hangs gives up after
30 seconds. Reinstalling on Windows replaces the task in place, so a
failed reinstall no longer leaves no task while the setting stays on.
If Settings installs the check but cannot save config.yaml, it says
the check is installed and its settings were not saved.
- #351 `memanga check --quiet` on a terminal without `--download` now
skips new chapters and exits 1 with a hint, as it already did without a
terminal. It used to skip them silently and exit 0. `--quiet` never
prompts and never gives permission to download.
### Deprecated
- #348 `memanga set TITLE STATUS` is deprecated in favour of
`memanga edit TITLE --status STATUS`. It still works in this release
with the same output and exit codes, prints the matching `edit` command
on stderr, and no longer appears in help or completion. It will be
removed in the next release.
- #245 `memanga.emailer.test_email_config` is renamed
`check_email_config`. The old name still works, warns with a
`DeprecationWarning`, and is no longer collected by pytest when a test
module imports it.
### Removed
- Python 3.10 is no longer supported: MeManga needs Python 3.11 or
newer. Python 3.10 reached its end of life in October 2026, and the
Pillow releases that fix its known vulnerabilities need Python 3.11
(#385). Installing on Python 3.10 now stops with pip's
`requires-python` error.
### Fixed
- On Windows, `memanga` run without a console (a scheduled task, or
stdin from `NUL`) no longer opens the interactive menu and fails with
an `EOFError` traceback; it exits with an error, as on Linux and
macOS.
- The license texts in the Windows release download are the exact,
unmodified files again; the Windows build's checkout converted their
line endings.
- #233 An unsupported source is reported in one short line that points
to `memanga sources`, instead of listing every supported domain
(`check`, downloads and the logs). A scraper that fails with a parse
error while listing chapters is now reported as a failed fetch, not as
an unsupported source. `get_scraper()` raises the new
`UnsupportedSourceError`, which is still a `ValueError`.
- #235 Browsers opened during a run are now closed when MeManga exits.
The exit cleanup ran only after Python had stopped the threads that own
the browsers, so every close failed silently and the browsers were left
to end with the process. Exit cleanup also no longer starts a thread
for a scraper that never opened a browser, and restarting a MangaFire
token browser that was never started no longer logs a restart.
- #333 The Docker image runs MeManga under `tini`, so containers no
longer collect zombie browser processes. MeManga ran as PID 1, which
never reaped the processes left behind when a Playwright driver or
browser exited early; they stayed until the container stopped. This
now works however the container is started, without `docker run
--init` or Compose `init: true`, which the `scheduler` service no
longer sets (both still work). `docker stop` and Ctrl-C reach MeManga
as before, and exit codes are unchanged.
- #335 `memanga cron install` refuses to run inside a Docker or Podman
container, where no cron daemon would ever run the check. It exits 1,
runs no `crontab` command, leaves `config.yaml` unchanged, and points
to `memanga watch` (the Compose `scheduler` service) and the Docker
scheduling guide. Before, it failed with a bare "could not read the
current crontab" error, or, in an image with `crontab`, wrote an entry
that never ran. `cron status` and `cron remove` work as before.
- #396 The desktop app can be used from the keyboard. Library cards and
rows, continue-reading cards and the theme cards could only be clicked;
`Tab` now reaches them, `Enter` or `Space` opens them, and the `Menu`
key or `Shift+F10` opens a card's quick actions. The Auto / Manual and
layout drop-downs can be picked with the arrow keys and `Enter`. Buttons,
tabs, chips, sidebar items, check boxes, drop-downs and cards show a
focus ring when focused from the keyboard, not after a click; so does the
Search field. Page scroll areas are no longer invisible `Tab` stops
(`Page Up` / `Page Down` still scroll), dialogs `Tab` in reading order,
and menu highlights are easier to see. Opening a page from the keyboard
moves focus to its first control instead of leaving it in the sidebar,
and focus returns to a card after its quick action. In the reader, clicking a toolbar button or the page no longer
takes the reader keys away; `Ctrl/Cmd+0` resets the zoom as documented,
and `Page Up`, `Page Down`, `Space`, `Home` and `End` scroll in
continuous mode. New shortcuts: `Ctrl/Cmd+F` for the filter field,
`Ctrl/Cmd+,` for Settings and `Alt+←` (`Cmd+[` on macOS) from Detail back
to Library. The README's reader key table was wrong in places and now
lists every key for each layout.
- #394 Screen readers announce the desktop app's controls by name. Icon
and glyph buttons (grid/list view, reader layout and zoom, download
cancel, the sources "⋯" menu), cover cards and list rows, theme cards,
source checkboxes, progress bars and the Settings fields used to be
announced as a symbol or with no name at all. Sidebar badges say what
they count, repeated buttons such as "Read" or "+ Add" say which
chapter or title they act on, and the active view, layout and theme are
announced. `docs/ACCESSIBILITY.md` has a manual screen-reader checklist.
- #259 The desktop app's Settings header shows the config file it really
uses, including one chosen with `--config-dir` or `MEMANGA_CONFIG_DIR`,
and the path can be selected and copied. It used to name a
`~/.memanga/config.toml` that MeManga never reads or writes.
- #389 The desktop reader opens long chapters without freezing the
window. It used to decode every page up front, which on long webtoon
chapters took seconds and hundreds of MB to several GB of memory.
Opening a chapter now only reads each page's size, so scrolling, the
page count and resuming where you left off work at once. Pages are
decoded in the background, starting with the ones on screen and a few
ahead. Pages far from where you are reading are released again, so
memory no longer grows with the chapter's length. A page that can't be
decoded shows a short message in its place. With "remove chapters
after reading" on, a finished chapter's file is now removed when you
leave the chapter rather than the moment you reach its end, so you can
still scroll back through it.
- #382 The desktop reader no longer switches silently to PyMuPDF, an
AGPL-licensed library MeManga does not declare, whenever that happens to
be installed, which also changed the page sizes. Desktop builds now
exclude PyMuPDF so a build environment that has it can't bundle it. PDF
pages MeManga wrote, one image each, show that image as stored. Every
other PDF page (text, drawings, links and other annotations, rotated or
cropped pages, PDFs from other programs) is drawn whole with Qt PDF,
which ships with Qt, instead of showing only the images on it. Filled-in
form fields are merged into an in-memory copy of their page so they are
drawn as well; the file is never changed. A filled-in field with no
appearance to draw makes its page show as one that couldn't be loaded,
instead of the page without the field. Desktop builds' third-party
notices reproduce the licenses of PDFium and the other components Qt PDF
contains, taken from the Qt release the build ships, and the build stops
when the Qt version changes until they are updated. A failed page's
"couldn't be loaded" message now stays readable on very small pages.
- #324, #336 The downloaded desktop app no longer offers to install a
scheduled check it cannot run. Its only executable starts the app, so
the daily task opened the window instead of checking while Settings
reported success. Settings now turns off the daily auto-check, its time
and Install there, and says to use `memanga cron install` from the
command-line version; Remove and Status still work for a task set up
earlier. Source, pip and pipx installs schedule checks as before.
- #300 The packaged desktop app no longer contacts httpbin.org before
opening its window. That test request held up every launch for up to
several seconds on a slow, offline or firewalled network. Startup now
only picks the bundled certificate file, and logs which one it uses.
- #362 Chapters saved as CBZ or ZIP are no longer emailed to the Kindle,
which rejects them; only PDF and EPUB are sent, and image folders stay
unsent as before. The chapter is still saved and kept, and the command
line and the desktop app both say why it was not sent. With Kindle
delivery on, `check` warns once before downloading in such a format,
and `config set`, `config edit`, interactive `config`, `doctor` and
Settings warn when the delivery mode and output format conflict.
- #338 With `delivery.delete_after_send` on, the desktop app now says
what happened to the local copy after a Kindle send: "Sent to Kindle:
<file> — local copy deleted", or a warning with the reason when the
file could not be deleted (the chapter was still sent and the file is
kept). The download history records whether the local copy was
deleted, and the History tab shows "Sent" or "Sent · deleted" for
chapters that went to the Kindle, including chapters sent later with
Send or `memanga send --pending`. Files are still only deleted after a
successful send.
- #341 The command line now honors the per-manga mode and Kindle settings
of the desktop app. `check --download` (and cron's `check --auto
--quiet`) without a manga name lists the new chapters of `manual`-mode
manga instead of downloading them, and the summary counts them;
naming the manga or answering the per-chapter question still
downloads. A manga with Kindle delivery turned off is never emailed by
`check`, `failed retry`, `send --pending` or the desktop app's Send
button; its chapters are saved as usual. Entries without these fields
keep the old defaults (automatic, Kindle on).
- #342 The desktop app no longer cuts error messages off after 30-80
characters. Toasts, download rows and the Settings email test show a
short summary, and the Notifications entry keeps the complete error
behind a Details button, with a Copy action. For the 20 most recent
errors longer than 4,000 characters, up to 100,000 characters are kept
in a private file in the config folder's `error-details` directory
(removed with its notification, about 2 MB at most); when less than
the whole error is kept, the Details view says so. Kindle delivery
failures now get a notification too. The Search page has a Failure
details button listing why each source failed in the current search
(up to 20,000 characters per source and 100,000 per search, with any
cut marked). Passwords, tokens, the whole user part of URLs
(`https://***@host/...`), the name part of email addresses and the
home folder are masked in shown, copied and saved error text,
notification titles included. Check, download, Kindle, search and
Settings (email test, schedule, export, import) failures are written
to the log. The log masks passwords, tokens and the user part of URLs,
now also when the app is started with the `memanga-gui` command, which
printed its log lines unmasked before; it does not mask email
addresses or the home folder.
- #246 File and folder names are valid on Windows, macOS and Linux:
control characters are removed and a Windows device name such as
`CON` or `nul` gets a `_` suffix. `add`, `edit --title`, `search --add`
and the app's Add page refuse a title that would share another
manga's download folder (`A:B` and `AB`), since their chapter files
would overwrite each other.
- #246 EPUB metadata no longer names the manga title as the author. The
author comes from the manga entry; the language comes from the entry's
`language` or from a source that serves one language (MangaDex, TCB
Scans, Thunder Scans EN, the Spanish and Indonesian sources), and is
`und` (undetermined) instead of English when unknown. CBZ ComicInfo
adds `LanguageISO` when the language is known and `Manga` =
`YesAndRightToLeft` only for titles known to read right to left (TCB
Scans, or `reading_direction: rtl` on the manga entry); manhwa and
webtoons are no longer marked right to left.
- #246 Cancelling a chapter download waits for page downloads already
in progress before the temporary folder is removed.
- #246 `add --fallback-days` without `--backup` fails instead of being
ignored. `import` reads files as UTF-8 (a BOM is accepted) and rejects,
before anything is written, manga entries whose `url`, `source`,
`sources` or `fallback_delay_days` have the wrong type, and imports
(merge or `--replace`) that would give two manga the same download
folder.
- #246 Config changes from different threads take the same lock as
saving, and scrapers no longer swallow Ctrl+C.
- #212 Installing the package (`pip install .`, `pip install -e ".[dev]"`,
`pip wheel .`) no longer runs the setup script. The build backend
executed the old root `setup.py`, which created a `venv`, installed
requirements, downloaded Playwright browsers and on Linux ran `sudo
apt-get`. The script is now `scripts/bootstrap.py` and runs only when
called: `python scripts/bootstrap.py` replaces `python setup.py`;
`scripts\windows\setup.bat` calls it as before.
- #244 Only one MeManga process at a time changes a config directory, so
a cron `check`, a manual command and the desktop app no longer overwrite
each other's downloads, failed records, reading progress or imports.
Commands that change config or state take a lock on the directory
(`memanga.lock`) before loading anything; while another check, command
or the desktop app holds it they exit 1 with a message on stderr and
change nothing, and the desktop app shows an error instead of starting.
Read-only commands (`list`, `status`, `path`, `open`, `sources`,
`export`, `doctor`, `failed` listing, `config show/get/path`,
`cron status`, `search --json` without `--add`) still run. The system
releases the lock when the process ends, even after a crash, so there
is nothing to clean up. Scheduled checks use the same lock. A
read-only command leaves a damaged `state.json` untouched while another
process holds the lock, and `export` refuses to write over MeManga's own
files in the config directory.
- #243 A damaged `state.json` is no longer replaced by empty state. It
is kept as `state.json.corrupt-<time>-<id>`, the previous copy is
restored from `state.json.bak` when there is one, and the CLI (on
stderr), the desktop app and `memanga doctor` say where the damaged
file went. A state file that can't be read or copied aside is never
overwritten: commands other than `doctor` stop with exit 1 and the
desktop app shows an error instead of starting. The same happens when
the restored copy can't be written to `state.json`, or when
`state.json.bak` exists but can't be read; the damaged file then stays
in place, so the next start tries the restore again, `state.json.bak`
is unchanged, and an identical damaged file is kept only once. Every
save keeps the previous `state.json` and `config.yaml` as `.bak` and
flushes the new file to disk before replacing the old one (and the
folder afterwards, where the system supports it); if the previous copy
can't be kept, the save fails and both files stay as they were. A CLI
command whose save fails (for example on a full disk) stops with exit
1 and a short message naming the file instead of a traceback. The
desktop app also shows an error for a broken `config.yaml` instead of
crashing.
- #230 `check` and `failed retry` write `state.json` after every chapter,
so a run that is killed, crashes or times out no longer forgets
chapters it already saved and sent, and the next run does not download
or send them again. If the state file can't be written, the command
stops with exit 1 before downloading or sending anything else. SIGTERM
(cron `timeout`, `systemctl stop`, `docker stop`) now saves pending
state like Ctrl-C and exits 143. A chapter can still be sent twice if
the process dies after sending it and before its state is written.
The desktop app is unchanged.
- #241 Downloaded chapter files and folders are named so that they sort in
chapter order, extension included, both by plain character order and
under locale sorting that skips punctuation. Numeric chapters use a
fixed-width number: four digits, a dot and three decimals
(`Chapter 0002.000`, `Chapter 0002.500`, `Chapter 0010.000`). Chapters
up to 9999 with up to three decimal places are ordered exactly. Part
chapters keep a readable label after their chapter's numeric names
(`Chapter 0002_Part 02`, `Chapter 0002_Part 10`) instead of the
decimal-looking `2.10`. Labels that the number alone would not spell
(`2.0`, `2.00`, `02`, `2.50`) get the source label added
(`Chapter 0002.000 (2.00)`), so different numeric chapters no longer
share a file and one download cannot replace another. Names for the same
chapter number stay together, in no fixed order among themselves. File
names are still capped at 100 characters, but a long manga title is now
shortened instead of the end of the name, so the chapter part is never
cut off. `{chapter}` in a custom naming template uses the same form.
Other labels such as `Extra` are unchanged. Existing files are not
renamed and still open in the reader. Post-processing `{chapter}` and
`MEMANGA_CHAPTER` still receive the original chapter number.
- #406 `scripts/run.sh` and `scripts\windows\run.bat` no longer switch to
the project folder before running MeManga. Relative paths such as
`import backup.json` or `export backup.json` now resolve in the folder
the command was typed in. On Windows, `run.bat` and `setup.bat` also
leave the Command Prompt in its original folder.
- #398 Scraper requests no longer retry permanent HTTP errors. A 403, 404
or 410 (and other 4xx) used to be sent three times with back-off; now
only connection errors, timeouts, 429 and 5xx responses are retried.
MangaBall still retries a 419 after refreshing its CSRF token.
- #351 `memanga check --dry-run` no longer changes state. It used to
record a check (last-check time and a history entry counting listed
chapters as downloaded), start or clear backup-delay clocks, advance the
catalogue baseline, and record or clear suspicious batches. In
particular, `--dry-run --force-suspicious`, `--dry-run --all` or
`--dry-run --from N` could accept a held suspicious batch so the next
scheduled check downloaded it. A forced preview now only shows what
accepting the batch would download.
- #231 `memanga cron install` and `cron remove` (and the GUI Settings
buttons) only change the crontab line they own, now marked with a
trailing `# memanga-managed` comment. Other lines, comments and blank
lines are kept as they are, including hand-written MeManga jobs. Lines
from earlier installs have no marker, so they are left in place and
listed; remove them with `crontab -e` to avoid running the check twice.
`cron remove` no longer rewrites the crontab when there is no managed
line, and `cron status` only reports a job as installed when it is marked.
The GUI Settings cron status and install also point out unmarked MeManga
lines. Install now refuses to write when `crontab -l` fails for a reason
other than "no crontab", and remove keeps scheduled checks enabled in
the config when writing the crontab fails.
- #250 CLI commands no longer print a MangaFire browser-restart notice
to stdout on exit, which broke `search --json` output.
- #250 An invalid `config.yaml` no longer crashes the CLI with a
traceback. `memanga doctor` reports it as a failed `config` check;
other commands exit 1 with a short error and leave the file untouched.
- #238 `memanga add` only asks questions with `--interactive`. Without it,
an unsupported source or a similar tracked title exits 1 with an error
instead of prompting, even in a terminal; pass the new `--force` (or the
existing `--yes`) to add it anyway. Exact duplicates are still refused.
An invalid fallback delay in interactive mode asks again instead of
crashing.
- #237 `remove`, `set`, `update` and `check -t` no longer pick the wrong
manga. An exact title (any case) wins over a partial one, and a partial
title that matches several manga exits 1 and lists them. A bare number
such as `86` now matches only an exact title; use `#N` (quoted in the
shell) for the Nth manga in `memanga list`. `remove --yes` keeps the
download history; pass the new `--purge` to delete it as well.
- #239 CLI exit codes are now predictable: 0 success, 1 error, 2 usage
error, 3 when `check` or `failed --retry` ran but some chapters failed,
and 130 when interrupted. `remove`, `set`, `update` and `check -t` exit
1 when the manga is not found (they used to exit 0), and `check` exits
1 when no manga could be checked. Errors and warnings are written to
stderr so stdout only carries results.
### Security
- #385 Pillow 13.0.0, certifi 2026.10.23 and soupsieve 3.0.4 (2.10 on
Python 3.11.0 to 3.11.4) replace releases with known vulnerabilities
in every pinned install, the Docker image and the release downloads.
## [0.4.4] - 2026-10-03
### Added
- #185 Thunder Scans EN (en-thunderscans.com) is now available as a
supported source with search, chapter lists and page downloads.
Coin-locked early-access chapters are left out of the chapter list, and
saved series links keep working when the site rotates its numeric slug
prefixes.
- #184 ZonaTMO (zonatmo.org) is now available as a supported source.
Search, chapter lists and reader pages are read from the site's HTML;
text novels are skipped since they have no page images to download.
- #183 Olympus Scanlation (olympusxyz.com) is now available as a supported
source through the site's catalogue, chapter-list and reader APIs. Search
covers comics only; the site's text novels have no page images to
download.
- #186 Lector Manga (lector-mangas.lat) is now available as a supported
source with search, chapter listing and page downloads. Links on the
old lectormangass.net host, which now redirects to the new one, keep
resolving to the same scraper.
- #187 Wurmz (wurmz.net) is now available as a supported source with
search, chapter lists and page downloads for its Indonesian manga,
manhwa and manhua translations.
### Changed
- Docker image publishing now builds and runs a local smoke-test image
before the multi-platform release images are published, so broken
container entrypoints fail before they reach Docker Hub or GHCR.
- Version metadata synchronized for the v0.4.4 release.
### Fixed
- #163 macOS release builds can optionally be signed and notarized. When
paid Apple Developer ID credentials are configured as repository
secrets, the release workflow signs the Apple Silicon and Intel apps with
the hardened runtime, notarizes them with Apple, staples the ticket and
stops before upload if signing, notarization, the Gatekeeper check or
the final app self-test fails. Without those credentials releases still
publish unsigned `MeManga.app` zips, which macOS may still report as
"damaged"; the README documents the `xattr` workaround for that case.
- #182 Kagane is skipped by the multi-source search sweep. kagane.org now
redirects to kagane.to, and both sit behind a Cloudflare challenge that
answers searches with a 403. Links on either domain still resolve to
the Kagane scraper so saved entries stay in the library, but searches,
chapter lists and page downloads will not work until a reliable way
past the challenge is found.
- #181 ComicK search and chapter lists work again. The scraper now reads
the site's JSON API instead of the browser-rendered pages, which sit
behind Cloudflare's headless verification and returned no results.
When several groups upload the same chapter, scan-group uploads are
preferred over official ones. Official/external chapters that only link
out to the publisher have no hosted images, so they still download no
pages rather than faking a download.
- #175 MangaHere.onl search now queries the site's catalogue API instead of
scraping the home page, so results match the query instead of listing
unrelated titles. Titles the site doesn't host (licensed series served
only on a sister domain) are left out, and chapter lists no longer pick
up other series' chapters or hidden placeholder links.
- #177 Asura Scans search works again and is no longer skipped in the
multi-source search sweep. The scraper now reads the site's JSON API
instead of driving a headless browser at the retired asuracomic.net
domain, which redirected to the homepage and dropped the query.
Chapter listing, page extraction, and covers use the same API, and
entries saved against the old domains keep resolving, including the
older `/manga/<slug>/` paths. Asura is also back in the curated
default source set, so fresh installs search it out of the box, and
a one-shot repair re-ticks it for installs that were seeded while it
was broken.
- #177 Asura early-access chapters are no longer listed as downloadable.
They appeared in the chapter list but served zero pages until their
paywall window closed.
- #174 MangaHere page downloads now fetch the real CDN images through the
reader's `chapterfun.ashx` endpoint instead of falling back to reader
page URLs, so chapters no longer download as HTML saved with an image
extension. Chapter listings also skip the sidebar links to other series,
and a hotlink-blocked response is rejected rather than written to disk.
## [0.4.3] - 2026-08-19
### Added
- #153 Atsumaru is now available as a supported source through the site's
Typesense and reader APIs.
- #156 VyManga is now available as a supported source, including legacy
host canonicalization for saved or manually added entries.
- #157 Mangadot is now available as a supported source through its rendered
search pages and JSON chapter/image APIs.
### Fixed
- #150 MangaBall search and reader extraction now use the current API flow.
- #151 Mangago connection failures now fail quickly on blocked networks
instead of hanging the multi-source search sweep.
- #152 MangaTaro page extraction now uses the current reader/API flow again.
- #163 macOS release downloads now ship as `.zip` archives containing
`MeManga.app`, so users get a normal launchable app bundle instead of a
raw extensionless binary.
- #167 Linux release downloads now ship as `MeManga-linux-x64.tar.gz` so
the executable bit survives download and extraction. A raw ELF asset
saved through a browser lost its `+x` bit and failed to launch with
"Permission denied"; the tarball records the executable bit inside the
archive, so `tar xzf` restores a runnable binary.
## [0.4.2] - 2026-08-06
### Added
- #147 macOS releases now publish separate Apple Silicon and Intel assets.
## [0.4.1] - 2026-08-02
### Fixed
- #142 MangaFire now signs each JSON API call with a per-request token, so
search, chapter listing, and page fetches no longer fail with HTTP 403.
## [0.4.0] - 2026-07-19
### Added
- #88 Official Docker images are now supported for headless servers, NAS boxes,
Raspberry Pi systems, and cron-style automation. Release tags publish a
CLI-only image to Docker Hub and GitHub Container Registry, while local
`docker build` and Compose workflows remain available for testing.
- #89 Downloads can now run a configurable post-processing command after a
chapter finishes, making it easier to plug MeManga into local conversion,
sync, or automation pipelines.
- #90 CBZ downloads now include ComicInfo.xml metadata so compatible comic
readers can show series, chapter, and title details.
- #104 Reader settings can remove chapters after they are marked read, helping
users keep local storage under control.
- #107 The reader can prefetch the next manual-mode chapter, reducing wait time
when moving through a series.
- #117 Accepted partial downloads are now tracked so missing pages can be
retried without discarding pages that were already saved.
### Changed
- #108 GUI click responsiveness and shared backend performance were improved,
especially around library refreshes and repeated user actions.
- #106 The reader now resumes the last viewed page when reopening a chapter.
- #102 Manual backlog checks now use a trusted chapter catalogue baseline so
suspicious-batch protection does not incorrectly reject intentional backlog
downloads.
### Fixed
- #109 Unix cron setup now quotes scheduled-check paths, so installs work when
the repository path contains spaces or shell-sensitive characters.
- #110 State mutations are consistently synchronized to avoid races between GUI,
background, and persistence paths.
- #111 The reader can locate downloaded chapters even when title or chapter
labels were normalized on disk.
- #112 Download-from-chapter actions no longer crash when history contains
non-numeric or part-style chapter labels.
- #113 Kindle attachment-size errors now report the correct limit and recovery
guidance.
- #114 Backup imports no longer append duplicate titles from the same file.
- #115 Backup imports now preserve existing manga state while merging incoming
records.
- #116 The Settings email test now reports results through the GUI thread instead
of updating Qt widgets from a background thread.
- #118 Auto-mode new-chapter badges now remain stable until the active download
batch finishes.
### Security
- Mail credential handling and download path handling were hardened to reduce
the risk of unsafe paths or credential exposure during local workflows.
## [0.3.3] - 2026-07-12
### Fixed
- #83 MangaDex API requests could fail with HTTP 400 because the shared
scraper session claimed a browser user agent without the `Sec-Fetch-*`
headers MangaDex expects. Default scraper headers now include those
browser fetch metadata headers, restoring MangaDex search and chapter
requests.
- #84 The GUI could falsely report offline on connected networks because
the network probe used TCP port 53, which some Windows networks reject
even while normal HTTPS access works. The probe now checks an HTTPS
host on port 443 so connected users are not blocked by DNS-over-TCP
policy.
### Acknowledgements
- Special thanks to @Camponotus-vagus for the detailed issue diagnostics
and follow-up testing that helped shape the fixes.
## [0.3.2] - 2026-07-08
### Added
- #77 Comix.to is now available as a supported source. Search runs
through the rendered search flow, chapter discovery reads paginated
chapter rows, and reader image extraction/downloads use the headers
required by the site.
- #78 MangaPark is now available as a supported source through
`mangapark1.com`, including search, chapter-list parsing, reader page
extraction, CDN image downloads, and live scraper diagnostics.
- Live scraper diagnostics now include staged parsing probes that make
source-specific breakage easier to confirm without running the full
application workflow.
### Fixed
- #74 MangaFire search now reads the current `/api/titles` JSON payload
instead of scraping the old browser search page, restoring title
discovery for queries such as `one piece`, `ao no hako`, and
`super no ura`.
## [0.3.1] - 2026-07-06
### Fixed
- #71 MangaFire changed its chapter and page endpoints, so saved
MangaFire library entries could no longer fetch real chapter lists.
MangaFire now reads the current `/api` chapter and page payloads,
keeps old saved MangaFire URLs compatible, follows paginated chapter
lists, and deduplicates repeated chapter numbers before update checks
or downloads run.
## [0.3.0] - 2026-06-13
### Added
- #31 CLI-only users had no way to discover manga by title without
leaving the terminal, finding a source URL manually, then pasting it
back into `memanga add`. The new `memanga search` command reuses the
same multi-source search engine as the GUI, with relevance filtering,
source ordering, chapter-count probes, JSON output, and direct add
support.
- #32 The Reader only supported continuous vertical scrolling, which is
awkward for print-style manga where pages are meant to advance one at
a time. Reader layout mode now supports continuous, single-page, and
two-page reading with keyboard navigation and per-manga persistence.
- #35 A source could report a huge bogus chapter jump and MeManga would
trust it, potentially downloading or emailing dozens of incorrect
chapters. Suspicious update batches are now scored before delivery,
checked against backup sources when available, and held back unless
they are confirmed or explicitly forced.
### Changed
- #45 Reader progress previously marked a chapter as read before the
user actually reached the end. The read threshold now waits until the
final portion of the chapter, so library progress reflects real
reading progress instead of early scroll position.
- #46 Clicking the concurrent-downloads slider could snap straight to
the minimum or maximum instead of the clicked value. Slider clicks now
map to the actual clicked position, making the setting predictable.
- Release workflow actions now use Node 24-compatible major versions,
avoiding the GitHub Actions Node 20 deprecation warning before the
v0.3.0 tag build runs.
### Fixed
- #42 Backup import ignored the export schema version, so unsupported
backup data could be accepted silently. Import now validates the
version field before restoring data, giving future migrations a safe
rejection path instead of corrupt or surprising state.
- #43 Reader arrow keys did not navigate, even though page-based
reading expects keyboard controls. Arrow/Page/Home/End handling now
works with the active reader layout mode.
- #44 Very long filename-template previews in Settings could overflow
and break the theme options layout. The preview now stays constrained
inside the settings panel.
- #47 The Downloads page left "Cancel All" enabled when there was no
active or queued work, then reported a misleading cancellation. The
action is now disabled for an empty queue.
- #48 MangaPill cover images could fail to load in the GUI because the
source rejected image requests without its expected referer. Cover
fetching now sends the required source referer.
- #49 The Reader's "Next chapter" button could hide its label, making
the navigation control unclear. The button layout now keeps the label
visible.
## [0.2.2] - 2026-06-10
### Added
- Release builds now run an actual frozen-executable Playwright
self-test before publishing artifacts. Windows runs the no-console
app with null standard handles to match a user double-click; macOS
runs the same `--verify-playwright` gate against the built binary.
- Tagged releases now build and upload Windows, macOS, and Linux
single-file binaries through GitHub Actions.
### Fixed
- #28 Playwright-based sources could still fail inside frozen desktop
builds when the bundled driver looked in the wrong browser cache path
or inherited invalid standard handles from a windowed executable.
MeManga now pins the browser install path for packaged builds,
creates valid hidden subprocess handles where needed, and verifies the
real release artifact before publishing.
- #39 Open-folder buttons in the Windows release exe did nothing because
Explorer was launched through a hidden subprocess path. Folder opening
now uses the platform shell directly so the action works from the
packaged GUI.
- #40 Pause All / Resume All could make queued downloads disappear from
the active downloads tab, and in some flows lose the queued work
entirely. Paused items now stay represented in the queue model and are
restored correctly when downloads resume.
- #41 Renaming a manga could orphan already-downloaded chapter files, so
the Detail page later failed with "couldn't find the chapter". Rename
operations now move the downloaded files along with the library entry.
- #50 "Download All" and explicit "Download from" actions could do
nothing for manual-mode manga: no chapters were queued and the UI gave
no useful feedback. Explicit download actions now bypass the
reading-only update filter and queue the requested chapters.
- #55 Selecting Email to Kindle delivery could prevent manga detail
pages from opening because the delivery setting was normalized through
a stale config shape. The Detail page now accepts the modern email
delivery mode and renders normally.
- MangaFire chapter checks now raise and retry on network errors,
non-JSON responses, HTTP failures, and Cloudflare-wrapped 5xx payloads
instead of silently reporting an empty chapter list.
## [0.2.1] - 2026-06-04
### Fixed
- #28 Playwright-based sources (MangaFire, WeebCentral, Comick,
MangaKatana, …) silently returned no search results in the no-console
release exe. A `console=False` Windows build has null standard
streams, so Playwright's driver subprocess inherited an invalid
stderr handle and failed to start. The frozen entry point now
restores real, file-descriptor-backed streams before any scraper
runs.
- #29 Source-health checks flagged almost every source as "warning":
the slow threshold was 500 ms, but healthy sites routinely answer in
500–2000 ms. Raised to a tunable `State.SLOW_LATENCY_MS` (2500 ms) so
the warning tier is reserved for genuinely slow responses.
- #30 The Detail-page "Check updates" button silently did nothing for
manga whose status wasn't "reading". Explicit per-manga actions now
check regardless of status; only the library-wide sweep keeps the
reading-only filter.
- MangaFire `get_chapters` now raises on network error, non-200,
non-JSON, and wrapped Cloudflare 5xx envelopes (with 3× backoff
retries) instead of returning an empty list, so `check_for_updates`
logs a real error and falls back to the backup source instead of
reporting "No new chapters". MangaDex chapter dedup is now stable
across repeated checks.
## [0.2.0] - 2026-05-28
### Added
- PySide6 desktop GUI (Library / Detail / Reader / Downloads / Search /
Notifications / Sources / Settings) — full rewrite of the user-facing
app.
- First-run Firefox install dialog with streaming progress bar and
collapsible log, replacing the blocking "please wait" message box.
- App icon: a custom open-book + download-chevron mark drawn from
primitives via `scripts/generate_icon.py`. Bundled as multi-resolution
PNG / ICO / ICNS and applied as the window + dock / taskbar icon.
- Offline mode: `NetworkMonitor` daemon publishes online/offline events
on a 30 s / 5 s probe cadence; UI gates network-bound actions and
auto-recovers when the connection returns.
- Search-time chapter-count chips per source so out-of-date or empty
sources are visible at a glance.
- `memanga failed` CLI command: lists, retries, or clears failed
chapter download records.
- Two build modes: `python build.py` (single-file dev exe with console)
and `python build_app.py` (single-file release exe, no console).
- Live scraper health-check test suite under `tests/scrapers/live/`
(opt-in via `-m live`).
- Three previously-orphaned scrapers wired in: `blamemanga.com`,
`jjkmanga.net`, `kagane.org`.
### Changed
- Search now sweeps ~120 curated aggregators (was 290) — template-
based single-manga sites are filtered out by default since their
`search()` only matches their own keyword list.
- Search results are sorted by source popularity (MangaDex first,
then MangaPill, MangaFire, …).
- Search results are filtered for query relevance — single-manga
aggregators no longer pollute results with their hardcoded title.
- WeebCentral search hits the real `/search/data?text=…` HTMX endpoint
directly instead of typing into the quick-search sidebar, so results
actually filter to the query.
- MangaFire search reuses a persistent Firefox via the existing
`VRFGenerator` singleton instead of launching a fresh browser per
call (~10× faster after warm-up).
- Each `PlaywrightScraper` subclass now owns its own
`ThreadPoolExecutor` + lock, so WeebCentral / Comick / MangaKatana /
MangaClash run in parallel inside the search worker pool instead of
queueing through a single shared browser thread.
- Email attachment threshold lowered from 23 MB to 18 MB to account
for base64 encoding overhead (Gmail's 25 MB limit applies to the
encoded size).
- Partial chapter downloads are no longer silently saved as an
incomplete CBZ. The downloader retries failed pages up to 3× with
exponential backoff and raises `DownloaderError` if pages are still
missing — the chapter is not marked as downloaded.
### Fixed
- `_get_browser_in_thread` is now atomic: on `firefox.launch()` failure
it rolls back `sync_playwright().start()` instead of leaving
`_thread_local.playwright` half-set, which previously crashed every
subsequent scraper on the same worker thread.
- Windows release builds bundle `keyring.backends.Windows` +
`pywin32_ctypes` as explicit PyInstaller hidden imports, so saved
email passwords persist via the Credential Manager instead of being
silently discarded by keyring's `Null` backend.
- Windows release builds no longer flash a `cmd.exe` window when the
scheduled-task helpers run (`schtasks` calls now pass
`no_window_kwargs()`).
- Bundled-driver Playwright install path correctly unpacks the
`(node, cli)` tuple returned by `compute_driver_executable` on
playwright >= 1.40 — previously failed silently with
`FileNotFoundError`.
- Notable historical issues closed:
- #13 GUI palette mismatch with theme tokens
- #14 "Cancel all" wasn't draining the download queue
- #15 Detail page wasn't preserving the downloaded-chapter list
- #16 Reader's Ctrl+wheel zoom was firing on plain wheel
- #18 Library cards didn't show read count
- #20 `download_from N` didn't update last_chapter threshold
- #21 Reader pan wasn't enabled when zoomed
- #23 Output paths weren't ending up under `<dir>/<title>/`
- #26 Failed downloads created an incomplete CBZ marked complete
### Removed
- Design references (HTML/CSS/JS used during the GUI port) are no
longer tracked.
- Internal "Not implemented" punch list moved out of the repo.
## Earlier versions
Pre-PySide6 versions tracked the CLI-only releases — see the git tag
history (`v0.0.x` → `v0.1.0`) for details.