What's Changed
- fix: report the actual 1-based failed browser-step number (#4200) by @ebarkhordar in #4258
- UI medium refactor by @dgtlmoon in #4183
- Show regex-tagged watches under their group tab by @willyjfarrell in #4267
- Watch history - fix for restock.previous_price returns the first-ever price once a watch has 3+ snapshots by @dgtlmoon in #4268
- Fix LLM token counter race condition by @honma89 in #4276
- fix: Visual Selector renders scraped selectors as text, not markup by @kah-ja in #4282
- fix: sanitize lone unicode surrogates before filtering JSON by @snowyukitty in #4293
- fix: invalidate favicon cache when clearing watch history by @snowyukitty in #4286
- fix: avoid division by zero when logging watch load rate by @snowyukitty in #4289
- UI - Move rendering of each watchlist row out of the watchlist main template so it can be re-used by the realtime update by @dgtlmoon in #4305
- Security: hide the running version from anonymous visitors when a password is set (#2190) by @pongoe in #4306
- Move development tools out of runtime requirements by @Nameless-Monster-Nerd in #4280
- CSRF - Test fix by @dgtlmoon in #4316
- feature: allow a watch or group to append to the inherited AI Change Summary prompt by @snowyukitty in #4294
- RSS - RSS pubDate is wrong on any non-UTC container: local time is relabelled as UTC - #4309 by @dgtlmoon in #4314
- GHSA-56fq-63vj-9992 Improved URL filtering by @dgtlmoon in #4315
- GHSA-4j9m-cxq4-9c36 - Improved validation Stored CSS Injection via
tag_colourField by @dgtlmoon in #4317 - Bump actions/setup-python from 6 to 7 in the all group across 1 directory by @dependabot[bot] in #4291
- GHSA-23mp-8222-96fr - reflected XSS in /diff//download-patch via from_version - Using built-in plain text response instead. Reported-by: Mayssare Amakhtari (@cy3erm) Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com by @dgtlmoon in #4324
- LIBXML Data integrity fix, libxml must be locked across threads for any XML parsing by @dgtlmoon in #4325
- Add Polish translation by @osaczony30 in #4329
- Add Ukrainian support for the 'In stock'/'Not in stock' status by @iG8R in #4330
- Add watch UI should show which browser(s) are available and set default browser by @dgtlmoon in #4334
- feat: make Playwright CSP bypass configurable by @kquinsland in #4298
- Restock detection - fix inverted condition that skipped the OpenGraph availability fallback by @TowyTowy in #4262
- Add watch UI default browser by @dgtlmoon in #4335
- fix: Browser Steps picker cannot select a nested in a by @thejdubb02 in https://github.com//pull/4336 deps: update litellm dependency cap by @apeabody in https://github.com//pull/4341 fix(backup): add utf-8 encoding when writing url list files by @apeabody in https://github.com//pull/4345 Puppeteer/Playwright CSP bypass - test refactor by @dgtlmoon in https://github.com//pull/4346 Python 3.10 EOL October/2026 - Dropping support - conflicts with jsonschema and litellm by @dgtlmoon in https://github.com//pull/4347 fix(llm): support reasoning models (), safe booleans, and timestamp diffs by @apeabody in https://github.com//pull/4340 fix(llm): handle reasoning blocks that aren't a well-formed pair by @dgtlmoon in https://github.com//pull/4349 Memory - GC freeze after startup to save CPU cycles and improve memory management by @dgtlmoon in https://github.com//pull/4351 Scheduler+API Bug - if an invalid timezone was set (through edit of watch or API) it could have crashed the scheduler, Added timezone to the official API docs by @dgtlmoon in https://github.com//pull/4350 Memory usage - small improvement by tidying up module imports by @dgtlmoon in https://github.com//pull/4352 UTF-8/Lone Surrogate encoding test improvements related to #4273 by @dgtlmoon in https://github.com//pull/4353 LLM - Per watch/group settings and UI tidyup by @dgtlmoon in https://github.com//pull/4354 Update - pyppeteer-ng to 2.0.0rc16 by @dgtlmoon in https://github.com//pull/4357 fix(llm): support Gemini flash-lite & reasoning models, strip extra_body on 400 retry by @apeabody in https://github.com//pull/4342 Watch loading - Dont crawl whole datastore on disk, just check each directory for watch.json / tag.json by @dgtlmoon in https://github.com//pull/4358 Env var - PAGE_WATCH_LIMIT enhancements by @dgtlmoon in https://github.com//pull/4359 Feature/watch limit by @dgtlmoon in https://github.com//pull/4360 fix(api): accept an existing tag UUID in the watch tag field, and deprecate it by @dgtlmoon in https://github.com//pull/4361 fix(conditions): support zero values in condition filtering and json logic conversion by @apeabody in https://github.com//pull/4362 New Contributors @willyjfarrell made their first contribution in https://github.com//pull/4267 @honma89 made their first contribution in https://github.com//pull/4276 @kah-ja made their first contribution in https://github.com//pull/4282 @snowyukitty made their first contribution in https://github.com//pull/4293 @pongoe made their first contribution in https://github.com//pull/4306 @Nameless-Monster-Nerd made their first contribution in https://github.com//pull/4280 @osaczony30 made their first contribution in https://github.com//pull/4329 @iG8R made their first contribution in https://github.com//pull/4330 @kquinsland made their first contribution in https://github.com//pull/4298 @thejdubb02 made their first contribution in https://github.com//pull/4336 Full Changelog: https://github.com/dgtlmoon/changedetection.io/compare/0.55.8...0.60.1