├── .gitignore ├── package.json ├── test.js ├── license ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | *.swp 5 | npm-debug.log* 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # nyc test coverage 19 | .nyc_output 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Compiled binary addons (http://nodejs.org/api/addons.html) 28 | build/Release 29 | 30 | # Dependency directories 31 | node_modules 32 | jspm_packages 33 | 34 | # Optional npm cache directory 35 | .npm 36 | 37 | # Optional REPL history 38 | .node_repl_history 39 | 40 | # Custom 41 | fixture* 42 | secrets 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "facebook-api-video-upload", 3 | "version": "2.0.1", 4 | "description": "A handy function to upload video in chunk on the facebook graph.", 5 | "license": "MIT", 6 | "author": "mrdotb", 7 | "main": "index.js", 8 | "scripts": { 9 | "fixture": "youtube-dl https://www.youtube.com/watch?v=NrB35qqOyhU -o 'fixture.%(ext)s' --format mp4 --write-thumbnail", 10 | "test": "" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/MRdotB/facebook-api-video-upload.git" 15 | }, 16 | "keywords": [ 17 | "stream", 18 | "facebook-api", 19 | "facebook", 20 | "graph", 21 | "api", 22 | "upload", 23 | "video" 24 | ], 25 | "bugs": { 26 | "url": "https://github.com/MRdotB/facebook-api-video-upload/issues" 27 | }, 28 | "homepage": "https://github.com/MRdotB/facebook-api-video-upload#readme", 29 | "dependencies": { 30 | "request-promise": "^3.0.0", 31 | "stream-to-promise": "^2.1.1" 32 | }, 33 | "devDependencies": {} 34 | } 35 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const fbUpload = require('./'); 3 | 4 | // You can download some fixture using npm run fixture cmd 5 | 6 | const args = { 7 | token: "", // with the permission to upload 8 | id: "", //The id represent {page_id || user_id || event_id || group_id} 9 | stream: fs.createReadStream('./fixture.mp4'), //path to the video, 10 | title: "my video", 11 | description: "my description", 12 | thumb: { 13 | value: fs.createReadStream('./fixture.jpg'), 14 | options: { 15 | filename: 'fixture.jpg', 16 | contentType: 'image/jpg' 17 | } 18 | } 19 | // if you want the default thumb from the video just remove the field 20 | // you can add any extra fields from the api https://developers.facebook.com/docs/graph-api/reference/page/videos/#Creating 21 | // all keys except token, id, stream are passed to the final request 22 | }; 23 | 24 | fbUpload(args).then((res) => { 25 | console.log('res: ', res); 26 | //res: { success: true, video_id: '1838312909759132' } 27 | }).catch((e) => { 28 | console.error(e); 29 | }); 30 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) mrdotb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # facebook-api-video-upload 2 | > Upload a video in chunk on the facebook api. [more info](https://developers.facebook.com/docs/graph-api/video-uploads) 3 | 4 | ## Install 5 | ``` 6 | $ npm i facebook-api-video-upload --save 7 | ``` 8 | Tested on OS X and Linux. 9 | 10 | ## Usage 11 | ```javascript 12 | const fs = require('fs'); 13 | const fbUpload = require('facebook-api-video-upload'); 14 | 15 | const args = { 16 | token: "YOURTOKEN", // with the permission to upload 17 | id: "YOURID", //The id represent {page_id || group_id} 18 | stream: fs.createReadStream('./fixture.mp4'), //path to the video, 19 | title: "my video", 20 | description: "my description", 21 | thumb: { 22 | value: fs.createReadStream('./fixture.jpg'), 23 | options: { 24 | filename: 'fixture.jpg', 25 | contentType: 'image/jpg' 26 | } 27 | } 28 | // if you want the default thumb from the video just remove the field 29 | // you can add any extra fields from the api https://developers.facebook.com/docs/graph-api/reference/page/videos/#Creating 30 | // all keys except token, id, stream are passed to the final request 31 | }; 32 | 33 | fbUpload(args).then((res) => { 34 | console.log('res: ', res); 35 | //res: { success: true, video_id: '1838312909759132' } 36 | }).catch((e) => { 37 | console.error(e); 38 | }); 39 | ``` 40 | 41 | ## Note 42 | The Video API allows you to publish Videos on Pages and Groups. Publishing on Users is not supported. [Read more](https://developers.facebook.com/docs/video-api/guides/publishing) 43 | 44 | ## License 45 | MIT © [MrdotB](https://github.com/MRdotB) 46 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const streamToPromise = require('stream-to-promise') 2 | const rp = require('request-promise') 3 | 4 | const url = 'https://graph-video.facebook.com' 5 | const version = 'v3.2' 6 | 7 | const retryMax = 10 8 | let retry = 0 9 | 10 | function apiInit(args, videoSize) { 11 | const options = { 12 | method: 'POST', 13 | uri: `${url}/${version}/${args.id}/videos?access_token=${args.token}`, 14 | json: true, 15 | form: { 16 | upload_phase: 'start', 17 | file_size: videoSize 18 | } 19 | } 20 | 21 | return rp(options).then(res => res) 22 | } 23 | 24 | function apiFinish(args, upload_session_id, video_id) { 25 | const {token, id, stream, ...extraParams} = args 26 | 27 | const options = { 28 | method: 'POST', 29 | json: true, 30 | uri: `${url}/${version}/${args.id}/videos`, 31 | formData: { 32 | ...extraParams, 33 | upload_session_id, 34 | access_token: args.token, 35 | upload_phase: 'finish', 36 | } 37 | } 38 | 39 | return rp(options) 40 | .then(res => ({...res, video_id})) 41 | } 42 | 43 | function uploadChunk(args, id, start, chunk) { 44 | const formData = { 45 | access_token: args.token, 46 | upload_phase: 'transfer', 47 | start_offset: start, 48 | upload_session_id: id, 49 | video_file_chunk: { 50 | value: chunk, 51 | options: { 52 | filename: 'chunk' 53 | } 54 | } 55 | } 56 | const options = { 57 | method: 'POST', 58 | uri: `${url}/${version}/${args.id}/videos`, 59 | formData: formData, 60 | json: true 61 | } 62 | 63 | return rp(options) 64 | .then(res => { 65 | retry = 0 66 | return res 67 | }) 68 | .catch(err => { 69 | if (retry++ >= retryMax) { 70 | return err 71 | } 72 | return uploadChunk(args, id, start, chunk) 73 | }) 74 | } 75 | 76 | function uploadChain(buffer, args, res, ids) { 77 | if (res.start_offset === res.end_offset) { 78 | return ids 79 | } 80 | 81 | var chunk = buffer.slice(res.start_offset, res.end_offset) 82 | return uploadChunk(args, ids[0], res.start_offset, chunk) 83 | .then(res => uploadChain(buffer, args, res, ids)) 84 | } 85 | 86 | function facebookApiVideoUpload(args) { 87 | return streamToPromise(args.stream) 88 | .then(buffer => Promise.all([buffer, apiInit(args, buffer.length)])) 89 | .then(([buffer, res]) => uploadChain(buffer, args, res, [res.upload_session_id, res.video_id])) 90 | .then(([id, video_id]) => apiFinish(args, id, video_id)) 91 | } 92 | 93 | module.exports = facebookApiVideoUpload 94 | --------------------------------------------------------------------------------