Skip to content

Instantly share code, notes, and snippets.

@mxsgx
Last active November 14, 2023 11:04
Show Gist options
  • Save mxsgx/1f306576c8ce25e5a99e35546220bc26 to your computer and use it in GitHub Desktop.
Save mxsgx/1f306576c8ce25e5a99e35546220bc26 to your computer and use it in GitHub Desktop.
const axios = require("axios");
const fs = require("fs");
/**
* @param {string} baseUrl Base URL of API (example: `https://peertube.cpy.re/api/v1`)
* @param {string} bearerToken Access token
* @param {string} filePath Pathlike file video want to upload
* @param {number} chunkSize Chunk size in bytes
* @param {number} channelId
* @param {string} fileName
* @param {string} name
* @returns {Promise<void>}
*/
async function uploadResumableFile(
baseUrl,
bearerToken,
filePath,
chunkSize,
channelId,
fileName,
name
) {
try {
const url = new URL(baseUrl);
const fileSize = fs.statSync(filePath).size;
const client = axios.default.create({
baseURL: baseUrl,
headers: {
Authorization: `Bearer ${bearerToken}`,
},
validateStatus: function (status) {
return status < 400;
},
});
const resumableVideoResponse = await client.post(
"/videos/upload-resumable",
{
channelId,
filename: fileName,
name,
},
{
headers: {
"X-Upload-Content-Length": fileSize,
"X-Upload-Content-Type": "video/mp4",
},
}
);
if (resumableVideoResponse.status != 201) {
throw new Error("Failed to initialize resumable video");
}
const resumableUplaodId = new URL(
`${url.protocol}${resumableVideoResponse.headers.get("location")}`
).searchParams.get("upload_id");
const fileStream = fs.createReadStream(filePath, {
highWaterMark: chunkSize,
});
let bytesRangeStart = 0;
fileStream.on("data", (chunk) => {
fileStream.pause();
const bytesRangeEnd = bytesRangeStart + chunk.length - 1;
client
.put(`/videos/upload-resumable?upload_id=${resumableUplaodId}`, chunk, {
headers: {
"Content-Type": "application/octet-stream",
"Content-Length": chunk.length,
"Content-Range": `bytes ${bytesRangeStart}-${bytesRangeEnd}/${fileSize}`,
},
})
.then(() => {
console.log(
`Uploaded range ${bytesRangeStart}-${bytesRangeEnd}/${fileSize}`
);
bytesRangeStart += chunk.length;
fileStream.resume();
})
.catch((err) => {
fileStream.destroy(err);
});
});
fileStream.on("error", (err) => {
throw err;
});
} catch (e) {
throw e;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment