ref impl : yt-dlp wrapper: whatever :)

This commit is contained in:
lovebird 2025-03-10 14:50:27 +01:00
parent 4565803076
commit 8de2ffc4cd
3 changed files with 203 additions and 0 deletions

View File

@ -0,0 +1,99 @@
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
import { existsSync, statSync } from 'node:fs';
import { unlink } from 'node:fs/promises';
import * as path from 'node:path';
import { YtDlp } from '../ytdlp.js';
describe('TikTok Download Tests', () => {
// TikTok URL to test
const tiktokUrl = 'https://www.tiktok.com/@woman.power.quote/video/7476910372121971970';
// Temporary output directory for test downloads
const outputDir = path.join(process.cwd(), 'test-downloads');
// Instance of YtDlp
let ytdlp: YtDlp;
// Path to the downloaded file (will be set during test)
let downloadedFilePath: string;
beforeAll(() => {
// Initialize YtDlp instance with test options
ytdlp = new YtDlp({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
});
// Set up spy for console.log to track progress messages
vi.spyOn(console, 'log').mockImplementation(() => {});
});
afterAll(async () => {
// Clean up downloaded files if they exist
if (downloadedFilePath && existsSync(downloadedFilePath)) {
try {
await unlink(downloadedFilePath);
console.log(`Test cleanup: Deleted ${downloadedFilePath}`);
} catch (error) {
console.error(`Failed to delete test file: ${error}`);
}
}
// Restore console.log
vi.restoreAllMocks();
});
it('should download a TikTok video successfully', async () => {
// Define download options
const options = {
format: 'best',
outputDir,
// Add a timestamp to ensure unique filenames across test runs
outputTemplate: `tiktok-test-${Date.now()}.%(ext)s`,
};
// Download the video
downloadedFilePath = await ytdlp.downloadVideo(tiktokUrl, options);
// Verify the download was successful
expect(downloadedFilePath).toBeTruthy();
expect(existsSync(downloadedFilePath)).toBe(true);
// Check file has some content (not empty)
const stats = statSync(downloadedFilePath).size;
expect(stats).toBeGreaterThan(0);
console.log(`Downloaded TikTok video to: ${downloadedFilePath}`);
}, 60000); // Increase timeout for download to complete
it('should get video info from TikTok URL', async () => {
// Get video info
const videoInfo = await ytdlp.getVideoInfo(tiktokUrl);
// Verify basic video information
expect(videoInfo).toBeTruthy();
expect(videoInfo.id).toBeTruthy();
expect(videoInfo.title).toBeTruthy();
expect(videoInfo.uploader).toBeTruthy();
console.log(`TikTok Video Title: ${videoInfo.title}`);
console.log(`TikTok Video Uploader: ${videoInfo.uploader}`);
}, 30000); // Increase timeout for API response
it('should list available formats for TikTok video', async () => {
// List available formats
const formats = await ytdlp.listFormats(tiktokUrl);
// Verify formats are returned
expect(formats).toBeInstanceOf(Array);
expect(formats.length).toBeGreaterThan(0);
// At least one format should have resolution and format_id
const hasValidFormat = formats.some(format =>
format.format_id && (format.resolution || format.width || format.height)
);
expect(hasValidFormat).toBe(true);
console.log(`Found ${formats.length} formats for TikTok video`);
}, 30000); // Increase timeout for format listing
});

View File

@ -0,0 +1,79 @@
import { describe, it, expect, afterEach } from 'vitest';
import { YtDlp } from '../ytdlp.js';
import * as fs from 'node:fs';
import * as path from 'node:path';
// Create a test directory for downloads
const TEST_DIR = path.join(process.cwd(), 'test-downloads');
const YOUTUBE_URL = 'https://www.youtube.com/watch?v=_oVI0GW-Xd4';
describe('YouTube Video Download', () => {
// Ensure the test directory exists
if (!fs.existsSync(TEST_DIR)) {
fs.mkdirSync(TEST_DIR, { recursive: true });
}
let downloadedFiles: string[] = [];
// Clean up after tests
afterEach(() => {
// Delete any downloaded files
downloadedFiles.forEach(file => {
const fullPath = path.resolve(file);
if (fs.existsSync(fullPath)) {
fs.unlinkSync(fullPath);
console.log(`Cleaned up test file: ${fullPath}`);
}
});
downloadedFiles = [];
});
it('should successfully download a YouTube video', async () => {
// Create a new YtDlp instance
const ytdlp = new YtDlp();
// Check if yt-dlp is installed
const isInstalled = await ytdlp.isInstalled();
expect(isInstalled).toBe(true);
// Download the video with specific options to keep the test fast
// Use a lower quality format to speed up the test
const downloadOptions = {
outputDir: TEST_DIR,
format: 'worst[ext=mp4]', // Use lowest quality for faster test
outputTemplate: 'youtube-test-%(id)s.%(ext)s'
};
// Execute the download
const filePath = await ytdlp.downloadVideo(YOUTUBE_URL, downloadOptions);
console.log(`Downloaded file: ${filePath}`);
// Add to cleanup list
downloadedFiles.push(filePath);
// Assert that the file exists
expect(fs.existsSync(filePath)).toBe(true);
// Assert that the file has content (not empty)
const stats = fs.statSync(filePath);
expect(stats.size).toBeGreaterThan(0);
}, 60000); // Increase timeout to 60 seconds as downloads may take time
it('should retrieve video information correctly', async () => {
const ytdlp = new YtDlp();
// Get video info
const videoInfo = await ytdlp.getVideoInfo(YOUTUBE_URL);
// Assert video properties
expect(videoInfo).toBeDefined();
expect(videoInfo.id).toBeDefined();
expect(videoInfo.title).toBeDefined();
expect(videoInfo.webpage_url).toBeDefined();
// Verify the video ID matches the expected ID from the URL
const expectedVideoId = '_oVI0GW-Xd4';
expect(videoInfo.id).toBe(expectedVideoId);
});
});

View File

@ -0,0 +1,25 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
// Enable verbose test output
reporters: ['verbose'],
// Enable ESM support
environment: 'node',
// Ensure includes are properly configured for TypeScript files
include: ['src/**/*.{test,spec}.ts'],
// Enable code coverage
coverage: {
provider: 'v8',
reporter: ['text', 'html'],
exclude: ['node_modules/', 'dist/'],
},
// Add global timeout for long-running tests like video downloads
testTimeout: 30000,
},
});