feat: add random filename fallback when filename cannot be retrieved - Add generateRandomFilename utility function - Modify downloadVideo to use random filename when yt-dlp fails to get filename - Update version to 0.6.26
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@kevinwatt/yt-dlp-mcp",
|
"name": "@kevinwatt/yt-dlp-mcp",
|
||||||
"version": "0.6.25",
|
"version": "0.6.26",
|
||||||
"description": "An MCP server implementation that integrates with yt-dlp, providing video and audio content download capabilities (e.g. YouTube, Facebook, Tiktok, etc.) for LLMs.",
|
"description": "An MCP server implementation that integrates with yt-dlp, providing video and audio content download capabilities (e.g. YouTube, Facebook, Tiktok, etc.) for LLMs.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"mcp",
|
"mcp",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { downloadVideo } from "./modules/video.js";
|
|||||||
import { downloadAudio } from "./modules/audio.js";
|
import { downloadAudio } from "./modules/audio.js";
|
||||||
import { listSubtitles, downloadSubtitles } from "./modules/subtitle.js";
|
import { listSubtitles, downloadSubtitles } from "./modules/subtitle.js";
|
||||||
|
|
||||||
const VERSION = '0.6.25';
|
const VERSION = '0.6.26';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate system configuration
|
* Validate system configuration
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
|
import { randomBytes } from 'crypto';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates if a given string is a valid URL.
|
* Validates if a given string is a valid URL.
|
||||||
@@ -126,4 +127,22 @@ export function getFormattedTimestamp(): string {
|
|||||||
.replace(/[:.]/g, '-')
|
.replace(/[:.]/g, '-')
|
||||||
.replace('T', '_')
|
.replace('T', '_')
|
||||||
.split('.')[0];
|
.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}`;
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,8 @@ import {
|
|||||||
_spawnPromise,
|
_spawnPromise,
|
||||||
validateUrl,
|
validateUrl,
|
||||||
getFormattedTimestamp,
|
getFormattedTimestamp,
|
||||||
isYouTubeUrl
|
isYouTubeUrl,
|
||||||
|
generateRandomFilename
|
||||||
} from "./utils.js";
|
} from "./utils.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,27 +77,30 @@ export async function downloadVideo(
|
|||||||
format = "bestvideo[height>=720]+bestaudio/best[height>=720]/best";
|
format = "bestvideo[height>=720]+bestaudio/best[height>=720]/best";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用安全的文件名模板
|
|
||||||
const outputTemplate = path.join(
|
|
||||||
userDownloadsDir,
|
|
||||||
sanitizeFilename(`%(title)s [%(id)s] ${timestamp}`, config.file) + '.%(ext)s'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get expected filename
|
let outputTemplate: string;
|
||||||
let expectedFilename: string;
|
let expectedFilename: string;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// 嘗試獲取檔案名稱
|
||||||
|
outputTemplate = path.join(
|
||||||
|
userDownloadsDir,
|
||||||
|
sanitizeFilename(`%(title)s [%(id)s] ${timestamp}`, config.file) + '.%(ext)s'
|
||||||
|
);
|
||||||
|
|
||||||
expectedFilename = await _spawnPromise("yt-dlp", [
|
expectedFilename = await _spawnPromise("yt-dlp", [
|
||||||
"--get-filename",
|
"--get-filename",
|
||||||
"-f", format,
|
"-f", format,
|
||||||
"--output", outputTemplate,
|
"--output", outputTemplate,
|
||||||
url
|
url
|
||||||
]);
|
]);
|
||||||
|
expectedFilename = expectedFilename.trim();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Failed to get filename: ${error instanceof Error ? error.message : String(error)}`);
|
// 如果無法獲取檔案名稱,使用隨機檔案名
|
||||||
|
const randomFilename = generateRandomFilename('mp4');
|
||||||
|
outputTemplate = path.join(userDownloadsDir, randomFilename);
|
||||||
|
expectedFilename = randomFilename;
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedFilename = expectedFilename.trim();
|
|
||||||
|
|
||||||
// Download with progress info
|
// Download with progress info
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user