skystream-cli 1.4.4 → 1.4.6
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/dist/index.js +73 -63
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ const program = new Command();
|
|
|
12
12
|
program
|
|
13
13
|
.name('skystream')
|
|
14
14
|
.description('SkyStream Plugin Development Kit CLI (Sky Gen 2)')
|
|
15
|
-
.version('1.4.
|
|
15
|
+
.version('1.4.6');
|
|
16
16
|
// Schemas
|
|
17
17
|
const pluginSchema = z.object({
|
|
18
18
|
packageName: z.string().min(5).regex(/^[a-z0-9._-]+$/),
|
|
@@ -82,23 +82,7 @@ const JS_TEMPLATE = `(function() {
|
|
|
82
82
|
url: \`\${manifest.baseUrl}/series\`,
|
|
83
83
|
posterUrl: \`https://placehold.co/400x600.png?text=Series+Poster\`,
|
|
84
84
|
type: "series",
|
|
85
|
-
|
|
86
|
-
score: 8.5,
|
|
87
|
-
status: "ongoing", // ongoing, completed, upcoming
|
|
88
|
-
description: "This category appears as a thumbnail row.",
|
|
89
|
-
cast: [
|
|
90
|
-
new Actor({ name: "John Doe", role: "Protagonist", image: "https://..." })
|
|
91
|
-
],
|
|
92
|
-
episodes: [
|
|
93
|
-
new Episode({
|
|
94
|
-
name: "Episode 1",
|
|
95
|
-
url: \`\${manifest.baseUrl}/series/1\`,
|
|
96
|
-
season: 1,
|
|
97
|
-
episode: 1,
|
|
98
|
-
airDate: "2024-03-12",
|
|
99
|
-
dubStatus: "subbed" // subbed, dubbed, none
|
|
100
|
-
})
|
|
101
|
-
]
|
|
85
|
+
description: "This category appears as a thumbnail row."
|
|
102
86
|
})
|
|
103
87
|
]
|
|
104
88
|
}
|
|
@@ -163,6 +147,30 @@ const JS_TEMPLATE = `(function() {
|
|
|
163
147
|
type: "series",
|
|
164
148
|
bannerUrl: \`https://placehold.co/1280x720.png?text=Series+Banner\`,
|
|
165
149
|
description: "This is a detailed description of the media.",
|
|
150
|
+
year: 2024,
|
|
151
|
+
score: 8.5,
|
|
152
|
+
duration: 120, // (optional, in minutes)
|
|
153
|
+
status: "ongoing", // ongoing, completed, upcoming
|
|
154
|
+
contentRating: "PG-13",
|
|
155
|
+
logoUrl: \`https://placehold.co/200x100.png?text=Logo\`,
|
|
156
|
+
isAdult: false,
|
|
157
|
+
tags: ["Action", "Adventure"],
|
|
158
|
+
cast: [
|
|
159
|
+
new Actor({ name: "John Doe", role: "Protagonist", image: "https://placehold.co/200x300.png" })
|
|
160
|
+
],
|
|
161
|
+
trailers: [
|
|
162
|
+
new Trailer({ name: "Official Trailer", url: "https://www.youtube.com/watch?v=..." })
|
|
163
|
+
],
|
|
164
|
+
nextAiring: new NextAiring({ episode: 5, season: 1, airDate: "2024-04-01" }),
|
|
165
|
+
recommendations: [
|
|
166
|
+
new MultimediaItem({ title: "Similar Show", url: \`\${manifest.baseUrl}/similar\`, posterUrl: "https://placehold.co/400x600", type: "series" })
|
|
167
|
+
],
|
|
168
|
+
playbackPolicy: "none", // 'none' | 'VPN Recommended' | 'torrent' | 'externalPlayerOnly' | 'internalPlayerOnly'
|
|
169
|
+
syncData: { "my_service_id": "12345" }, // Optional: external metadata sync
|
|
170
|
+
streams: [
|
|
171
|
+
// Optional: "Instant Load" - bypass loadStreams by providing links here
|
|
172
|
+
new StreamResult({ url: "https://example.com/movie.mp4", source: "Instant High" })
|
|
173
|
+
],
|
|
166
174
|
headers: { "Referer": \`\${manifest.baseUrl}\` },
|
|
167
175
|
episodes: [
|
|
168
176
|
new Episode({
|
|
@@ -172,7 +180,8 @@ const JS_TEMPLATE = `(function() {
|
|
|
172
180
|
episode: 1,
|
|
173
181
|
description: "Episode summary...",
|
|
174
182
|
posterUrl: \`https://placehold.co/400x600.png?text=Episode+Poster\`,
|
|
175
|
-
headers: { "Referer": \`\${manifest.baseUrl}\` }
|
|
183
|
+
headers: { "Referer": \`\${manifest.baseUrl}\` },
|
|
184
|
+
streams: [] // Optional: "Instant Load" for episodes
|
|
176
185
|
}),
|
|
177
186
|
new Episode({
|
|
178
187
|
name: "Episode 2",
|
|
@@ -198,25 +207,19 @@ const JS_TEMPLATE = `(function() {
|
|
|
198
207
|
*/
|
|
199
208
|
async function loadStreams(url, cb) {
|
|
200
209
|
try {
|
|
201
|
-
// Standard: Return a List of stream
|
|
210
|
+
// Standard: Return a List of stream objects
|
|
202
211
|
cb({
|
|
203
212
|
success: true,
|
|
204
213
|
data: [
|
|
205
214
|
new StreamResult({
|
|
206
215
|
url: "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8",
|
|
207
|
-
source: "
|
|
208
|
-
headers: { "Referer": \`\${manifest.baseUrl}\` }
|
|
209
|
-
subtitles: [
|
|
210
|
-
{ url: \`\${manifest.baseUrl}/sub.vtt\`, label: "English", lang: "en" } // (optional)
|
|
211
|
-
],
|
|
212
|
-
drmKid: "kid_value", // (optional)
|
|
213
|
-
drmKey: "key_value", // (optional)
|
|
214
|
-
licenseUrl: "https://license-server.com" // (optional)
|
|
216
|
+
source: "Direct Quality",
|
|
217
|
+
headers: { "Referer": \`\${manifest.baseUrl}\` }
|
|
215
218
|
})
|
|
216
219
|
]
|
|
217
220
|
});
|
|
218
221
|
} catch (e) {
|
|
219
|
-
cb({ success: false, errorCode: "STREAM_ERROR", message:
|
|
222
|
+
cb({ success: false, errorCode: "STREAM_ERROR", message: String(e) });
|
|
220
223
|
}
|
|
221
224
|
}
|
|
222
225
|
|
|
@@ -445,6 +448,7 @@ program.command('test')
|
|
|
445
448
|
const manifest = await fs.readJson(manifestPath);
|
|
446
449
|
const jsContent = await fs.readFile(jsPath, 'utf8');
|
|
447
450
|
console.log(`\n--- Testing ${manifest.packageName} -> ${options.function} ---`);
|
|
451
|
+
const preferences = {};
|
|
448
452
|
const context = {
|
|
449
453
|
manifest,
|
|
450
454
|
console: {
|
|
@@ -453,67 +457,68 @@ program.command('test')
|
|
|
453
457
|
},
|
|
454
458
|
http_get: async (url, headers, cb) => {
|
|
455
459
|
try {
|
|
456
|
-
const
|
|
457
|
-
|
|
460
|
+
const finalHeaders = { ...(headers || {}) };
|
|
461
|
+
if (!Object.keys(finalHeaders).some(k => k.toLowerCase() === 'user-agent')) {
|
|
462
|
+
finalHeaders['User-Agent'] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36";
|
|
463
|
+
}
|
|
464
|
+
const res = await axios.get(url, { headers: finalHeaders });
|
|
465
|
+
const body = typeof res.data === 'string' ? res.data : JSON.stringify(res.data);
|
|
458
466
|
if (cb)
|
|
459
|
-
cb(
|
|
460
|
-
return
|
|
467
|
+
cb({ status: res.status, statusCode: res.status, body, headers: res.headers });
|
|
468
|
+
return body;
|
|
461
469
|
}
|
|
462
470
|
catch (e) {
|
|
463
471
|
const res = { status: e.response?.status || 500, statusCode: e.response?.status || 500, body: e.response?.data || e.message, headers: e.response?.headers || {} };
|
|
464
472
|
if (cb)
|
|
465
473
|
cb(res);
|
|
466
|
-
return res;
|
|
474
|
+
return typeof res.body === 'string' ? res.body : JSON.stringify(res.body);
|
|
467
475
|
}
|
|
468
476
|
},
|
|
469
477
|
http_post: async (url, headers, body, cb) => {
|
|
470
478
|
try {
|
|
471
|
-
const
|
|
472
|
-
|
|
479
|
+
const finalHeaders = { ...(headers || {}) };
|
|
480
|
+
if (!Object.keys(finalHeaders).some(k => k.toLowerCase() === 'user-agent')) {
|
|
481
|
+
finalHeaders['User-Agent'] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36";
|
|
482
|
+
}
|
|
483
|
+
const res = await axios.post(url, body, { headers: finalHeaders });
|
|
484
|
+
const resBody = typeof res.data === 'string' ? res.data : JSON.stringify(res.data);
|
|
473
485
|
if (cb)
|
|
474
|
-
cb(
|
|
475
|
-
return
|
|
486
|
+
cb({ status: res.status, statusCode: res.status, body: resBody, headers: res.headers });
|
|
487
|
+
return resBody;
|
|
476
488
|
}
|
|
477
489
|
catch (e) {
|
|
478
490
|
const res = { status: e.response?.status || 500, statusCode: e.response?.status || 500, body: e.response?.data || e.message, headers: e.response?.headers || {} };
|
|
479
491
|
if (cb)
|
|
480
492
|
cb(res);
|
|
481
|
-
return res;
|
|
493
|
+
return typeof res.body === 'string' ? res.body : JSON.stringify(res.body);
|
|
482
494
|
}
|
|
483
495
|
},
|
|
484
|
-
_fetch: async (url) => {
|
|
485
|
-
try {
|
|
486
|
-
const res = await axios.get(url);
|
|
487
|
-
return typeof res.data === 'string' ? res.data : JSON.stringify(res.data);
|
|
488
|
-
}
|
|
489
|
-
catch (e) {
|
|
490
|
-
throw new Error(`HTTP Error ${e.response?.status || 500} fetching ${url}`);
|
|
491
|
-
}
|
|
492
|
-
},
|
|
493
|
-
fetch: async (url) => {
|
|
494
|
-
const res = await axios.get(url);
|
|
495
|
-
return {
|
|
496
|
-
status: res.status,
|
|
497
|
-
statusCode: res.status,
|
|
498
|
-
body: typeof res.data === 'string' ? res.data : JSON.stringify(res.data),
|
|
499
|
-
headers: res.headers
|
|
500
|
-
};
|
|
501
|
-
},
|
|
502
496
|
registerSettings: (schema) => {
|
|
503
497
|
console.log(' [Mock SDK]: Plugin registered settings:', JSON.stringify(schema, null, 2));
|
|
504
498
|
},
|
|
499
|
+
getPreference: (key) => {
|
|
500
|
+
return preferences[key] || null;
|
|
501
|
+
},
|
|
502
|
+
setPreference: (key, value) => {
|
|
503
|
+
preferences[key] = value;
|
|
504
|
+
return true;
|
|
505
|
+
},
|
|
505
506
|
solveCaptcha: async (siteKey, url) => {
|
|
506
507
|
console.log(' [Mock SDK]: solveCaptcha requested for ' + url + ' with key ' + siteKey);
|
|
507
508
|
return "mock_captcha_token";
|
|
508
509
|
},
|
|
509
|
-
crypto: {
|
|
510
|
-
decryptAES: (data, key, iv) => {
|
|
511
|
-
return "decrypted(" + data + ")";
|
|
512
|
-
}
|
|
513
|
-
},
|
|
514
510
|
btoa: (s) => Buffer.from(s).toString('base64'),
|
|
515
511
|
atob: (s) => Buffer.from(s, 'base64').toString('utf8'),
|
|
516
512
|
sendMessage: async (id, arg) => {
|
|
513
|
+
if (id === 'get_preference') {
|
|
514
|
+
const { key } = JSON.parse(arg);
|
|
515
|
+
return preferences[key] || null;
|
|
516
|
+
}
|
|
517
|
+
if (id === 'set_preference') {
|
|
518
|
+
const { key, value } = JSON.parse(arg);
|
|
519
|
+
preferences[key] = value;
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
517
522
|
if (id === 'crypto_decrypt_aes') {
|
|
518
523
|
const { data, key, iv } = JSON.parse(arg);
|
|
519
524
|
try {
|
|
@@ -548,6 +553,7 @@ program.command('test')
|
|
|
548
553
|
},
|
|
549
554
|
globalThis: {},
|
|
550
555
|
};
|
|
556
|
+
context.globalThis = context;
|
|
551
557
|
const entityDefs = `
|
|
552
558
|
class Actor {
|
|
553
559
|
constructor(params) {
|
|
@@ -572,8 +578,10 @@ program.command('test')
|
|
|
572
578
|
Object.assign(this, {
|
|
573
579
|
type: 'movie',
|
|
574
580
|
status: 'ongoing',
|
|
575
|
-
|
|
581
|
+
playbackPolicy: 'none',
|
|
576
582
|
isAdult: false,
|
|
583
|
+
streams: [],
|
|
584
|
+
syncData: {},
|
|
577
585
|
...params
|
|
578
586
|
});
|
|
579
587
|
}
|
|
@@ -585,6 +593,8 @@ program.command('test')
|
|
|
585
593
|
season: 0,
|
|
586
594
|
episode: 0,
|
|
587
595
|
dubStatus: 'none',
|
|
596
|
+
playbackPolicy: 'none',
|
|
597
|
+
streams: [],
|
|
588
598
|
...params
|
|
589
599
|
});
|
|
590
600
|
}
|