skystream-cli 1.4.5 → 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 +55 -47
- 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._-]+$/),
|
|
@@ -163,7 +163,13 @@ const JS_TEMPLATE = `(function() {
|
|
|
163
163
|
],
|
|
164
164
|
nextAiring: new NextAiring({ episode: 5, season: 1, airDate: "2024-04-01" }),
|
|
165
165
|
recommendations: [
|
|
166
|
-
new MultimediaItem({ title: "Similar Show", url: \`\${manifest.baseUrl}/similar\`, posterUrl: "
|
|
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" })
|
|
167
173
|
],
|
|
168
174
|
headers: { "Referer": \`\${manifest.baseUrl}\` },
|
|
169
175
|
episodes: [
|
|
@@ -174,7 +180,8 @@ const JS_TEMPLATE = `(function() {
|
|
|
174
180
|
episode: 1,
|
|
175
181
|
description: "Episode summary...",
|
|
176
182
|
posterUrl: \`https://placehold.co/400x600.png?text=Episode+Poster\`,
|
|
177
|
-
headers: { "Referer": \`\${manifest.baseUrl}\` }
|
|
183
|
+
headers: { "Referer": \`\${manifest.baseUrl}\` },
|
|
184
|
+
streams: [] // Optional: "Instant Load" for episodes
|
|
178
185
|
}),
|
|
179
186
|
new Episode({
|
|
180
187
|
name: "Episode 2",
|
|
@@ -200,25 +207,19 @@ const JS_TEMPLATE = `(function() {
|
|
|
200
207
|
*/
|
|
201
208
|
async function loadStreams(url, cb) {
|
|
202
209
|
try {
|
|
203
|
-
// Standard: Return a List of stream
|
|
210
|
+
// Standard: Return a List of stream objects
|
|
204
211
|
cb({
|
|
205
212
|
success: true,
|
|
206
213
|
data: [
|
|
207
214
|
new StreamResult({
|
|
208
215
|
url: "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8",
|
|
209
|
-
source: "
|
|
210
|
-
headers: { "Referer": \`\${manifest.baseUrl}\` }
|
|
211
|
-
subtitles: [
|
|
212
|
-
{ url: \`\${manifest.baseUrl}/sub.vtt\`, label: "English", lang: "en" } // (optional)
|
|
213
|
-
],
|
|
214
|
-
drmKid: "kid_value", // (optional)
|
|
215
|
-
drmKey: "key_value", // (optional)
|
|
216
|
-
licenseUrl: "https://license-server.com" // (optional)
|
|
216
|
+
source: "Direct Quality",
|
|
217
|
+
headers: { "Referer": \`\${manifest.baseUrl}\` }
|
|
217
218
|
})
|
|
218
219
|
]
|
|
219
220
|
});
|
|
220
221
|
} catch (e) {
|
|
221
|
-
cb({ success: false, errorCode: "STREAM_ERROR", message:
|
|
222
|
+
cb({ success: false, errorCode: "STREAM_ERROR", message: String(e) });
|
|
222
223
|
}
|
|
223
224
|
}
|
|
224
225
|
|
|
@@ -447,6 +448,7 @@ program.command('test')
|
|
|
447
448
|
const manifest = await fs.readJson(manifestPath);
|
|
448
449
|
const jsContent = await fs.readFile(jsPath, 'utf8');
|
|
449
450
|
console.log(`\n--- Testing ${manifest.packageName} -> ${options.function} ---`);
|
|
451
|
+
const preferences = {};
|
|
450
452
|
const context = {
|
|
451
453
|
manifest,
|
|
452
454
|
console: {
|
|
@@ -455,67 +457,68 @@ program.command('test')
|
|
|
455
457
|
},
|
|
456
458
|
http_get: async (url, headers, cb) => {
|
|
457
459
|
try {
|
|
458
|
-
const
|
|
459
|
-
|
|
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);
|
|
460
466
|
if (cb)
|
|
461
|
-
cb(
|
|
462
|
-
return
|
|
467
|
+
cb({ status: res.status, statusCode: res.status, body, headers: res.headers });
|
|
468
|
+
return body;
|
|
463
469
|
}
|
|
464
470
|
catch (e) {
|
|
465
471
|
const res = { status: e.response?.status || 500, statusCode: e.response?.status || 500, body: e.response?.data || e.message, headers: e.response?.headers || {} };
|
|
466
472
|
if (cb)
|
|
467
473
|
cb(res);
|
|
468
|
-
return res;
|
|
474
|
+
return typeof res.body === 'string' ? res.body : JSON.stringify(res.body);
|
|
469
475
|
}
|
|
470
476
|
},
|
|
471
477
|
http_post: async (url, headers, body, cb) => {
|
|
472
478
|
try {
|
|
473
|
-
const
|
|
474
|
-
|
|
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);
|
|
475
485
|
if (cb)
|
|
476
|
-
cb(
|
|
477
|
-
return
|
|
486
|
+
cb({ status: res.status, statusCode: res.status, body: resBody, headers: res.headers });
|
|
487
|
+
return resBody;
|
|
478
488
|
}
|
|
479
489
|
catch (e) {
|
|
480
490
|
const res = { status: e.response?.status || 500, statusCode: e.response?.status || 500, body: e.response?.data || e.message, headers: e.response?.headers || {} };
|
|
481
491
|
if (cb)
|
|
482
492
|
cb(res);
|
|
483
|
-
return res;
|
|
484
|
-
}
|
|
485
|
-
},
|
|
486
|
-
_fetch: async (url) => {
|
|
487
|
-
try {
|
|
488
|
-
const res = await axios.get(url);
|
|
489
|
-
return typeof res.data === 'string' ? res.data : JSON.stringify(res.data);
|
|
490
|
-
}
|
|
491
|
-
catch (e) {
|
|
492
|
-
throw new Error(`HTTP Error ${e.response?.status || 500} fetching ${url}`);
|
|
493
|
+
return typeof res.body === 'string' ? res.body : JSON.stringify(res.body);
|
|
493
494
|
}
|
|
494
495
|
},
|
|
495
|
-
fetch: async (url) => {
|
|
496
|
-
const res = await axios.get(url);
|
|
497
|
-
return {
|
|
498
|
-
status: res.status,
|
|
499
|
-
statusCode: res.status,
|
|
500
|
-
body: typeof res.data === 'string' ? res.data : JSON.stringify(res.data),
|
|
501
|
-
headers: res.headers
|
|
502
|
-
};
|
|
503
|
-
},
|
|
504
496
|
registerSettings: (schema) => {
|
|
505
497
|
console.log(' [Mock SDK]: Plugin registered settings:', JSON.stringify(schema, null, 2));
|
|
506
498
|
},
|
|
499
|
+
getPreference: (key) => {
|
|
500
|
+
return preferences[key] || null;
|
|
501
|
+
},
|
|
502
|
+
setPreference: (key, value) => {
|
|
503
|
+
preferences[key] = value;
|
|
504
|
+
return true;
|
|
505
|
+
},
|
|
507
506
|
solveCaptcha: async (siteKey, url) => {
|
|
508
507
|
console.log(' [Mock SDK]: solveCaptcha requested for ' + url + ' with key ' + siteKey);
|
|
509
508
|
return "mock_captcha_token";
|
|
510
509
|
},
|
|
511
|
-
crypto: {
|
|
512
|
-
decryptAES: (data, key, iv) => {
|
|
513
|
-
return "decrypted(" + data + ")";
|
|
514
|
-
}
|
|
515
|
-
},
|
|
516
510
|
btoa: (s) => Buffer.from(s).toString('base64'),
|
|
517
511
|
atob: (s) => Buffer.from(s, 'base64').toString('utf8'),
|
|
518
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
|
+
}
|
|
519
522
|
if (id === 'crypto_decrypt_aes') {
|
|
520
523
|
const { data, key, iv } = JSON.parse(arg);
|
|
521
524
|
try {
|
|
@@ -550,6 +553,7 @@ program.command('test')
|
|
|
550
553
|
},
|
|
551
554
|
globalThis: {},
|
|
552
555
|
};
|
|
556
|
+
context.globalThis = context;
|
|
553
557
|
const entityDefs = `
|
|
554
558
|
class Actor {
|
|
555
559
|
constructor(params) {
|
|
@@ -574,8 +578,10 @@ program.command('test')
|
|
|
574
578
|
Object.assign(this, {
|
|
575
579
|
type: 'movie',
|
|
576
580
|
status: 'ongoing',
|
|
577
|
-
|
|
581
|
+
playbackPolicy: 'none',
|
|
578
582
|
isAdult: false,
|
|
583
|
+
streams: [],
|
|
584
|
+
syncData: {},
|
|
579
585
|
...params
|
|
580
586
|
});
|
|
581
587
|
}
|
|
@@ -587,6 +593,8 @@ program.command('test')
|
|
|
587
593
|
season: 0,
|
|
588
594
|
episode: 0,
|
|
589
595
|
dubStatus: 'none',
|
|
596
|
+
playbackPolicy: 'none',
|
|
597
|
+
streams: [],
|
|
590
598
|
...params
|
|
591
599
|
});
|
|
592
600
|
}
|