trakt-tools 1.9.3 → 1.10.0
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.
- package/README.md +2 -0
- package/dist/index.js +15 -3
- package/openclaw.plugin.json +12 -2
- package/package.json +1 -1
- package/skills/trakt/SKILL.md +40 -1
- package/src/index.ts +21 -3
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ Or set `TRAKT_CLI_PATH` environment variable, or configure `cliPath` in plugin s
|
|
|
25
25
|
| `cliPath` | Path to trakt-cli binary (auto-detected on PATH) |
|
|
26
26
|
| `clientId` | Trakt API client ID (from https://trakt.tv/oauth/applications) |
|
|
27
27
|
| `clientSecret` | Trakt API client secret |
|
|
28
|
+
| `syncEnabled` | Register the opt-in `trakt_sync` tool (default `false`) |
|
|
28
29
|
|
|
29
30
|
## Available Tools
|
|
30
31
|
|
|
@@ -36,6 +37,7 @@ Or set `TRAKT_CLI_PATH` environment variable, or configure `cliPath` in plugin s
|
|
|
36
37
|
| `trakt_watchlist` | View watchlist |
|
|
37
38
|
| `trakt_progress` | Show watch progress for TV shows |
|
|
38
39
|
| `trakt_auth` | Set up Trakt.tv authentication |
|
|
40
|
+
| `trakt_sync` | Opt-in: import from streaming services (only when `syncEnabled`) |
|
|
39
41
|
|
|
40
42
|
## License
|
|
41
43
|
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,16 @@ function whichBinary(name) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// src/index.ts
|
|
32
|
+
var SYNC_TOOL = {
|
|
33
|
+
name: "trakt_sync",
|
|
34
|
+
command: "sync",
|
|
35
|
+
description: "Import watched items from streaming services (Apple TV Up Next, Netflix, HBO Max, Paramount+) into Trakt history, using the sync config at ~/.config/trakt-cli/sync.yaml. Skips denied titles, items older than the configured window, and anything already in history. Shows not yet in history and all movies are returned in pending_review and NOT written; ask the user before approving any. Use dry_run first to preview.",
|
|
36
|
+
parameters: Type.Object({
|
|
37
|
+
dry_run: Type.Optional(
|
|
38
|
+
Type.Boolean({ description: "Preview what would be added without writing (default false)" })
|
|
39
|
+
)
|
|
40
|
+
})
|
|
41
|
+
};
|
|
32
42
|
var TOOLS = [
|
|
33
43
|
{
|
|
34
44
|
name: "trakt_search",
|
|
@@ -262,12 +272,13 @@ var index_default = definePluginEntry({
|
|
|
262
272
|
description: "Track movies and TV shows using trakt.tv",
|
|
263
273
|
register(api) {
|
|
264
274
|
const config = api.pluginConfig;
|
|
275
|
+
const tools = config?.syncEnabled ? [...TOOLS, SYNC_TOOL] : TOOLS;
|
|
265
276
|
let cliPath;
|
|
266
277
|
try {
|
|
267
278
|
cliPath = resolveCliPath(config);
|
|
268
279
|
} catch (error) {
|
|
269
280
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
270
|
-
for (const tool of
|
|
281
|
+
for (const tool of tools) {
|
|
271
282
|
api.registerTool({
|
|
272
283
|
name: tool.name,
|
|
273
284
|
label: tool.name,
|
|
@@ -282,7 +293,7 @@ var index_default = definePluginEntry({
|
|
|
282
293
|
}
|
|
283
294
|
return;
|
|
284
295
|
}
|
|
285
|
-
for (const tool of
|
|
296
|
+
for (const tool of tools) {
|
|
286
297
|
api.registerTool({
|
|
287
298
|
name: tool.name,
|
|
288
299
|
label: tool.name,
|
|
@@ -304,7 +315,8 @@ var index_default = definePluginEntry({
|
|
|
304
315
|
try {
|
|
305
316
|
const args = buildCliArgs(tool.command, tool.subcommand, params, config);
|
|
306
317
|
const { stdout } = await runCli(cliPath, args, {
|
|
307
|
-
|
|
318
|
+
// sync walks several services plus per-show history lookups.
|
|
319
|
+
timeout: tool.command === "sync" ? 6e5 : 12e4,
|
|
308
320
|
maxBuffer: 4 * 1024 * 1024
|
|
309
321
|
});
|
|
310
322
|
let result;
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "trakt-tools",
|
|
3
3
|
"name": "Trakt",
|
|
4
4
|
"description": "Track movies and TV shows using trakt.tv",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.10.0",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"properties": {
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
"clientSecret": {
|
|
19
19
|
"type": "string",
|
|
20
20
|
"description": "Trakt API client secret"
|
|
21
|
+
},
|
|
22
|
+
"syncEnabled": {
|
|
23
|
+
"type": "boolean",
|
|
24
|
+
"description": "Opt in to the trakt_sync tool (imports from streaming services). Off by default.",
|
|
25
|
+
"default": false
|
|
21
26
|
}
|
|
22
27
|
},
|
|
23
28
|
"additionalProperties": false
|
|
@@ -37,6 +42,10 @@
|
|
|
37
42
|
"label": "Client Secret",
|
|
38
43
|
"help": "Trakt API client secret from https://trakt.tv/oauth/applications",
|
|
39
44
|
"sensitive": true
|
|
45
|
+
},
|
|
46
|
+
"syncEnabled": {
|
|
47
|
+
"label": "Enable streaming sync",
|
|
48
|
+
"help": "Registers trakt_sync. Also requires ~/.config/trakt-cli/sync.yaml with enabled: true; see `trakt-cli sync --help`."
|
|
40
49
|
}
|
|
41
50
|
},
|
|
42
51
|
"contracts": {
|
|
@@ -50,7 +59,8 @@
|
|
|
50
59
|
"trakt_watchlist_remove",
|
|
51
60
|
"trakt_calendar",
|
|
52
61
|
"trakt_progress",
|
|
53
|
-
"trakt_auth"
|
|
62
|
+
"trakt_auth",
|
|
63
|
+
"trakt_sync"
|
|
54
64
|
]
|
|
55
65
|
}
|
|
56
66
|
}
|
package/package.json
CHANGED
package/skills/trakt/SKILL.md
CHANGED
|
@@ -66,13 +66,52 @@ trakt-cli history add "Pluribus" --json
|
|
|
66
66
|
trakt-cli history add "The Sopranos" "The Wire" --json
|
|
67
67
|
trakt-cli history add --type movie "The Godfather" --json
|
|
68
68
|
trakt-cli history add --watched-at 2025-06-15 "Dark" --json
|
|
69
|
+
trakt-cli history add --rewatch "Severance" --json
|
|
69
70
|
```
|
|
70
71
|
|
|
71
72
|
- Searches by name, prefers exact title matches
|
|
73
|
+
- For shows, only episodes that have aired **and** are not yet in your
|
|
74
|
+
history are added: catching up on a partially watched show never creates
|
|
75
|
+
duplicate plays, and a fully caught-up show adds nothing
|
|
76
|
+
- Season 0 (specials) is never marked watched, so this agrees with what
|
|
77
|
+
`progress` reports
|
|
78
|
+
- `--rewatch` deliberately records another play for every aired episode,
|
|
79
|
+
including ones already watched. Use it only when the user actually means
|
|
80
|
+
a rewatch; without it a finished show is a no-op
|
|
81
|
+
- Repeated titles (or aliases resolving to the same show) are handled once
|
|
82
|
+
per call — later matches add nothing and come back with a
|
|
83
|
+
`duplicate_of` field in `queries` (text output: `duplicate of "<query>"`)
|
|
84
|
+
- Every requested title gets a `queries` entry in JSON output, show or
|
|
85
|
+
movie alike (`query`, `type`): matched titles carry `matched` (shows
|
|
86
|
+
also `new_episodes` / `already_watched_episodes`), titles that match
|
|
87
|
+
nothing have no `matched` field, and a title whose Trakt search failed
|
|
88
|
+
carries `search_error` — so a failed lookup is distinguishable from
|
|
89
|
+
"not found"
|
|
72
90
|
- `--type show` (default) or `--type movie`
|
|
73
91
|
- `--watched-at`: RFC3339 or YYYY-MM-DD (defaults to now)
|
|
74
92
|
- Accepts multiple titles in one call
|
|
75
|
-
- JSON output: `{ "added_episodes": N, "added_movies": N, "not_found_movies": N, "not_found_shows": N }`
|
|
93
|
+
- JSON output: `{ "added_episodes": N, "added_movies": N, "not_found_movies": N, "not_found_shows": N, "not_found_seasons": N, "not_found_episodes": N, "queries": [{ "query", "type", "matched", "new_episodes", "already_watched_episodes", "duplicate_of", "search_error" }] }`
|
|
94
|
+
- A show whose pending-episode lookup fails is skipped and reported in an
|
|
95
|
+
additive `skipped_shows` array; if every lookup fails, nothing is written
|
|
96
|
+
and the command exits 1 with `{"error": "pending episode lookup failed", "skipped_shows": [...]}`
|
|
97
|
+
- On a Trakt rate limit (429) the command stops immediately, syncs nothing,
|
|
98
|
+
and exits 1 with `{"error": ..., "retry_after": N}` (marker also on
|
|
99
|
+
stderr) — wait out `retry_after` before calling any trakt tool again
|
|
100
|
+
|
|
101
|
+
### Streaming Sync (opt-in)
|
|
102
|
+
|
|
103
|
+
Only if the user has set up `~/.config/trakt-cli/sync.yaml` (otherwise `sync` reports `"enabled": false` and does nothing).
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
trakt-cli sync --dry-run --json
|
|
107
|
+
trakt-cli sync --json
|
|
108
|
+
trakt-cli sync approve "Title"
|
|
109
|
+
trakt-cli sync deny "Title"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- JSON output: `{ "enabled", "sources": {name: {items, error}}, "planned", "pending_review", "skipped_denied", "skipped_old", "already_watched", "unresolved", "added" }`
|
|
113
|
+
- Confirmed episodes of shows already in history sync automatically; new shows, all movies, and implied episodes (e.g. skipped ones before an Up Next pointer) land in `pending_review` and are NOT written. Ask the user before running `sync approve` for any title; never approve on their behalf
|
|
114
|
+
- Use `sync deny` for titles the user says belong to someone else
|
|
76
115
|
|
|
77
116
|
### Search
|
|
78
117
|
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,8 @@ interface PluginConfig {
|
|
|
16
16
|
cliPath?: string;
|
|
17
17
|
clientId?: string;
|
|
18
18
|
clientSecret?: string;
|
|
19
|
+
/** Opt-in: register trakt_sync. Off by default so existing installs are unchanged. */
|
|
20
|
+
syncEnabled?: boolean;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
interface ToolDef {
|
|
@@ -26,6 +28,20 @@ interface ToolDef {
|
|
|
26
28
|
parameters: ReturnType<typeof Type.Object>;
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
// Opt-in streaming sync tool. Registered only when pluginConfig.syncEnabled is
|
|
32
|
+
// true; the CLI itself also stays inert without ~/.config/trakt-cli/sync.yaml.
|
|
33
|
+
const SYNC_TOOL: ToolDef = {
|
|
34
|
+
name: 'trakt_sync',
|
|
35
|
+
command: 'sync',
|
|
36
|
+
description:
|
|
37
|
+
'Import watched items from streaming services (Apple TV Up Next, Netflix, HBO Max, Paramount+) into Trakt history, using the sync config at ~/.config/trakt-cli/sync.yaml. Skips denied titles, items older than the configured window, and anything already in history. Shows not yet in history and all movies are returned in pending_review and NOT written; ask the user before approving any. Use dry_run first to preview.',
|
|
38
|
+
parameters: Type.Object({
|
|
39
|
+
dry_run: Type.Optional(
|
|
40
|
+
Type.Boolean({ description: 'Preview what would be added without writing (default false)' })
|
|
41
|
+
),
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
|
|
29
45
|
// Tool metadata — each maps to a CLI subcommand
|
|
30
46
|
const TOOLS: ToolDef[] = [
|
|
31
47
|
{
|
|
@@ -306,6 +322,7 @@ export default definePluginEntry({
|
|
|
306
322
|
|
|
307
323
|
register(api) {
|
|
308
324
|
const config = api.pluginConfig as PluginConfig | undefined;
|
|
325
|
+
const tools = config?.syncEnabled ? [...TOOLS, SYNC_TOOL] : TOOLS;
|
|
309
326
|
|
|
310
327
|
let cliPath: string;
|
|
311
328
|
try {
|
|
@@ -314,7 +331,7 @@ export default definePluginEntry({
|
|
|
314
331
|
// Defer error to tool execution time — plugin still loads
|
|
315
332
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
316
333
|
|
|
317
|
-
for (const tool of
|
|
334
|
+
for (const tool of tools) {
|
|
318
335
|
api.registerTool({
|
|
319
336
|
name: tool.name,
|
|
320
337
|
label: tool.name,
|
|
@@ -330,7 +347,7 @@ export default definePluginEntry({
|
|
|
330
347
|
return;
|
|
331
348
|
}
|
|
332
349
|
|
|
333
|
-
for (const tool of
|
|
350
|
+
for (const tool of tools) {
|
|
334
351
|
api.registerTool({
|
|
335
352
|
name: tool.name,
|
|
336
353
|
label: tool.name,
|
|
@@ -362,7 +379,8 @@ export default definePluginEntry({
|
|
|
362
379
|
// Follow-up: parallelize GetShowProgress loop or add a --filter
|
|
363
380
|
// flag so per-show progress checks don't hammer 50 API calls.
|
|
364
381
|
const { stdout } = await runCli(cliPath, args, {
|
|
365
|
-
|
|
382
|
+
// sync walks several services plus per-show history lookups.
|
|
383
|
+
timeout: tool.command === 'sync' ? 600_000 : 120_000,
|
|
366
384
|
maxBuffer: 4 * 1024 * 1024,
|
|
367
385
|
});
|
|
368
386
|
|