simklcli 0.1.0__py3-none-any.whl
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.
- simklcli/__init__.py +3 -0
- simklcli/__main__.py +4 -0
- simklcli/api.py +431 -0
- simklcli/catalog.py +167 -0
- simklcli/cli.py +496 -0
- simklcli/commands.py +437 -0
- simklcli/filesystem.py +31 -0
- simklcli/media.py +190 -0
- simklcli/output.py +55 -0
- simklcli/rate_control.py +99 -0
- simklcli/runtime.py +242 -0
- simklcli/snapshots.py +162 -0
- simklcli/storage.py +347 -0
- simklcli/targets.py +117 -0
- simklcli/tracking.py +484 -0
- simklcli-0.1.0.dist-info/METADATA +217 -0
- simklcli-0.1.0.dist-info/RECORD +20 -0
- simklcli-0.1.0.dist-info/WHEEL +4 -0
- simklcli-0.1.0.dist-info/entry_points.txt +2 -0
- simklcli-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simklcli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Track movies, shows, and anime on Simkl from the command line.
|
|
5
|
+
Author: Javier Ochoa
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Javier Ochoa
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Python: >=3.11
|
|
29
|
+
Requires-Dist: filelock<4,>=3.18
|
|
30
|
+
Requires-Dist: httpx<1,>=0.28
|
|
31
|
+
Requires-Dist: keyring<26,>=25
|
|
32
|
+
Requires-Dist: platformdirs<5,>=4.3
|
|
33
|
+
Requires-Dist: rich<15,>=14
|
|
34
|
+
Requires-Dist: typer<1,>=0.27
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# simklcli
|
|
38
|
+
|
|
39
|
+
`simklcli` is a public command-line client for the core Simkl tracking loop:
|
|
40
|
+
authentication, catalog search and lookup, Library management, Watched State,
|
|
41
|
+
and User Ratings. The PyPI distribution exposes the shorter `simkl` command.
|
|
42
|
+
|
|
43
|
+
The CLI supports Simkl PIN Authorization, catalog search and lookup, Library
|
|
44
|
+
management, Watched State, and User Ratings. It reconciles account state online
|
|
45
|
+
and retains a dated Library Snapshot for explicit offline reads.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
Python 3.11 or newer is required. Once the first release is published, install
|
|
50
|
+
the supported package with:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
uv tool install simklcli
|
|
54
|
+
# or: pipx install simklcli
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Authentication
|
|
58
|
+
|
|
59
|
+
The CLI ships with simklcli's public AUTH V2 app ID, so no developer
|
|
60
|
+
registration is needed:
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
simkl auth login
|
|
64
|
+
simkl auth status --check
|
|
65
|
+
simkl search "Cowboy Bebop" --kind anime
|
|
66
|
+
simkl library list
|
|
67
|
+
simkl library list --offline
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
From a checkout, run the same commands through `uv sync --locked` and
|
|
71
|
+
`uv run simkl …`.
|
|
72
|
+
|
|
73
|
+
Login uses the V2 device-based PIN Authorization flow. Open the printed link
|
|
74
|
+
and approve the application on Simkl; no client secret, redirect URL, or PKCE
|
|
75
|
+
parameters are used by this flow. The client ID is public by design: on its
|
|
76
|
+
own it reaches only public catalog data, and every user-scoped request also
|
|
77
|
+
needs that user's Access Token.
|
|
78
|
+
|
|
79
|
+
To use your own app instead, register an **AUTH V2** application as
|
|
80
|
+
**TV, devices & command line** at
|
|
81
|
+
[Simkl Developer Settings](https://simkl.com/settings/developer/) and set
|
|
82
|
+
`SIMKL_CLIENT_ID` to its public ID before logging in. The issuing app ID is
|
|
83
|
+
stored with each credential, so later invocations keep using it without the
|
|
84
|
+
environment variable. An override must match the app that issued the stored
|
|
85
|
+
tokens.
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
simkl auth login
|
|
89
|
+
simkl auth status
|
|
90
|
+
simkl auth status --check
|
|
91
|
+
simkl auth logout
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Login stores the Access Token and Refresh Token together in the OS keyring.
|
|
95
|
+
If the platform has no usable keyring, plaintext storage must be
|
|
96
|
+
selected explicitly with `simkl auth login --storage file`. Set
|
|
97
|
+
`SIMKL_ACCESS_TOKEN` for a non-persisted automation override; it takes
|
|
98
|
+
precedence over local credentials and must come from the built-in app or from
|
|
99
|
+
the app named by `SIMKL_CLIENT_ID`.
|
|
100
|
+
Environment overrides are not refreshed or persisted; supply a fresh Access
|
|
101
|
+
Token when it expires. The old embedded V1 client ID has been removed.
|
|
102
|
+
|
|
103
|
+
Access Tokens last seven days; the CLI refreshes shortly before expiry or once
|
|
104
|
+
after an explicit token rejection. Refresh Tokens last 180 days with sliding
|
|
105
|
+
expiry. Refresh and storage changes share an account lock across processes.
|
|
106
|
+
Search and External ID resolution require sign-in. An anonymous known-ID lookup
|
|
107
|
+
is available with `simkl lookup simkl:<id> --kind movie|show|anime`.
|
|
108
|
+
|
|
109
|
+
An existing V1 account reconnects through `simkl auth login` without first
|
|
110
|
+
logging out: approval must match the recorded account, and its Library Snapshot
|
|
111
|
+
is retained. A failed or cancelled login preserves the existing credentials.
|
|
112
|
+
Expired or revoked grants require explicit login and keep offline snapshots.
|
|
113
|
+
See the [migration guide](docs/auth-v2-migration.md) for local verification.
|
|
114
|
+
|
|
115
|
+
Logout removes local credentials and the Library Snapshot and makes a
|
|
116
|
+
best-effort request to revoke the stored V2 grant. `--local-only` skips that
|
|
117
|
+
request. Simkl acknowledges revocation without revealing whether a token was
|
|
118
|
+
valid; the CLI reports acknowledgement rather than proof of revocation.
|
|
119
|
+
|
|
120
|
+
Use `simkl auth status --json` for a single machine-readable stdout payload.
|
|
121
|
+
The default status check is local-only; `--check` explicitly validates the
|
|
122
|
+
Access Token with Simkl and refreshes the display name.
|
|
123
|
+
|
|
124
|
+
## Development
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
uv sync --locked
|
|
128
|
+
uv run ruff check .
|
|
129
|
+
uv run mypy src tests scripts
|
|
130
|
+
uv run pytest
|
|
131
|
+
uv build --no-sources
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Tracking
|
|
135
|
+
|
|
136
|
+
```sh
|
|
137
|
+
simkl search "Cowboy Bebop" --kind anime
|
|
138
|
+
simkl lookup imdb:tt0133093
|
|
139
|
+
simkl lookup tmdb:603 --kind movie
|
|
140
|
+
simkl library list --kind anime --status watching
|
|
141
|
+
simkl library set-status simkl:3708 plan-to-watch
|
|
142
|
+
simkl watched mark simkl:3708 --episode 1 --at 2026-08-08T20:00:00Z
|
|
143
|
+
simkl watched mark simkl:3708 --all --yes
|
|
144
|
+
simkl watched unmark simkl:3708 --episode 1
|
|
145
|
+
simkl rating set simkl:3708 9
|
|
146
|
+
simkl rating remove simkl:3708
|
|
147
|
+
simkl library remove simkl:3708 --yes
|
|
148
|
+
simkl library list --offline --json
|
|
149
|
+
simkl library repair
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Media References accept `simkl:<id>`, supported provider-qualified External
|
|
153
|
+
IDs, or title text with optional `--kind` and `--year`. TMDB IDs require
|
|
154
|
+
`--kind movie` or `--kind show`. An ambiguous title returns candidates and fails
|
|
155
|
+
in scripts; interactive terminals can select a candidate. Search accepts
|
|
156
|
+
`--page` (1–20) and `--limit` (1–50 results per media kind).
|
|
157
|
+
|
|
158
|
+
Movies and standalone Anime take no Episode selectors. Shows require
|
|
159
|
+
`--season N --episode N`; episodic Anime uses `--episode N` without a Season.
|
|
160
|
+
Both accept `--all`; Shows also accept `--season N --all`. Bulk marks select
|
|
161
|
+
aired Episodes. `--episode-id tvdb:<id>` or `--episode-id anidb:<id>` accepts an
|
|
162
|
+
episode-level External ID with a parent Media Reference. When a response to
|
|
163
|
+
such a write is lost, parent state alone cannot prove which Episode changed,
|
|
164
|
+
so the CLI reports an unknown outcome instead of encouraging a blind retry.
|
|
165
|
+
|
|
166
|
+
`watched mark --rewatch` explicitly records another Viewing and requires
|
|
167
|
+
Simkl PRO or VIP. Use `--rewatch-id` to resume a specific known session.
|
|
168
|
+
Unmark Watched preserves Library membership, List Status, and User Rating;
|
|
169
|
+
`library remove` deletes all three along with Watched State.
|
|
170
|
+
Simkl makes Completed Movies watched automatically, so `watched unmark` rejects
|
|
171
|
+
that case before changing anything. Use an explicit `library set-status` move
|
|
172
|
+
to `plan-to-watch` or `dropped` to clear a Movie's Watched State while keeping
|
|
173
|
+
its User Rating.
|
|
174
|
+
|
|
175
|
+
Every command accepts `--json`: stdout contains one JSON result, diagnostics
|
|
176
|
+
go to stderr, and prompts are disabled. Whole-item removal, bulk updates, and
|
|
177
|
+
logout require `--yes` in JSON or noninteractive use. User Ratings range from
|
|
178
|
+
1 to 10 and apply to Movies, Shows, and Anime.
|
|
179
|
+
|
|
180
|
+
Environment-token accounts can read their snapshots offline after one online
|
|
181
|
+
Library read validates their identity. Only a token fingerprint and account ID
|
|
182
|
+
are retained for that association; the Access Token is never persisted.
|
|
183
|
+
|
|
184
|
+
Online Library reads check activities, merge changed List Status and rating
|
|
185
|
+
state, and compare IDs when removals occur. Offline reads require a complete
|
|
186
|
+
snapshot and report its age. Focused writes work before that first complete
|
|
187
|
+
read. A successful remote write followed by failed reconciliation reports
|
|
188
|
+
success and dirty local state; the next online read reconciles it. No writes
|
|
189
|
+
are queued or automatically replayed.
|
|
190
|
+
|
|
191
|
+
## Releases
|
|
192
|
+
|
|
193
|
+
The [release guide](docs/releasing.md) describes the mandatory live smoke,
|
|
194
|
+
restoration backup, GitHub environments, PyPI Trusted Publishing, and version
|
|
195
|
+
tag checks. Merge-gating tests use authored HTTPX responses and never contact
|
|
196
|
+
Simkl; the manually triggered smoke is the only live test workflow.
|
|
197
|
+
|
|
198
|
+
## Project map
|
|
199
|
+
|
|
200
|
+
- [`docs/spec.md`](docs/spec.md) — build-ready v1 product and engineering specification
|
|
201
|
+
- [`CONTEXT.md`](CONTEXT.md) — canonical domain vocabulary
|
|
202
|
+
- [`docs/adr/`](docs/adr/) — architectural decisions
|
|
203
|
+
- [`docs/research/`](docs/research/) — cited API and prior-art research
|
|
204
|
+
- [`src/simklcli/`](src/simklcli/) — installable tracking CLI
|
|
205
|
+
- [`tests/`](tests/) — offline unit, HTTPX transport, and Typer CLI tests
|
|
206
|
+
- [`prototypes/command-surface/`](prototypes/command-surface/) — runnable Typer command-surface prototype
|
|
207
|
+
|
|
208
|
+
Run the prototype from the repository root:
|
|
209
|
+
|
|
210
|
+
```sh
|
|
211
|
+
./prototypes/command-surface/run surface
|
|
212
|
+
./prototypes/command-surface/run --help
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
MIT. See [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
simklcli/__init__.py,sha256=6dywuJOhdI4NoXIu6i_yUqiPjZiyRLiWdIgBNFOlTkE,47
|
|
2
|
+
simklcli/__main__.py,sha256=9COydJZB76bwe42rh0BUe6U4DbBdgzI1-mq9DqxDR4s,67
|
|
3
|
+
simklcli/api.py,sha256=V2rxL-ApGAFmDwf5_wU6qKCIVji5dRMi7VT7six2Fc0,16052
|
|
4
|
+
simklcli/catalog.py,sha256=iQyz3h3vvlTk_6l_h4giLQVI3tRZj9Zle9UlCMPzPpE,6926
|
|
5
|
+
simklcli/cli.py,sha256=o4gP61MTI1Hh7ScGJym129XoCxqeCM27Tz09CnVhTlw,20375
|
|
6
|
+
simklcli/commands.py,sha256=4MMgc1IDqDN_rl0HkFyOi5rSq_s6DCLAPh0wk1U_Kjc,17203
|
|
7
|
+
simklcli/filesystem.py,sha256=DTDTERLHK-u1051hrOJPerKauX0BpbbCkmL56_f_nho,925
|
|
8
|
+
simklcli/media.py,sha256=X3dnJPtG1B5RFVckfcdyjze2lZTbyW15yU2pKa6SAUc,6650
|
|
9
|
+
simklcli/output.py,sha256=wow9jcoaws4sRaeSnqeMi2bsBbSrcEFAu4lyfCB6QHQ,1818
|
|
10
|
+
simklcli/rate_control.py,sha256=UzIjZ_ADzw1BnX4CwlhHzJ7pvhjgd-B82_wfG9La1wo,3831
|
|
11
|
+
simklcli/runtime.py,sha256=aOWe0FCzNXoGJoRnxrXUcbdixqr9vNL1yQsLngZ6-Q0,9668
|
|
12
|
+
simklcli/snapshots.py,sha256=_A0wNpXJ7Lw54SgFJmmCY1pvxs3PG89GzVOly4XnLNA,6891
|
|
13
|
+
simklcli/storage.py,sha256=0I8VoFznfqXsS0OsxvsxEzaFWswD40AfxP422Kecup4,13685
|
|
14
|
+
simklcli/targets.py,sha256=Zj5fhZqJ9_cLSid13hWM6V-wRjekZc4e13n1iLWOYyI,5163
|
|
15
|
+
simklcli/tracking.py,sha256=adIAuV7-NmvcfgdQJkVwBS7Dl18oSS7Eqo5oZct-Etc,20913
|
|
16
|
+
simklcli-0.1.0.dist-info/METADATA,sha256=iODURbeL1co1vs_YVcOTfJ2reLHMZK8SkmqI0q5orpQ,9389
|
|
17
|
+
simklcli-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
18
|
+
simklcli-0.1.0.dist-info/entry_points.txt,sha256=83TaZ6LnJDx60INKPBTGj43KmVFMWSbD2HN6_2ca4GM,43
|
|
19
|
+
simklcli-0.1.0.dist-info/licenses/LICENSE,sha256=n_CWabjY_86040ujq4X0r5VBTGNM9KriO2cK5JvdmnI,1069
|
|
20
|
+
simklcli-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Javier Ochoa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|