YouTube MCP Server
by kevinwatt
- yt-dlp-mcp
- src
- modules
import * as fs from 'fs';
import { spawn } from 'child_process';
import { randomBytes } from 'crypto';
/**
* Validates if a given string is a valid URL.
*
* @param url - The URL string to validate
* @returns True if the URL is valid, false otherwise
*
* @example
* ```typescript
* if (validateUrl('https://youtube.com/watch?v=...')) {
* // URL is valid
* }
* ```
*/
export function validateUrl(url: string): boolean {
try {
new URL(url);
return true;
} catch {
return false;
}
}
/**
* Checks if a URL is from YouTube.
*
* @param url - The URL to check
* @returns True if the URL is from YouTube, false otherwise
*
* @example
* ```typescript
* if (isYouTubeUrl('https://youtube.com/watch?v=...')) {
* // URL is from YouTube
* }
* ```
*/
export function isYouTubeUrl(url: string): boolean {
try {
const parsedUrl = new URL(url);
return parsedUrl.hostname.includes('youtube.com') || parsedUrl.hostname.includes('youtu.be');
} catch {
return false;
}
}
/**
* Safely cleans up a directory and its contents.
*
* @param directory - Path to the directory to clean up
* @returns Promise that resolves when cleanup is complete
* @throws {Error} When directory cannot be removed
*
* @example
* ```typescript
* try {
* await safeCleanup('/path/to/temp/dir');
* } catch (error) {
* console.error('Cleanup failed:', error);
* }
* ```
*/
export async function safeCleanup(directory: string): Promise<void> {
try {
await fs.promises.rm(directory, { recursive: true, force: true });
} catch (error) {
console.error(`Error cleaning up directory ${directory}:`, error);
}
}
/**
* Spawns a child process and returns its output as a promise.
*
* @param command - The command to execute
* @param args - Array of command arguments
* @returns Promise resolving to the command output
* @throws {Error} When command execution fails
*
* @example
* ```typescript
* try {
* const output = await _spawnPromise('yt-dlp', ['--version']);
* console.log('yt-dlp version:', output);
* } catch (error) {
* console.error('Command failed:', error);
* }
* ```
*/
export function _spawnPromise(command: string, args: string[]): Promise<string> {
return new Promise((resolve, reject) => {
const process = spawn(command, args);
let output = '';
process.stdout.on('data', (data) => {
output += data.toString();
});
process.stderr.on('data', (data) => {
output += data.toString();
});
process.on('close', (code) => {
if (code === 0) {
resolve(output);
} else {
reject(new Error(`Failed with exit code: ${code}\n${output}`));
}
});
});
}
/**
* Generates a formatted timestamp string for file naming.
*
* @returns Formatted timestamp string in the format 'YYYY-MM-DD_HH-mm-ss'
*
* @example
* ```typescript
* const timestamp = getFormattedTimestamp();
* console.log(timestamp); // '2024-03-20_12-30-00'
* ```
*/
export function getFormattedTimestamp(): string {
return new Date().toISOString()
.replace(/[:.]/g, '-')
.replace('T', '_')
.split('.')[0];
}
/**
* Generates a random filename with timestamp prefix.
*
* @param extension - Optional file extension (default: 'mp4')
* @returns A random filename with timestamp
*
* @example
* ```typescript
* const filename = generateRandomFilename('mp3');
* console.log(filename); // '2024-03-20_12-30-00_a1b2c3d4.mp3'
* ```
*/
export function generateRandomFilename(extension: string = 'mp4'): string {
const timestamp = getFormattedTimestamp();
const randomId = randomBytes(4).toString('hex');
return `${timestamp}_${randomId}.${extension}`;
}