├── .travis.yml ├── .npmignore ├── .gitignore ├── lib ├── help.js ├── logout.js ├── login.js ├── utils.js ├── index.js └── upload.js ├── LICENSE ├── package.json └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: node_js 4 | node_js: 5 | - "8" 6 | 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | 2 | # build output 3 | lib 4 | 5 | # dependencies 6 | node_modules 7 | 8 | # logs 9 | npm-debug.log 10 | 11 | # fake data 12 | db.json 13 | image.jpg 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # build output 3 | dist 4 | /dist/ 5 | 6 | # dependencies 7 | node_modules 8 | 9 | # logs 10 | yarn.lock 11 | yarn.log 12 | npm-debug.log 13 | 14 | # fake data 15 | db.json 16 | image.jpg -------------------------------------------------------------------------------- /lib/help.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | console.log( 3 | ` 4 | Usage: ig-upload [command] 5 | 6 | Commands: 7 | login - login and create session 8 | upload - upload images or videos 9 | help - display help 10 | ` 11 | ); 12 | process.exit(0); 13 | -------------------------------------------------------------------------------- /lib/logout.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { homedir } from 'os'; 3 | import { resolve } from 'path'; 4 | import fs from 'fs-promise'; 5 | import readlineSync from 'readline-sync'; 6 | import del from 'del'; 7 | import chalk from 'chalk'; 8 | 9 | let fileExists; 10 | let file = resolve(homedir(), '.ig-upload.json'); 11 | 12 | try { 13 | fileExists = fs.readFileSync(file, 'utf8'); 14 | } catch (err) {} 15 | 16 | if (fileExists) { 17 | del.sync(file, { force: true }); 18 | console.log(`${chalk.cyan('Logout successfully!')}`); 19 | } else { 20 | console.log(`${chalk.red('Not logged in - try `ig-upload login')}`); 21 | } 22 | -------------------------------------------------------------------------------- /lib/login.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import chalk from 'chalk'; 3 | import readlineSync from 'readline-sync'; 4 | import { Client, device, file, checkFile } from './utils'; 5 | 6 | checkFile(); 7 | 8 | const storage = new Client.CookieFileStorage(file); 9 | const username = readlineSync.question('Enter your username: '); 10 | const password = readlineSync.question('Enter your password: ', { 11 | hideEchoBack: true 12 | }); 13 | Client.Session.create(device, storage, username, password).then(session => { 14 | session.getAccount().then(function(account) { 15 | console.log(`${chalk.cyan(`Welcome ${account.params.fullName} !`)}`); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import { homedir } from 'os'; 3 | import fs from 'fs-promise'; 4 | export const Client = require('instagram-private-api').V1; 5 | export const device = new Client.Device('ig-upload'); 6 | export let file = resolve(homedir(), '.ig-upload.json'); 7 | 8 | export function checkFile(file) { 9 | let fileExists; 10 | try { 11 | fileExists = fs.readFileSync(file, 'utf8'); 12 | } catch (err) {} 13 | 14 | if (fileExists) { 15 | console.log(`${chalk.red('Already login - try `ig-upload logout`')}`); 16 | process.exit(); 17 | } else { 18 | fs.writeFile(resolve(homedir(), '.ig-upload.json'), '{}'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import path from 'path'; 3 | import minimist from 'minimist'; 4 | import spawn from 'cross-spawn-async'; 5 | 6 | const Client = require('instagram-private-api').V1; 7 | 8 | const defaultCommand = 'upload'; 9 | 10 | const commands = new Set([defaultCommand, 'login', 'help', 'logout']); 11 | 12 | const exit = code => { 13 | process.exit(code); 14 | }; 15 | 16 | const args = process.argv.slice(2); 17 | let cmd = args[0] ? args[0] : defaultCommand; 18 | 19 | if (!commands.has(cmd)) { 20 | cmd = defaultCommand; 21 | } 22 | 23 | if (cmd === 'upload') { 24 | process.argv = process.argv.slice(0, 2).concat(args); 25 | } 26 | 27 | const bin = path.resolve(__dirname, cmd); 28 | 29 | require(bin, 'may-exclude'); 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Arana Jhonny 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/upload.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { homedir } from 'os'; 3 | import { resolve } from 'path'; 4 | import fs from 'fs-promise'; 5 | import minimist from 'minimist'; 6 | import chalk from 'chalk'; 7 | import { Client, device, file } from './utils'; 8 | import clipboardy from 'clipboardy'; 9 | import ora from 'ora'; 10 | const storage = new Client.CookieFileStorage(file); 11 | const session = new Client.Session(device, storage); 12 | 13 | const argv = minimist(process.argv.slice(2)); 14 | const image = argv._[0]; 15 | const caption = argv._[1]; 16 | 17 | if (image === undefined) { 18 | console.log(`${chalk.red('No image to upload')}`); 19 | process.exit(); 20 | } 21 | 22 | const spinner = ora({ 23 | text: 'Uploading...' 24 | }).start(); 25 | 26 | Client.Upload 27 | .photo(session, image) 28 | .then(function(upload) { 29 | return Client.Media.configurePhoto( 30 | session, 31 | upload.params.uploadId, 32 | caption 33 | ); 34 | }) 35 | .then(function(medium) { 36 | clipboardy.writeSync(medium.params.webLink); 37 | spinner.text = `${chalk.cyan('Ready ')} ${chalk.bold(medium.params.webLink)} (copied to clipboard)`; 38 | spinner.stopAndPersist('✔'); 39 | }); 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ig-upload", 3 | "version": "1.0.2", 4 | "description": "A tiny command line tool for upload images to instagram", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run test && babel lib -d dist", 8 | "test": "prettier --write --single-quote lib/**/*.js utils/**/*.js" 9 | }, 10 | "files": "dist", 11 | "bin": { 12 | "ig-upload": "./dist/index.js" 13 | }, 14 | "babel": { 15 | "presets": [ 16 | "env" 17 | ] 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/aranajhonny/ig-upload" 22 | }, 23 | "keywords": [ 24 | "upload", 25 | "upload-images", 26 | "api", 27 | "instagram" 28 | ], 29 | "author": "aranajhonny", 30 | "license": "MIT", 31 | "dependencies": { 32 | "chalk": "^1.1.3", 33 | "clipboardy": "^1.1.0", 34 | "cross-spawn-async": "^2.2.5", 35 | "del": "^2.2.2", 36 | "fs-promise": "^2.0.2", 37 | "instagram-private-api": "^0.5.16", 38 | "minimist": "^1.2.0", 39 | "ora": "^1.2.0", 40 | "readline-sync": "^1.4.7" 41 | }, 42 | "devDependencies": { 43 | "babel-cli": "^6.24.1", 44 | "babel-preset-env": "^1.4.0", 45 | "prettier": "^1.2.2" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ig-upload [WIP] 2 | 3 | [![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier) 4 | [![Build Status](https://travis-ci.org/aranajhonny/blog.svg?branch=master)](https://travis-ci.org/aranajhonny/ig-upload) 5 | 6 | A tiny command line tool for upload images to instagram, using [Unofficial API](https://github.com/huttarichard/instagram-private-api/). 7 | 8 | #### `login` 9 | 10 | ![screen2](https://cloud.githubusercontent.com/assets/9091881/25283358/7a376e9a-2681-11e7-862e-a29cfbe0caac.png) 11 | 12 | #### `upload` 13 | 14 | ![screen1](https://cloud.githubusercontent.com/assets/9091881/25283473/ec13353a-2681-11e7-9d68-41ab09a4ac7c.png) 15 | 16 | ## Installation 17 | 18 | Install using npm: 19 | ``` 20 | npm install -g ig-upload 21 | ``` 22 | or yarn 23 | ``` 24 | yarn global add ig-upload 25 | ``` 26 | ## Usage 27 | 28 | ```bash 29 | ig-upload [command] || [filename ...] 30 | ``` 31 | ### Comands 32 | ``` 33 | logout - login and remove session 34 | login - login and create session 35 | upload - upload images or videos 36 | help - display help 37 | ``` 38 | ## Caution 39 | 40 | Note that I am not a master doing CLI applications. I'm learning and I needed this. Possibly the code sucks. 41 | 42 | ## Authors 43 | 44 | - Jhonny Arana ([@aranajhonny](https://twitter.com/aranajhonny)) 45 | 46 | ## Please 47 | 48 | > You will not use this repository for sending mass spam or any other malicious activity 49 | --------------------------------------------------------------------------------