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.
Files changed (2) hide show
  1. package/dist/index.js +55 -47
  2. 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.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: "...", type: "series" })
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 urls
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: "Server [1080p]", // (optional)
210
- headers: { "Referer": \`\${manifest.baseUrl}\` }, // (optional)
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: (e instanceof Error) ? e.message : String(e) });
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 res = await axios.get(url, { headers: headers || {} });
459
- const result = { status: res.status, statusCode: res.status, body: typeof res.data === 'string' ? res.data : JSON.stringify(res.data), headers: res.headers };
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(result);
462
- return result;
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 res = await axios.post(url, body, { headers: headers || {} });
474
- const result = { status: res.status, statusCode: res.status, body: typeof res.data === 'string' ? res.data : JSON.stringify(res.data), headers: res.headers };
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(result);
477
- return result;
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
- vpnStatus: 'none',
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skystream-cli",
3
- "version": "1.4.5",
3
+ "version": "1.4.6",
4
4
  "type": "module",
5
5
  "description": "SkyStream Plugin Development Kit & Repository Manager",
6
6
  "main": "dist/index.js",