@lunarity/nebula-fetch-cli 0.0.2 → 0.0.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/index.ts CHANGED
@@ -1,29 +1,57 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { Command } from "commander";
4
+ import { version } from "@/package.json";
5
+
4
6
  import chalk from "chalk";
5
- import { downloadYoutubeAudio } from "./commands/youtube";
7
+
8
+ import { downloadYoutube } from "@/commands/youtube";
9
+ import { isValidYoutubeUrl } from "@/utils/validators";
6
10
 
7
11
  const program = new Command();
8
12
 
9
13
  program
10
14
  .name("nebula-fetch")
11
15
  .description("CLI tool for downloading media from different platforms")
12
- .version("1.0.0");
16
+ .version(version);
13
17
 
14
18
  program
15
19
  .command("youtube")
20
+ .alias("yt")
16
21
  .description("Download a video from YouTube")
17
22
  .argument("<url>", "URL of the video")
18
23
  .option("-o, --output <path>", "Output path for the video")
24
+ .option("-a, --audio", "Download only the audio", false)
25
+ .option("-v, --verbose", "Show verbose output", false)
19
26
  .action(async (url, options) => {
20
27
  try {
21
- console.log(chalk.blue(`Downloading video from: ${url}`));
22
- await downloadYoutubeAudio(url, options.output);
28
+ if (!isValidYoutubeUrl(url)) {
29
+ console.error(
30
+ chalk.red(
31
+ "Error: Invalid YouTube URL. Please provide a valid YouTube video URL"
32
+ )
33
+ );
34
+ process.exit(1);
35
+ }
36
+
37
+ console.log(
38
+ chalk.blue(
39
+ `🚀 Downloading ${options.audio ? "audio" : "video"} from: ${url}`
40
+ )
41
+ );
42
+ await downloadYoutube({
43
+ url,
44
+ audioOnly: options.audio,
45
+ outputPath: options.output,
46
+ verbose: options.verbose,
47
+ });
23
48
  } catch (error) {
24
49
  console.error(chalk.red("Error:"), error);
25
50
  process.exit(1);
26
51
  }
27
52
  });
28
53
 
29
- program.parse();
54
+ program.parseAsync().catch((error) => {
55
+ console.error(chalk.red("Fatal error:"), error);
56
+ process.exit(1);
57
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunarity/nebula-fetch-cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "module": "index.ts",
5
5
  "description": "CLI tool for downloading media from different platforms",
6
6
  "type": "module",
@@ -12,7 +12,7 @@
12
12
  "typescript": "^5.0.0"
13
13
  },
14
14
  "dependencies": {
15
- "@ybd-project/ytdl-core": "latest",
15
+ "@ybd-project/ytdl-core": "6.0.8",
16
16
  "chalk": "^5.3.0",
17
17
  "commander": "^12.1.0"
18
18
  },
@@ -27,6 +27,13 @@
27
27
  "keywords": [
28
28
  "cli",
29
29
  "media",
30
- "download"
31
- ]
30
+ "download",
31
+ "youtube"
32
+ ],
33
+ "author": "Krzysztof Oszczapiński",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/LUNARITYai/nebula-fetch-cli.git"
38
+ }
32
39
  }
package/tsconfig.json CHANGED
@@ -22,6 +22,11 @@
22
22
  // Some stricter flags (disabled by default)
23
23
  "noUnusedLocals": false,
24
24
  "noUnusedParameters": false,
25
- "noPropertyAccessFromIndexSignature": false
25
+ "noPropertyAccessFromIndexSignature": false,
26
+
27
+ "baseUrl": ".",
28
+ "paths": {
29
+ "@/*": ["./*"]
30
+ }
26
31
  }
27
32
  }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Validates YouTube URLs in various formats:
3
+ * - Standard: https://www.youtube.com/watch?v=VIDEO_ID
4
+ * - Short: https://youtu.be/VIDEO_ID
5
+ * - Embedded: https://www.youtube.com/embed/VIDEO_ID
6
+ * - Mobile: https://m.youtube.com/watch?v=VIDEO_ID
7
+ * - With timestamps: https://www.youtube.com/watch?v=VIDEO_ID&t=123s
8
+ */
9
+ export function isValidYoutubeUrl(url: string): boolean {
10
+ try {
11
+ const urlObj = new URL(url);
12
+
13
+ // Check for valid YouTube domains
14
+ const validDomains = [
15
+ "youtube.com",
16
+ "www.youtube.com",
17
+ "m.youtube.com",
18
+ "youtu.be",
19
+ ];
20
+ if (!validDomains.includes(urlObj.hostname)) {
21
+ return false;
22
+ }
23
+
24
+ // Handle youtu.be format
25
+ if (urlObj.hostname === "youtu.be") {
26
+ return urlObj.pathname.length > 1; // Must have video ID after /
27
+ }
28
+
29
+ // Handle standard YouTube URLs
30
+ if (urlObj.pathname === "/watch") {
31
+ const videoId = urlObj.searchParams.get("v");
32
+ return !!videoId && videoId.length === 11;
33
+ }
34
+
35
+ // Handle embedded format
36
+ if (urlObj.pathname.startsWith("/embed/")) {
37
+ const videoId = urlObj.pathname.split("/")[2];
38
+ return !!videoId && videoId.length === 11;
39
+ }
40
+
41
+ return false;
42
+ } catch {
43
+ return false;
44
+ }
45
+ }