mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-07-09 12:41:05 +02:00
main
1044 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
305ee52576 |
ci(deps): bump github/codeql-action from 4.35.2 to 4.35.3 in the all-actions group (#1029)
Bumps the all-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 4.35.2 to 4.35.3 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/github/codeql-action/releases">github/codeql-action's releases</a>.</em></p> <blockquote> <h2>v4.35.3</h2> <ul> <li><em>Upcoming breaking change</em>: Add a deprecation warning for customers using CodeQL version 2.19.3 and earlier. These versions of CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise Server 3.15, and will be unsupported by the next minor release of the CodeQL Action. <a href="https://redirect.github.com/github/codeql-action/pull/3837">#3837</a></li> <li>Configurations for private registries that use Cloudsmith or GCP OIDC are now accepted. <a href="https://redirect.github.com/github/codeql-action/pull/3850">#3850</a></li> <li>Best-effort connection tests for private registries now use <code>GET</code> requests instead of <code>HEAD</code> for better compatibility with various registry implementations. For NuGet feeds, the test is now always performed against the service index. <a href="https://redirect.github.com/github/codeql-action/pull/3853">#3853</a></li> <li>Fixed a bug where two diagnostics produced within the same millisecond could overwrite each other on disk, causing one of them to be lost. <a href="https://redirect.github.com/github/codeql-action/pull/3852">#3852</a></li> <li>Update default CodeQL bundle version to <a href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.3">2.25.3</a>. <a href="https://redirect.github.com/github/codeql-action/pull/3865">#3865</a></li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action's changelog</a>.</em></p> <blockquote> <h1>CodeQL Action Changelog</h1> <p>See the <a href="https://github.com/github/codeql-action/releases">releases page</a> for the relevant changes to the CodeQL CLI and language packs.</p> <h2>[UNRELEASED]</h2> <p>No user facing changes.</p> <h2>4.35.3 - 01 May 2026</h2> <ul> <li><em>Upcoming breaking change</em>: Add a deprecation warning for customers using CodeQL version 2.19.3 and earlier. These versions of CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise Server 3.15, and will be unsupported by the next minor release of the CodeQL Action. <a href="https://redirect.github.com/github/codeql-action/pull/3837">#3837</a></li> <li>Configurations for private registries that use Cloudsmith or GCP OIDC are now accepted. <a href="https://redirect.github.com/github/codeql-action/pull/3850">#3850</a></li> <li>Best-effort connection tests for private registries now use <code>GET</code> requests instead of <code>HEAD</code> for better compatibility with various registry implementations. For NuGet feeds, the test is now always performed against the service index. <a href="https://redirect.github.com/github/codeql-action/pull/3853">#3853</a></li> <li>Fixed a bug where two diagnostics produced within the same millisecond could overwrite each other on disk, causing one of them to be lost. <a href="https://redirect.github.com/github/codeql-action/pull/3852">#3852</a></li> <li>Update default CodeQL bundle version to <a href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.3">2.25.3</a>. <a href="https://redirect.github.com/github/codeql-action/pull/3865">#3865</a></li> </ul> <h2>4.35.2 - 15 Apr 2026</h2> <ul> <li>The undocumented TRAP cache cleanup feature that could be enabled using the <code>CODEQL_ACTION_CLEANUP_TRAP_CACHES</code> environment variable is deprecated and will be removed in May 2026. If you are affected by this, we recommend disabling TRAP caching by passing the <code>trap-caching: false</code> input to the <code>init</code> Action. <a href="https://redirect.github.com/github/codeql-action/pull/3795">#3795</a></li> <li>The Git version 2.36.0 requirement for improved incremental analysis now only applies to repositories that contain submodules. <a href="https://redirect.github.com/github/codeql-action/pull/3789">#3789</a></li> <li>Python analysis on GHES no longer extracts the standard library, relying instead on models of the standard library. This should result in significantly faster extraction and analysis times, while the effect on alerts should be minimal. <a href="https://redirect.github.com/github/codeql-action/pull/3794">#3794</a></li> <li>Fixed a bug in the validation of OIDC configurations for private registries that was added in CodeQL Action 4.33.0 / 3.33.0. <a href="https://redirect.github.com/github/codeql-action/pull/3807">#3807</a></li> <li>Update default CodeQL bundle version to <a href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.2">2.25.2</a>. <a href="https://redirect.github.com/github/codeql-action/pull/3823">#3823</a></li> </ul> <h2>4.35.1 - 27 Mar 2026</h2> <ul> <li>Fix incorrect minimum required Git version for <a href="https://redirect.github.com/github/roadmap/issues/1158">improved incremental analysis</a>: it should have been 2.36.0, not 2.11.0. <a href="https://redirect.github.com/github/codeql-action/pull/3781">#3781</a></li> </ul> <h2>4.35.0 - 27 Mar 2026</h2> <ul> <li>Reduced the minimum Git version required for <a href="https://redirect.github.com/github/roadmap/issues/1158">improved incremental analysis</a> from 2.38.0 to 2.11.0. <a href="https://redirect.github.com/github/codeql-action/pull/3767">#3767</a></li> <li>Update default CodeQL bundle version to <a href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.1">2.25.1</a>. <a href="https://redirect.github.com/github/codeql-action/pull/3773">#3773</a></li> </ul> <h2>4.34.1 - 20 Mar 2026</h2> <ul> <li>Downgrade default CodeQL bundle version to <a href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3">2.24.3</a> due to issues with a small percentage of Actions and JavaScript analyses. <a href="https://redirect.github.com/github/codeql-action/pull/3762">#3762</a></li> </ul> <h2>4.34.0 - 20 Mar 2026</h2> <ul> <li>Added an experimental change which disables TRAP caching when <a href="https://redirect.github.com/github/roadmap/issues/1158">improved incremental analysis</a> is enabled, since improved incremental analysis supersedes TRAP caching. This will improve performance and reduce Actions cache usage. We expect to roll this change out to everyone in March. <a href="https://redirect.github.com/github/codeql-action/pull/3569">#3569</a></li> <li>We are rolling out improved incremental analysis to C/C++ analyses that use build mode <code>none</code>. We expect this rollout to be complete by the end of April 2026. <a href="https://redirect.github.com/github/codeql-action/pull/3584">#3584</a></li> <li>Update default CodeQL bundle version to <a href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.0">2.25.0</a>. <a href="https://redirect.github.com/github/codeql-action/pull/3585">#3585</a></li> </ul> <h2>4.33.0 - 16 Mar 2026</h2> <ul> <li> <p>Upcoming change: Starting April 2026, the CodeQL Action will skip collecting file coverage information on pull requests to improve analysis performance. File coverage information will still be computed on non-PR analyses. Pull request analyses will log a warning about this upcoming change. <a href="https://redirect.github.com/github/codeql-action/pull/3562">#3562</a></p> <p>To opt out of this change:</p> <ul> <li><strong>Repositories owned by an organization:</strong> Create a custom repository property with the name <code>github-codeql-file-coverage-on-prs</code> and the type "True/false", then set this property to <code>true</code> in the repository's settings. For more information, see <a href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">Managing custom properties for repositories in your organization</a>. Alternatively, if you are using an advanced setup workflow, you can set the <code>CODEQL_ACTION_FILE_COVERAGE_ON_PRS</code> environment variable to <code>true</code> in your workflow.</li> <li><strong>User-owned repositories using default setup:</strong> Switch to an advanced setup workflow and set the <code>CODEQL_ACTION_FILE_COVERAGE_ON_PRS</code> environment variable to <code>true</code> in your workflow.</li> </ul> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href=" |
||
|
|
c9894d4aea |
docs: unify Linux and Mac installation command (#1028)
## ℹ️ 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 --> |
||
|
|
e0857fb9d6 |
chore: ✔ Update types-requests 2.33.0.20260408 -> 2.33.0.20260503 (#1027)
✔ Update types-requests 2.33.0.20260408 -> 2.33.0.20260503 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
bd422fbf0f | chore: ✔ Update typer 0.25.0 -> 0.25.1 (#1026) | ||
|
|
5674d65bf4 |
fix(publish): prioritize mapped condition values (#1025)
## ℹ️ Description Fixes the legacy condition probe order from issue #1002 by trying the mapped/API value first and keeping the legacy value as fallback. ## 📋 Changes Summary - Reorder `__set_condition()` candidate probing so the mapped API value is tried before the configured legacy value. - Keep the minimal regression coverage for mapped-first and fallback behavior. ### ⚙️ 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. Fixes #1002 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Bug Fixes** * Improved condition value handling by prioritizing API-mapped values over legacy configuration tokens for better compatibility * Enhanced fallback mechanism for condition selection when preferred UI elements are unavailable, ensuring proper value translation and fallback to generic handlers <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d843672865 |
ci(deps): bump vegardit/fast-apt-mirror.sh from 1.4.3 to 1.4.4 in the all-actions group (#1022)
Bumps the all-actions group with 1 update: [vegardit/fast-apt-mirror.sh](https://github.com/vegardit/fast-apt-mirror.sh). Updates `vegardit/fast-apt-mirror.sh` from 1.4.3 to 1.4.4 <details> <summary>Commits</summary> <ul> <li><a href=" |
||
|
|
56ba21b899 |
feat(publish): warn on legacy German condition values (#1021)
## ℹ️ Description *Provide a concise summary of the changes introduced in this pull request.* - Link to the related issue(s): Issue #1001 - Describe the motivation and context for this change: surface a warning when legacy German condition tokens are still used so users can migrate to the current English API values. ## 📋 Changes Summary - Logs a warning in `KleinanzeigenBot.__set_condition()` when a legacy German condition value is mapped to a newer API value. - Preserves the existing fallback behavior so legacy configs continue to work. - Adds unit coverage for legacy warning behavior, English values, and the dialog-unavailable path. - Adds a German translation for the warning message. ### ⚙️ 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 * **Chores** * Added deprecation warning when using legacy condition configuration values, guiding users to update their settings. * **Tests** * Enhanced test coverage for condition value handling and deprecation messaging to ensure proper system behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
e0ca47ba0b |
chore: ✔ Update pathspec 1.1.0 -> 1.1.1 (#1020)
✔ Update pathspec 1.1.0 -> 1.1.1 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
2c45a51d3f |
fix: guard condition mappings against API drift (#1019)
## ℹ️ Description *Provide a concise summary of the changes introduced in this pull request.* - Link to the related issue(s): Issue #1004 - Add import-time validation to catch condition API drift early. ## 📋 Changes Summary - Introduce a shared canonical set of allowed condition API values in `src/kleinanzeigen_bot/model/ad_model.py`. - Validate the publish and extract condition mapping tables at import time. - Keep the two mapping tables independent while failing fast on unknown API codes. - Clean up a few low-value tests in the touched area to focus on behavior instead of constant snapshots. ### ⚙️ 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`). - [ ] 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 * **Tests** * Added a unit test to ensure invalid condition mappings are rejected with a clear error. * Enhanced a test to assert that a truncation warning is logged when title length limits are hit. * **Chores** * Added upfront validation of condition mappings at initialization to surface invalid configurations early with detailed error messages. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
ea7c799fec |
fix(logging): clarify delete, upload and price logs (#1018)
## ℹ️ Description - Improve logging for ad deletion outcomes, image upload progress, and auto price reduction transitions. - Clean up nearby tests by removing brittle log-wording assertions while preserving behavior coverage. - Link to the related issue(s): N/A - Describe the motivation and context for this change. ## 📋 Changes Summary - Log success/skipped outcomes for delete operations. - Log image uploads as `uploading image 1/16`. - Include price transitions in auto price reduction logs. - Update translations and tests accordingly. ### ⚙️ 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 * **Bug Fixes** * Enhanced logging clarity for auto price reduction operations with improved price transition reporting * Improved ad deletion lifecycle logs with clearer messaging for skipped and successful deletions * Added progress indicators (image index/total) to image upload logging for better operation tracking <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
1182b3f75e |
chore: Update Python dependencies (#1017)
✔ Update typer 0.24.2 -> 0.25.0 successful ✔ Update packaging 26.1 -> 26.2 successful ✔ Update ruff 0.15.11 -> 0.15.12 successful --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Jens <1742418+1cu@users.noreply.github.com> |
||
|
|
2856feae8d |
fix(publish): handle category-suggestion radio picker fallback (#1013)
## Summary Kleinanzeigen's React redesign shows a category-suggestion radio picker (`fieldset#ad-category-picker`, radios `name="category-suggestions"`) on the posting form when the configured category path cannot be resolved by the category-change flow (outdated or ambiguous path). Before this fix, `__set_category` did not detect the picker, so submission proceeded with an empty hidden `categoryId`, the server rejected it, and the retry loop tripped the submit-limit duplicate-guard **without publishing** — surfacing as: ``` [WARN] Versuch 1/3 für [<title>] hat die Submit-Grenze erreicht, ist aber fehlgeschlagen: submission may have succeeded before failure. Kein erneuter Versuch, um doppelte Anzeigen zu vermeiden. [WARN] Manuelle Wiederherstellung für [<title>] erforderlich. ``` ## Change New helper `__resolve_category_suggestions(category)` runs after the category-change "Weiter" click: - If `fieldset#ad-category-picker` is not present → no-op. - If present: match path segments of configured `category` (deepest first) against the offered radio `value` attrs. Click the associated `<label for="...">` (the radio input itself is `sr-only` so label is the click target). - If the picker is present but no segment matches → raise `TimeoutError` listing the offered IDs so the user can correct the ad's `category`. - If the picker is present but no radios have rendered yet (transient / unrelated fieldset) → skip silently so we don't false-positive on DOM reuse. ## Test plan - [x] New `TestCategorySuggestionPicker` class with 4 tests: - picker absent → no `web_find_all` / `web_click` - picker present, leaf segment matches → label click targets `#ad-category-picker` - picker present, no match → `TimeoutError` with offered IDs in message - picker present, deepest segment preferred over parent - [x] Updated `test_set_category_uses_probe_for_auto_selected_marker` to use a selective `probe` side-effect (returns the marker for `ad-category-path`, `None` for `ad-category-picker`) so the test no longer implicitly depends on a single `web_probe` call. - [x] `pdm run pytest tests/unit -q` — 1044 passed, 4 skipped - [x] `pdm run ruff check src/kleinanzeigen_bot/__init__.py tests/unit/test_init.py` — clean - [x] Translations added under `__resolve_category_suggestions` in `translations.de.yaml` for all three strings (`test_all_log_messages_have_translations[de]` passes). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Automatically detects Kleinanzeigen’ category-suggestion picker and matches configured category paths against offered suggestions. * **Bug Fixes** * Fails fast when a category cannot be deterministically resolved (no retries), and logs/skips affected ads. * Improved error feedback listing available suggestion IDs when no match is found. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Jens <1742418+1cu@users.noreply.github.com> |
||
|
|
96734cc5ed |
docs: clarify download naming examples (#1016)
## ℹ️ 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 --> |
||
|
|
78e9a82467 |
chore: Update Python dependencies (#1015)
✔ Update typer 0.24.1 -> 0.24.2 successful ✔ Update idna 3.12 -> 3.13 successful ✔ Update click 8.3.2 -> 8.3.3 successful ✔ Update mss 10.1.0 -> 10.2.0 successful ✔ Update certifi 2026.2.25 -> 2026.4.22 successful ✔ Update pathspec 1.0.4 -> 1.1.0 successful ✔ Update pyinstaller 6.19.0 -> 6.20.0 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
a0011e6104 |
docs: introduce AGENTS.md (#1014)
## ℹ️ Description Introduce `AGENTS.md` as the repo's first agent playbook and contributor quick guide. - Link to the related issue(s): N/A - Describe the motivation and context for this change. ## 📋 Changes Summary - Added `AGENTS.md` to provide repo-specific guidance for contributors and AI agents. - Documented the source-of-truth hierarchy, testing expectations, PR requirements, and validation steps. - Kept the guidance concise and aligned with the existing repo docs and workflows. ### ⚙️ 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 * **Documentation** * Added contributor guidelines documenting repository standards, conventions, testing practices, and pre-merge validation steps. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d26f39de03 | fix(publish): persist individual shipping costs past React re-render (#1011) | ||
|
|
53d0c9646e |
chore: Update Python dependencies (#1012)
✔ Update idna 3.11 -> 3.12 successful ✔ Update mypy 1.20.1 -> 1.20.2 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
2089115b64 | chore: Update Python dependencies (#1010) | ||
|
|
5a4c9a4bc9 | chore: Update Python dependencies (#1008) | ||
|
|
71dcfbf818 | ci(deps): bump the all-actions group with 2 updates (#1009) | ||
|
|
0c5083192b |
chore: add a link to kleinanzeigen-bot-ui (#1007)
## ℹ️ 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 --> |
||
|
|
fd3bf64a12 |
fix(download): retry stale staging cleanup on Windows (#1005)
## ℹ️ Description *Fix intermittent Windows cleanup failures for stale staging dirs in issue #998.* - Link to the related issue(s): Issue #998 - Retry cleanup of stale `.tmp-*` dirs while preserving the existing abort-on-dirty-dir behavior. ## 📋 Changes Summary - Add a retrying `rmtree` helper with Windows read-only recovery. - Reuse it for stale staging, rollback staging, and backup cleanup. - Add regression tests for transient, persistent, and non-retryable cleanup failures. ### ⚙️ 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 * **Improvements** * More reliable cleanup during extraction: rmtree operations now retry on transient permission/OS errors and include improved Windows permission handling, reducing failed or stalled extractions. * **Tests** * Expanded and consolidated unit tests covering retry behavior, error classification, Windows vs POSIX cleanup handling, and various failure/success scenarios to ensure robustness. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
2f869f8420 |
chore: Update Python dependencies (#1006)
✔ Update pydantic 2.13.1 -> 2.13.2 successful ✔ Update pydantic-core 2.46.1 -> 2.46.2 successful ✔ Update ruff 0.15.10 -> 0.15.11 successful ✔ Update basedpyright 1.39.0 -> 1.39.2 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
b2970eb4f0 |
feat(delete): add after_delete config for post-delete YAML cleanup (#1000)
## ℹ️ Description - Link to the related issue(s): Issue #994 - Adds a `deleting.after_delete` config toggle that controls what happens to the local ad YAML file after the standalone `delete` command runs. Three modes: `NONE` (default, no change), `RESET` (clear server-side metadata so the ad is eligible for republication as "new"), `DISABLE` (set `active: false` so the ad is skipped until manually re-enabled). ## 📋 Changes Summary - Added `DeletingConfig` model with `after_delete: Literal["NONE", "RESET", "DISABLE"]` field (default `"NONE"`) - Added `deleting: DeletingConfig` field to `Config` class - Added `_apply_after_delete_policy()` helper that mutates `Ad` model and dict in-place based on mode - Integrated policy in `delete_ads` with detection heuristic: cleanup runs when `delete_ad` returns `True` (200) or when `ad_cfg.id` transitions from non-None to None (404) - Policy does NOT apply during publish-time `delete_ad` call sites — only the standalone delete command - Regenerated `docs/config.default.yaml` and `schemas/config.schema.json` ### ⚙️ 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** * Added configurable post-delete cleanup options to control how local ad records are handled after deletion (leave, reset metadata, or disable). * **Bug Fixes** * More accurate detection of attempted vs. successful deletions and correct incrementing of deletion counts. * Ensure metadata cleanup is skipped when no targets are found while still handling 404-style removals appropriately. * **Tests** * Added unit tests covering post-delete behaviours and edge cases. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
2b7a8bfde0 |
fix(publish): handle missing PICKUP toggle (books/comics) and map legacy German condition_s values (#999)
## ℹ️ Description Two small publish-time failures observed against the current Kleinanzeigen DOM for ads in specific categories. ### 1. PICKUP skip for categories without a shipping toggle Books (`76/77`) and comics (`76/77/15156`) render the "Eigenschaften und Versand" fieldset with only price/description/images — there is no `ad-shipping-enabled-yes/no` radio because the site treats these categories as pickup-only. Today `__set_shipping` raises `Failed to set shipping attribute for type 'PICKUP'!` because the radio is absent. Fix: probe for the radio first; if absent, treat that as "already PICKUP" (which matches the configured `shipping_type: PICKUP`) and return without an error. Live DOM diagnostic captured during the failure: ``` {"url":"…/p-anzeige-aufgeben-schritt2.html", "ids":[], "headings":[{"tag":"LEGEND","text":"Eigenschaften und Versand"}]} ``` No `[id*=shipping]` / `[id*=versand]` elements exist for these categories. ### 2. German → English condition value mapping The condition dialog radios now use English API codes: ``` {value:"new"}, {value:"like_new"}, {value:"ok"}, {value:"alright"} ``` Ad YAMLs written against the previous DOM use German tokens (`neu`, `wie_neu`, `sehr_gut`, `gut`, `in_ordnung`, `defekt`), which no longer match any radio and produce `Failed to set attribute 'condition_s'`. Fix: try the configured value first (preserves behaviour for English configs), then fall back to the mapped equivalent. `wie_neu` and the legacy `sehr_gut` both collapse to `like_new` because the site now exposes a single "like new" tier. Mapping: | Legacy German | Current English | |-----------------|-----------------| | `neu` | `new` | | `wie_neu` | `like_new` | | `sehr_gut` | `like_new` | | `gut` | `ok` | | `in_ordnung` | `alright` | | `defekt` | `defect` | ## 📋 Changes Summary - `__set_shipping`: probe `ad-shipping-enabled-no` before the state check; return on absence with a debug log. - `__set_condition`: switch to `web_probe` with a candidate-value list (configured value → mapped API code); preserves the existing label-click-then-radio-click flow. - New constant `_CONDITION_GERMAN_TO_API` mapping legacy tokens to current API codes. No behavioural change for ads in categories that do render the shipping toggle, or for ad YAMLs already using English condition codes. ### ⚙️ 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. - [ ] I have tested my changes and ensured that all tests pass (`pdm run test`) — verified manually against the live site; unit tests for the new branches not yet added. - [ ] I have formatted the code (`pdm run format`). - [ ] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary (no user-facing docs change needed; the YAML token format is unchanged because the old tokens continue to work via the fallback map). Happy to add focused unit tests for both branches and run `pdm run format`/`lint` if the direction looks right. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved compatibility with German condition values for item listings. * Enhanced robustness when setting item conditions by probing multiple candidate values instead of failing immediately. * Fixed pickup-only shipping type handling to gracefully manage missing toggle controls. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
5fd67ed851 | chore: Update Python dependencies (#996) | ||
|
|
26a199a7a6 |
fix(delete): report actual deletion outcome and reduce log noise (#995)
## ℹ️ Description - Link to the related issue(s): Issue #991 - `delete_ad` previously always returned `True` and always cleared `ad_cfg.id`, regardless of whether the ad was actually found or deleted. The title-based and ID-based matching paths behaved differently, and 404 responses were treated inconsistently. This made it impossible to distinguish "ad confirmed deleted" from "ad already gone" from "no matching ad found" — causing misleading log output and preventing accurate deletion tracking. ## 📋 Changes Summary - Restructure `delete_ad` into two clear phases: **Phase A** (unified target selection via `ids_to_delete: set[int]`) and **Phase B** (shared delete execution loop) - Return `True` only when at least one delete request returned HTTP 200 (confirmed deleted); return `False` for no matches or all 404s - Clear `ad_cfg.id = None` whenever a delete was **attempted** (both 200 and 404), but preserve it on early return (no targets found) - Fix falsy-zero bug: `elif ad_cfg.id:` → `elif ad_cfg.id is not None:` to correctly handle `id == 0` - Replace `published_ad.get("id", -1)` with explicit None check + `try/except` around `int()` to avoid silent invalid delete attempts - Update `delete_ads` orchestrator to track `deleted_count` accurately - Replace 3 old tests with 9 behavior-focused tests covering: ID-only match, title match, multiple title matches, title+ID deduplication, zero ID, invalid published ad ID, 404 handling, no-match early return, exception preserves ID ### ⚙️ 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 * **Bug Fixes** * Summary now reports the actual number of ads deleted (not processed attempts). * Skips invalid/missing IDs and avoids unnecessary page loads when nothing to delete. * Treats HTTP 404 as missing ad (warn) while counting only successful deletions. * Ensures ad configuration is cleared after deletion attempts; preserves config if deletion errors occur. * **Tests** * Expanded scenario tests covering title/ID deletion, deduplication, mixed responses, invalid IDs, and error propagation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
69d5b69310 |
fix(publish): add confirmation redirect fallback to recover ad ID (#993)
## ℹ️ Description - Link to the related issue(s): Issue #991 (related delete bug), Issue #992 (diagnostics follow-up) - During a publish run, the Kleinanzeigen confirmation page auto-redirected to the user's ad management page (`m-meine-anzeigen.html`) before the bot's URL polling could observe the confirmation URL containing the new ad ID. This caused `PublishSubmissionUncertainError` even though the ad was actually published successfully (verified via diagnostics HTML showing ad ID 3382410263 in Belen tracking data). The fix adds a two-layer fallback to recover the ad ID from page tracking data when URL polling times out. ## 📋 Changes Summary - Add `_try_recover_ad_id_from_redirect()` helper with two-layer fallback: Layer 1 checks `document.referrer` for the confirmation URL; Layer 2 scans inline `<script>` tags for the confirmation URL pattern containing `adId`. - Restructure the confirmation block in `publish_ad` to attempt recovery before raising `PublishSubmissionUncertainError`. On successful recovery, logs a WARNING about the fast redirect and continues normally. - Add defensive `RuntimeError` guard (unreachable in current code) with i18n-translated message including `ad_file` context. - Add DEBUG log for the deferred title set (explaining why title appears empty before submit). - Add stale-ID assumption comment documenting why `document.referrer` cannot contain a previous ad's ID. - Add German translations for new WARNING log message and RuntimeError guard message. - DRY test setup: extract `_mock_post_submit_dependencies()` (ExitStack-based context manager) and `_build_publish_ad_cfg()` helpers, eliminating ~80 lines of duplicated mock boilerplate across 4 integration tests. - Test scout cleanup: merge duplicate `test_extract_ad_id_handles_empty_referrer` + `test_extract_ad_id_handles_none_referrer` into one parametrized test (both hit identical code path via `str(... or "")`). - Move `web_sleep` mock to unconditional patch list, eliminating real `asyncio.sleep` delays in error-path tests. ### ⚙️ 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 * **Bug Fixes** * Improved ad publication reliability with a new fallback for retrieving confirmation details when initial extraction fails. * Expanded error handling to mark uncertain submissions appropriately and prevent silent failures. * Added targeted debug logging to aid troubleshooting of the publish flow. * **Tests** * Added comprehensive unit tests covering fallback recovery, confirmation timing scenarios, and error paths. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
31d1f53ab6 |
chore: Update Python dependencies (#990)
✔ Update filelock 3.25.2 -> 3.28.0 successful ✔ Update packaging 26.0 -> 26.1 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
dfe73bc81e | ci: replace github-app app id with client id | ||
|
|
ae6c1cfde7 |
enh(publish): normalize continue to break at max-retries exhaustion (#989)
## ℹ️ Description *Provide a concise summary of the changes introduced in this pull request.* - Link to the related issue(s): Issue #976 - The `publish_ads` method used `continue` to exit its inner retry loop at max-retries exhaustion, while the newer `update_ads` method correctly uses `break`. Since this is always the last loop iteration, both produce identical runtime behavior, but `continue` reads as "skip to the next attempt" while `break` reads as "done with this ad's retries." This normalizes the control flow to match the consistent pattern. ## 📋 Changes Summary - Changed `continue` to `break` in `publish_ads` retry exhaustion path (line 2226 of `src/kleinanzeigen_bot/__init__.py`) - No behavior change — purely a readability improvement - Matches the identical pattern already used in `update_ads` ### ⚙️ 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 * **Bug Fixes** * Improved error handling for ad publishing failures, ensuring proper status reporting when an ad fails to publish after maximum retry attempts. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
154af7c206 |
ci(deps): bump the all-actions group with 3 updates (#987)
Bumps the all-actions group with 3 updates: [actions/upload-artifact](https://github.com/actions/upload-artifact), [actions/create-github-app-token](https://github.com/actions/create-github-app-token) and [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request). Updates `actions/upload-artifact` from 7.0.0 to 7.0.1 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's releases</a>.</em></p> <blockquote> <h2>v7.0.1</h2> <h2>What's Changed</h2> <ul> <li>Update the readme with direct upload details by <a href="https://github.com/danwkennedy"><code>@danwkennedy</code></a> in <a href="https://redirect.github.com/actions/upload-artifact/pull/795">actions/upload-artifact#795</a></li> <li>Readme: bump all the example versions to v7 by <a href="https://github.com/danwkennedy"><code>@danwkennedy</code></a> in <a href="https://redirect.github.com/actions/upload-artifact/pull/796">actions/upload-artifact#796</a></li> <li>Include changes in typespec/ts-http-runtime 0.3.5 by <a href="https://github.com/yacaovsnc"><code>@yacaovsnc</code></a> in <a href="https://redirect.github.com/actions/upload-artifact/pull/797">actions/upload-artifact#797</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/upload-artifact/compare/v7...v7.0.1">https://github.com/actions/upload-artifact/compare/v7...v7.0.1</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href=" |
||
|
|
a13fb4f106 |
feat(timing): tune default timeouts and migrate optional probes to web_probe (#985)
## ℹ️ Description - Link to the related issue(s): Issue # - Analyzed 524 timing records across 18 sessions from real-world usage to identify genuine timeout failures vs expected element-absence probes. Three timeout defaults were too tight for observed latency spikes, and four call sites were wasting time on retry/backoff for elements that are intentionally absent in most flows. ## 📋 Changes Summary ### Timeout default changes (`config_model.py` → generated `config.default.yaml` + `config.schema.json`) | Key | Old | New | Rationale | |---|---|---|---| | `sms_verification` | 4.0 | **5.0** | ~11% margin over observed 4.46s failure | | `email_verification` | 4.0 | **5.0** | ~23% margin over observed 4.05s failure | | `login_detection` | 10.0 | **12.0** | ~11% margin over observed 10.6–10.8s failures | | `captcha_detection` | 2.0 | unchanged | No evidence of benefit from timing data | ### Call-site migration (`__init__.py`) Migrated 4 optional-probe methods from `web_find` (retry-backed, raises `TimeoutError`) to `web_probe` (single attempt, returns `None`): - **`_check_sms_verification`**: `web_find` → `web_probe` with explicit `sms_verification` timeout, returns early with debug log when absent - **`_check_email_verification`**: Same pattern with `email_verification` timeout - **`_dismiss_consent_banner`**: Eliminated double-lookup (`web_find` + `web_click`) → single `web_probe` + `element.click()` + `web_sleep()` - **`_click_gdpr_banner`**: Same double-lookup elimination, added debug log on absent path Removed 4 `try/except TimeoutError` wrappers from callers (`handle_after_login_logic` and `login`) since `web_probe` never raises `TimeoutError`. ### Performance impact - Worst-case wait on absent elements reduced from ~19s → 5s (SMS/email verification with retry/backoff vs single probe) - GDPR banner clicks: double DOM lookup eliminated → single lookup ### Test cleanup (`test_init.py`) - **Added 8 behavioral tests** for `_dismiss_consent_banner` (found + absent), `_check_sms_verification` (found + absent), `_check_email_verification` (found + absent), and `_click_gdpr_banner` absent path - **Removed 3 low-value tests**: `test_handle_after_login_logic` (structural mock wiring), `test_is_logged_in_returns_true_with_alternative_element` (duplicate branch), `test_wait_for_post_auth0_submit_transition_sleep_fallback_when_login_not_confirmed` (duplicate outcome) - **Upgraded 1 test**: `test_fill_login_data_and_send` from mock-count assertions to behavioral argument assertions verifying correct selectors and credentials ### ⚙️ 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. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Post-login flows now safely handle absent SMS/email prompts and consent/GDPR banners, avoiding interruptions and clicking banners when present. * **Improvements** * Increased default timeouts for SMS verification, email verification, and login detection to improve login reliability. * **Documentation** * Configuration docs now reference authoritative default timeout values instead of embedding examples. * **Tests** * Strengthened unit tests for login interactions, verification prompts, and banner dismissal behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
fd568637c5 |
chore: Update Python dependencies (#986)
✔ Update pydantic 2.12.5 -> 2.13.0 successful ✔ Update pydantic-core 2.41.5 -> 2.46.0 successful ✔ Update mypy 1.20.0 -> 1.20.1 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
cf61c99233 |
fix(core): correct progress counter in publish/update ad loops (#984)
## ℹ️ Description - Link to the related issue(s): Issue #977 - The "Processing N/M" progress counter in `publish_ads()`, `update_ads()`, and `update_content_hashes()` used the same `count` variable for both display and tally. Since `count` only incremented for ads that passed skip checks, paused/skipped ads caused the counter to stall or repeat (e.g. `1/5, 1/5, 2/5`). This decouples the display counter from the processing tally using `enumerate()`. ## 📋 Changes Summary - **`publish_ads()`**: Use `enumerate(ad_cfgs, start=1)` with `idx` for the display counter instead of `count + 1`. - **`update_ads()`**: Same enumerate swap; moved the "Processing" log before both skip checks (not-found and paused) so the counter is always sequential even for skipped ads. - **`update_content_hashes()`**: Same enumerate swap; renamed `count` → `changed` for clarity since `idx` is now the display counter. - **`delete_ads()`**: Left untouched (already correct — no skip paths, counter increments before log). - Added `TestDisplayCounterProgression` class with 4 regression tests covering counter progression with paused, active, and not-found ads. - Removed duplicate `test_update_ads_summary_reports_mixed_outcomes` (same scenario as continuation test, only unique assertion was a log format-string template check). - Removed duplicate `location_non_convergence` parametrize case (second TimeoutError hitting the same branch). ### ⚙️ 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 * **Bug Fixes** * Progress counter now accurately reports only changed items instead of all processed items during content updates. * **Tests** * Added comprehensive regression tests for progress counter display across ad processing workflows, including edge cases with paused and not-found ads. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
04de9025f6 |
fix(ad): reject titles exceeding 65 characters (#982)
## ℹ️ Description - Link to the related issue(s): Issue #979 - kleinanzeigen.de enforces a hard 65-character limit on ad titles. When a title exceeds this limit, the site silently rejects it, causing the bot to hang during publishing. This fix adds early validation so users get a clear, actionable error before any browser interaction occurs. ## 📋 Changes Summary - Added `MAX_TITLE_LENGTH = 65` constant to `ad_model.py` - Applied `Field(max_length=MAX_TITLE_LENGTH)` to the `title` field in `AdPartial`, leveraging Pydantic's built-in validation (semantic error type, auto-localized messages) - Regenerated `schemas/ad.schema.json` — now includes `"maxLength": 65` on the title property - Added parametrized test covering both boundary cases (65 chars accepted, 66 chars rejected) - Cleaned up stale defensive `model_construct` tests that tested unreachable code paths ### ⚙️ 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. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Enforced both minimum (10) and maximum (65) title length limits and improved validation so titles outside bounds produce clear validation errors. * **Tests** * Added unit tests covering title-length boundary behavior and updated related test setups. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
c346720743 |
refactor(publish): rename __react_input to __set_input_value (#980)
## ℹ️ Description - Link to the related issue(s): Issue #930 - The method `__react_input` uses the native `HTMLInputElement`/`HTMLTextAreaElement` value setter — a standard DOM API, not a React-specific one. The rename makes the name match what the method actually does. ## 📋 Changes Summary - Rename `__react_input` → `__set_input_value` (definition + 6 call sites + test mock) - Update docstring: "React-controlled" → "framework-controlled" ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) ## ✅ 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 * **Refactor** * Internal improvements to input handling mechanisms with updated method naming and documentation to enhance code maintainability and clarity across form field operations. Test infrastructure has been aligned with these changes. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
f659c98aca |
chore: ✔ Update rich 14.3.4 -> 15.0.0 (#978)
✔ Update rich 14.3.4 -> 15.0.0 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
668768bd1b |
fix(update): harden per-ad retries and location convergence (#975)
## ℹ️ Description This PR implements issue #940 by making the update flow resilient per ad and hardening ZIP/city selection so unresolved location states fail closed instead of silently proceeding. - Link to the related issue(s): Issue #940 - Describe the motivation and context for this change. ## 📋 Changes Summary - Added per-ad retry/isolation semantics to `update_ads` (re-raise cancellation, no-retry for `PublishSubmissionUncertainError`, retry-and-continue for `TimeoutError`/`ProtocolException`, non-fatal publish-result timeout, mixed success/failure summary). - Hardened contact/location handling: ZIP set now fails closed for the ad, city combobox selection waits for option load + post-click convergence, and ambiguous city-only matches now fail closed. - Improved city selection read-back robustness by preferring live DOM value/text (`element.apply`) over stale serialized attributes. - Renamed `PUBLISH_MAX_RETRIES` to `SUBMISSION_MAX_RETRIES` and updated related diagnostics/tests/translations. - Added focused unit coverage for update resilience and contact/location hardening. - Live verification succeeded on this branch using real ads: - `pdm run python -m kleinanzeigen_bot -v --ads=due publish` (2 ads republished) - `pdm run python -m kleinanzeigen_bot -v --ads=changed update` (2 ads updated) Mention any dependencies, configuration changes, or additional requirements introduced. No new dependencies or config schema changes. ### ⚙️ 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 * **Bug Fixes** * Improved per-ad retry behavior for submissions: retries occur only for transient failures, certain uncertain failures stop retries immediately, and confirmation timeouts no longer trigger retries. * Stricter contact handling: zip code and city selection are now validated more rigorously and fail fast on ambiguous or non-converging selections. * Enhanced diagnostics and clearer completion reporting for mixed success/failure runs. * **Tests** * Added comprehensive unit tests covering retry resilience and contact-location hardening. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
1892399fbc |
fix(update): stabilize edit-flow probes and image cleanup (#973)
## ℹ️ Description This PR fixes update-flow instability by switching absence-valid UI checks to probe semantics and by fixing image replacement on edit pages. - Link to the related issue(s): Issue #N/A - Describe the motivation and context for this change. - The update flow used stale thumbnail/remove selectors on edit pages, so existing images were not removed and configured images were uploaded again, causing duplicates. ## 📋 Changes Summary - Updated update/publish optional checks (captcha in publish flow, buy-now optional branch, phone field presence, imprint/payment/without-image prompts) to use probe-first handling to avoid noisy timeout retries when elements are absent by design. - Reworked pre-upload cleanup to use the current edit-page remove control (`button[aria-label='Bild entfernen']`) and hidden image markers, ensuring old images are removed before uploading configured images. - Simplified upload completion detection to marker-delta tracking and reduced retry noise for marker lookups. - Added/updated regression tests for probe behavior and image cleanup/upload flows. - Performed targeted test-scout cleanup in `tests/unit/test_init.py` (removed low-signal URL concatenation/log-wording checks and consolidated duplicate workspace-skip tests). - Updated German translation key for the new image-removal log message. - No additional dependencies or configuration changes required. ### ⚙️ 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 * **New Features** * Marker-based image tracking for upload, cleanup, and accurate progress counting. * **Bug Fixes** * More reliable captcha detection that returns early when absent and handles present captchas consistently. * Safer “buy now” / sell-directly handling with explicit error when required control is missing. * Robust image removal loop with clear failure reporting. * Simplified post-submit/payment probing to reduce flakiness. * Improved phone-field visibility handling and clearer shipping-cost validation messages. * **Tests** * Expanded/refactored tests for image cleanup, upload completion, captcha, buy-now scenarios, and validation rules; consolidated workspace-resolution tests. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
8214ba312f |
chore: ✔ Update rich 14.3.3 -> 14.3.4 (#974)
✔ Update rich 14.3.3 -> 14.3.4 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
c65d1b67b0 |
test: improve test quality by replacing brittle assertions (#972)
## ℹ️ Description This PR improves overall test quality by removing brittle assertion patterns, consolidating duplicate coverage, and migrating tests to clearer ownership while preserving behavior coverage. - Link to the related issue(s): Issue #N/A - Describe the motivation and context for this change. - Reduce flaky/wording-coupled tests and improve long-term maintainability. - Keep high-signal behavior assertions while preserving existing coverage paths. ## 📋 Changes Summary - Replaced gettext/log-wording-dependent assertions in price reduction tests with stable behavior-oriented checks. - Cleaned low-value log assertions in extract/pagination/bot tests. - Simplified mixed-category assertions in init/diagnostics tests and removed redundant debug log checks. - Extracted shared `PYTEST_CURRENT_TEST` fixture handling in chrome version tests. - Removed duplicate/subsumed tests in ad-model and update-checker suites; simplified brittle full-message log checks. - Parametrized legacy migration tests in config-model for clearer, less repetitive coverage. - Removed tests in `test_bot.py` that were subsumed by `test_init.py`, then migrated remaining unique tests and deleted `test_bot.py`. - No runtime behavior changes; this is test-suite quality and maintainability work. ### ⚙️ 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 * **Tests** * Refactored and simplified the unit test suite for maintainability: consolidated legacy migration checks into parametrized tests, introduced shared fixtures, and streamlined test setup/formatting. * Removed many log-capture assertions and several redundant or overly-specific tests, and adjusted assertions to focus on functional outcomes. * No production code or user-facing behavior changed. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
c3584d0b2e |
feat(pricing): support update-mode reductions and verify previews (#970)
## ℹ️ 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 --> |
||
|
|
6482d2dbaf |
chore: Update Python dependencies (#971)
✔ Update more-itertools 11.0.1 -> 11.0.2 successful ✔ Update librt 0.8.1 -> 0.9.0 successful ✔ Update ruff 0.15.9 -> 0.15.10 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
80eea4e6c2 |
fix(publish): fix multi-image uploads with real waits and fresh file inputs (#969)
## ℹ️ Description *Provide a concise summary of the changes introduced in this pull request.* - Link to the related issue(s): Issue #958, Issue #964 - Describe the motivation and context for this change. Publishing ads with many images could fail on first try because two independent issues stacked: 1) Requested waits were effectively skipped because nodriver `Tab.sleep()` returns near-instantly (`asyncio.wait(..., return_when=FIRST_COMPLETED)` with a fast task), so upload pacing and polling were too aggressive. 2) After the first image upload, the page replaced the hidden `input[type=file]`; reusing the old element handle meant subsequent `send_file(...)` calls had no effect. Technical evidence gathered during live probes: - Before the sleep fix, a 12-image run produced only ~0.108s cumulative delay across 17 `web_sleep` calls (expected ~20–40s). - After switching to `asyncio.sleep`, timing probes showed real waits: - upload-phase waits (~1.0–2.2s requested) measured ~1019–2238ms actual, - `web_await` polling waits (0.5s requested) measured ~500–501ms actual. - Stale-input probe showed `isConnected` becomes `False` after first upload when reusing the same file input; refetching per image restored marker increments on each upload. ## 📋 Changes Summary - Replaced `page.sleep(...)` with `asyncio.sleep(...)` in `web_sleep()` so requested delays are actually honored. - Replaced `page.sleep(...)` with `asyncio.sleep(...)` in `web_await()` polling to avoid near-zero busy-loop behavior. - Fixed image upload loop to re-fetch `input[type=file]` per image, preventing stale-element uploads after the first file. - Updated and added regression tests: - timing-based tests for real sleep behavior, - per-image file-input refetch behavior, - consolidated timeout marker tests into one parametrized, behavior-focused test. - Live verification after fix: 15-image smoke upload completed with marker delta `15/15`. Mention any dependencies, configuration changes, or additional requirements introduced. ### ⚙️ 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 * **Bug Fixes** * Improved image upload reliability by refetching file input elements during multi-image uploads, preventing stale element errors. * Enhanced timeout and delay behavior for more consistent performance during web scraping operations. * **Tests** * Updated tests to verify actual timing behavior and improved error reporting for upload operations. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
5b7621b0de |
fix(publish): stabilize condition trigger handling and speed probe checks (#968)
## ℹ️ Description *Provide a concise summary of the changes introduced in this pull request.* - Link to the related issue(s): Issue #956, Issue #938 - This change addresses a selector-collision regression where `condition_s` handling could resolve to shipping controls (`ad-shipping-options`) and open the wrong dialog, and improves publish performance by replacing retry-heavy branch probes with a single-attempt probe API for settled DOM checks. ## 📋 Changes Summary - Added `web_probe(...)` in `WebScrapingMixin` for single-attempt, no-retry DOM presence checks (returns `Element | None`). - Migrated two high-cost probe call sites to `web_probe`: - category auto-selected marker lookup (`ad-category-path`) in `__set_category` - individual shipping price visibility probe (`ad-individual-shipping-price`) in `__set_shipping` - Polished `condition_s` handling to avoid condition/shipping trigger collisions and keep fallback behavior explicit when dialog handling is not applicable. - Added/updated high-signal tests for: - probe semantics (no retry even when global retries are enabled) - migrated category/shipping probe branches - condition trigger collision and fallback behavior - Applied targeted test-scout cleanup in touched files: - removed one low-signal version getter test - consolidated duplicate invalid-pid close-session tests into one parametrized test - No dependency, schema, or configuration changes were introduced. ### ⚙️ 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 * **Bug Fixes** * Reduced spurious errors and blocking waits when setting condition, category, and shipping options; probe-based checks improve automatic selection, fallback behavior, and avoid incorrect clicks. * **Tests** * Expanded and refactored unit tests to cover probe behavior, dialog handling, fallback scenarios, and category/shipping regressions to ensure more robust, faster interactions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
45170b457f | ci: build Linux ARM binaries (#967) | ||
|
|
5bffe8eb27 |
chore: ✔ Update platformdirs 4.9.4 -> 4.9.6 (#965)
✔ Update platformdirs 4.9.4 -> 4.9.6 successful Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
825480089e |
fix(publish): add 'Anzeige speichern' to submit button selector (#966)
## Summary - Kleinanzeigen renamed the edit-page submit button from `Änderungen speichern` to `Anzeige speichern` - This caused the bot to timeout when clicking the submit button during ad updates, resulting in `PublishSubmissionUncertainError` for every update - Added the new button label to the XPath selector alongside the existing labels ## Test plan - [x] Verified manually: navigated to edit page via Chrome DevTools, confirmed button text is `Anzeige speichern` - [x] Confirmed update succeeds with the fix (clicks the button, proceeds to confirmation) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved reliability of posting and editing by broadening detection of submit buttons to recognize additional label variants (including "Anzeige speichern"), reducing failed submissions when interface labels differ. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
2c06944cca | fix: restore ASCII art logo. Fixes #963 |