Skip to content

Commit 719d142

Browse files
authored
Fix download for big size file
1 parent 9b4f837 commit 719d142

1 file changed

Lines changed: 135 additions & 17 deletions

File tree

utils/googleDriveService.js

Lines changed: 135 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,84 @@ function extractFileId(driveUrl) {
2222

2323
async function downloadFile(fileId, progressCallback = null) {
2424
try {
25-
const downloadUrl = `https://drive.google.com/uc?export=download&id=${fileId}`;
26-
2725
const tempFilename = `temp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
2826
const tempPath = path.join(paths.videos, tempFilename);
2927

30-
const response = await axios({
31-
method: 'GET',
32-
url: downloadUrl,
33-
responseType: 'stream',
34-
timeout: 300000,
35-
headers: {
36-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
28+
let response;
29+
let retryCount = 0;
30+
const maxRetries = 3;
31+
let downloadUrl = `https://drive.google.com/uc?export=download&id=${fileId}&confirm=t`;
32+
33+
while (retryCount < maxRetries) {
34+
try {
35+
console.log(`Attempting download from: ${downloadUrl}`);
36+
37+
const headResponse = await axios.head(downloadUrl, {
38+
timeout: 30000,
39+
maxRedirects: 10,
40+
headers: {
41+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
42+
}
43+
});
44+
45+
const contentType = headResponse.headers['content-type'] || '';
46+
console.log(`Content-Type: ${contentType}`);
47+
48+
if (contentType.includes('text/html')) {
49+
console.log('Received HTML response, trying alternative download method...');
50+
downloadUrl = `https://drive.usercontent.google.com/download?id=${fileId}&export=download&authuser=0&confirm=t`;
51+
52+
if (retryCount === 1) {
53+
downloadUrl = `https://docs.google.com/uc?export=download&id=${fileId}&confirm=t`;
54+
}
55+
56+
retryCount++;
57+
if (retryCount >= maxRetries) {
58+
throw new Error('File appears to be private or requires additional authentication. Please ensure the file is publicly accessible.');
59+
}
60+
continue;
61+
}
62+
63+
response = await axios({
64+
method: 'GET',
65+
url: downloadUrl,
66+
responseType: 'stream',
67+
timeout: 600000,
68+
maxRedirects: 10,
69+
headers: {
70+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
71+
'Accept': '*/*',
72+
'Accept-Language': 'en-US,en;q=0.9',
73+
'Accept-Encoding': 'gzip, deflate, br',
74+
'Connection': 'keep-alive',
75+
'Upgrade-Insecure-Requests': '1'
76+
}
77+
});
78+
break;
79+
} catch (error) {
80+
retryCount++;
81+
console.log(`Download attempt ${retryCount} failed:`, error.message);
82+
83+
if (retryCount >= maxRetries) {
84+
throw error;
85+
}
86+
87+
if (error.code === 'ENOTFOUND' || error.code === 'ECONNRESET') {
88+
downloadUrl = `https://drive.usercontent.google.com/download?id=${fileId}&export=download&authuser=0&confirm=t`;
89+
}
90+
91+
await new Promise(resolve => setTimeout(resolve, 2000 * retryCount));
3792
}
38-
});
93+
}
3994

4095
if (response.status !== 200) {
4196
throw new Error(`HTTP ${response.status}: Failed to download file`);
4297
}
98+
99+
const responseContentType = response.headers['content-type'] || '';
100+
if (responseContentType.includes('text/html')) {
101+
throw new Error('Received HTML page instead of video file. The file might be private or require additional permissions.');
102+
}
43103

44104
const totalSize = parseInt(response.headers['content-length'] || '0');
45105
let downloadedSize = 0;
@@ -78,7 +138,57 @@ async function downloadFile(fileId, progressCallback = null) {
78138

79139
if (fileSize === 0) {
80140
fs.unlinkSync(tempPath);
81-
reject(new Error('Downloaded file is empty. File might be private or not accessible.'));
141+
reject(new Error('Downloaded file is empty. The file might be private, not accessible, or the link is invalid.'));
142+
return;
143+
}
144+
145+
if (fileSize < 1024) {
146+
fs.unlinkSync(tempPath);
147+
reject(new Error('Downloaded file is too small to be a valid video. Please check if the Google Drive link is correct and the file is publicly accessible.'));
148+
return;
149+
}
150+
151+
const buffer = Buffer.alloc(512);
152+
const fd = fs.openSync(tempPath, 'r');
153+
fs.readSync(fd, buffer, 0, 512, 0);
154+
fs.closeSync(fd);
155+
156+
const fileHeader = buffer.toString('utf8', 0, 100).toLowerCase();
157+
158+
if (fileHeader.includes('<!doctype html') || fileHeader.includes('<html') || fileHeader.includes('<head>')) {
159+
fs.unlinkSync(tempPath);
160+
reject(new Error('Downloaded content is an HTML page, not a video file. The file might be private, require authentication, or the sharing settings are incorrect.'));
161+
return;
162+
}
163+
164+
const validVideoHeaders = [
165+
[0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70],
166+
[0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70],
167+
[0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70],
168+
[0x1A, 0x45, 0xDF, 0xA3],
169+
[0x00, 0x00, 0x01, 0xBA],
170+
[0x00, 0x00, 0x01, 0xB3],
171+
[0x46, 0x4C, 0x56, 0x01]
172+
];
173+
174+
let isValidVideo = false;
175+
for (const header of validVideoHeaders) {
176+
let matches = true;
177+
for (let i = 0; i < header.length && i < buffer.length; i++) {
178+
if (buffer[i] !== header[i]) {
179+
matches = false;
180+
break;
181+
}
182+
}
183+
if (matches) {
184+
isValidVideo = true;
185+
break;
186+
}
187+
}
188+
189+
if (!isValidVideo && !buffer.includes(Buffer.from('ftyp'))) {
190+
fs.unlinkSync(tempPath);
191+
reject(new Error('Downloaded file does not appear to be a valid video format. Please ensure the Google Drive link points to a video file and is publicly accessible.'));
82192
return;
83193
}
84194

@@ -123,18 +233,26 @@ async function downloadFile(fileId, progressCallback = null) {
123233

124234
if (error.response) {
125235
if (error.response.status === 403) {
126-
throw new Error('File is private or sharing is disabled. Please make sure the file is publicly accessible.');
236+
throw new Error('File is private or sharing is disabled. Please make sure the file is publicly accessible and try again.');
127237
} else if (error.response.status === 404) {
128-
throw new Error('File not found. Please check the Google Drive URL.');
238+
throw new Error('File not found. Please check the Google Drive URL and ensure the file exists.');
239+
} else if (error.response.status === 429) {
240+
throw new Error('Too many requests. Please wait a few minutes and try again.');
241+
} else if (error.response.status >= 500) {
242+
throw new Error('Google Drive server error. Please try again later.');
129243
} else {
130-
throw new Error(`HTTP ${error.response.status}: ${error.response.statusText}`);
244+
throw new Error(`Download failed with HTTP ${error.response.status}. Please try again or check if the file is accessible.`);
131245
}
132246
} else if (error.code === 'ENOTFOUND') {
133-
throw new Error('Network error: Unable to connect to Google Drive');
247+
throw new Error('Network connection failed. Please check your internet connection and try again.');
134248
} else if (error.code === 'ETIMEDOUT') {
135-
throw new Error('Download timeout: File might be too large or connection is slow');
249+
throw new Error('Download timeout. The file might be too large or your connection is slow. Please try again.');
250+
} else if (error.code === 'ECONNRESET' || error.code === 'ECONNREFUSED') {
251+
throw new Error('Connection was reset. Please check your internet connection and try again.');
252+
} else if (error.code === 'ECONNABORTED') {
253+
throw new Error('Download was interrupted. Please try again.');
136254
} else {
137-
throw new Error(`Download failed: ${error.message}`);
255+
throw new Error(`Download failed: ${error.message}. Please try again or check your internet connection.`);
138256
}
139257
}
140258
}

0 commit comments

Comments
 (0)