@onpeek/nuvio 1.0.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/LICENSE +22 -0
- package/README.md +83 -0
- package/assets/nuvio-wordmark-dark.png +0 -0
- package/assets/nuvio-wordmark-light.png +0 -0
- package/dist/cli/confirmation.js +45 -0
- package/dist/cli/registry.js +14 -0
- package/dist/commands/account.js +66 -0
- package/dist/commands/addons.js +84 -0
- package/dist/commands/collections.js +147 -0
- package/dist/commands/helpers.js +186 -0
- package/dist/commands/index.js +26 -0
- package/dist/commands/library.js +105 -0
- package/dist/commands/plugins.js +58 -0
- package/dist/commands/profiles.js +126 -0
- package/dist/commands/providers.js +57 -0
- package/dist/commands/sessions.js +46 -0
- package/dist/commands/settings.js +43 -0
- package/dist/commands/trackers.js +84 -0
- package/dist/commands/undo.js +165 -0
- package/dist/config.js +60 -0
- package/dist/index.js +195 -0
- package/dist/mask.js +33 -0
- package/dist/nuvio/auth.js +123 -0
- package/dist/nuvio/call-context.js +20 -0
- package/dist/nuvio/client.js +149 -0
- package/dist/nuvio/errors.js +43 -0
- package/dist/nuvio/keys.js +23 -0
- package/dist/nuvio/ops/account.js +91 -0
- package/dist/nuvio/ops/addons.js +126 -0
- package/dist/nuvio/ops/collections.js +158 -0
- package/dist/nuvio/ops/library.js +139 -0
- package/dist/nuvio/ops/plan.js +728 -0
- package/dist/nuvio/ops/plugins.js +127 -0
- package/dist/nuvio/ops/profiles.js +383 -0
- package/dist/nuvio/ops/providers.js +103 -0
- package/dist/nuvio/ops/readers.js +57 -0
- package/dist/nuvio/ops/sessions.js +36 -0
- package/dist/nuvio/ops/settings.js +143 -0
- package/dist/nuvio/ops/trackers.js +80 -0
- package/dist/nuvio/ops/transitions.js +100 -0
- package/dist/nuvio/paths.js +74 -0
- package/dist/nuvio/safe-fetch.js +131 -0
- package/dist/nuvio/schemas.js +143 -0
- package/dist/nuvio/snapshots.js +664 -0
- package/dist/nuvio/types.js +1 -0
- package/dist/version.js +12 -0
- package/package.json +62 -0
- package/skills/nuvio/SKILL.md +19 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { NuvioError } from './errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Nuvio/Stremio accept addon/plugin URLs without an explicit scheme (implicitly
|
|
5
|
+
* https) and list_addons/list_plugins return them verbatim. Accept both forms and
|
|
6
|
+
* never normalise: the stored string must be matched exactly.
|
|
7
|
+
*/
|
|
8
|
+
const SCHEME_LESS_URL = /^[^\s/]+\.[^\s/]+(?::\d+)?(?:\/\S*)?$/;
|
|
9
|
+
export const schemeTolerantUrl = z
|
|
10
|
+
.string()
|
|
11
|
+
.trim()
|
|
12
|
+
.min(1)
|
|
13
|
+
.refine((value) => {
|
|
14
|
+
try {
|
|
15
|
+
const parsed = new URL(value);
|
|
16
|
+
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return SCHEME_LESS_URL.test(value);
|
|
20
|
+
}
|
|
21
|
+
}, 'Expected an http(s) URL, or a host/path without a scheme');
|
|
22
|
+
/**
|
|
23
|
+
* Canonical argument schemas shared by the direct tools and `nuvio_apply_plan`.
|
|
24
|
+
* A plan validates every operation against exactly the same Zod schema the
|
|
25
|
+
* direct tool uses, so it can never accept arguments a direct call would reject.
|
|
26
|
+
*/
|
|
27
|
+
export const profile = z.number().int().min(1).max(6).default(1);
|
|
28
|
+
export const platform = z.string().default('tv');
|
|
29
|
+
export const settingsEditShape = {
|
|
30
|
+
patch: z.record(z.string(), z.unknown()).optional().describe('Deep-merged into the settings tree.'),
|
|
31
|
+
set: z
|
|
32
|
+
.array(z.object({ path: z.string().min(1), value: z.unknown() }))
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('Set nested values by dot path, applied after patch.'),
|
|
35
|
+
unset: z.array(z.string().min(1)).optional().describe('Delete nested keys by dot path, applied last.'),
|
|
36
|
+
};
|
|
37
|
+
const settingsBase = { profile_id: profile, platform };
|
|
38
|
+
export const updateSettingsShape = { ...settingsBase, ...settingsEditShape };
|
|
39
|
+
export const getSettingsShape = { ...settingsBase };
|
|
40
|
+
export const addonAddShape = {
|
|
41
|
+
profile_id: profile,
|
|
42
|
+
url: z.url().describe('Addon manifest URL'),
|
|
43
|
+
name: z.string().optional(),
|
|
44
|
+
enabled: z.boolean().optional().default(true),
|
|
45
|
+
sort_order: z.number().int().optional(),
|
|
46
|
+
};
|
|
47
|
+
export const addonUpdateShape = {
|
|
48
|
+
profile_id: profile,
|
|
49
|
+
url: schemeTolerantUrl.optional(),
|
|
50
|
+
id: z.uuid().optional(),
|
|
51
|
+
name: z.string().nullable().optional(),
|
|
52
|
+
enabled: z.boolean().optional(),
|
|
53
|
+
sort_order: z.number().int().optional(),
|
|
54
|
+
};
|
|
55
|
+
export const addonReorderShape = {
|
|
56
|
+
profile_id: profile,
|
|
57
|
+
ordered_urls: z.array(schemeTolerantUrl).min(1),
|
|
58
|
+
};
|
|
59
|
+
export const addonRemoveShape = {
|
|
60
|
+
profile_id: profile,
|
|
61
|
+
url: schemeTolerantUrl.optional(),
|
|
62
|
+
id: z.uuid().optional(),
|
|
63
|
+
};
|
|
64
|
+
export const pluginAddShape = {
|
|
65
|
+
profile_id: profile,
|
|
66
|
+
url: z.url(),
|
|
67
|
+
name: z.string().optional(),
|
|
68
|
+
repo_type: z.string().optional(),
|
|
69
|
+
enabled: z.boolean().optional().default(true),
|
|
70
|
+
};
|
|
71
|
+
export const pluginUpdateShape = {
|
|
72
|
+
profile_id: profile,
|
|
73
|
+
url: schemeTolerantUrl.optional(),
|
|
74
|
+
id: z.uuid().optional(),
|
|
75
|
+
name: z.string().nullable().optional(),
|
|
76
|
+
enabled: z.boolean().optional(),
|
|
77
|
+
repo_type: z.string().nullable().optional(),
|
|
78
|
+
sort_order: z.number().int().optional(),
|
|
79
|
+
};
|
|
80
|
+
export const pluginReorderShape = { profile_id: profile, ordered_urls: z.array(schemeTolerantUrl).min(1) };
|
|
81
|
+
export const pluginRemoveShape = {
|
|
82
|
+
profile_id: profile,
|
|
83
|
+
url: schemeTolerantUrl.optional(),
|
|
84
|
+
id: z.uuid().optional(),
|
|
85
|
+
};
|
|
86
|
+
export const providerSetShape = {
|
|
87
|
+
profile_id: profile,
|
|
88
|
+
provider: z.string().describe('One of the supported provider ids'),
|
|
89
|
+
api_key: z.string().min(1).describe('API key / client id value'),
|
|
90
|
+
};
|
|
91
|
+
export const providerDeleteShape = { profile_id: profile, provider: z.string() };
|
|
92
|
+
export const libraryItemSchema = z.object({
|
|
93
|
+
content_id: z.string().min(1),
|
|
94
|
+
content_type: z.string().min(1),
|
|
95
|
+
name: z.string().nullable().optional(),
|
|
96
|
+
poster: z.string().nullable().optional(),
|
|
97
|
+
poster_shape: z.string().nullable().optional(),
|
|
98
|
+
background: z.string().nullable().optional(),
|
|
99
|
+
description: z.string().nullable().optional(),
|
|
100
|
+
release_info: z.string().nullable().optional(),
|
|
101
|
+
imdb_rating: z.number().nullable().optional(),
|
|
102
|
+
genres: z.array(z.string()).nullable().optional(),
|
|
103
|
+
addon_base_url: z.string().nullable().optional(),
|
|
104
|
+
added_at: z.number().int().nullable().optional(),
|
|
105
|
+
});
|
|
106
|
+
export const libraryAddShape = { profile_id: profile, items: z.array(libraryItemSchema).min(1) };
|
|
107
|
+
export const libraryRemoveShape = {
|
|
108
|
+
profile_id: profile,
|
|
109
|
+
keys: z.array(z.object({ content_id: z.string().min(1), content_type: z.string().min(1) })).min(1),
|
|
110
|
+
};
|
|
111
|
+
export const progressKeySchema = z.object({
|
|
112
|
+
content_id: z.string().min(1),
|
|
113
|
+
season: z.number().int().nullable().optional(),
|
|
114
|
+
episode: z.number().int().nullable().optional(),
|
|
115
|
+
});
|
|
116
|
+
export const progressEntrySchema = z.object({
|
|
117
|
+
content_id: z.string().min(1),
|
|
118
|
+
content_type: z.string().min(1),
|
|
119
|
+
video_id: z.string().nullable().optional(),
|
|
120
|
+
season: z.number().int().nullable().optional(),
|
|
121
|
+
episode: z.number().int().nullable().optional(),
|
|
122
|
+
position: z.number(),
|
|
123
|
+
duration: z.number(),
|
|
124
|
+
last_watched: z.number().int().nullable().optional(),
|
|
125
|
+
});
|
|
126
|
+
export const progressSetShape = { profile_id: profile, entries: z.array(progressEntrySchema).min(1) };
|
|
127
|
+
export const progressDeleteShape = { profile_id: profile, keys: z.array(progressKeySchema).min(1) };
|
|
128
|
+
export const historyItemSchema = z.object({
|
|
129
|
+
content_id: z.string().min(1),
|
|
130
|
+
content_type: z.string().min(1),
|
|
131
|
+
title: z.string().nullable().optional(),
|
|
132
|
+
season: z.number().int().nullable().optional(),
|
|
133
|
+
episode: z.number().int().nullable().optional(),
|
|
134
|
+
watched_at: z.number().int().nullable().optional(),
|
|
135
|
+
});
|
|
136
|
+
export const historyAddShape = { profile_id: profile, items: z.array(historyItemSchema).min(1) };
|
|
137
|
+
export const historyDeleteShape = { profile_id: profile, keys: z.array(progressKeySchema).min(1) };
|
|
138
|
+
/** Validation shared by direct addon/plugin tools and plans: exactly one of url/id when identifying. */
|
|
139
|
+
export function assertTarget(tool, args, requireOne = true) {
|
|
140
|
+
if (requireOne && !args.url && !args.id) {
|
|
141
|
+
throw new NuvioError(`${tool}: provide either url or id to identify the item.`);
|
|
142
|
+
}
|
|
143
|
+
}
|