├── .gitignore ├── .npmignore ├── package.json ├── LICENSE ├── shorturl ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .*.swp 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .*.swp 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { "name": "shorturl" 2 | , "version": "v0.0.3" 3 | , "description": "Simple URL shortener client library" 4 | , "keywords": ["shorturl", "shortlink", "bit.ly", "bitly", "goo.gl", "is.gd"] 5 | , "author": "Jeff Waugh " 6 | , "homepage": "https://github.com/jdub/node-shorturl" 7 | , "bugs": { "url": "https://github.com/jdub/node-shorturl/issues" } 8 | , "licenses": 9 | [ { "type": "MIT" 10 | , "url": "https://github.com/jdub/node-shorturl/raw/master/LICENSE" 11 | } ] 12 | , "repository": 13 | { "type": "git" 14 | , "url": "https://github.com/jdub/node-shorturl.git" 15 | } 16 | , "dependencies": 17 | { "request": ">=2.9.153", 18 | "optimist": ">=0.3.1" 19 | } 20 | , "engines": ["node >=0.6.0"] 21 | , "main": "./index" 22 | , "bin": { 23 | "shorturl": "./shorturl" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | node-shorturl: Copyright (c) 2011 Jeff Waugh 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /shorturl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | try { 3 | var shorturl = require('shorturl'); 4 | } catch(e) { 5 | var shorturl = require('./index'); 6 | } 7 | 8 | var opts = require('optimist') 9 | .usage("Usage: shorturl [options] ") 10 | .boolean('debug') 11 | .describe('service', "URL shortening service (such as: bit.ly, goo.gl, is.gd)") 12 | .describe('user', "User name for services which require it") 13 | .describe('key', "API key for services which require it") 14 | .describe('debug', "Display troubleshooting information") 15 | .default('service', 'is.gd') 16 | .default('debug', false) 17 | .alias('d', 'debug') 18 | .check(function(argv) { 19 | return ( argv._.length == 1 && /^https?:/.test(argv._[0]) ); 20 | }) 21 | .argv, 22 | longurl = opts._[0], 23 | params = {}; 24 | 25 | // Service-specific parameter building 26 | switch ( opts.service ) { 27 | case 'bit.ly': 28 | params.login = opts.user; 29 | params.apiKey = opts.key; 30 | break; 31 | case 'goo.gl': 32 | params.key = opts.key; 33 | break; 34 | } 35 | 36 | // DEBUG 37 | if ( opts.debug ) { 38 | console.log('\nargv[]: ' + require('util').inspect(opts)); 39 | console.log('\nparams: '+require('util').inspect(params)); 40 | } 41 | 42 | shorturl(longurl, opts.service, params, function(result) { 43 | // DEBUG 44 | if ( opts.debug ) { 45 | console.log('\nresult: ' + require('util').inspect(arguments)); 46 | return; 47 | } 48 | 49 | if ( result instanceof Error ) { 50 | console.log('Error: ' + result.message); 51 | process.exit(1); 52 | } else { 53 | console.log(result); 54 | } 55 | }); 56 | 57 | /* vim: set ft=javascript: */ 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Simple URL shortener client library for node.js 2 | =============================================== 3 | 4 | [shorturl](https://github.com/jdub/node-shorturl) is a simple, asynchronous client library for common URL shortener services. It currently supports: arseh.at, bit.ly, goo.gl, is.gd, v.gd and string substitution links (with %@). It includes a perky little script for shortening URLs on the command line, also named [shorturl](https://github.com/jdub/node-shorturl/blob/master/shorturl). 5 | 6 | If you [need to go deeper](http://www.imdb.com/title/tt1375666/), try the more complete client libraries for individual services such as [node-bitly](https://github.com/tanepiper/node-bitly) or [node-googl](https://github.com/ukstv/node-googl). 7 | 8 | 9 | ## Requirements 10 | 11 | You can install node-shorturl and its dependencies with npm: `npm install shorturl`. Otherwise, manually install: 12 | 13 | - [node](http://nodejs.org/) 0.6+ 14 | - [request](https://github.com/mikeal/request) 2.9+ 15 | - [optimist](https://github.com/substack/node-optimist) 0.3.1 16 | 17 | ## Examples 18 | 19 | var shorturl = require('shorturl'); 20 | shorturl('http://bethesignal.org/', function(result) { 21 | console.log(result); 22 | }); 23 | 24 | By default it will shorten URLs with is.gd, but you can choose an alternative service and pass parameters: 25 | 26 | shorturl('http://bethesignal.org/', 'bit.ly', { 27 | login: 'STATE YOUR NAME', 28 | apiKey: 'STATE YOUR IDENTIFICATION NUMBER' 29 | }, function(result) { 30 | console.log(result); 31 | }); 32 | 33 | Simple services can be described using a string substitution link. Pass the entire link as the service name; '%@' will be replaced with your URL: 34 | 35 | var arsehat = 'http://arseh.at/api.php?action=shorturl&format=simple&url=%@'; 36 | shorturl('http://bethesignal.org/', arsehat, function(result) { 37 | console.log(result); 38 | }); 39 | 40 | ## Command line script 41 | 42 | $ shorturl 43 | Usage: shorturl [options] 44 | 45 | $ shorturl --service=goo.gl --key=STATE_YOUR_ID_NUMBER http://bethesignal.org/ 46 | http://goo.gl/dgTLo 47 | 48 | $ ARSEHAT="http://arseh.at/api.php?action=shorturl&format=simple&url=%@" 49 | $ shorturl --service=$ARSEHAT https://github.com/jdub/node-shorturl 50 | http://arseh.at/3yd 51 | 52 | Display the built-in command line documentation with `shorten --help`. 53 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var VERSION = '0.0.3', 2 | request = require('request'), 3 | querystring = require('querystring').stringify; 4 | 5 | function shorturl(longurl, shorter, params, callback) { 6 | // callback passed in params 7 | if ( typeof params === 'function' ) { 8 | callback = params; 9 | params = {}; 10 | } 11 | // callback passed in shorter 12 | if ( typeof shorter === 'function' ) { 13 | callback = shorter; 14 | params = {}; 15 | shorter = 'is.gd'; 16 | // params passed in shorter 17 | } else if ( typeof shorter === 'object' ) { 18 | params = shorter; 19 | shorter = 'is.gd'; 20 | } 21 | 22 | // check shorter validity 23 | if ( shorter in shorteners ) { 24 | // short circuit the rest of the checks to avoid match() 25 | } else if ( !shorter ) { 26 | shorter = 'is.gd'; 27 | } else if ( shorter.match(/^https?:\/\/.*%@/) ) { 28 | params.url = shorter; 29 | shorter = 'string'; 30 | } else { 31 | shorter = 'is.gd'; 32 | } 33 | 34 | if ( typeof callback === 'function' ) { 35 | shorteners[shorter](longurl, params, callback); 36 | } else { 37 | // FIXME: explode usefully here? 38 | } 39 | } 40 | module.exports = shorturl; 41 | 42 | var shorteners = { 43 | 'arseh.at': function(longurl, params, callback) { 44 | params.url = 'http://arseh.at/api.php?action=shorturl&format=simple&url=%@'; 45 | shorteners['string'](longurl, params, callback); 46 | }, 47 | 48 | 'bit.ly': function(longurl, params, callback) { 49 | if ( !(params.login && params.apiKey) ) { 50 | callback(new Error("bit.ly requires a user and apiKey for authorisation.")); 51 | return; 52 | } 53 | 54 | var uri = 'https://api-ssl.bit.ly/v3/shorten?' + querystring({ 55 | login: params.login || null, 56 | apiKey: params.apiKey || null, 57 | longUrl: longurl, 58 | format: 'json' 59 | }); 60 | request({uri:uri}, function(error, response, body) { 61 | if ( response && response.statusCode === 200 ) { 62 | try { 63 | var json = JSON.parse(body); 64 | if ( json.data && json.data.url ) 65 | callback(json.data.url, json); 66 | } catch(e) { 67 | // FIXME: e vs. error? kinda stupid 68 | callback(e, error, response, body); 69 | } 70 | } else { 71 | callback.call(arguments); 72 | } 73 | }); 74 | }, 75 | 76 | 'goo.gl': function(longurl, params, callback) { 77 | request({ 78 | uri: 'https://www.googleapis.com/urlshortener/v1/url', 79 | method: 'POST', 80 | json: {longUrl:longurl} 81 | }, function(error, response, body) { 82 | if ( response && response.statusCode === 200 && body.id ) { 83 | callback(body.id); 84 | } else { 85 | callback.call(arguments); 86 | } 87 | }); 88 | }, 89 | 90 | 'is.gd': function(longurl, params, callback) { 91 | var host = 'http://is.gd/'; 92 | if ( 'host' in params && ['is.gd', 'v.gd'].indexOf(params.host) >= 0 ) { 93 | host = 'http://' + params.host + '/'; 94 | delete params.host; 95 | } 96 | var uri = host + 'create.php?' + querystring({ 97 | format: 'simple', 98 | url: longurl 99 | }); 100 | request({uri:uri}, function(error, response, body) { 101 | if ( response && response.statusCode === 200 && body.substr(0, host.length) === host ) { 102 | callback(body); 103 | } else { 104 | callback.call(arguments); 105 | } 106 | }); 107 | }, 108 | 109 | 'v.gd': function(longurl, params, callback) { 110 | params.host = 'v.gd'; 111 | shorteners['is.gd'](longurl, params, callback); 112 | }, 113 | 114 | 'string': function(longurl, params, callback) { 115 | if ( !('url' in params) ) { 116 | callback(); 117 | return; 118 | } 119 | 120 | var uri = params.url.replace('%@', escape(longurl)); 121 | request({uri:uri}, function(error, response, body) { 122 | if ( response && response.statusCode === 200 ) { 123 | callback(body); 124 | } else { 125 | callback.call(arguments); 126 | } 127 | }); 128 | } 129 | }; 130 | --------------------------------------------------------------------------------