├── .editorconfig ├── .gitattributes ├── .gitignore ├── .travis.yml ├── cli.js ├── commands ├── history.js └── index.js ├── index.js ├── lib ├── config.js ├── download.js ├── history.js ├── post.js └── spin.js ├── license ├── package.json └── readme.md /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'stable' 4 | - '0.12' 5 | - '0.10' 6 | 7 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | require('colorful').toxic(); 4 | const meow = require('meow'); 5 | const updateNotifier = require('update-notifier'); 6 | const pkg = require('./package'); 7 | const imageCli = require('./'); 8 | updateNotifier({pkg}).notify(); 9 | 10 | global.cli = meow([ 11 | 'Usage:'.bold, 12 | '', 13 | ' $ image ', 14 | '', 15 | 'Options', 16 | ' -p/--proxy Download image via proxy host, system http_proxy by default', 17 | ' -e/--ext Extenstion name for downloaded remote image', 18 | ' -v/--version Print version', 19 | ' -h/--help Print docs', 20 | '' 21 | ], { 22 | alias: { 23 | v: 'version', 24 | h: 'help', 25 | e: 'ext', 26 | p: 'proxy' 27 | } 28 | }); 29 | 30 | if (cli.flags.version) { 31 | console.log(pkg.name.cyan, '~', pkg.version.magenta); 32 | process.exit(); 33 | } 34 | 35 | imageCli(); 36 | -------------------------------------------------------------------------------- /commands/history.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const history = require('../lib/history'); 3 | 4 | module.exports = function () { 5 | const images = history.get(); 6 | console.log(images.join('\n').cyan); 7 | }; 8 | -------------------------------------------------------------------------------- /commands/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const co = require('co'); 3 | const clip = require('cliparoo'); 4 | const pify = require('pify'); 5 | const boxen = require('boxen'); 6 | const post = require('../lib/post'); 7 | const history = require('../lib/history'); 8 | 9 | const main = co.wrap(function* (filePath, cli) { 10 | if (typeof filePath !== 'string' || !filePath) { 11 | return console.log(`Expected a string`.red); 12 | } 13 | 14 | // the data to be logged 15 | let result = []; 16 | 17 | const data = yield post(filePath, cli); 18 | const url = data.url; 19 | 20 | // print image info after success 21 | result.push(url.cyan); 22 | 23 | // add to history 24 | history.add(url); 25 | 26 | // copy to clipboard 27 | try { 28 | yield pify(clip)(url); 29 | result.push('The URL is also in your clipboard now!'.bold); 30 | } catch (e) { 31 | console.log(e.stack.red); 32 | process.exit(1); 33 | } 34 | 35 | result.push(`To delete, click ${data.delete.red}`); 36 | 37 | // print result in box 38 | console.log(boxen(result.join('\n'), {borderStyle: 'classic', padding: 1})); 39 | }); 40 | 41 | module.exports = main; 42 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const history = require('./commands/history'); 3 | const defaultRoute = require('./commands/index'); 4 | 5 | module.exports = function () { 6 | const route = cli.input[0]; 7 | switch (route) { 8 | case 'history': 9 | return history(); 10 | default: 11 | return defaultRoute(route, cli).catch(e => { 12 | console.log(e.stack); 13 | process.exit(1); 14 | }); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | 'user strict'; 2 | const pkg = require('../package'); 3 | const Config = require('configstore'); 4 | 5 | module.exports = new Config(pkg.name, { 6 | history: [] 7 | }); 8 | -------------------------------------------------------------------------------- /lib/download.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const got = require('got'); 5 | const tempfile = require('tempfile'); 6 | const tunnel = require('tunnel'); 7 | const spin = require('./spin'); 8 | const downloadSpin = spin('Downloading'); 9 | 10 | module.exports = function (url, cli) { 11 | return new Promise((resolve, reject) => { 12 | downloadSpin.start(); 13 | const ext = cli.flags.ext || path.extname(url.replace(/\?[^.]+$/, '')); 14 | const filePath = tempfile(ext); 15 | const opt = {}; 16 | let proxy = process.env.http_proxy || process.env.https_proxy || cli.flags.proxy; 17 | if (proxy) { 18 | proxy = proxy.match(/(?:(?:http|https)\:\/\/)?([^~]+)\:([0-9]{1,5})/); 19 | opt.agent = tunnel.httpOverHttp({ 20 | proxy: { 21 | host: proxy[1], 22 | port: proxy[2] 23 | } 24 | }); 25 | } 26 | const request = got.stream(url, opt); 27 | const write = request.pipe(fs.createWriteStream(filePath)); 28 | request.on('error', error => { 29 | if (error.statusCode !== 200) { 30 | downloadSpin.stop(); 31 | reject(error); 32 | } 33 | }); 34 | write.on('finish', () => { 35 | downloadSpin.stop(); 36 | resolve(filePath); 37 | }); 38 | write.on('error', err => { 39 | downloadSpin.stop(); 40 | reject(new Error(err)); 41 | }); 42 | }); 43 | }; 44 | -------------------------------------------------------------------------------- /lib/history.js: -------------------------------------------------------------------------------- 1 | 'user strict'; 2 | const config = require('./config'); 3 | 4 | exports.add = function (item) { 5 | const history = config.get('history'); 6 | if (history.length === 10) { 7 | history.pop(); 8 | } 9 | history.unshift(item); 10 | config.set('history', history); 11 | }; 12 | 13 | exports.get = function () { 14 | return config.get('history'); 15 | }; 16 | -------------------------------------------------------------------------------- /lib/post.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const co = require('co'); 5 | const got = require('got'); 6 | const isUrl = require('is-url'); 7 | const imgcat = require('term-img'); 8 | const FormData = require('form-data'); 9 | const form = new FormData(); 10 | const download = require('./download'); 11 | const spin = require('./spin'); 12 | 13 | const uploadSpin = spin('Uploading'); 14 | 15 | module.exports = co.wrap(function* post(filePath, cli) { 16 | // if filePath is url 17 | // download it and temp-write it to a file 18 | if (isUrl(filePath)) { 19 | filePath = yield download(filePath, cli).catch(err => { 20 | console.log(err.stack); 21 | process.exit(1); 22 | }); 23 | } 24 | 25 | // output image in terminal 26 | yield imgcat(filePath).catch(() => {}); // eslint-disable-line 27 | const file = fs.createReadStream(path.resolve(filePath)); 28 | 29 | // start spinner 30 | uploadSpin.start(); 31 | 32 | // create form 33 | form.append('smfile', file); 34 | form.append('ssl', 'true'); 35 | 36 | // post form 37 | const data = yield got.post('https://sm.ms/api/upload', { 38 | headers: form.getHeaders(), 39 | body: form, 40 | json: true 41 | }).then(res => res.body); 42 | 43 | // stop spinner 44 | uploadSpin.stop(); 45 | 46 | // exit when error occurs 47 | if (data.code !== 'success') { 48 | console.log(data.msg.red); 49 | process.exit(1); 50 | } 51 | 52 | // return result 53 | return data.data; 54 | }); 55 | -------------------------------------------------------------------------------- /lib/spin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const Spin = require('io-spin'); 3 | 4 | module.exports = function (text) { 5 | return new Spin('Box1', text.cyan); 6 | }; 7 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 egoist 0x142857@gmail.com 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. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "image-cli", 3 | "version": "0.4.0", 4 | "description": "Uploading local or remote images from Cli to store in Cloud.", 5 | "license": "MIT", 6 | "repository": "egoist/image-cli", 7 | "author": { 8 | "name": "egoist", 9 | "email": "0x142857@gmail.com", 10 | "url": "github.com/egoist" 11 | }, 12 | "bin": { 13 | "image": "cli.js" 14 | }, 15 | "engines": { 16 | "node": ">=4" 17 | }, 18 | "scripts": { 19 | "test": "xo" 20 | }, 21 | "keywords": [ 22 | "cli-app", 23 | "cli", 24 | "image" 25 | ], 26 | "dependencies": { 27 | "boxen": "^0.5.0", 28 | "cliparoo": "^1.1.1", 29 | "co": "^4.6.0", 30 | "colorful": "^2.1.0", 31 | "configstore": "^1.4.0", 32 | "form-data": "^1.0.0-rc3", 33 | "got": "^6.2.0", 34 | "io-spin": "^0.2.2", 35 | "is-url": "^1.2.1", 36 | "meow": "^3.6.0", 37 | "pify": "^2.3.0", 38 | "tempfile": "^1.1.1", 39 | "term-img": "^0.1.2", 40 | "tunnel": "0.0.4", 41 | "update-notifier": "^0.6.0" 42 | }, 43 | "devDependencies": { 44 | "xo": "^0.12.1" 45 | }, 46 | "xo": { 47 | "ignores": [ 48 | "test.js" 49 | ], 50 | "space": true, 51 | "globals": [ 52 | "cli" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # image-cli [![npm](https://img.shields.io/npm/v/image-cli.svg)](https://www.npmjs.com/package/image-cli) [![Build Status](https://travis-ci.org/egoist/image-cli.svg?branch=master)](https://travis-ci.org/egoist/image-cli) 2 | 3 | 8MB GIF Preview 😅 4 | 5 | ![preview](http://ww4.sinaimg.cn/large/a15b4afegw1f1ws1vl1h9g20v70i07wo.gif) 6 | 7 | ## Install 8 | 9 | ```bash 10 | $ npm install -g image-cli 11 | ``` 12 | 13 | ## Example 14 | 15 | ```bash 16 | $ image a.jpg 17 | 18 | $ image [Drag and Drop an image here from your file system] 19 | 20 | $ image http://remote/path/to/image.jpg 21 | 22 | # if a given image url is not ended with .xxx but something like .xxx:large 23 | # you can specific the extension you actually need using `-e/--ext`: 24 | $ image http://path/to/a.jpg/large -e .jpg 25 | 26 | # use proxy to download images behide firewall 27 | # for example you are using lantern to bypass firewall 28 | $ image http://blocked-website.com/xxx.jpg -p localhost:8787 29 | # or system proxy, http_proxy or https_proxy 30 | $ http_proxy=localhost:8787 image http://blocked-website.com/xxx.jpg 31 | ``` 32 | 33 | ## License 34 | 35 | MIT © [EGOIST](https://github.com/egoist) 36 | --------------------------------------------------------------------------------