העלאת קובץ בapi לימות המשיח | קוד שבפייתון עובד וב nodejs לא כל כך
-
אני מנסה להעלות קובץ גדול מ50 מגה אל ימות המשיח לפי התיעוד כאן
יש לי קוד פייתון שכתב לי בזמנו @צדיק-תמים שמעלה תקין את הקובץ, מחלק אותו לחלקים של 50 מגה ומעלה אותם לימות המשיח, בסיום הוא מאחד את הקבצים, והכל עולה תקין.
ניסתי לשכתב אותו בnodejs , וזה נראה שהוא באמת מעלה את החלקים, אבל בתגובה, וכן במערכת עצמה, הקובץ שוקל 0 kb .
לא ראיתי פה דרך לשים בספוילר את הקודים, אז אני מעלה את הקבצים עצמם, שלא יכביד על העין סתם שורות קוד.
זה הקוד פייתון המקורי , שעובד upload.py
זה הקוד nodejs , שלא עובד טוב test.jsאם מישהו רוצה לבדוק את זה וצריך טוקן מימות המשיח, שישלח לי מייל בפרטי, ואשלח לו טוקן.
-
שלח לי טוקן, אני רוצה לנסות.
הנה בינתיים (בלי תיקון לעצם הבעיה) קוד הרבה יותר יעיל
(כמו הפייתון המקורי, היעילות היא מבחינת זיכרון וגבול עליון לזיכרון), וגם יותר נח לעבודה (ובלי שום ספריה חיצונית).
עריכה: הfetch המובנה של נוד כנראה לא שם אוטומטית contentType לFormData אז כן השתמשתי בספריה node-fetch.import fs from 'fs/promises'; import fetch from 'node-fetch'; import FormData from 'form-data'; async function* getChunks(filePath, chunkSize = 5000000) { const file = await fs.open(filePath, 'r'); const buffer = Buffer.alloc(chunkSize); while (true) { const result = await file.read(buffer, 0, chunkSize); if (result.bytesRead === chunkSize) yield result.buffer; else { yield result.buffer.slice(0, result.bytesRead); break; } } await file.close(); } function createFormData(bytes, partialData = null) { const formData = new FormData(); formData.append('token', tokenYemot); formData.append('path', remotePath); formData.append('convertAudio', 1); formData.append('autoNumbering', 1); if (partialData) { formData.append('qquuid', partialData.uuid); formData.append('qqfilename', partialData.contentName); formData.append('qqtotalfilesize', partialData.fileSize); formData.append('qqtotalparts', partialData.partCount); formData.append('qqchunksize', chunkSize); //in final post request we don't need to send the file if (partialData.partCount > (partialData.part + 1)) { formData.append('qqpartbyteoffset', chunkSize * partialData.part); formData.append('qqpartindex', partialData.part); formData.append('qqfile', bytes); } } else formData.append('file', bytes); return formData; } const tokenYemot = ''; const chunkSize = 5000000; const remotePath = 'ivr2:/2'; async function uploadFile(filePath) { const fileSize = (await fs.stat(filePath)).size; const callApi = (url, payload) => fetch(url, {method: 'POST', body: payload}); const chunks = getChunks(filePath, chunkSize); if (fileSize <= chunkSize) { const formData = createFormData((await chunks.next()).value, false); return await callApi('https://www.call2all.co.il/ym/api/UploadFile', formData).then(x => x.json()); } else { const contentName = filePath.split('/').pop(); const uuid = crypto.randomUUID(); const partCount = Math.ceil(chunkSize / fileSize); let part = 0; for await (const chunk of chunks) { const formData = createFormData(chunk, {contentName, uuid, fileSize, partCount, part}); part++; const status = await callApi('https://www.call2all.co.il/ym/api/UploadFile', formData).then(x => x.json()); if(!status.success){ console.log(status); throw new Error(status.message); } } return await callApi('https://www.call2all.co.il/ym/api/UploadFile?done', createFormData(null, {contentName, uuid, fileSize, partCount, part})).then(x => x.json()); } } const result = await uploadFile("D:/a.txt"); console.log(result);
-
@dovid כתב בהעלאת קובץ בapi לימות המשיח | קוד שבפייתון עובד וב nodejs לא כל כך:
קיבלתי את הקוד מ@צבי-ש ויש שגיאה מצד ימות, עם הודעה Syste, error, וmessageCode 105.
בקוד המקורי שהעלתי פה אין שגיאה כזאת, אלא על כל חלק וחלק אני מקבל תשובה שהכל תקין, וגם בסוף שעלה בסדר, שולח גם את הנתיב של הקובץ, אבל מעלה אותו עם 0kb
מה שיוצר לי תחושה כאילו אני סתם מחלק את הקובץ לחלקים, כשבפועל בכל קריאה אני מעלה 0kb
(תוכל לראות בשלוחה 1 שם קובץ כזה) -
עובד לי כעת קובץ בודד, בתנאי שאני מציין את שם הקובץ לFormData. הנה הקוד המעודכן:
import fs from 'fs/promises'; import fetch from 'node-fetch'; import FormData from 'form-data'; async function* getChunks(filePath, chunkSize = 5000000) { const file = await fs.open(filePath, 'r'); const buffer = Buffer.alloc(chunkSize); while (true) { const result = await file.read(buffer, 0, chunkSize); if (result.bytesRead === chunkSize) yield result.buffer; else { yield result.buffer.slice(0, result.bytesRead); break; } } await file.close(); } function createFormData(bytes, contentName, partialData = null) { const formData = new FormData(); formData.append('token', tokenYemot); formData.append('path', remotePath); formData.append('convertAudio', 1); formData.append('autoNumbering', 1); if (partialData) { formData.append('qquuid', partialData.uuid); formData.append('qqfilename', contentName); formData.append('qqtotalfilesize', partialData.fileSize); formData.append('qqtotalparts', partialData.partCount); formData.append('qqchunksize', chunkSize); //in final post request we don't need to send the file if (partialData.partCount > (partialData.part + 1)) { formData.append('qqpartbyteoffset', chunkSize * partialData.part); formData.append('qqpartindex', partialData.part); formData.append('qqfile', bytes, contentName); } } else formData.append('file', bytes, contentName); return formData; } const tokenYemot = ''; const chunkSize = 5000000; const remotePath = 'ivr2:/'; async function uploadFile(filePath) { const fileSize = (await fs.stat(filePath)).size; const callApi = (url, payload) => fetch(url, {method: 'POST', body: payload}); const chunks = getChunks(filePath, chunkSize); const contentName = filePath.split('/').pop(); if (fileSize <= chunkSize) { const formData = createFormData((await chunks.next()).value, contentName); return await callApi('https://www.call2all.co.il/ym/api/UploadFile', formData).then(x => x.json()); } else { const uuid = crypto.randomUUID(); const partCount = Math.ceil(chunkSize / fileSize); let part = 0; for await (const chunk of chunks) { const formData = createFormData(chunk, contentName, { uuid, fileSize, partCount, part}); part++; const status = await callApi('https://www.call2all.co.il/ym/api/UploadFile', formData).then(x => x.json()); if(!status.success){ console.log(status); throw new Error(status.message); } } return await callApi('https://www.call2all.co.il/ym/api/UploadFile?done', createFormData(null, { uuid, fileSize, partCount, part})).then(x => x.json()); } } const result = await uploadFile("D:/testS.mp3"); console.log(result);
-
פוסט זה נמחק!
-
@צבי-ש בשורה 55 תחליף מ:
formData.append('qqfile', chunk)
ל:
formData.append('qqfile', chunk, { filename: contentName, contentType: 'application/octet-stream', });
-
סליחה על המענה המאוחר, אני השתמשתי בפיתרון ש @ivrtikshoret כתב פה,
עבד לי מעולה, ערכתי את הפונקציה שתתאים גם לקבצים קטנים יותר.const readInChunks = (filePath, chunkSize = 5000000) => { const file = fs.readFileSync(filePath); const chunks = []; for (let offset = 0; offset < file.length; offset += chunkSize) { const chunk = file.slice(offset, offset + chunkSize); chunks.push(chunk); } return chunks; }; export const uploadFileInYemot = async (filePath, path, tokenYemot) => { const fileSize = fs.statSync(filePath).size; const contentName = filePath.split('/').pop(); if (fileSize <= 5000000) { const formData = new FormData(); formData.append('token', tokenYemot); formData.append('path', path); formData.append('convertAudio', 1); formData.append('autoNumbering', 1); formData.append('file', fs.readFileSync(filePath), { filename: contentName, contentType: 'application/octet-stream', }); const response = await fetch('https://www.call2all.co.il/ym/api/UploadFile', { method: 'POST', body: formData, }); return await response.json(); } else { const chunks = readInChunks(filePath); const qquuid = uuidv4().toString(); for (let i = 0; i < chunks.length; i++) { const chunk = chunks[i]; const formData = new FormData(); formData.append('token', tokenYemot); formData.append('path', path); formData.append('qquuid', qquuid); formData.append('convertAudio', 0); formData.append('autoNumbering', 'true'); formData.append('uploader', 'yemot-admin'); formData.append('qqfilename', contentName); formData.append('qqtotalfilesize', fileSize); formData.append('qqtotalparts', chunks.length); formData.append('qqchunksize', chunk.length); formData.append('qqpartbyteoffset', i * chunk.length); formData.append('qqpartindex', i); formData.append('qqfile', chunk, { filename: contentName, contentType: 'application/octet-stream', }); const response = await fetch('https://www.call2all.co.il/ym/api/UploadFile', { method: 'POST', body: formData, }); const responseData = await response.json(); console.log(responseData); } const finalFormData = new FormData(); finalFormData.append('token', tokenYemot); finalFormData.append('path', path); finalFormData.append('uploader', 'yemot-admin'); finalFormData.append('convertAudio', '0'); finalFormData.append('autoNumbering', 'true'); finalFormData.append('qquuid', qquuid); finalFormData.append('qqfilename', contentName); finalFormData.append('qqtotalfilesize', fileSize); finalFormData.append('qqtotalparts', chunks.length); try { const response = await fetch('https://www.call2all.co.il/ym/api/UploadFile?done', { method: 'POST', body: finalFormData, }); const responseData = await response.text(); console.log(responseData); } catch (error) { console.error("Error during the fetch:", error); } } };
תודה לכל העוזרים.
נ.ב. תודה למי שפנה אליי באישי והאיר לי על הנושא.
-
מעלה את הקוד המתוקן שלי שמציע כמה שיפורים, ב"ה כעת זה עובד.
import fs from 'fs/promises'; const baseUrl = 'https://www.call2all.co.il'; async function* getChunks(filePath, chunkSize) { const file = await fs.open(filePath, 'r'); const buffer = Buffer.alloc(chunkSize); try { while (true) { const result = await file.read(buffer, 0, chunkSize); if (result.bytesRead === chunkSize) yield result.buffer; else { yield result.buffer.slice(0, result.bytesRead); break; } } } finally { await file.close(); } } function createFormData(bytes, contentName, partialData = null) { const data = { token: tokenYemot, path: remotePath, convertAudio: 1, autoNumbering: 0 }; if (partialData) { data.uploader = 'yemot-admin'; data.qquuid = partialData.uuid; data.qqfilename = contentName; data.qqtotalfilesize = partialData.fileSize; data.qqtotalparts = partialData.partCount; //in final post request we don't need to send the file if (partialData.part < partialData.partCount) { data.qqpartbyteoffset = chunkSize * partialData.part; data.qqpartindex = partialData.part; data.qqchunksize = bytes.length; } } const formData = new FormData(); for (const [key, value] of Object.entries(data)) formData.append(key, value); if(bytes) formData.append( partialData ? 'qqfile' : 'file', new Blob([bytes]), {filename: contentName, contentType: 'application/octet-stream'}); return formData; } let tokenYemot = ''; const chunkSize = 20000000; const remotePath = 'ivr2:/'; async function uploadFile(filePath) { const fileSize = (await fs.stat(filePath)).size; const callApi = (url, payload) => fetch(url, {method: 'POST', body: payload}); const chunks = getChunks(filePath, chunkSize); const contentName = filePath.split('/').pop(); if (fileSize <= chunkSize) { const formData = createFormData((await chunks.next()).value, contentName); await chunks.return(); return await callApi(baseUrl + '/ym/api/UploadFile', formData).then(x => x.json()); } else { const uuid = crypto.randomUUID(); const partCount = Math.ceil(fileSize / chunkSize); let part = 0; for await (const chunk of chunks) { const formData = createFormData(chunk, contentName, {uuid, fileSize, partCount, part: part++}); const status = await callApi(baseUrl + '/ym/api/UploadFile', formData).then(x => x.json()); if (!status.success) { console.log(status); throw new Error(status.message); } } return await callApi(baseUrl + '/ym/api/UploadFile?done', createFormData(null, contentName, {uuid, fileSize, partCount, part})).then(x => x.text()); } }