/** * Video Upload and NFT Minting Script * * This script demonstrates the complete video upload flow including: * 1. Checking and creating a TBA (Token Bound Account) * 2. Uploading a video to the platform * 3. Monitoring video processing status * 4. Minting an IP NFT * * Usage: * 1. Create a .env file and set the following environment variables: * - PRIVATE_KEY: Private key of the NFT holder * - API_KEY: GoodTake API key (optional) * * 2. Prepare a test video file and place it in scripts/assets/ directory * * 3. Run the script: * npm run upload-video * or * yarn upload-video */ import { GoTakeSDK, NetworkId, VideoStatus } from "../src"; import * as dotenv from 'dotenv'; import { ethers } from 'ethers'; import * as fs from 'fs'; import * as path from 'path'; import { Blob } from 'fetch-blob'; import File from 'fetch-blob/file'; dotenv.config(); // Utility function: Convert file system file to browser File object function createFileFromPath(filePath: string): File { const fileName = path.basename(filePath); const fileBuffer = fs.readFileSync(filePath); const fileBlob = new Blob([fileBuffer]); return new File([fileBlob], fileName, { type: getMimeType(fileName) }); } // Utility function: Get MIME type based on file extension function getMimeType(fileName: string): string { const ext = fileName.split('.').pop()?.toLowerCase(); const mimeTypes: Record = { 'mp4': 'video/mp4', 'mov': 'video/quicktime', 'avi': 'video/x-msvideo', 'webm': 'video/webm' }; return mimeTypes[ext || ''] || 'application/octet-stream'; } // Utility function: Wait for specified time function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } async function main() { // Check required environment variables if (!process.env.PRIVATE_KEY) { throw new Error("PRIVATE_KEY is not defined in environment variables. Please set it in your .env file"); } const videoFilePath = path.join(__dirname, 'assets', 'sample-video.mp4'); if (!fs.existsSync(videoFilePath)) { throw new Error(`Test video file not found: ${videoFilePath}`); } try { console.log("=== GoodTake Video Upload Demo ==="); // Create Provider and Signer const rpcUrl = "https://sepolia.base.org"; const ethersProvider = new ethers.providers.JsonRpcProvider(rpcUrl); const ethersSigner = new ethers.Wallet(process.env.PRIVATE_KEY, ethersProvider); const userAddress = await ethersSigner.getAddress(); console.log(`Using address: ${userAddress}`); // Initialize SDK const sdk = new GoTakeSDK({ network: NetworkId.BASE_SEPOLIA, provider: ethersProvider, signer: ethersSigner, apiEndpoint: process.env.API_ENDPOINT || 'https://api.goodtake.io', apiKey: process.env.API_KEY }); console.log("SDK initialized successfully"); // Step 1: Check and create TBA if needed console.log("\n=== Step 1: Check/Create TBA ==="); const { tbaAddress, isNew } = await sdk.checkAndCreateTBA(); if (isNew) { console.log(`Created new TBA: ${tbaAddress}`); } else { console.log(`Using existing TBA: ${tbaAddress}`); } // Step 2: Prepare video file and upload console.log("\n=== Step 2: Upload Video ==="); const videoFile = createFileFromPath(videoFilePath); console.log(`Preparing to upload: ${videoFile.name} (${videoFile.size} bytes)`); const videoMetadata = { title: "GoodTake Test Video", description: "This is a test video uploaded via SDK", tags: ["test", "sdk", "demo"], creator: userAddress }; console.log("Uploading video..."); const videoId = await sdk.uploadVideo(videoFile, videoMetadata); console.log(`Video uploaded successfully! Video ID: ${videoId}`); // Step 3: Monitor video processing status console.log("\n=== Step 3: Monitor Video Processing ==="); console.log("Setting up status monitoring..."); // Method A: Using polling console.log("Using polling to monitor processing:"); let videoReady = false; while (!videoReady) { const status = await sdk.getVideoStatus(videoId); console.log(`Current status: ${status.status}, Progress: ${status.progress || 'unknown'}%`); if (status.status === VideoStatus.READY || status.status === VideoStatus.MINT_READY) { videoReady = true; console.log("Video processing completed, ready for minting"); } else if (status.status === VideoStatus.ERROR) { throw new Error(`Video processing failed: ${status.error?.message || 'Unknown error'}`); } else { console.log("Waiting for processing to complete..."); await sleep(5000); } } // Step 4: Mint IP NFT console.log("\n=== Step 4: Mint IP NFT ==="); console.log("Starting NFT minting..."); const mintResult = await sdk.mintContentNFT(videoId); console.log("NFT minted successfully!"); console.log(`Token ID: ${mintResult.tokenId}`); console.log(`Transaction Hash: ${mintResult.transactionHash}`); console.log(`Owner: ${mintResult.owner}`); console.log(`Metadata: ${JSON.stringify(mintResult.metadata, null, 2)}`); // Display final status const finalStatus = await sdk.getVideoStatus(videoId); console.log("\n=== Final Status ==="); console.log(`Video ID: ${videoId}`); console.log(`Status: ${finalStatus.status}`); if (finalStatus.assetInfo?.playbackUrl) { console.log(`Playback URL: ${finalStatus.assetInfo.playbackUrl}`); } if (finalStatus.mintInfo) { console.log(`NFT Token ID: ${finalStatus.mintInfo.tokenId}`); console.log(`NFT Transaction: ${finalStatus.mintInfo.transactionHash}`); } console.log("\nProcess completed! Video uploaded and minted as NFT successfully."); } catch (error) { console.error("Error during video upload process:"); console.error(error); process.exitCode = 1; } } main().catch(error => { console.error("Error executing script:"); console.error(error); process.exitCode = 1; });