skystream-cli 1.4.3 → 1.4.4
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 +86 -59
- 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.4');
|
|
16
16
|
// Schemas
|
|
17
17
|
const pluginSchema = z.object({
|
|
18
18
|
packageName: z.string().min(5).regex(/^[a-z0-9._-]+$/),
|
|
@@ -45,12 +45,18 @@ const JS_TEMPLATE = `(function() {
|
|
|
45
45
|
*/
|
|
46
46
|
// var manifest is injected at runtime
|
|
47
47
|
|
|
48
|
+
// 1. (Optional) Register your plugin settings
|
|
49
|
+
registerSettings([
|
|
50
|
+
{ id: "quality", name: "Default Quality", type: "select", options: ["1080p", "720p"], default: "1080p" },
|
|
51
|
+
{ id: "prefer_dub", name: "Prefer Dubbed", type: "toggle", default: false }
|
|
52
|
+
]);
|
|
48
53
|
|
|
49
54
|
/**
|
|
50
55
|
* Loads the home screen categories.
|
|
51
56
|
* @param {(res: Response) => void} cb
|
|
52
57
|
*/
|
|
53
58
|
async function getHome(cb) {
|
|
59
|
+
// Example: Using solveCaptcha if needed (await solveCaptcha(siteKey, url))
|
|
54
60
|
try {
|
|
55
61
|
// Dashboard Layout:
|
|
56
62
|
// - "Trending" is a reserved category promoted to the Hero Carousel.
|
|
@@ -75,23 +81,22 @@ const JS_TEMPLATE = `(function() {
|
|
|
75
81
|
title: "Example Series (Thumb)",
|
|
76
82
|
url: \`\${manifest.baseUrl}/series\`,
|
|
77
83
|
posterUrl: \`https://placehold.co/400x600.png?text=Series+Poster\`,
|
|
78
|
-
type: "series",
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
type: "series",
|
|
85
|
+
year: 2024,
|
|
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
|
+
],
|
|
81
92
|
episodes: [
|
|
82
93
|
new Episode({
|
|
83
94
|
name: "Episode 1",
|
|
84
95
|
url: \`\${manifest.baseUrl}/series/1\`,
|
|
85
96
|
season: 1,
|
|
86
97
|
episode: 1,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
new Episode({
|
|
90
|
-
name: "Episode 2",
|
|
91
|
-
url: \`\${manifest.baseUrl}/series/2\`,
|
|
92
|
-
season: 1,
|
|
93
|
-
episode: 2,
|
|
94
|
-
posterUrl: \`https://placehold.co/400x600.png?text=EP2+Poster\`
|
|
98
|
+
airDate: "2024-03-12",
|
|
99
|
+
dubStatus: "subbed" // subbed, dubbed, none
|
|
95
100
|
})
|
|
96
101
|
]
|
|
97
102
|
})
|
|
@@ -106,9 +111,10 @@ const JS_TEMPLATE = `(function() {
|
|
|
106
111
|
/**
|
|
107
112
|
* Searches for media items.
|
|
108
113
|
* @param {string} query
|
|
114
|
+
* @param {number} page
|
|
109
115
|
* @param {(res: Response) => void} cb
|
|
110
116
|
*/
|
|
111
|
-
async function search(query, cb) {
|
|
117
|
+
async function search(query, page, cb) {
|
|
112
118
|
try {
|
|
113
119
|
// Standard: Return a List of items
|
|
114
120
|
// Samples show both a movie and a series
|
|
@@ -409,7 +415,7 @@ program.command('validate')
|
|
|
409
415
|
count++;
|
|
410
416
|
}
|
|
411
417
|
catch (e) {
|
|
412
|
-
console.error(
|
|
418
|
+
console.error(`\u2717 ${item} invalid: ${e.message}`);
|
|
413
419
|
if (e instanceof z.ZodError) {
|
|
414
420
|
console.error(JSON.stringify(e.format(), null, 2));
|
|
415
421
|
}
|
|
@@ -493,14 +499,24 @@ program.command('test')
|
|
|
493
499
|
headers: res.headers
|
|
494
500
|
};
|
|
495
501
|
},
|
|
502
|
+
registerSettings: (schema) => {
|
|
503
|
+
console.log(' [Mock SDK]: Plugin registered settings:', JSON.stringify(schema, null, 2));
|
|
504
|
+
},
|
|
505
|
+
solveCaptcha: async (siteKey, url) => {
|
|
506
|
+
console.log(' [Mock SDK]: solveCaptcha requested for ' + url + ' with key ' + siteKey);
|
|
507
|
+
return "mock_captcha_token";
|
|
508
|
+
},
|
|
509
|
+
crypto: {
|
|
510
|
+
decryptAES: (data, key, iv) => {
|
|
511
|
+
return "decrypted(" + data + ")";
|
|
512
|
+
}
|
|
513
|
+
},
|
|
496
514
|
btoa: (s) => Buffer.from(s).toString('base64'),
|
|
497
515
|
atob: (s) => Buffer.from(s, 'base64').toString('utf8'),
|
|
498
516
|
sendMessage: async (id, arg) => {
|
|
499
517
|
if (id === 'crypto_decrypt_aes') {
|
|
500
518
|
const { data, key, iv } = JSON.parse(arg);
|
|
501
519
|
try {
|
|
502
|
-
// Standardize key and iv to correct lengths
|
|
503
|
-
// They are often passed as base64 strings
|
|
504
520
|
const decodeBuffer = (s) => {
|
|
505
521
|
return s.length % 4 === 0 && /^[A-Za-z0-9+/=]+$/.test(s) ? Buffer.from(s, 'base64') : Buffer.from(s, 'utf8');
|
|
506
522
|
};
|
|
@@ -533,41 +549,50 @@ program.command('test')
|
|
|
533
549
|
globalThis: {},
|
|
534
550
|
};
|
|
535
551
|
const entityDefs = `
|
|
552
|
+
class Actor {
|
|
553
|
+
constructor(params) {
|
|
554
|
+
Object.assign(this, params);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
class Trailer {
|
|
559
|
+
constructor(params) {
|
|
560
|
+
Object.assign(this, params);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
class NextAiring {
|
|
565
|
+
constructor(params) {
|
|
566
|
+
Object.assign(this, params);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
536
570
|
class MultimediaItem {
|
|
537
|
-
constructor(
|
|
538
|
-
this
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
this.headers = headers;
|
|
546
|
-
this.provider = provider;
|
|
571
|
+
constructor(params) {
|
|
572
|
+
Object.assign(this, {
|
|
573
|
+
type: 'movie',
|
|
574
|
+
status: 'ongoing',
|
|
575
|
+
vpnStatus: 'none',
|
|
576
|
+
isAdult: false,
|
|
577
|
+
...params
|
|
578
|
+
});
|
|
547
579
|
}
|
|
548
580
|
}
|
|
549
581
|
|
|
550
582
|
class Episode {
|
|
551
|
-
constructor(
|
|
552
|
-
this
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
this.headers = headers;
|
|
583
|
+
constructor(params) {
|
|
584
|
+
Object.assign(this, {
|
|
585
|
+
season: 0,
|
|
586
|
+
episode: 0,
|
|
587
|
+
dubStatus: 'none',
|
|
588
|
+
...params
|
|
589
|
+
});
|
|
559
590
|
}
|
|
560
591
|
}
|
|
561
592
|
|
|
562
593
|
class StreamResult {
|
|
563
|
-
constructor(
|
|
564
|
-
this
|
|
565
|
-
this.source = source || quality || 'Auto';
|
|
566
|
-
this.headers = headers;
|
|
567
|
-
this.subtitles = subtitles;
|
|
568
|
-
this.drmKid = drmKid;
|
|
569
|
-
this.drmKey = drmKey;
|
|
570
|
-
this.licenseUrl = licenseUrl;
|
|
594
|
+
constructor(params) {
|
|
595
|
+
Object.assign(this, params);
|
|
571
596
|
}
|
|
572
597
|
}
|
|
573
598
|
|
|
@@ -617,21 +642,23 @@ program.command('test')
|
|
|
617
642
|
const callback = (res) => {
|
|
618
643
|
console.log('\n--- Result ---');
|
|
619
644
|
if (res && res.success === false) {
|
|
620
|
-
console.log(
|
|
621
|
-
console.log(
|
|
645
|
+
console.log('\x1b[31mStatus: FAILED\x1b[0m');
|
|
646
|
+
console.log('\x1b[31mError Code: ' + (res.errorCode || 'UNKNOWN') + '\x1b[0m');
|
|
622
647
|
if (res.message)
|
|
623
|
-
console.log(
|
|
648
|
+
console.log('\x1b[31mMessage: ' + res.message + '\x1b[0m');
|
|
624
649
|
}
|
|
625
650
|
else {
|
|
626
|
-
console.log(
|
|
651
|
+
console.log('\x1b[32mStatus: SUCCESS\x1b[0m');
|
|
627
652
|
}
|
|
628
653
|
console.log(JSON.stringify(res, null, 2));
|
|
629
654
|
};
|
|
630
655
|
try {
|
|
631
656
|
if (options.function === 'getHome')
|
|
632
657
|
await fn(callback);
|
|
658
|
+
else if (options.function === 'search')
|
|
659
|
+
await fn(options.query, 1, callback);
|
|
633
660
|
else if (!options.query || options.query.trim() === "") {
|
|
634
|
-
console.warn(
|
|
661
|
+
console.warn('\x1b[33mWarning: Function \'' + options.function + '\' usually requires a query/URL (-q), but none was provided.\x1b[0m');
|
|
635
662
|
await fn(options.query, callback);
|
|
636
663
|
}
|
|
637
664
|
else {
|
|
@@ -639,8 +666,8 @@ program.command('test')
|
|
|
639
666
|
}
|
|
640
667
|
}
|
|
641
668
|
catch (e) {
|
|
642
|
-
console.error(
|
|
643
|
-
console.error(
|
|
669
|
+
console.error('\n\x1b[31m--- CRITICAL ERROR DURING EXECUTION ---\x1b[0m');
|
|
670
|
+
console.error('\x1b[31m' + (e.stack || e.message) + '\x1b[0m\n');
|
|
644
671
|
process.exit(2);
|
|
645
672
|
}
|
|
646
673
|
});
|
|
@@ -660,27 +687,27 @@ program.command('deploy')
|
|
|
660
687
|
const catalog = [];
|
|
661
688
|
// Standardize URL: Append /dist automatically
|
|
662
689
|
const baseRaw = options.url.endsWith('/') ? options.url.slice(0, -1) : options.url;
|
|
663
|
-
const distUrl =
|
|
690
|
+
const distUrl = baseRaw + "/dist";
|
|
664
691
|
for (const item of items) {
|
|
665
692
|
const itemPath = path.join(rootDir, item);
|
|
666
693
|
const mPath = path.join(itemPath, 'plugin.json');
|
|
667
694
|
if (await fs.pathExists(mPath) && (await fs.stat(itemPath)).isDirectory()) {
|
|
668
695
|
const manifest = await fs.readJson(mPath);
|
|
669
696
|
const packageName = manifest.packageName || manifest.id || item;
|
|
670
|
-
const bundleName =
|
|
697
|
+
const bundleName = packageName + ".sky";
|
|
671
698
|
const outPath = path.join(distDir, bundleName);
|
|
672
699
|
const arch = archiver('zip', { zlib: { level: 9 } });
|
|
673
700
|
arch.pipe(fs.createWriteStream(outPath));
|
|
674
701
|
arch.file(mPath, { name: 'plugin.json' });
|
|
675
702
|
arch.file(path.join(itemPath, 'plugin.js'), { name: 'plugin.js' });
|
|
676
703
|
await arch.finalize();
|
|
677
|
-
catalog.push({ ...manifest, url:
|
|
678
|
-
console.log(
|
|
704
|
+
catalog.push({ ...manifest, url: distUrl + "/" + bundleName });
|
|
705
|
+
console.log("✓ Bundled " + manifest.packageName);
|
|
679
706
|
}
|
|
680
707
|
}
|
|
681
708
|
const finalRepo = {
|
|
682
709
|
...repo,
|
|
683
|
-
pluginLists: [
|
|
710
|
+
pluginLists: [distUrl + "/plugins.json"]
|
|
684
711
|
};
|
|
685
712
|
await fs.writeJson(repoPath, finalRepo, { spaces: 2 });
|
|
686
713
|
await fs.writeJson(path.join(distDir, 'plugins.json'), catalog, { spaces: 2 });
|
|
@@ -689,15 +716,15 @@ program.command('deploy')
|
|
|
689
716
|
if (await fs.pathExists(readmePath)) {
|
|
690
717
|
let readme = await fs.readFile(readmePath, 'utf8');
|
|
691
718
|
const placeholder = 'https://raw.githubusercontent.com/USER_NAME/REPO_NAME/main/repo.json';
|
|
692
|
-
const liveUrl =
|
|
719
|
+
const liveUrl = baseRaw + "/repo.json";
|
|
693
720
|
if (readme.includes(placeholder)) {
|
|
694
721
|
readme = readme.replace(placeholder, liveUrl);
|
|
695
722
|
await fs.writeFile(readmePath, readme);
|
|
696
|
-
console.log(
|
|
723
|
+
console.log("✓ Updated README.md with live URL");
|
|
697
724
|
}
|
|
698
725
|
}
|
|
699
|
-
console.log(
|
|
700
|
-
console.log(
|
|
701
|
-
console.log(
|
|
726
|
+
console.log("\nDeployment Complete. Assets generated in dist/");
|
|
727
|
+
console.log("\nYour Repo Link for the app:");
|
|
728
|
+
console.log("> " + baseRaw + "/repo.json");
|
|
702
729
|
});
|
|
703
730
|
program.parse();
|