## ℹ️ Description
- Moves APR preview information out of verify output and into status
reporting.
- Improves status output into readable per-ad blocks with full relative
file paths and structured APR update/publish details.
## 📋 Changes Summary
- Keep verify focused on validation while preserving its full ad-loading
validation path.
- Show APR preview details in status without requiring verbose mode.
- Render status as path-first per-ad report lines with title, id,
status, APR update/publish details, and unchanged summary.
- Use structured APR detail data and translated human-readable reasons
instead of raw reason tokens.
- Remove the now-dead APR preview logger and stale translations.
- Update CLI help, README/docs, smoke tests, and focused unit tests.
### ⚙️ Type of Change
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [x] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
- [x] I have reviewed my changes to ensure they meet the project
standards.
- [x] I have tested my changes and ensured that all tests pass (pdm run
test).
- [x] I have formatted the code (pdm run format).
- [x] I have verified that linting passes (pdm run lint).
- [x] I have updated documentation where necessary.
Validation run:
- pdm run format
- pdm run lint
- pdm run test — 1467 passed, 4 skipped
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* `status` now shows detailed APR preview information for ads in a
clearer, per-ad layout.
* Help text and documentation now point users to `status` for APR
preview details.
* **Bug Fixes**
* `verify` no longer displays APR preview output, making its results
focused on configuration and integrity checks.
* Improved status output readability and APR detail handling for publish
and update scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
- Link to the related issue(s): Issue #
- Clarifies what `download` can infer for shipping options after the old
cheapest-option limitation became inaccurate.
## 📋 Changes Summary
- Replaces the outdated README limitation with the current download
shipping inference behavior.
- Documents pickup handling, `Versand möglich` without price, visible
shipping prices, inferred `shipping_options`,
`download.include_all_matching_shipping_options`, and `sell_directly`
scope.
- No dependency or configuration changes.
### ⚙️ Type of Change
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Updated the README “download” limitations to clarify that shipping
details are inferred dynamically.
* Added a detailed explanation of how pickup vs. “Versand möglich”
listings are handled, how “shipping from” prices map to shipping costs
and options, and how direct-buy eligibility is determined.
* Documented the option to include all matching non-excluded shipping
options during download.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
- Link to the related issue(s): N/A
- Keeps the README Usage command block in sync with the CLI help by
generating it as part of the artifact pipeline.
## 📋 Changes Summary
- Added a README Usage generator that renders normalized English CLI
help between explicit README markers.
- Added `generate-readme-commands` and wired it into
`generate-artifacts`.
- Extended generated artifact checks to detect README Usage drift
without mutating files.
- Added focused unit tests for marker replacement, locale/executable
normalization, ANSI stripping, and command coverage.
- No dependency changes introduced.
### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [x] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Kept the README “Usage” section automatically synchronized with the
app’s CLI help.
* Added a new `--preserve-local-settings` option to the CLI help output.
* **Bug Fixes**
* Improved and clarified CLI command/option descriptions (notably around
`verify`, `extend`, and `update` behavior).
* CI now fails early if the generated README “Usage” content is out of
date.
* **Documentation**
* Regenerated the README “Usage” console block to reflect the latest
help text and command details.
* Updated agent guidance to match the expanded README generation
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
- Link to the related issue(s): N/A
- Shortens the pip-only install note in the README so it is a side note
rather than prominent guidance.
## 📋 Changes Summary
- Condensed the pip-only note from a long block to two lines.
- No dependencies, configuration changes, or additional requirements
introduced.
### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [ ] I have tested my changes and ensured that all tests pass (`pdm run
test`). Not run; documentation-only change.
- [ ] I have formatted the code (`pdm run format`). Not run;
documentation-only change.
- [ ] I have verified that linting passes (`pdm run lint`). Not run;
documentation-only change.
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
## ℹ️ Description
- Link to the related issue(s): Issue #1184
- Fixes two publish-flow failures reported in issue #1184:
- persistent nodriver `ProtocolException(code=-32601)` could spin
forever in `web_await()` while repeatedly re-attaching the CDP session;
- special-attribute button comboboxes in the Handy & Telefon category
needed open/read/select to happen atomically in one browser execution.
## 📋 Changes Summary
- Bound `web_await()` CDP reattach retries by the configured timeout and
add a short nonzero retry delay to avoid event-loop starvation.
- Update special-attribute button-combobox selection to use one async
`web_execute()` script that opens via pointer/mouse events, discovers
options, matches API values, and clicks the selected option before the
dropdown can close.
- Add regression tests for bounded `-32601` retry behavior and atomic
button-combobox selection.
- Update the German translation for the enhanced combobox failure
message.
- Verified with the live `button-combobox` DOM probe.
### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
## Validation
- `pdm run format`
- `pdm run lint`
- `pdm run test` — 1370 passed, 4 skipped
- `pdm run python data/verify_dom_assumptions.py run --yes --probe
button-combobox --report
data/.temp/dom-assumptions-issue-1184-button-combobox.json` — passed
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved dropdown/combobox option selection with stronger matching and
more informative timeout/error reporting.
* Tightened CDP re-attach retry logic to strictly follow the remaining
timeout budget.
* Added a startup runtime warning if the required nodriver CDP re-attach
patch isn’t detected.
* **Documentation / Chores**
* Updated source installation guidance (pip-only users) to ensure the
nodriver patch is applied.
* Made the nodriver fix script marker-based and idempotent, including
normalization of legacy patched installs.
* **Tests**
* Expanded unit tests for combobox selection, re-attach timeout/bounds
behavior, CLI patch warning behavior, and the nodriver fix script.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Description
- Link to the related issue(s): Issue #1077
- Align Docker image tags with the existing GitHub release channels so
`main` publishes preview images and `release` publishes stable latest
images.
## Changes Summary
- Publish per-arch Docker images as `preview-amd64` / `preview-arm64`
from `main`.
- Publish per-arch Docker images as `latest-amd64` / `latest-arm64` from
`release`.
- Stitch the matching multi-arch channel manifest as `:preview` or
`:latest`.
- Document `:latest` as the stable Docker image tag and mention
`:preview` in the README.
### Type of Change
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (adds new functionality without breaking existing
usage)
- [ ] Breaking change (changes that might break existing user setups,
scripts, or configurations)
## Validation
- [x] `pdm run format`
- [x] `pdm run lint`
- [x] `pdm run test` (`1176 passed, 4 skipped`)
## Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Docker preview channel is now available for testing
* **Documentation**
* Updated Docker installation instructions with image references and
guidance on using the preview channel
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
Adds support for `${KLEINANZEIGEN_BOT_USERNAME}` and
`${KLEINANZEIGEN_BOT_PASSWORD}` environment variable substitution in
`login.username` and `login.password` config values. Also supports
`${VAR:-default}` fallback syntax.
This allows users to commit `config.yaml` to VCS without exposing
credentials.
Closes#1060.
## 📋 Changes Summary
- New `_resolve_login_credentials()` static method on `KleinanzeigenBot`
— resolves `${VAR}` and `${VAR:-default}` patterns from `os.environ` for
`login.username` and `login.password` only
- Called in `load_config()` after YAML loading, before Pydantic
validation — `LoginConfig` model remains unchanged (`Field(...,
min_length=1)`)
- Module-level `_LOGIN_ENV_PATTERN` regex for the `${VAR}` /
`${VAR:-default}` pattern
- Guard against non-dict YAML input (passes through to Pydantic for
clean validation errors)
- Updated `README.md` and `docs/CONFIGURATION.md` with env var examples
- Removed obsolete "Config file not found" translation (no longer
raised)
- 9 new unit tests in `TestResolveLoginCredentials` covering resolution,
fallback, error cases, edge cases, and `load_config` integration
### ⚙️ Type of Change
- [x] ✨ New feature (adds new functionality without breaking existing
usage)
## ✅ Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Login credentials support environment variable substitution using
${VARIABLE} with optional fallbacks (${VARIABLE:-default}); plaintext
values remain supported.
* **Documentation**
* Configuration docs updated with YAML and shell examples (exporting
variables) and an explicit security note advising against committing
plaintext credentials.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/Second-Hand-Friends/kleinanzeigen-bot/pull/1061?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
Autoselect kernel name and arch
- Link to the related issue(s): non
- Motiviation: The current install command hardcodes `amd64` as the
target architecture. This caused me quite some frustration when setting
up the bot on my Apple Silicon Mac — I initially downloaded the wrong
binary without realizing it, and it took me a while to figure out that
architecture-specific binaries exist for both `amd64` and `arm64`.
This change makes the install command automatically detect the correct
architecture and OS at runtime using `uname`, so users get the right
binary without having to know or think about their system architecture.
This should lower the barrier for new users and prevent silent failures
on Apple Silicon machines.
## 📋 Changes Summary
Autoselect kernel name and arch for install command
### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Simplified Linux/macOS installation instructions by consolidating them
into a single step with automatic OS detection, removing the need for
separate OS-specific commands.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
Documentation-only update to clarify how `ad_files` differs from
download naming templates and how published IDs are handled.
- Link to the related discussion:
https://github.com/Second-Hand-Friends/kleinanzeigen-bot/discussions/839
- Describe the motivation and context for this change: reduce confusion
around downloaded ad naming and local file behavior.
## 📋 Changes Summary
- Clarified `ad_files` as a file-selection glob, separate from download
naming.
- Added concrete sample ID/title render examples for folder and file
templates.
- Documented that publish updates the YAML `id` in place and does not
auto-rename local files or folders.
- Regenerated config docs and schema artifacts to keep generated output
in sync.
### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Expanded ad configuration and setup documentation with improved
guidance on file pattern matching and download directory configuration.
* Clarified how placeholder templates work in file naming, including
required and optional parameters.
* Added comprehensive examples demonstrating template rendering and
configuration best practices.
* Documented republish behavior and workflow guidance for managing
downloaded ad files.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
*Provide a concise summary of the changes introduced in this pull
request.*
- Link to the related issue(s): Discussion #997
- Add a link to the ui project at
https://github.com/bkd3sign/kleinanzeigen-bot-ui
## 📋 Changes Summary
Just the additional link in the README.md
### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [x] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Added reference to a related TypeScript-based web interface tool in
the project documentation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
Automatic price reduction now works reliably during `update` runs
(MODIFY mode), not only during `publish`, while staying backward
compatible for existing configurations. The verify flow also explains
what will happen in both modes before any command touches live ads.
- Link to the related issue(s): Issue # N/A
- Describe the motivation and context for this change.
- Update-mode reductions needed to be explicitly opt-in so existing
setups remain unchanged by default.
- Pricing behavior had to stay deterministic across retries and mixed
publish/update workflows.
- Preview output and documentation now mirror real runtime behavior so
configuration decisions are easier to trust.
## 📋 Changes Summary
- Added `auto_price_reduction.on_update` (`bool`, default `false`) in
model/schema so update-mode reductions are explicitly opt-in.
- Refactored price reduction flow into decision + apply steps:
- `evaluate_auto_price_reduction(...)` computes mode-aware outcomes
- `apply_auto_price_reduction(...)` applies mutations and logs from that
decision
- Implemented restore-first behavior so effective reduced price is
recomputed from base `price` + `price_reduction_count` before deciding a
new cycle.
- Updated `verify` to preview both publish and update outcomes.
- Kept update-mode semantics explicit:
- `delay_days` applies
- `delay_reposts` is ignored in MODIFY mode
- Fixed retry idempotency in `publish_ads` by restoring baseline `price`
and `price_reduction_count` before each retry.
- Addressed follow-up review feedback:
- no-visible-change cycles advance counters (for fractional
accumulation)
- verify output stays non-misleading for no-visible-change cases
- tightened a unit assertion from `>= 1` to `== 1`
- tightened smoke behavior for `create-config` when config already
exists
- clarified README/docs and documented `price_reduction_count` as
auto-managed
- Expanded/updated tests for:
- MODIFY `on_update` behavior
- restore-first invariant
- cross-mode interactions
- retry baseline reset
- verify mode previews
- floor-clamped no-visible-change counter advancement
Mention any dependencies, configuration changes, or additional
requirements introduced.
- Configuration change: new optional field
`auto_price_reduction.on_update` (default `false`, backward compatible).
- No external runtime dependency changes.
- Existing configurations continue to work unchanged unless `on_update`
is enabled.
### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [x] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* `verify` now previews automatic price-reduction outcomes for both
publish and update modes.
* New config option (auto_price_reduction.on_update, default false) to
enable reductions during update runs.
* **Documentation**
* Clarified publish vs. update reduction behavior, timing rules,
restore-first semantics, logging, examples, and troubleshooting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
Refactors and reorganizes documentation to improve navigation and keep
the README concise.
- Link to the related issue(s): Issue #N/A
- Describe the motivation and context for this change.
- The README had grown long and duplicated detailed config/ad
references; this consolidates docs into focused guides and adds an
index.
## 📋 Changes Summary
- Add dedicated docs pages for configuration, ad configuration, update
checks, and a docs index.
- Slim README and CONTRIBUTING to reference dedicated guides and clean
up formatting/markdownlint issues.
- Refresh browser troubleshooting and update-check guidance; keep the
update channel name aligned with schema/implementation.
- Add markdownlint configuration for consistent docs formatting.
### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [x] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Reorganized and enhanced contributing guidelines with improved
structure and formatting
* Streamlined README with better organization and updated installation
instructions
* Added comprehensive configuration reference documentation for
configuration and ad settings
* Improved browser troubleshooting guide with updated guidance,
examples, and diagnostic information
* Created new documentation index for easier navigation
<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
- Link to the related issue(s): Issue #761
- Describe the motivation and context for this change.
- This PR bundles several small fixes identified during recent testing,
covering issue #761 and related publishing/download edge cases.
## 📋 Changes Summary
- Avoid crashes in `download --ads=new` when existing local ads lack an
ID; skip those files for the “already downloaded” set and log a clear
reason.
- Harden publishing contact fields: clear ZIP before typing; tolerate
missing phone field; handle missing street/name/ZIP/location gracefully
with warnings instead of aborting.
- Improve location selection by matching full option text or the
district suffix after ` - `.
- Preserve `contact.location` in defaults (config model + regenerated
schema with example).
### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Release Notes
* **New Features**
* Added optional location field to contact configuration for specifying
city/locality details in listings.
* Enhanced contact field validation with improved error handling and
fallback mechanisms.
* **Bug Fixes**
* Ad download process now gracefully handles unpublished or manually
created ads instead of failing.
* **Documentation**
* Clarified shipping type requirements and cost configuration guidance
in README.
<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
Add a manual "extend" command to extend listings shortly before they
expire. This keeps existing watchers/savers and does not count toward
the current 100 ads/month quota.
- Link to the related issue(s): Issue #664
- **Motivation**: Users need a way to extend ads before they expire
without republishing (which consumes quota).
## 📋 Changes Summary
### Implementation
- Add `extend` command case in `run()`
- Implement `extend_ads()` to filter and process eligible ads
- Implement `extend_ad()` for browser automation
- Add German translations for all user-facing messages
### Testing
- Tests cover: filtering logic, date parsing, browser automation, error
handling, edge cases
### Features
- Detects ads within the **8-day extension window** (kleinanzeigen.de
policy)
- Uses API `endDate` from `/m-meine-anzeigen-verwalten.json` for
eligibility
- Only extends active ads (`state == "active"`)
- Handles confirmation dialog (close dialog / skip paid bump-up)
- Updates `updated_on` in YAML after successful extension
- Supports `--ads` parameter to extend specific ad IDs
### Usage
```bash
kleinanzeigen-bot extend # Extend all eligible ads
kleinanzeigen-bot extend --ads=1,2,3 # Extend specific ads
```
### ⚙️ Type of Change
- [x] ✨ New feature (adds new functionality without breaking existing
usage)
## ✅ Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have updated documentation where necessary (help text in English
+ German).
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added an "extend" command to find ads nearing expiry (default 8-day
window) or target specific IDs, open a session, attempt extensions, and
record per-ad outcomes.
* **Documentation**
* Updated CLI/help (bilingual) and README to document the extend
command, options (--ads), default behavior, and expiry-window
limitations.
* **Tests**
* Added comprehensive unit tests for eligibility rules, date parsing
(including German format), edge cases, UI interaction flows, timing, and
error handling.
<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
This PR fixes intermittent login detection failures where the bot fails
to detect existing login sessions and unnecessarily re-logins,
potentially causing IP blocks.
- Link to the related issue(s): Issue #701
- Describe the motivation and context for this change:
Users reported that the bot sometimes fails to detect existing login
sessions (50/50 behavior), especially for browser profiles that haven't
been used for 20+ days. This appears to be a race condition where:
1. `web_open()` completes when `document.readyState == 'complete'`
2. But kleinanzeigen.de's client-side JavaScript hasn't yet rendered
user profile elements
3. The login detection timeout (5s default) is too short for slow
networks or sessions requiring server-side validation
## 📋 Changes Summary
- **Add dedicated `login_detection` timeout** to `TimeoutConfig`
(default: 10s, previously used generic 5s timeout)
- **Apply timeout to both DOM checks** in `is_logged_in()`: `.mr-medium`
and `#user-email` elements
- **Add debug logging** to track which element detected login or if no
login was found
- **Regenerate JSON schema** to include new timeout configuration
- **Effective total timeout**: ~22.5s (10s base × 1.0 multiplier × 1.5
backoff × 2 retries) vs previous ~11.25s
### Benefits:
- Addresses race condition between page load completion and client-side
rendering
- Provides sufficient time for sessions requiring server-side validation
(20+ days old)
- User-configurable via `timeouts.login_detection` in `config.yaml`
- Follows established pattern of dedicated timeouts (`sms_verification`,
`gdpr_prompt`, etc.)
### ⚙️ Type of Change
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a configurable login-detection timeout (default 10s, min 1s) to
tune session detection.
* **Bug Fixes**
* More reliable login checks using a timeout-aware, two-step detection
sequence.
* Improved diagnostic logging for login attempts, retry behavior,
detection outcomes, and timeout events.
* **Documentation**
* Added troubleshooting guidance explaining the login-detection timeout
and when to adjust it.
<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
Fixes a race condition where ads were submitted before all images
finished uploading to the server, causing some images to be missing from
published ads.
- Link to the related issue(s): Issue #715
- The bot was submitting ads immediately after the last image
`send_file()` call completed, only waiting 1-2.5 seconds via
`web_sleep()`. This wasn't enough time for server-side image processing,
thumbnail generation, and DOM updates to complete, resulting in missing
images in published ads.
## 📋 Changes Summary
### Image Upload Verification (Initial Fix)
- Added thumbnail verification in `__upload_images()` method to wait for
all image thumbnails to appear in the DOM after upload
- Added configurable timeout `image_upload` to `TimeoutConfig` (default:
30s, minimum: 5s)
- Improved error messages to show expected vs actual image count when
upload times out
- Added German translations for new log messages and error messages
- Regenerated JSON schemas to include new timeout configuration
### Polling Performance & Crash Fix (Follow-up Fix)
- Fixed critical bug where `web_find_all()` would raise `TimeoutError`
when no thumbnails exist yet, causing immediate crash
- Wrapped DOM queries in `try/except TimeoutError` blocks to handle
empty results gracefully
- Changed polling to use `self._timeout("quick_dom")` (~1s with PR #718)
instead of default timeout
- Improved polling performance: reduced cycle time from ~2s to ~1.5s
- DOM queries are client-side only (no server load from frequent
polling)
**New configuration option:**
```yaml
timeouts:
image_upload: 30.0 # Total timeout for image upload and server-side processing
quick_dom: 1.0 # Per-poll timeout for thumbnail checks (adjustable via multiplier)
```
The bot now polls the DOM for `ul#j-pictureupload-thumbnails >
li.ui-sortable-handle` elements after uploading images, ensuring
server-side processing is complete before submitting the ad form.
### ⚙️ Type of Change
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Image uploads now verify completion by waiting for all uploaded
thumbnails to appear before proceeding.
* **Improvements**
* Added a configurable image upload timeout (default 30s, minimum 5s).
* Improved timeout reporting: when thumbnails don’t appear in time, the
app returns clearer feedback showing expected vs. observed counts.
<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ℹ️ Description
This PR addresses issue #708 by improving the README's About section to
make the bot's purpose clearer to new users. It also fixes a technical
inaccuracy in the configuration documentation.
- Link to the related issue(s): Issue #708
- **Motivation**: The current About section uses ambiguous terminology
("ads" instead of "listings") and doesn't clearly communicate what the
bot does. Additionally, the configuration example incorrectly documents
`shipping_costs` as available in `ad_defaults`, when it's only
implemented for per-ad configuration.
## 📋 Changes Summary
**About Section Improvements:**
- Changed "ads" to "listings" for clarity (addresses confusion mentioned
in #708)
- Added "Key Features" section with 6 concrete capabilities
- Added "Why This Project?" section explaining the rewrite and
differences from legacy client
- Preserved all legal disclaimers
**Configuration Documentation Fix:**
- Removed `shipping_costs` from `ad_defaults` example (not implemented
in `AdDefaults` Pydantic class)
- Added clarifying comment that `shipping_costs` and `shipping_options`
must be configured per-ad
- Verified `shipping_costs` remains documented in ad configuration
section
### ⚙️ Type of Change
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
*Note: This is a documentation-only change with no code modifications.*
## ✅ Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (N/A -
documentation only).
- [x] I have formatted the code (N/A - documentation only).
- [x] I have verified that linting passes (N/A - documentation only).
- [x] I have updated documentation where necessary.
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
## ℹ️ Description
- Related issues: #671, #658
- Introduces configurable timeout controls plus retry/backoff handling
for flaky DOM operations.
We often see timeouts which are note reproducible in certain
configurations. I suspect timeout issues based on a combination of
internet speed, browser, os, age of the computer and the weather.
This PR introduces a comprehensive config model to tweak timeouts.
## 📋 Changes Summary
- add TimeoutConfig to the main config/schema and expose timeouts in
README/docs
- wire WebScrapingMixin, extractor, update checker, and browser
diagnostics to honor the configurable timeouts and retries
- update translations/tests to cover the new behaviour and ensure
lint/mypy/pyright pipelines remain green
### ⚙️ Type of Change
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [x] ✨ New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)
## ✅ Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Centralized, configurable timeout system for web interactions,
detection flows, publishing, and pagination.
* Optional retry with exponential backoff for operations that time out.
* **Improvements**
* Replaced fixed wait times with dynamic timeouts throughout workflows.
* More informative timeout-related messages and diagnostics.
* **Tests**
* New and expanded test coverage for timeout behavior, pagination,
diagnostics, and retry logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
feat(update-check): add robust update check with interval support, state management, and CLI integration
- Implement version and interval-based update checks with configurable settings
- Add CLI command `kleinanzeigen-bot update-check` for manual checks
- Introduce state file with versioning, UTC timestamps, and migration logic
- Validate and normalize intervals (1d–4w) with fallback for invalid values
- Ensure correct handling of timezones and elapsed checks
- Improve error handling, logging, and internationalization (i18n)
- Add comprehensive test coverage for config, interval logic, migration, and CLI
- Align default config, translations, and schema with new functionality
- Improve help command UX by avoiding config/log loading for `--help`
- Update documentation and README with full feature overview
This commit implements a new 'changed' selector for the --ads option that
publishes only ads that have been modified since their last publication.
The 'due' selector now only republishes ads based on the time interval,
without considering content changes.
The implementation allows combining selectors with commas (e.g., --ads=changed,due)
to publish both changed and due ads. Documentation and translations have been
updated accordingly.
Fixes#411