skystream-cli 1.4.3 → 1.4.5
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 +96 -67
- 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,25 +81,8 @@ 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
|
-
description: "This category appears as a thumbnail row."
|
|
80
|
-
headers: { "Referer": \`\${manifest.baseUrl}\` }, // (optional)
|
|
81
|
-
episodes: [
|
|
82
|
-
new Episode({
|
|
83
|
-
name: "Episode 1",
|
|
84
|
-
url: \`\${manifest.baseUrl}/series/1\`,
|
|
85
|
-
season: 1,
|
|
86
|
-
episode: 1,
|
|
87
|
-
posterUrl: \`https://placehold.co/400x600.png?text=EP1+Poster\`
|
|
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\`
|
|
95
|
-
})
|
|
96
|
-
]
|
|
84
|
+
type: "series",
|
|
85
|
+
description: "This category appears as a thumbnail row."
|
|
97
86
|
})
|
|
98
87
|
]
|
|
99
88
|
}
|
|
@@ -106,9 +95,10 @@ const JS_TEMPLATE = `(function() {
|
|
|
106
95
|
/**
|
|
107
96
|
* Searches for media items.
|
|
108
97
|
* @param {string} query
|
|
98
|
+
* @param {number} page
|
|
109
99
|
* @param {(res: Response) => void} cb
|
|
110
100
|
*/
|
|
111
|
-
async function search(query, cb) {
|
|
101
|
+
async function search(query, page, cb) {
|
|
112
102
|
try {
|
|
113
103
|
// Standard: Return a List of items
|
|
114
104
|
// Samples show both a movie and a series
|
|
@@ -157,6 +147,24 @@ const JS_TEMPLATE = `(function() {
|
|
|
157
147
|
type: "series",
|
|
158
148
|
bannerUrl: \`https://placehold.co/1280x720.png?text=Series+Banner\`,
|
|
159
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: "...", type: "series" })
|
|
167
|
+
],
|
|
160
168
|
headers: { "Referer": \`\${manifest.baseUrl}\` },
|
|
161
169
|
episodes: [
|
|
162
170
|
new Episode({
|
|
@@ -409,7 +417,7 @@ program.command('validate')
|
|
|
409
417
|
count++;
|
|
410
418
|
}
|
|
411
419
|
catch (e) {
|
|
412
|
-
console.error(
|
|
420
|
+
console.error(`\u2717 ${item} invalid: ${e.message}`);
|
|
413
421
|
if (e instanceof z.ZodError) {
|
|
414
422
|
console.error(JSON.stringify(e.format(), null, 2));
|
|
415
423
|
}
|
|
@@ -493,14 +501,24 @@ program.command('test')
|
|
|
493
501
|
headers: res.headers
|
|
494
502
|
};
|
|
495
503
|
},
|
|
504
|
+
registerSettings: (schema) => {
|
|
505
|
+
console.log(' [Mock SDK]: Plugin registered settings:', JSON.stringify(schema, null, 2));
|
|
506
|
+
},
|
|
507
|
+
solveCaptcha: async (siteKey, url) => {
|
|
508
|
+
console.log(' [Mock SDK]: solveCaptcha requested for ' + url + ' with key ' + siteKey);
|
|
509
|
+
return "mock_captcha_token";
|
|
510
|
+
},
|
|
511
|
+
crypto: {
|
|
512
|
+
decryptAES: (data, key, iv) => {
|
|
513
|
+
return "decrypted(" + data + ")";
|
|
514
|
+
}
|
|
515
|
+
},
|
|
496
516
|
btoa: (s) => Buffer.from(s).toString('base64'),
|
|
497
517
|
atob: (s) => Buffer.from(s, 'base64').toString('utf8'),
|
|
498
518
|
sendMessage: async (id, arg) => {
|
|
499
519
|
if (id === 'crypto_decrypt_aes') {
|
|
500
520
|
const { data, key, iv } = JSON.parse(arg);
|
|
501
521
|
try {
|
|
502
|
-
// Standardize key and iv to correct lengths
|
|
503
|
-
// They are often passed as base64 strings
|
|
504
522
|
const decodeBuffer = (s) => {
|
|
505
523
|
return s.length % 4 === 0 && /^[A-Za-z0-9+/=]+$/.test(s) ? Buffer.from(s, 'base64') : Buffer.from(s, 'utf8');
|
|
506
524
|
};
|
|
@@ -533,41 +551,50 @@ program.command('test')
|
|
|
533
551
|
globalThis: {},
|
|
534
552
|
};
|
|
535
553
|
const entityDefs = `
|
|
554
|
+
class Actor {
|
|
555
|
+
constructor(params) {
|
|
556
|
+
Object.assign(this, params);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
class Trailer {
|
|
561
|
+
constructor(params) {
|
|
562
|
+
Object.assign(this, params);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
class NextAiring {
|
|
567
|
+
constructor(params) {
|
|
568
|
+
Object.assign(this, params);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
536
572
|
class MultimediaItem {
|
|
537
|
-
constructor(
|
|
538
|
-
this
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
this.headers = headers;
|
|
546
|
-
this.provider = provider;
|
|
573
|
+
constructor(params) {
|
|
574
|
+
Object.assign(this, {
|
|
575
|
+
type: 'movie',
|
|
576
|
+
status: 'ongoing',
|
|
577
|
+
vpnStatus: 'none',
|
|
578
|
+
isAdult: false,
|
|
579
|
+
...params
|
|
580
|
+
});
|
|
547
581
|
}
|
|
548
582
|
}
|
|
549
583
|
|
|
550
584
|
class Episode {
|
|
551
|
-
constructor(
|
|
552
|
-
this
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
this.headers = headers;
|
|
585
|
+
constructor(params) {
|
|
586
|
+
Object.assign(this, {
|
|
587
|
+
season: 0,
|
|
588
|
+
episode: 0,
|
|
589
|
+
dubStatus: 'none',
|
|
590
|
+
...params
|
|
591
|
+
});
|
|
559
592
|
}
|
|
560
593
|
}
|
|
561
594
|
|
|
562
595
|
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;
|
|
596
|
+
constructor(params) {
|
|
597
|
+
Object.assign(this, params);
|
|
571
598
|
}
|
|
572
599
|
}
|
|
573
600
|
|
|
@@ -617,21 +644,23 @@ program.command('test')
|
|
|
617
644
|
const callback = (res) => {
|
|
618
645
|
console.log('\n--- Result ---');
|
|
619
646
|
if (res && res.success === false) {
|
|
620
|
-
console.log(
|
|
621
|
-
console.log(
|
|
647
|
+
console.log('\x1b[31mStatus: FAILED\x1b[0m');
|
|
648
|
+
console.log('\x1b[31mError Code: ' + (res.errorCode || 'UNKNOWN') + '\x1b[0m');
|
|
622
649
|
if (res.message)
|
|
623
|
-
console.log(
|
|
650
|
+
console.log('\x1b[31mMessage: ' + res.message + '\x1b[0m');
|
|
624
651
|
}
|
|
625
652
|
else {
|
|
626
|
-
console.log(
|
|
653
|
+
console.log('\x1b[32mStatus: SUCCESS\x1b[0m');
|
|
627
654
|
}
|
|
628
655
|
console.log(JSON.stringify(res, null, 2));
|
|
629
656
|
};
|
|
630
657
|
try {
|
|
631
658
|
if (options.function === 'getHome')
|
|
632
659
|
await fn(callback);
|
|
660
|
+
else if (options.function === 'search')
|
|
661
|
+
await fn(options.query, 1, callback);
|
|
633
662
|
else if (!options.query || options.query.trim() === "") {
|
|
634
|
-
console.warn(
|
|
663
|
+
console.warn('\x1b[33mWarning: Function \'' + options.function + '\' usually requires a query/URL (-q), but none was provided.\x1b[0m');
|
|
635
664
|
await fn(options.query, callback);
|
|
636
665
|
}
|
|
637
666
|
else {
|
|
@@ -639,8 +668,8 @@ program.command('test')
|
|
|
639
668
|
}
|
|
640
669
|
}
|
|
641
670
|
catch (e) {
|
|
642
|
-
console.error(
|
|
643
|
-
console.error(
|
|
671
|
+
console.error('\n\x1b[31m--- CRITICAL ERROR DURING EXECUTION ---\x1b[0m');
|
|
672
|
+
console.error('\x1b[31m' + (e.stack || e.message) + '\x1b[0m\n');
|
|
644
673
|
process.exit(2);
|
|
645
674
|
}
|
|
646
675
|
});
|
|
@@ -660,27 +689,27 @@ program.command('deploy')
|
|
|
660
689
|
const catalog = [];
|
|
661
690
|
// Standardize URL: Append /dist automatically
|
|
662
691
|
const baseRaw = options.url.endsWith('/') ? options.url.slice(0, -1) : options.url;
|
|
663
|
-
const distUrl =
|
|
692
|
+
const distUrl = baseRaw + "/dist";
|
|
664
693
|
for (const item of items) {
|
|
665
694
|
const itemPath = path.join(rootDir, item);
|
|
666
695
|
const mPath = path.join(itemPath, 'plugin.json');
|
|
667
696
|
if (await fs.pathExists(mPath) && (await fs.stat(itemPath)).isDirectory()) {
|
|
668
697
|
const manifest = await fs.readJson(mPath);
|
|
669
698
|
const packageName = manifest.packageName || manifest.id || item;
|
|
670
|
-
const bundleName =
|
|
699
|
+
const bundleName = packageName + ".sky";
|
|
671
700
|
const outPath = path.join(distDir, bundleName);
|
|
672
701
|
const arch = archiver('zip', { zlib: { level: 9 } });
|
|
673
702
|
arch.pipe(fs.createWriteStream(outPath));
|
|
674
703
|
arch.file(mPath, { name: 'plugin.json' });
|
|
675
704
|
arch.file(path.join(itemPath, 'plugin.js'), { name: 'plugin.js' });
|
|
676
705
|
await arch.finalize();
|
|
677
|
-
catalog.push({ ...manifest, url:
|
|
678
|
-
console.log(
|
|
706
|
+
catalog.push({ ...manifest, url: distUrl + "/" + bundleName });
|
|
707
|
+
console.log("✓ Bundled " + manifest.packageName);
|
|
679
708
|
}
|
|
680
709
|
}
|
|
681
710
|
const finalRepo = {
|
|
682
711
|
...repo,
|
|
683
|
-
pluginLists: [
|
|
712
|
+
pluginLists: [distUrl + "/plugins.json"]
|
|
684
713
|
};
|
|
685
714
|
await fs.writeJson(repoPath, finalRepo, { spaces: 2 });
|
|
686
715
|
await fs.writeJson(path.join(distDir, 'plugins.json'), catalog, { spaces: 2 });
|
|
@@ -689,15 +718,15 @@ program.command('deploy')
|
|
|
689
718
|
if (await fs.pathExists(readmePath)) {
|
|
690
719
|
let readme = await fs.readFile(readmePath, 'utf8');
|
|
691
720
|
const placeholder = 'https://raw.githubusercontent.com/USER_NAME/REPO_NAME/main/repo.json';
|
|
692
|
-
const liveUrl =
|
|
721
|
+
const liveUrl = baseRaw + "/repo.json";
|
|
693
722
|
if (readme.includes(placeholder)) {
|
|
694
723
|
readme = readme.replace(placeholder, liveUrl);
|
|
695
724
|
await fs.writeFile(readmePath, readme);
|
|
696
|
-
console.log(
|
|
725
|
+
console.log("✓ Updated README.md with live URL");
|
|
697
726
|
}
|
|
698
727
|
}
|
|
699
|
-
console.log(
|
|
700
|
-
console.log(
|
|
701
|
-
console.log(
|
|
728
|
+
console.log("\nDeployment Complete. Assets generated in dist/");
|
|
729
|
+
console.log("\nYour Repo Link for the app:");
|
|
730
|
+
console.log("> " + baseRaw + "/repo.json");
|
|
702
731
|
});
|
|
703
732
|
program.parse();
|