Spaces:
Running
Running
File size: 6,846 Bytes
1fbeebb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
class InstagramDownloader {
constructor() {
this.currentFilename = null;
this.init();
}
init() {
this.cacheElements();
this.attachEventListeners();
}
cacheElements() {
this.downloadUrl = document.getElementById('downloadUrl');
this.downloadBtn = document.getElementById('downloadBtn');
this.progressSection = document.getElementById('progressSection');
this.progressTitle = document.getElementById('progressTitle');
this.progressPercent = document.getElementById('progressPercent');
this.progressFill = document.getElementById('progressFill');
this.progressMessage = document.getElementById('progressMessage');
this.successResult = document.getElementById('successResult');
this.errorResult = document.getElementById('errorResult');
this.errorMessage = document.getElementById('errorMessage');
this.retryBtn = document.getElementById('retryBtn');
this.downloadAgainBtn = document.getElementById('downloadAgainBtn');
this.loadingOverlay = document.getElementById('loadingOverlay');
this.toast = document.getElementById('toast');
}
attachEventListeners() {
this.downloadBtn.addEventListener('click', () => this.handleDownload());
this.retryBtn.addEventListener('click', () => this.resetForm());
this.downloadAgainBtn.addEventListener('click', () => this.resetForm());
this.downloadUrl.addEventListener('keypress', (e) => {
if (e.key === 'Enter') this.handleDownload();
});
}
async handleDownload() {
const url = this.downloadUrl.value.trim();
if (!url) {
this.showToast('Please enter a valid Instagram Reel URL', 'error');
return;
}
this.hideResults();
this.showProgress('Downloading...', 30, 'Preparing to download reel...');
try {
// Step 1: Request download from server
this.updateProgress('Downloading...', 40, 'Downloading from Instagram...');
const response = await fetch('/download', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url })
});
const data = await response.json();
if (!data.success) {
throw new Error(data.error || data.details || 'Download failed');
}
this.currentFilename = data.filename;
// Step 2: Download the file using fetch and blob
this.updateProgress('Downloading...', 70, 'Preparing file for download...');
try {
const videoResponse = await fetch(`/get-video/${data.filename}`);
if (!videoResponse.ok) {
throw new Error('Failed to fetch video file from server');
}
// Get the video as a blob
const blob = await videoResponse.blob();
// Create a download URL from the blob
const downloadUrl = window.URL.createObjectURL(blob);
// Create and trigger download
const link = document.createElement('a');
link.href = downloadUrl;
link.download = data.filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
// Cleanup
setTimeout(() => {
document.body.removeChild(link);
window.URL.revokeObjectURL(downloadUrl);
}, 100);
// Step 3: Show success
this.updateProgress('Complete!', 100, 'Download completed successfully!');
setTimeout(() => {
this.showSuccess();
this.showToast('Download completed! Check your downloads folder.', 'success');
// Clean up file after 30 seconds
setTimeout(() => this.cleanupFile(data.filename), 30000);
}, 500);
} catch (downloadError) {
console.error('Download error:', downloadError);
throw new Error('Failed to download video file. Please try again.');
}
} catch (error) {
console.error('Download error:', error);
this.showError(error.message);
}
}
async cleanupFile(filename) {
try {
await fetch(`/cleanup/${filename}`, { method: 'POST' });
} catch (error) {
console.log('Cleanup error (non-critical):', error);
}
}
updateProgress(title, percent, message) {
this.progressTitle.textContent = title;
this.progressPercent.textContent = `${percent}%`;
this.progressFill.style.width = `${percent}%`;
this.progressMessage.textContent = message;
}
showProgress(title = 'Downloading...', percent = 0, message = 'Starting...') {
this.progressSection.style.display = 'block';
this.updateProgress(title, percent, message);
}
showSuccess() {
this.progressSection.style.display = 'none';
this.successResult.style.display = 'block';
}
showError(message) {
this.progressSection.style.display = 'none';
this.errorResult.style.display = 'block';
this.errorMessage.textContent = message;
this.showToast('Download failed: ' + message, 'error');
}
hideResults() {
this.successResult.style.display = 'none';
this.errorResult.style.display = 'none';
this.progressSection.style.display = 'none';
}
resetForm() {
this.downloadUrl.value = '';
this.hideResults();
this.currentFilename = null;
}
showToast(message, type = 'info') {
this.toast.textContent = message;
this.toast.className = 'toast show';
if (type === 'success') {
this.toast.style.borderLeft = '4px solid var(--success)';
} else if (type === 'error') {
this.toast.style.borderLeft = '4px solid var(--error)';
}
setTimeout(() => {
this.toast.classList.remove('show');
}, 4000);
}
}
document.addEventListener('DOMContentLoaded', () => {
new InstagramDownloader();
});
|