class YouTubeUploader { constructor() { this.CLIENT_ID = '728787049181-iq4lnrcks0fifee7r6h57h7h71berii6.apps.googleusercontent.com'; this.SCOPES = ['https://www.googleapis.com/auth/youtube.upload']; this.initializeUploadButton(); } initializeUploadButton() { const uploadButton = document.getElementById('upload-youtube'); console.log('Upload button found:', !!uploadButton); if (uploadButton) { uploadButton.addEventListener('click', async (e) => { console.log('Upload button clicked'); e.preventDefault(); try { await this.prepareAndUploadVideo(); } catch (error) { console.error('Complete upload error:', error); this.showError(`Upload failed: ${error.message}`); } }); } else { console.error('YouTube upload button not found in DOM'); } } async prepareAndUploadVideo() { try { // Detailed logging for video retrieval const videoData = await this.getRecordedVideoFromStorage(); console.log('Video data retrieved:', !!videoData); if (!videoData) { this.showError('No video available to upload'); return; } // Convert base64 to blob with detailed logging const videoBlob = this.base64ToBlob(videoData); console.log('Video blob created, size:', videoBlob.size); // Get authentication token const token = await this.getAuthToken(); console.log('Authentication token obtained'); // Prepare metadata for the video const metadata = { snippet: { title: `Screen Recording ${new Date().toLocaleString()}`, description: 'Screen recording uploaded from Chrome Extension', tags: ['screen recording'], categoryId: '22' // Category for 'People & Blogs' }, status: { privacyStatus: 'private' } }; // Perform the upload const uploadResult = await this.uploadVideo(token, videoBlob, metadata); console.log('Upload result:', uploadResult); this.showSuccess('Video uploaded to YouTube successfully!'); } catch (error) { console.error('Complete YouTube Upload Error:', error); this.showError(`Upload failed: ${error.message}`); } } getRecordedVideoFromStorage() { return new Promise((resolve, reject) => { chrome.storage.local.get(['recordedVideoData'], (result) => { console.log('Storage retrieval:', result.recordedVideoData ? 'Video found' : 'No video'); if (chrome.runtime.lastError) { reject(chrome.runtime.lastError); } else { resolve(result.recordedVideoData); } }); }); } getAuthToken() { return new Promise((resolve, reject) => { console.log('Attempting to get auth token'); // Fallback authentication method const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?${new URLSearchParams({ client_id: this.CLIENT_ID, redirect_uri: chrome.identity.getRedirectURL(), response_type: 'token', scope: this.SCOPES.join(' '), prompt: 'consent' })}`; chrome.identity.launchWebAuthFlow( { url: authUrl, interactive: true }, (redirectUrl) => { console.log('Auth flow redirect received'); if (chrome.runtime.lastError) { console.error('Auth flow error:', chrome.runtime.lastError); reject(chrome.runtime.lastError); return; } const urlParams = new URLSearchParams(new URL(redirectUrl).hash.slice(1)); const accessToken = urlParams.get('access_token'); if (!accessToken) { console.error('No access token retrieved'); reject(new Error('Failed to retrieve access token')); return; } console.log('Access token successfully retrieved'); resolve(accessToken); } ); }); } base64ToBlob(base64Data) { // Remove the data URL prefix if it exists const base64String = base64Data.replace(/^data:video\/\w+;base64,/, ''); // Decode base64 const byteCharacters = atob(base64String); const byteArrays = []; for (let offset = 0; offset < byteCharacters.length; offset += 512) { const slice = byteCharacters.slice(offset, offset + 512); const byteNumbers = new Array(slice.length); for (let i = 0; i < slice.length; i++) { byteNumbers[i] = slice.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } return new Blob(byteArrays, { type: 'video/webm' }); } async uploadVideo(token, videoBlob, metadata) { const formData = new FormData(); const metadataBlob = new Blob([JSON.stringify(metadata)], { type: 'application/json; charset=UTF-8' }); formData.append('metadata', metadataBlob, 'metadata.json'); formData.append('file', videoBlob, 'screen_recording.webm'); try { const response = await fetch( `https://www.googleapis.com/upload/youtube/v3/videos?uploadType=multipart&part=snippet,status`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}` }, body: formData } ); if (!response.ok) { const errorBody = await response.text(); console.error('Upload response error:', errorBody); throw new Error(`Upload failed: ${errorBody}`); } const result = await response.json(); console.log('YouTube Upload Success:', result); return result; } catch (error) { console.error('Upload Error Details:', error); throw error; } } showSuccess(message) { const notification = document.createElement('div'); notification.textContent = message; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background-color: green; color: white; padding: 10px 20px; border-radius: 5px; z-index: 1000; `; document.body.appendChild(notification); setTimeout(() => notification.remove(), 3000); } showError(message) { const notification = document.createElement('div'); notification.textContent = message; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background-color: red; color: white; padding: 10px 20px; border-radius: 5px; z-index: 1000; `; document.body.appendChild(notification); setTimeout(() => notification.remove(), 3000); } } // Initialize the uploader when the page loads document.addEventListener('DOMContentLoaded', () => { console.log('DOM loaded, initializing YouTube Uploader'); new YouTubeUploader(); }); // Add global error logging window.addEventListener('error', (event) => { console.error('Unhandled error:', event.error); }); class VimeoUploader { constructor() { // Replace with your Vimeo API access token this.ACCESS_TOKEN = 'fad52305c371058da84097cefb9a95a3'; this.initializeUploadButton(); } initializeUploadButton() { const uploadButton = document.getElementById('upload-vimeo'); console.log('Vimeo upload button found:', !!uploadButton); if (uploadButton) { uploadButton.addEventListener('click', async (e) => { console.log('Vimeo upload button clicked'); e.preventDefault(); try { await this.prepareAndUploadVideo(); } catch (error) { console.error('Vimeo upload error:', error); this.showError(`Upload failed: ${error.message}`); } }); } else { console.error('Vimeo upload button not found'); } } async prepareAndUploadVideo() { try { // Retrieve video from storage const videoData = await this.getRecordedVideoFromStorage(); console.log('Video data retrieved:', !!videoData); if (!videoData) { this.showError('No video available to upload'); return; } // Convert base64 to blob const videoBlob = this.base64ToBlob(videoData); console.log('Video blob created, size:', videoBlob.size); // Initiate upload and get upload link const uploadTicket = await this.createUploadTicket(videoBlob.size); // Upload the video await this.uploadVideoToVimeo(uploadTicket.upload_link, videoBlob); this.showSuccess('Video uploaded to Vimeo successfully!'); } catch (error) { console.error('Vimeo Upload Error:', error); this.showError(`Upload failed: ${error.message}`); } } async createUploadTicket(fileSize) { try { const response = await fetch('https://api.vimeo.com/me/videos', { method: 'POST', headers: { 'Authorization': `bearer ${this.ACCESS_TOKEN}`, 'Content-Type': 'application/json', 'Accept': 'application/vnd.vimeo.*+json;version=3.4' }, body: JSON.stringify({ upload: { approach: 'tus', size: fileSize }, name: `Screen Recording ${new Date().toLocaleString()}`, description: 'Screen recording uploaded from Chrome Extension' }) }); if (!response.ok) { const errorText = await response.text(); console.error('Vimeo API Response:', errorText); throw new Error(`Failed to create upload ticket: ${errorText}`); } const uploadTicket = await response.json(); console.log('Complete Upload Ticket:', uploadTicket); // Explicitly log the upload link const uploadLink = uploadTicket.upload?.upload_link; console.log('Extracted Upload Link:', uploadLink); if (!uploadLink) { throw new Error('No upload link found in Vimeo response'); } return uploadTicket; } catch (error) { console.error('Upload Ticket Creation Error:', error); throw error; } } async uploadVideoToVimeo(uploadTicket, videoBlob) { const uploadLink = uploadTicket.upload ? uploadTicket.upload.upload_link : uploadTicket.upload_link || uploadTicket.uri; console.log('Actual Upload Link:', uploadLink); if (!uploadLink) { throw new Error('No upload link found'); } try { const response = await fetch(uploadLink, { method: 'PATCH', headers: { 'Content-Type': 'application/offset+octet-stream', 'Upload-Offset': '0', 'Tus-Resumable': '1.0.0', 'Authorization': `bearer ${this.ACCESS_TOKEN}` }, body: videoBlob }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Vimeo upload failed: ${errorText}`); } return response; } catch (error) { console.error('Upload detailed error:', error); throw error; } } getRecordedVideoFromStorage() { return new Promise((resolve, reject) => { chrome.storage.local.get(['recordedVideoData'], (result) => { console.log('Storage retrieval:', result.recordedVideoData ? 'Video found' : 'No video'); if (chrome.runtime.lastError) { reject(chrome.runtime.lastError); } else { resolve(result.recordedVideoData); } }); }); } base64ToBlob(base64Data) { const base64String = base64Data.replace(/^data:video\/\w+;base64,/, ''); const byteCharacters = atob(base64String); const byteArrays = []; for (let offset = 0; offset < byteCharacters.length; offset += 512) { const slice = byteCharacters.slice(offset, offset + 512); const byteNumbers = new Array(slice.length); for (let i = 0; i < slice.length; i++) { byteNumbers[i] = slice.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } return new Blob(byteArrays, { type: 'video/webm' }); } showSuccess(message) { const notification = document.createElement('div'); notification.textContent = message; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background-color: green; color: white; padding: 10px 20px; border-radius: 5px; z-index: 1000; `; document.body.appendChild(notification); setTimeout(() => notification.remove(), 3000); } showError(message) { const notification = document.createElement('div'); notification.textContent = message; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background-color: red; color: white; padding: 10px 20px; border-radius: 5px; z-index: 1000; `; document.body.appendChild(notification); setTimeout(() => notification.remove(), 3000); } } // Initialize the uploader when the page loads document.addEventListener('DOMContentLoaded', () => { console.log('DOM loaded, initializing Vimeo Uploader'); new VimeoUploader(); });