From 8de2ffc4cd691295c0ebfcacb1dc934b753c9416 Mon Sep 17 00:00:00 2001 From: babayaga Date: Mon, 10 Mar 2025 14:50:27 +0100 Subject: [PATCH] ref impl : yt-dlp wrapper: whatever :) --- .../media/ref/src/__tests__/tiktok.test.ts | 99 +++++++++++++++++++ .../media/ref/src/__tests__/youtube.test.ts | 79 +++++++++++++++ packages/media/ref/vitest.config.ts | 25 +++++ 3 files changed, 203 insertions(+) create mode 100644 packages/media/ref/src/__tests__/tiktok.test.ts create mode 100644 packages/media/ref/src/__tests__/youtube.test.ts create mode 100644 packages/media/ref/vitest.config.ts diff --git a/packages/media/ref/src/__tests__/tiktok.test.ts b/packages/media/ref/src/__tests__/tiktok.test.ts new file mode 100644 index 00000000..d3a02995 --- /dev/null +++ b/packages/media/ref/src/__tests__/tiktok.test.ts @@ -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 +}); + diff --git a/packages/media/ref/src/__tests__/youtube.test.ts b/packages/media/ref/src/__tests__/youtube.test.ts new file mode 100644 index 00000000..0da2b5c0 --- /dev/null +++ b/packages/media/ref/src/__tests__/youtube.test.ts @@ -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); + }); +}); + diff --git a/packages/media/ref/vitest.config.ts b/packages/media/ref/vitest.config.ts new file mode 100644 index 00000000..891cf437 --- /dev/null +++ b/packages/media/ref/vitest.config.ts @@ -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, + }, +}); +