youpdated 0.4.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {youpdated-0.4.0 → youpdated-0.5.0}/ADDING_SOURCES.md +45 -17
- {youpdated-0.4.0 → youpdated-0.5.0}/CHANGELOG.md +63 -2
- {youpdated-0.4.0 → youpdated-0.5.0}/CONTRIBUTING.md +1 -1
- {youpdated-0.4.0 → youpdated-0.5.0}/PKG-INFO +38 -11
- {youpdated-0.4.0 → youpdated-0.5.0}/README.md +36 -10
- {youpdated-0.4.0 → youpdated-0.5.0}/SECURITY.md +3 -2
- {youpdated-0.4.0 → youpdated-0.5.0}/pyproject.toml +2 -2
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/__init__.py +1 -1
- youpdated-0.5.0/youpdated/api.py +1380 -0
- youpdated-0.5.0/youpdated/cleanup.py +226 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/cli.py +514 -91
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/config.py +232 -27
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/crypto.py +87 -14
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/edit.py +150 -21
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/http.py +38 -25
- youpdated-0.5.0/youpdated/icons.py +124 -0
- youpdated-0.5.0/youpdated/importers.py +301 -0
- youpdated-0.5.0/youpdated/models.py +113 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/notify.py +83 -12
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/registry.py +4 -4
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/render/json_out.py +2 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/render/rss_out.py +2 -2
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/render/terminal.py +33 -15
- youpdated-0.5.0/youpdated/runner.py +368 -0
- youpdated-0.5.0/youpdated/sources/__init__.py +7 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/base.py +18 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/browser.py +46 -26
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/feed.py +6 -2
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/generic.py +20 -2
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/git.py +222 -112
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/itch.py +7 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/npm.py +13 -15
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/pypi.py +20 -21
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/steam.py +53 -1
- youpdated-0.5.0/youpdated/sources/webpage.py +608 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/youtube.py +119 -40
- youpdated-0.5.0/youpdated/state.py +1007 -0
- youpdated-0.5.0/youpdated/versions.py +168 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated.egg-info/PKG-INFO +38 -11
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated.egg-info/SOURCES.txt +5 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated.egg-info/requires.txt +1 -0
- youpdated-0.4.0/youpdated/cleanup.py +0 -118
- youpdated-0.4.0/youpdated/models.py +0 -76
- youpdated-0.4.0/youpdated/runner.py +0 -220
- youpdated-0.4.0/youpdated/sources/__init__.py +0 -5
- youpdated-0.4.0/youpdated/state.py +0 -453
- {youpdated-0.4.0 → youpdated-0.5.0}/LICENSE +0 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/MANIFEST.in +0 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/setup.cfg +0 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/__main__.py +0 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/py.typed +0 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/render/__init__.py +0 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated/sources/homebrew.py +0 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated.egg-info/dependency_links.txt +0 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated.egg-info/entry_points.txt +0 -0
- {youpdated-0.4.0 → youpdated-0.5.0}/youpdated.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ A source is one class with two methods. This guide builds a complete, working on
|
|
|
4
4
|
|
|
5
5
|
> Youpdated now ships a fuller `pypi` source ([youpdated/sources/pypi.py](youpdated/sources/pypi.py)).
|
|
6
6
|
> The version here is kept short to teach the contract. If you build it to follow along, give it
|
|
7
|
-
> another `name`:
|
|
7
|
+
> another `name`: duplicate named plugins are ignored.
|
|
8
8
|
|
|
9
9
|
- [The contract](#the-contract)
|
|
10
10
|
- [Two ways to add one](#two-ways-to-add-one)
|
|
@@ -93,7 +93,7 @@ so name the offending value and say what was expected.
|
|
|
93
93
|
|
|
94
94
|
## Step 2: fetch updates
|
|
95
95
|
|
|
96
|
-
`fetch()` gets one target and the shared `Client`. **Always use that client** never `httpx` or `requests` directly. It applies the user's proxy, rotates user agents, paces requests per host, and
|
|
96
|
+
`fetch()` gets one target and the shared `Client`. **Always use that client** never `httpx` or `requests` directly. It applies the user's proxy, rotates user agents, paces requests per host, and keeps no cookies.
|
|
97
97
|
|
|
98
98
|
```python
|
|
99
99
|
def fetch(self, target: Target, client: Client) -> Iterable[Update]:
|
|
@@ -111,7 +111,7 @@ Useful arguments:
|
|
|
111
111
|
| --- | --- |
|
|
112
112
|
| `conditional=True` | Send ETag/Last-Modified and get `None` on a 304. Use it for anything polled repeatedly. |
|
|
113
113
|
| `soft_statuses=(404,)` | Return the response instead of raising, when a status is expected. itch answers 404 for a game with no devlog. |
|
|
114
|
-
| `headers={...}` | Extra request headers. The user agent is added for you. |
|
|
114
|
+
| `headers={...}` | Extra request headers. The user agent is added for you. These are dropped on a redirect to another host, so put a key or token here, never in the URL, which `-v`, `--test`, and errors print. |
|
|
115
115
|
| `retries=0` | Skip retries when you're probing a fallback and want to fail fast. |
|
|
116
116
|
|
|
117
117
|
Any other non-200 raises `FetchError`, which the runner catches and reports without killing.
|
|
@@ -124,6 +124,10 @@ from youpdated.sources.feed import parse_feed
|
|
|
124
124
|
return parse_feed(fetched.content, source=self.name, target=target.key, tags=("release",))
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
+
A body that isn't a feed, such as a web page, raises `FetchError` instead of reading as an empty feed. A fetch that returns nothing counts as a target with nothing in it, and a first fetch records that as its baseline, so raise rather than return `[]` when you can't tell what the target holds.
|
|
128
|
+
|
|
129
|
+
Update fields are cleaned when an `Update` is made: control characters and lone surrogates are dropped and a non-string title becomes text, so the terminal, `--rss`, and `--json` are safe from what a site sends.
|
|
130
|
+
|
|
127
131
|
## The complete source
|
|
128
132
|
|
|
129
133
|
```python
|
|
@@ -137,7 +141,7 @@ from typing import Any, ClassVar, Iterable
|
|
|
137
141
|
from youpdated.http import Client
|
|
138
142
|
from youpdated.models import Target, Update
|
|
139
143
|
from youpdated.registry import register
|
|
140
|
-
from youpdated.sources.base import ConfigEntryError, entry_fields, require
|
|
144
|
+
from youpdated.sources.base import ConfigEntryError, entry_fields, parse_iso, require
|
|
141
145
|
|
|
142
146
|
MAX_VERSIONS = 10
|
|
143
147
|
|
|
@@ -171,7 +175,7 @@ class PyPISource:
|
|
|
171
175
|
for version, files in (doc.get("releases") or {}).items():
|
|
172
176
|
if not files or all(f.get("yanked") for f in files):
|
|
173
177
|
continue
|
|
174
|
-
dated.append((version,
|
|
178
|
+
dated.append((version, parse_iso(files[0].get("upload_time_iso_8601"))))
|
|
175
179
|
dated.sort(
|
|
176
180
|
key=lambda pair: pair[1] or datetime.min.replace(tzinfo=timezone.utc), reverse=True
|
|
177
181
|
)
|
|
@@ -190,18 +194,10 @@ class PyPISource:
|
|
|
190
194
|
)
|
|
191
195
|
for version, published in dated[:MAX_VERSIONS]
|
|
192
196
|
]
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
def _parse_iso(value: str | None) -> datetime | None:
|
|
196
|
-
if not value:
|
|
197
|
-
return None
|
|
198
|
-
try:
|
|
199
|
-
parsed = datetime.fromisoformat(str(value).replace("Z", "+00:00"))
|
|
200
|
-
except ValueError:
|
|
201
|
-
return None
|
|
202
|
-
return parsed if parsed.tzinfo else parsed.replace(tzinfo=timezone.utc)
|
|
203
197
|
```
|
|
204
198
|
|
|
199
|
+
`parse_iso()` reads an API's ISO 8601 timestamp, taking one with no zone as UTC, and returns `None` for anything it can't read.
|
|
200
|
+
|
|
205
201
|
## Notes
|
|
206
202
|
|
|
207
203
|
### The uid is the deduplication system
|
|
@@ -240,6 +236,25 @@ release and another ignore only the candidates.
|
|
|
240
236
|
You do not need to handle `ignore` yourself. It is lifted off the config entry
|
|
241
237
|
before `targets()` ever sees it, and applied to whatever you return.
|
|
242
238
|
|
|
239
|
+
### Set `version` on anything versioned
|
|
240
|
+
|
|
241
|
+
`version`: a user's `versions:` rules (only major bumps, only versions above
|
|
242
|
+
`3.13`) compare it, so set it on every item that is a version, even when the
|
|
243
|
+
title repeats it. Pass it as upstream writes it (`v3.15.0rc1`, `1.25.0_2`);
|
|
244
|
+
only its numbers are compared. Leave it `None` on items that aren't versions,
|
|
245
|
+
such as posts and commits, which the rules never filter. Like `ignore`,
|
|
246
|
+
`versions` is lifted off the config entry before `targets()` sees it.
|
|
247
|
+
Tag prereleases `prerelease`: `bump` counts only the first one toward a
|
|
248
|
+
version, and an untagged version counts as a final release.
|
|
249
|
+
|
|
250
|
+
### Listing the latest release
|
|
251
|
+
|
|
252
|
+
If your source lists only the newest few items, a busy upstream can push a
|
|
253
|
+
release off the list before it's seen. When the latest release is in the
|
|
254
|
+
document you already fetch, list it always. When it takes a request of its
|
|
255
|
+
own, ask only if `target.track_latest` is set, and add it only if it isn't
|
|
256
|
+
listed already, under the uid it would have there.
|
|
257
|
+
|
|
243
258
|
### Filling in a label during fetch
|
|
244
259
|
|
|
245
260
|
Sometimes the friendly name is only available from the response. Assign it to `target.label`; the renderers pick it up:
|
|
@@ -251,7 +266,7 @@ if not target.label:
|
|
|
251
266
|
|
|
252
267
|
### Caching a resolved value
|
|
253
268
|
|
|
254
|
-
`client.state` is a small key-value store for things that are expensive to resolve and never change: the Steam source caches appid
|
|
269
|
+
`client.state` is a small key-value store for things that are expensive to resolve and never change: the Steam source caches appid to name there, so it looks it up once:
|
|
255
270
|
|
|
256
271
|
```python
|
|
257
272
|
cached = client.state.cache_get("my_namespace", key) if client.state else None
|
|
@@ -269,6 +284,12 @@ If the key is the target's `key`, list the namespace on the source so `youpdated
|
|
|
269
284
|
caches: ClassVar[tuple[str, ...]] = ("my_namespace",)
|
|
270
285
|
```
|
|
271
286
|
|
|
287
|
+
A namespace shared by every target, like YouTube's list of Invidious instances, goes in `shared_caches` instead; `--wipe` on any of the source's targets clears it whole:
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
shared_caches: ClassVar[tuple[str, ...]] = ("my_shared_namespace",)
|
|
291
|
+
```
|
|
292
|
+
|
|
272
293
|
### Recognizing your entries
|
|
273
294
|
|
|
274
295
|
`youpdated add <value>` works without a source when only one source claims the value. To use, add an optional `claim()` returning the config entry for a value that can only be yours, or `None`. `accepted()` returns the entry if your `targets()` reads it, and `url_parts()` splits a URL:
|
|
@@ -286,6 +307,12 @@ def claim(self, value: str) -> str | None:
|
|
|
286
307
|
|
|
287
308
|
Claim only what is distinguishable and unique: a host you own, or a shape no other source uses. A bare name like `httpx` could be several sources' entry, and two sources claiming a value stops both from getting it. Like `targets()`, `claim()` must not touch the network.
|
|
288
309
|
|
|
310
|
+
A source that can read anything of a shape, like `webpage` reading any URL, sets `fallback`. Its claim counts only when no other source claims the value. It never claims a GitHub or itch.io URL away from the source made for it:
|
|
311
|
+
|
|
312
|
+
```python
|
|
313
|
+
fallback: ClassVar[bool] = True
|
|
314
|
+
```
|
|
315
|
+
|
|
289
316
|
### Thread
|
|
290
317
|
|
|
291
318
|
Targets are fetched concurrently. Keep everything in local variables or on the `Target`; don't mutate shared state on the source instance.
|
|
@@ -377,6 +404,7 @@ Users then configure it like any built-in source. A plugin that fails to import
|
|
|
377
404
|
- [ ] Returns `[]` rather than inventing an update
|
|
378
405
|
- [ ] `published` is timezone-aware UTC (or `None`)
|
|
379
406
|
- [ ] `tags` describe the update type, so `ignore:` rules can match them
|
|
407
|
+
- [ ] `version` is set on items that are versions, so `versions:` rules can compare them
|
|
380
408
|
- [ ] Tests cover parsing, both config shapes, and uid stability
|
|
381
409
|
- [ ] Optional: `claim()` for values only this source can mean, `caches` for namespaces keyed by target
|
|
382
|
-
- [ ] Registered
|
|
410
|
+
- [ ] Registered: `@register` plus an import, or an entry point
|
|
@@ -2,6 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
4
|
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.5.0] — 2026-11-06
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`youpdated import`** (#37). Adds everything in a `package.json`, `requirements.txt`, or `Brewfile`, with `youpdated add`, `--test` shows the change without writing it. `package.json` dependencies of every kind go under `npm`, requirements go under `pypi` with `-r` includes followed, and `brew`/`cask` lines go under `homebrew`. A dependency from a path, URL, git repo, editable install, third-party tap, and Brewfile lines like `mas` are skipped with reasons shown. Files are recognized by name, or read as named with `--format`. Requirements from another index (`--index-url`, `--no-index`) are skipped, as PyPI's package of that name may be a different one, and `--extra-index-url` is shown as a warning. Credentials in a dependency's URL are never printed.
|
|
12
|
+
- **Version filters** (#37). A `versions:` rule reports only some of a target's versions. `bump: major` reports a version only when its first number is higher than every release before it: 4.0.0, but not 4.0.1 or a 3.9.x backport. `minor` and `patch` do the same for the second and third numbers, and `min: "3.13"` drops versions below 3.13. Rules can be set for every source, for one, or on one entry, like `ignore:`, and an entry's rules override the others one rule at a time; `bump: any` turns a bump back off. Only the first prerelease toward a bump is reported, then the final, so a run of nightlies or canaries counts once. Versions are compared by their numbers, so any dotted or underscored scheme works (`v3.15.0rc1`, `131.0.6778.69`, `curl-8_11_1`, `REL_17_2`), and updates without a version, like commits, aren't filtered. A version left out still counts as seen, so loosening a rule doesn't report the past. A target with `bump` keeps its highest versions in its history, so a source listing only the current version (`homebrew`) has something to compare against; `rm --wipe` and `expiry:` clear. The summary says how many versions were left out, and `--json` counts them as `filtered`. A `versions:` key no source is listed under is warned about, like an `ignore:` one.
|
|
13
|
+
- **`youpdated edit`** (#59). Opens the config in an editor, then saves it once the editor closes. An editor that opens a window and returns at once, like the device defaults or `code`, is waited on: save there, then press Enter. `editor:` in the config picks one over `$VISUAL` and `$EDITOR`: a command, a program's path, or (on macOS) an app's name. Smart quotes around a value, an unquoted value starting with `@`, and no-break or invisible spaces are fixed on save, and listed. An encrypted config is decrypted to a copy only you can read, under `/dev/shm` where available, and written back encrypted with the same passphrase. A config that sets `privacy.proxy` and encrypts asks before writing the copy. The edit is checked before saving. Nothing is saved when the editor exits with an error.
|
|
14
|
+
- **`track_latest:`** (#37). With `track_latest: true`, `git` and `steam` entries also ask for the latest release, in case busier items pushed it off the list: where GitHub's `/releases/latest` points (the API's latest release with a token), GitLab's latest permalink, Forgejo's latest release, and the newest Steam post the developer marked as an update. It's added only when not already listed. Off by default, as it's one request more per entry.
|
|
15
|
+
- **`webpage` source** (#56). Watches the version a page shows, for apps with no feed, registry, or forge: `youpdated add https://www.videolan.org/vlc/`. The version is read from the page's structured data (`softwareVersion`), then download links with a version in the file name, then text naming the latest version, then text labeling one. The first that has a version decides and must name only one, and any other naming a different one fails the check. Where the version was found is remembered, and a later check finding it elsewhere fails. `regex:` names the version location, matched against the page's HTML. A page with no version that links a feed says that in its error, and an address that is a feed points to `feed`. Prereleases (`2.5.0-beta.1`) are tagged `prerelease`; `rm --wipe` forgets where the version was found.
|
|
16
|
+
- **Sorting and priority in the desktop example app** (#12). Right-click an update to mark its target high, normal, or low priority; high ones are tagged and low ones dimmed. The list sorts by priority, newest, source, or name. High targets get their own notification as soon as they update, and low ones never notify. `--digest 18:00` holds the rest for one notification a day, and `--bundle-high` holds high priority too. Settings live in the example only, beside the history as `state.desk.json` and encrypted when the history is; the youpdated config is unchanged. (example app available from the GitHub)
|
|
17
|
+
- **Youpdated for Mac (beta)** (#37). A menu bar app for macOS 15+ on Apple silicon, with its own copy of the engine (no Python needed). It shares a config and history with the CLI. See [docs/macos-app.md](docs/macos-app.md).
|
|
18
|
+
- **`youpdated api`** (#37). The JSON interface for desktop apps. `youpdated api serve` reads requests on stdin and answers on stdout; any other op runs once and prints a reply, for scripts: `youpdated api status --json`. Messages, a JSON Schema, and an example of every exchange are in `apps/contract/v1`. An encrypted setup is unlocked once over the pipe, and derived keys are kept in memory, so later requests don't each pay for scrypt.
|
|
19
|
+
- **Priorities and the digest in `notify:`** (#37). Each target is `high`, `normal`, or `low` priority, set in the desktop app. A webhook or command gets updates at its `priority:` and above, `normal` if not configured, and `digest: false` sends them as found while the app holds a digest. `command:` also takes a mapping, with the command under `run:`. The CLI applies `priority:` and ignores `digest:`.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **`youpdated add` with a URL no source recognizes adds it under `webpage`**, instead of asking for a source. A URL another source claims (a GitHub repo, an itch.io game, a feed) still goes to that source; plugins can claim the same way with `fallback = True`.
|
|
24
|
+
- **`youpdated add` lists entries already watched on one line per source** (`Already watching express, react under npm`), instead of one line each.
|
|
25
|
+
- **`youpdated uninstall` also removes the package.** Once the files are gone it runs the uninstaller used for the copy: `pipx uninstall` for pipx, `uv tool uninstall` for uv tools, `uv pip uninstall` for a uv-made environment, and `python -m pip uninstall` with the interpreter it runs on otherwise. The package is listed in `--test` and confirmation prompt. If the uninstaller fails, or exits but leaves the package, the command to run yourself is printed and exits 1. On Windows, which won't delete the running `youpdated.exe`, the uninstaller runs in the background once the command exits. `--keep-package` deletes files only. `--keep-config` now removes the package too; add `--keep-package` to only wipe history. A copy run from a checkout (`python -m youpdated`, `PYTHONPATH`) is not a package, and nothing other than files are removed.
|
|
26
|
+
- **One run at a time per history file.** A run holds a lock (`state.sqlite3.lock`, beside the database) and another waits up to a minute, then exits 1 saying the file is in use. An encrypted history is read whole and written back whole, so a `youpdated rm --wipe` during a scheduled check was undone, two overlapping checks could lose seen marks, and a file could be left undecryptable. `encrypt` and `decrypt` take the lock too. `uninstall` removes the lock file as well.
|
|
27
|
+
- **`--since` leaves what it hides unrecorded.** A new item older than the window was recorded as seen, so only `--all` could ever show it. It is now reported by the next check without `--since`.
|
|
28
|
+
- **`check --test` shows the config's problems** in the `problems` panel and exits 2 for them with `--fail-on-error`, and `--test --json` prints a report. It used to exit 0 and print nothing about them. A source that stops early for want of an answer is not counted as a problem.
|
|
29
|
+
- **`git` refuses `owner/repo/extra`** for GitHub and Forgejo instead of reading it as `owner/repo`: `add hashicorp/tap/terraform` landed under `git` as `hashicorp/tap`, and `rm python/cpython/typo` removed `python/cpython`. A pasted address (`https://github.com/o/r/releases/tag/v1`, `codeberg.org/o/r/releases`) is still trimmed to the repo.
|
|
30
|
+
- **A webhook is only sent again when it can't have arrived**: after a failed connection, `429`, `503`. Timeout or `500`, `502`, `504` could come after delivery, and aren't retried.
|
|
31
|
+
- **Notify commands no longer inherit** `YOUPDATED_PASSPHRASE`, `GITHUB_TOKEN`, `GITLAB_TOKEN`, `YOUTUBE_API_KEY`.
|
|
32
|
+
- **A warning for an `ignore:` key with no coverage**, such as `ignore: {github: …}` left behind after moving entries to `git:`. It shows after the report, and in a new `warnings` list in `--json`.
|
|
33
|
+
- **`expiry:` and `--since` max out at 100y.** `never` still works.
|
|
34
|
+
- **The release workflow's publish job now pins actions to exact commits**, since it holds `id-token: write` and a tag can be moved.
|
|
35
|
+
- **The desktop example shows one card per target.** Several updates from the same target share its card, newest first, one line each up to three and then a count; each line opens its own link.
|
|
36
|
+
- **`rm --wipe` also forgets what the desktop app stores about a target**: inbox items, priority, newest item, and icon.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- **More prereleases are recognized without a GitHub token.** The anonymous atom feeds have no prerelease flag, so the tag name is read, and now catches `-next.2` (Angular), milestones `-M2` and `.CR1` (Spring, Quarkus), `beta4` right after the version (Nextcloud), `-ea.3` (Traefik), `llvmorg-24-init`, mesa's `-branchpoint` tags, Swift's dated snapshots, and an rc with build metadata (`-rc.0+dedupelabels`). A tag without a number, like neovim's `nightly`, keeps it as its version, so it is a prerelease as the API path flags it, and a commit hash ending in `7b0` is no longer one. Checked against GitHub's own flags on 11,259 releases of 87 projects: missed prereleases went from 441 to 288, none of which have anything in the tag to go by.
|
|
41
|
+
- **npm and pypi could miss a release behind prereleases.** A check read the 10 newest versions, so a package publishing canaries or nightlies faster than it was checked could push a release out before it was seen: in three years of `next`'s history, weekly checks would never have seen 42 of its final releases, or 7 of `react`'s. The 10 newest final releases and the `latest` version are now listed too, from the same request.
|
|
42
|
+
- **Security: the YouTube Data API key could be printed.** It was part of the request URL, which errors, `--json`, `-v`, and `--test` show. It is now sent in the `X-Goog-Api-Key` header, which is dropped on a redirect to another host.
|
|
43
|
+
- **Security: escape codes in a title, body, or link reached the terminal.** A feed could clear the screen or plant links with ``. Control characters and lone surrogates are now removed from everything a site sends, which also keeps `--rss` valid XML when a title holds one, and stops a lone surrogate from crashing `--rss` and `--json`.
|
|
44
|
+
- **Security: the desktop example could run code from a title on Windows.** PowerShell ends a quoted string at curly quotes too. The text now reaches PowerShell through the environment.
|
|
45
|
+
- **Updates could be lost when the report failed.** Items were recorded as seen before the report, `--rss`, and pruning ran, so a failure in any of them, such as a label with `[/…]` in the problems panel, a numeric Invidious title, or an unwritable `--rss` path, used them up unseen. The report and feed are now first. An unwritable `--rss` path is an error.
|
|
46
|
+
- **An invalid entry no longer drops later entries of its source.** It is reported alone.
|
|
47
|
+
- **A web page at a feed's address was an empty feed**, with no error, and on a first fetch its empty baseline reported the whole feed as new once the feed returned. It is now an error, for feeds and sources that reads one.
|
|
48
|
+
- **Brave recorded an empty baseline when the GitHub API was rate-limited**, since the atom feed's 10 newest releases are nearly all nightlies, and then reported old stable releases as new. The target now fails until either path has a release for its channel, and the stable channel falls back to the release GitHub marks as latest.
|
|
49
|
+
- **YouTube's fallbacks**: a malformed Invidious reply (`{"videos": [null]}`, an out-of-range date) skipped the other instances and the Data API; it now moves on. Invidious addresses from the public list are used only if they are HTTPS on a public hostname; a test had fetched `http://127.0.0.1:9`. The list is refreshed on use (once a day) instead of never; each fetch tries a random four kept instances, not just the first four, and `rm --wipe` clears.
|
|
50
|
+
- **Cookies could pass between requests** run at the same time, and to the next hop of a redirect. Now none are kept.
|
|
51
|
+
- **A webhook redirected with `301`, `302`, `303`.** It was resent as a request without a body, and counted as delivered. It is now a failure; `307` and `308` are still followed.
|
|
52
|
+
- **A repo listed under both `github:` and `git:` with different ignore rules** was fetched fully on every run.
|
|
53
|
+
- **`youpdated encrypt` on a symlinked config** replaced the link and left the plaintext at its target. It now writes through the link, same as `add`/`rm`. A write also doesn't leave a fixed-name `.tmp`, which could make the result readable by others.
|
|
54
|
+
- **A GitLab group with a dot in its name** (`my.group/sub/project` with `host: gitlab.com`) was read as a hostname.
|
|
55
|
+
- **A plugin whose constructor raises** crashed every command, and kept later plugins from loading. It is now skipped.
|
|
56
|
+
- **Cleaner errors instead of tracebacks** for a config that isn't UTF-8, a `--state` file that isn't a database, and the desktop example given a `-c` config that doesn't exist.
|
|
57
|
+
- **`uninstall` exited 0 when it left files in place.** It now exits 1.
|
|
58
|
+
- **An ntfy webhook lost its query**, so `?auth=` didn't work; `headers:` was the only way.
|
|
59
|
+
- **`split_command` accepted** a YAML boolean (`yes`, `off`) or an empty string in a list command.
|
|
60
|
+
- **Timestamps with a fraction and a zone offset**, such as `.123+05:30`, lost the offset in the `browser` source. One parser now serves every source.
|
|
61
|
+
- **Trackpad scrolling in the desktop example on macOS.** Tk 9 sends trackpads as `<TouchpadScroll>`, which the window ignored, and reports a mouse wheel notch as 120 rather than 1, which scrolled 720 pixels a notch. Tk 8.6 behaves as before.
|
|
62
|
+
- **Link highlighting** has been fixed to correctly bold links without extra coloration or breakage at spaces in links.
|
|
63
|
+
- **Terminal resizing** no longer adds extra lines or breaks output formatting in cli.
|
|
64
|
+
|
|
5
65
|
## [0.4.0] — 2026-10-24
|
|
6
66
|
|
|
7
67
|
### Added
|
|
@@ -35,7 +95,7 @@ All notable changes to this project are documented here. The format follows [Kee
|
|
|
35
95
|
### Fixed
|
|
36
96
|
|
|
37
97
|
- **itch builds no longer re-report on unchanged pages.** itch.io shuffles HTML attribute order, and the upload list was only read in one order, so some fetches saw no files and fingerprinted a "new build". Successive runs each reported a different handful of games until every variant had been seen. Upload and timestamp parsing no longer depend on attribute order.
|
|
38
|
-
- **YouTube Shorts no longer re-report when the feed falls back.** The official feed links Shorts as `/shorts/<id>`, which was not
|
|
98
|
+
- **YouTube Shorts no longer re-report when the feed falls back.** The official feed links Shorts as `/shorts/<id>`, which was not recognized, so Shorts were recorded as `yt:video:yt:video:<id>` there and `yt:video:<id>` through Invidious or Data API. Each switch reported Shorts again. Existing history is migrated on first open, so nothing already seen comes back.
|
|
39
99
|
- **`--no-save` really leaves the state alone.** It still stored each feed's ETag/Last-Modified, so the next real run was answered 304 and silently skipped whatever the preview had shown. (Whoops)
|
|
40
100
|
- **A target that fails partway no longer hides its new items.** If one of a target's fetches failed (e.g. GitHub `watch: [releases, commits]` with commits down), the others' validators were still stored while their items were discarded, so the next run got a 304 and never reported them. Validators are now stored only alongside the items they cover.
|
|
41
101
|
- **Feeds listed oldest-first report new entries.** Entries were cut to the limit in document order before sorting, so on an oldest-first feed longer than the limit the newest posts never made it in. Affects `feed`, Steam, itch devlogs, and GitHub atom feeds.
|
|
@@ -93,7 +153,7 @@ All notable changes to this project are documented here. The format follows [Kee
|
|
|
93
153
|
|
|
94
154
|
A run now reuses each document across the targets that share it (`Client.run_scope()`), so the document is fetched once and every target sees it. The same config went from 8 requests reporting 2 of 8 targets, to 2 requests reporting 8 of 8. (And 147 ms to 43 ms of wall time) Outside a run the client is unchanged: one GET per call, and a 304 still means "nothing new".
|
|
95
155
|
|
|
96
|
-
- **The YouTube official-feed path never set the channel label.** `_label_and_parse` did not do the
|
|
156
|
+
- **The YouTube official-feed path never set the channel label.** `_label_and_parse` did not do the labeling it was supposed to, so a channel that answered on the primary path was reported by its raw `@handle` while the Invidious and Data API fallbacks named it properly. The label now comes from the feed on all three paths.
|
|
97
157
|
|
|
98
158
|
- **`feed` sources parsed every feed twice** A `feed:` entry given as a bare URL had no label, so `FeedSource.fetch` parsed the document once to read the feed's own `<title>` and then handed the same bytes to `parse_feed`, which parsed them again. Feed parsing is the most expensive part of a run, so this ~doubled the CPU cost of every bare-URL feed. One parse now feeds both the label and the entries.
|
|
99
159
|
|
|
@@ -167,6 +227,7 @@ First release.
|
|
|
167
227
|
- Firefox publishes current versions, so it reports one item per channel.
|
|
168
228
|
- Edge exposes release notes only for the stable and beta channels. (But like, it's Edge, why do you want to know when it updates?)
|
|
169
229
|
|
|
230
|
+
[0.5.0]: https://github.com/Void1-1/youpdated/releases/tag/v0.5.0
|
|
170
231
|
[0.4.0]: https://github.com/Void1-1/youpdated/releases/tag/v0.4.0
|
|
171
232
|
[0.3.1]: https://github.com/Void1-1/youpdated/releases/tag/v0.3.1
|
|
172
233
|
[0.3.0]: https://github.com/Void1-1/youpdated/releases/tag/v0.3.0
|
|
@@ -72,7 +72,7 @@ TLDR: implement `targets()` and `fetch()` from the protocol in [youpdated/source
|
|
|
72
72
|
|
|
73
73
|
## Building a release
|
|
74
74
|
|
|
75
|
-
Publishing is done by [.github/workflows/release.yml](.github/workflows/release.yml) when a GitHub Release is published. It runs the full test matrix, builds, checks the tag matches the version in `pyproject.toml`, installs the built wheel to make sure it runs, and uploads to PyPI through trusted publishing. No PyPI token is stored.
|
|
75
|
+
Publishing is done by [.github/workflows/release.yml](.github/workflows/release.yml) when a GitHub Release tagged `v*` is published. It runs the full test matrix, builds, checks the tag matches the version in `pyproject.toml`, installs the built wheel to make sure it runs, and uploads to PyPI through trusted publishing. No PyPI token is stored.
|
|
76
76
|
|
|
77
77
|
1. Bump `version` in `pyproject.toml` and add the matching `CHANGELOG.md` entry in the same commit.
|
|
78
78
|
**A version is permanent:** PyPI refuses to replace an existing version even after a delete.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: youpdated
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Simple update tracker for games, apps, and packages
|
|
5
5
|
Author-email: Void1-1 <161782542+Void1-1@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -39,18 +39,36 @@ Provides-Extra: dev
|
|
|
39
39
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
40
40
|
Requires-Dist: respx>=0.21; extra == "dev"
|
|
41
41
|
Requires-Dist: cryptography>=42.0; extra == "dev"
|
|
42
|
+
Requires-Dist: jsonschema>=4.18; extra == "dev"
|
|
42
43
|
Provides-Extra: publish
|
|
43
44
|
Requires-Dist: build>=1.2; extra == "publish"
|
|
44
45
|
Requires-Dist: twine>=5.0; extra == "publish"
|
|
45
46
|
Dynamic: license-file
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
<p align="center">
|
|
49
|
+
<picture>
|
|
50
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Void1-1/youpdated/main/.github/assets/logo-dark.png">
|
|
51
|
+
<img src="https://raw.githubusercontent.com/Void1-1/youpdated/main/.github/assets/logo-light.png" alt="Youpdated" width="340">
|
|
52
|
+
</picture>
|
|
53
|
+
</p>
|
|
54
|
+
|
|
55
|
+
<p align="center">
|
|
56
|
+
Youpdated keeps track of the games, apps, and packages you follow, and lets you know about updates or changes.
|
|
57
|
+
</p>
|
|
58
|
+
|
|
59
|
+
<p align="center">
|
|
60
|
+
<a href="https://pypi.org/project/youpdated/"><img src="https://img.shields.io/pypi/v/youpdated?color=006C7D&label=PyPI" alt="PyPI version"></a>
|
|
61
|
+
<a href="https://pypi.org/project/youpdated/"><img src="https://img.shields.io/pypi/pyversions/youpdated?color=006C7D&label=Python" alt="Supported Python versions"></a>
|
|
62
|
+
<a href="https://github.com/Void1-1/youpdated/actions/workflows/tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/Void1-1/youpdated/tests.yml?branch=main&label=Tests" alt="Test status"></a>
|
|
63
|
+
<a href="https://github.com/Void1-1/youpdated/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Void1-1/youpdated?color=006C7D&label=License" alt="MIT license"></a>
|
|
64
|
+
</p>
|
|
65
|
+
|
|
66
|
+
<p align="center">
|
|
67
|
+
<a href="#get-started">Get started</a> ·
|
|
68
|
+
<a href="#sources">Sources</a> ·
|
|
69
|
+
<a href="https://github.com/Void1-1/youpdated/blob/main/docs/macos-app.md">Youpdated MacOS App (beta)</a> ·
|
|
70
|
+
<a href="#learn-more">Docs</a>
|
|
71
|
+
</p>
|
|
54
72
|
|
|
55
73
|
```text
|
|
56
74
|
╭─ steam ──────────────────────────────────────────────────────────╮
|
|
@@ -78,9 +96,12 @@ It is built to be **privacy-preserving, anonymous, and customizable**: no accoun
|
|
|
78
96
|
| `youtube` | New videos on a channel or playlist |
|
|
79
97
|
| `browser` | New Chrome, Brave, Firefox, and Edge releases |
|
|
80
98
|
| `feed` | Anything else with an RSS or Atom feed |
|
|
99
|
+
| `webpage` | The version a download page shows, for anything with no feed |
|
|
81
100
|
|
|
82
101
|
## Get started
|
|
83
102
|
|
|
103
|
+
On a Mac and want an app version? [Youpdated for Mac](https://github.com/Void1-1/youpdated/blob/main/docs/macos-app.md) is in beta.
|
|
104
|
+
|
|
84
105
|
### 1. Install
|
|
85
106
|
|
|
86
107
|
Works on macOS, Linux, and Windows. Needs **Python 3.11 or newer** (`python3 --version` to check). Then:
|
|
@@ -116,11 +137,13 @@ youpdated add npm react
|
|
|
116
137
|
youpdated add youtube @NASA
|
|
117
138
|
```
|
|
118
139
|
|
|
119
|
-
A link or handle that can only work with one source doesn't need to be named: `youpdated add https://github.com/neovim/neovim`.
|
|
140
|
+
A link or handle that can only work with one source doesn't need to be named: `youpdated add https://github.com/neovim/neovim`. Any other web address goes under `webpage`.
|
|
141
|
+
|
|
142
|
+
To watch all dependencies of a project, import its `package.json`, `requirements.txt`, or `Brewfile`: `youpdated import package.json`.
|
|
120
143
|
|
|
121
144
|
The starter config comes with examples; `youpdated rm` to remove any you don't want.
|
|
122
145
|
|
|
123
|
-
Or open the file and list them under each source yourself:
|
|
146
|
+
Or run `youpdated edit` to open the file and list them under each source yourself:
|
|
124
147
|
|
|
125
148
|
```yaml
|
|
126
149
|
sources:
|
|
@@ -155,6 +178,7 @@ youpdated check
|
|
|
155
178
|
| A YouTube playlist | `playlist: PLxxxx` | The `list=` part of the playlist URL. A full playlist URL also works. |
|
|
156
179
|
| A browser | `chrome`, `brave`, `firefox`, `edge` | Just the name. |
|
|
157
180
|
| Anything else | `https://example.com/feed.xml` | Any RSS or Atom feed URL. Many sites publish one at `/feed.xml`, `/releases.atom`, or `/blog/rss`. |
|
|
181
|
+
| Anything without a feed | `https://www.videolan.org/vlc/` | The download page's URL. The version is read off the page. See [Web pages](docs/configuration.md#web-pages). |
|
|
158
182
|
|
|
159
183
|
## Basic commands
|
|
160
184
|
|
|
@@ -166,7 +190,9 @@ youpdated check -s steam # only one source
|
|
|
166
190
|
youpdated check --test -v # check your config without fetching anything
|
|
167
191
|
youpdated add npm react # start watching something
|
|
168
192
|
youpdated remove npm react # stop watching it
|
|
169
|
-
youpdated
|
|
193
|
+
youpdated import Brewfile # watch everything a package.json, requirements.txt, or Brewfile lists
|
|
194
|
+
youpdated edit # open the config in your default editor
|
|
195
|
+
youpdated uninstall # remove Youpdated and its files
|
|
170
196
|
```
|
|
171
197
|
|
|
172
198
|
## Privacy
|
|
@@ -177,6 +203,7 @@ youpdated uninstall # remove Youpdated files
|
|
|
177
203
|
|
|
178
204
|
## Learn more
|
|
179
205
|
|
|
206
|
+
- [Youpdated for Mac](https://github.com/Void1-1/youpdated/blob/main/docs/macos-app.md): the menu bar app, in beta
|
|
180
207
|
- [Configuration](https://github.com/Void1-1/youpdated/blob/main/docs/configuration.md): all options, ignoring update types, and how long history is kept
|
|
181
208
|
- [Usage](https://github.com/Void1-1/youpdated/blob/main/docs/usage.md): all commands, JSON and RSS output, and running on a schedule
|
|
182
209
|
- [Notifications](https://github.com/Void1-1/youpdated/blob/main/docs/notifications.md): get updates on your phone, Discord, Slack, or to a script
|
|
@@ -1,10 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Void1-1/youpdated/main/.github/assets/logo-dark.png">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/Void1-1/youpdated/main/.github/assets/logo-light.png" alt="Youpdated" width="340">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
Youpdated keeps track of the games, apps, and packages you follow, and lets you know about updates or changes.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://pypi.org/project/youpdated/"><img src="https://img.shields.io/pypi/v/youpdated?color=006C7D&label=PyPI" alt="PyPI version"></a>
|
|
14
|
+
<a href="https://pypi.org/project/youpdated/"><img src="https://img.shields.io/pypi/pyversions/youpdated?color=006C7D&label=Python" alt="Supported Python versions"></a>
|
|
15
|
+
<a href="https://github.com/Void1-1/youpdated/actions/workflows/tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/Void1-1/youpdated/tests.yml?branch=main&label=Tests" alt="Test status"></a>
|
|
16
|
+
<a href="https://github.com/Void1-1/youpdated/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Void1-1/youpdated?color=006C7D&label=License" alt="MIT license"></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="#get-started">Get started</a> ·
|
|
21
|
+
<a href="#sources">Sources</a> ·
|
|
22
|
+
<a href="https://github.com/Void1-1/youpdated/blob/main/docs/macos-app.md">Youpdated MacOS App (beta)</a> ·
|
|
23
|
+
<a href="#learn-more">Docs</a>
|
|
24
|
+
</p>
|
|
8
25
|
|
|
9
26
|
```text
|
|
10
27
|
╭─ steam ──────────────────────────────────────────────────────────╮
|
|
@@ -32,9 +49,12 @@ It is built to be **privacy-preserving, anonymous, and customizable**: no accoun
|
|
|
32
49
|
| `youtube` | New videos on a channel or playlist |
|
|
33
50
|
| `browser` | New Chrome, Brave, Firefox, and Edge releases |
|
|
34
51
|
| `feed` | Anything else with an RSS or Atom feed |
|
|
52
|
+
| `webpage` | The version a download page shows, for anything with no feed |
|
|
35
53
|
|
|
36
54
|
## Get started
|
|
37
55
|
|
|
56
|
+
On a Mac and want an app version? [Youpdated for Mac](https://github.com/Void1-1/youpdated/blob/main/docs/macos-app.md) is in beta.
|
|
57
|
+
|
|
38
58
|
### 1. Install
|
|
39
59
|
|
|
40
60
|
Works on macOS, Linux, and Windows. Needs **Python 3.11 or newer** (`python3 --version` to check). Then:
|
|
@@ -70,11 +90,13 @@ youpdated add npm react
|
|
|
70
90
|
youpdated add youtube @NASA
|
|
71
91
|
```
|
|
72
92
|
|
|
73
|
-
A link or handle that can only work with one source doesn't need to be named: `youpdated add https://github.com/neovim/neovim`.
|
|
93
|
+
A link or handle that can only work with one source doesn't need to be named: `youpdated add https://github.com/neovim/neovim`. Any other web address goes under `webpage`.
|
|
94
|
+
|
|
95
|
+
To watch all dependencies of a project, import its `package.json`, `requirements.txt`, or `Brewfile`: `youpdated import package.json`.
|
|
74
96
|
|
|
75
97
|
The starter config comes with examples; `youpdated rm` to remove any you don't want.
|
|
76
98
|
|
|
77
|
-
Or open the file and list them under each source yourself:
|
|
99
|
+
Or run `youpdated edit` to open the file and list them under each source yourself:
|
|
78
100
|
|
|
79
101
|
```yaml
|
|
80
102
|
sources:
|
|
@@ -109,6 +131,7 @@ youpdated check
|
|
|
109
131
|
| A YouTube playlist | `playlist: PLxxxx` | The `list=` part of the playlist URL. A full playlist URL also works. |
|
|
110
132
|
| A browser | `chrome`, `brave`, `firefox`, `edge` | Just the name. |
|
|
111
133
|
| Anything else | `https://example.com/feed.xml` | Any RSS or Atom feed URL. Many sites publish one at `/feed.xml`, `/releases.atom`, or `/blog/rss`. |
|
|
134
|
+
| Anything without a feed | `https://www.videolan.org/vlc/` | The download page's URL. The version is read off the page. See [Web pages](docs/configuration.md#web-pages). |
|
|
112
135
|
|
|
113
136
|
## Basic commands
|
|
114
137
|
|
|
@@ -120,7 +143,9 @@ youpdated check -s steam # only one source
|
|
|
120
143
|
youpdated check --test -v # check your config without fetching anything
|
|
121
144
|
youpdated add npm react # start watching something
|
|
122
145
|
youpdated remove npm react # stop watching it
|
|
123
|
-
youpdated
|
|
146
|
+
youpdated import Brewfile # watch everything a package.json, requirements.txt, or Brewfile lists
|
|
147
|
+
youpdated edit # open the config in your default editor
|
|
148
|
+
youpdated uninstall # remove Youpdated and its files
|
|
124
149
|
```
|
|
125
150
|
|
|
126
151
|
## Privacy
|
|
@@ -131,6 +156,7 @@ youpdated uninstall # remove Youpdated files
|
|
|
131
156
|
|
|
132
157
|
## Learn more
|
|
133
158
|
|
|
159
|
+
- [Youpdated for Mac](https://github.com/Void1-1/youpdated/blob/main/docs/macos-app.md): the menu bar app, in beta
|
|
134
160
|
- [Configuration](https://github.com/Void1-1/youpdated/blob/main/docs/configuration.md): all options, ignoring update types, and how long history is kept
|
|
135
161
|
- [Usage](https://github.com/Void1-1/youpdated/blob/main/docs/usage.md): all commands, JSON and RSS output, and running on a schedule
|
|
136
162
|
- [Notifications](https://github.com/Void1-1/youpdated/blob/main/docs/notifications.md): get updates on your phone, Discord, Slack, or to a script
|
|
@@ -32,8 +32,9 @@ Youpdated is a local CLI that reads public endpoints. The interesting attack sur
|
|
|
32
32
|
sent to any host other than the one they belong to, including by following a redirect. The same
|
|
33
33
|
goes for headers set on a webhook. Webhook URLs carry their secret in the path and must never be
|
|
34
34
|
logged or shown beyond their host.
|
|
35
|
-
- **`youpdated uninstall`.** It deletes files. Any way to make it remove
|
|
36
|
-
config and data directories
|
|
35
|
+
- **`youpdated uninstall`.** It deletes files and uninstalls the package. Any way to make it remove
|
|
36
|
+
something outside its own config and data directories, or uninstall anything but the running copy of
|
|
37
|
+
Youpdated, is in scope.
|
|
37
38
|
- **Encryption at rest.** When the config or history is encrypted, the passphrase and the decrypted
|
|
38
39
|
contents must exist only in memory. Anything that writes plaintext to disk, logs the passphrase,
|
|
39
40
|
accepts a file whose authentication tag does not verify, lets the KDF parameters be weakened, or
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "youpdated"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.0"
|
|
8
8
|
description = "Simple update tracker for games, apps, and packages"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -56,7 +56,7 @@ dependencies = [
|
|
|
56
56
|
|
|
57
57
|
[project.optional-dependencies]
|
|
58
58
|
encryption = ["cryptography>=42.0"]
|
|
59
|
-
dev = ["pytest>=8.0", "respx>=0.21", "cryptography>=42.0"]
|
|
59
|
+
dev = ["pytest>=8.0", "respx>=0.21", "cryptography>=42.0", "jsonschema>=4.18"]
|
|
60
60
|
publish = ["build>=1.2", "twine>=5.0"]
|
|
61
61
|
|
|
62
62
|
[project.urls]
|