├── .gitignore ├── README.md ├── designer.js ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | hackernews cli 2 | ========== 3 | 4 | ###A command line tool to print out the latest posts on Hacker News to your terminal. 5 | 6 | --- 7 | 8 | If you're anything like me, you visit Hacker news at least 4 times a day and you spend a lot of time in the terminal. 9 | 10 | I usually open the Hacker News site in my browser and decide if any of the headlines catch my attention, I thought it would be cool if I could see a summary of the new featured posts in my terminal and only open them in a browser if I wanted to read them, so I made this simple tool. 11 | 12 | ![Preview](http://s3-eu-west-1.amazonaws.com/matt-github/hn.png) 13 | 14 | ##Installation 15 | 16 | Before installation you will need node/npm installed. 17 | 18 | 19 | sudo npm install -g hacker-news-cli 20 | 21 | ##Usage 22 | 23 | The global installation will symlink an executable script and place it in your PATH. To use with hacker news simply type: 24 | 25 | hn 26 | 27 | or for designer news: 28 | 29 | dn 30 | 31 | You will then be prompted to open a post. Type the number of the post to open a post or type 0 to quit and return to your terminal session. 32 | 33 | ##Version history 34 | 35 | 0.1.0 - `stephenway` added dn command 36 | 37 | 0.2.0 - Support for Windows and Linux added, `mkozakov` added input validation -------------------------------------------------------------------------------- /designer.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var FeedParser = require('feedparser') 4 | , request = require('request') 5 | , posts = [] 6 | , colors = require('colors') 7 | , prompt = require('prompt') 8 | , exec = require('child_process').exec 9 | , platform = require('os').platform() 10 | , i = 1; 11 | 12 | const shellOpenCommand = { 13 | 'win32': 'start ', 14 | 'linux': 'xdg-open ', 15 | 'darwin': 'open ' 16 | }[platform]; 17 | 18 | request('https://www.designernews.co/?format=rss') 19 | .pipe(new FeedParser()) 20 | .on('error', function(error) { 21 | console.log("An error occured"); 22 | }) 23 | .on('readable', function () { 24 | var stream = this, item; 25 | if(i < 29){ 26 | while (item = stream.read()) { 27 | posts.push(item); 28 | console.log(i.toString().blue + ". " + item.title); 29 | i++; 30 | } 31 | } 32 | }) 33 | .on('finish', function(){ 34 | promptForPost(); 35 | }); 36 | 37 | function promptForPost() { 38 | prompt.start(); 39 | 40 | var schema = { 41 | properties: { 42 | post: { 43 | message: 'Type post number to open, or 0 to quit', 44 | required: true 45 | }, 46 | } 47 | }; 48 | 49 | prompt.get(schema, function (err, result) { 50 | if(result.post !== "0"){ 51 | var i = parseInt(result.post); 52 | if(isNaN(i) || i > posts.length || i < 1) { 53 | console.log("Invalid post number"); 54 | } else { 55 | exec(shellOpenCommand + posts[i - 1].link); 56 | } 57 | promptForPost(); 58 | } 59 | }); 60 | } 61 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var FeedParser = require('feedparser') 4 | , request = require('request') 5 | , posts = [] 6 | , colors = require('colors') 7 | , prompt = require('prompt') 8 | , exec = require('child_process').exec 9 | , platform = require('os').platform() 10 | , i = 1; 11 | 12 | const shellOpenCommand = { 13 | 'win32': 'start ', 14 | 'linux': 'xdg-open ', 15 | 'darwin': 'open ' 16 | }[platform]; 17 | 18 | request('https://news.ycombinator.com/rss') 19 | .pipe(new FeedParser()) 20 | .on('error', function(error) { 21 | console.log("An error occured"); 22 | }) 23 | .on('readable', function () { 24 | var stream = this, item; 25 | if(i < 29){ 26 | while (item = stream.read()) { 27 | posts.push(item); 28 | console.log(i.toString().red + ". " + item.title); 29 | i++; 30 | } 31 | } 32 | }) 33 | .on('finish', function(){ 34 | promptForPost(); 35 | }); 36 | 37 | function promptForPost() { 38 | prompt.start(); 39 | 40 | var schema = { 41 | properties: { 42 | post: { 43 | message: 'Type post number to open, or 0 to quit', 44 | required: true 45 | }, 46 | } 47 | }; 48 | 49 | prompt.get(schema, function (err, result) { 50 | 51 | if( !result || !result.post ) return console.log('\r'); 52 | 53 | if(result.post !== "0"){ 54 | var i = parseInt(result.post); 55 | if(isNaN(i) || i > posts.length || i < 1) { 56 | console.log("Invalid post number"); 57 | } else { 58 | exec(shellOpenCommand + posts[i - 1].link, function(error){ 59 | if(error) throw error; 60 | }); 61 | } 62 | promptForPost(); 63 | } 64 | }); 65 | } 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hacker-news-cli", 3 | "version": "1.0.0", 4 | "description": "A command line tool to print out the latest posts on Hacker News to your terminal.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "bin": { 10 | "hn": "./index.js", 11 | "dn": "./designer.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/mtharrison/hackernews.git" 16 | }, 17 | "author": "Matt Harrison ", 18 | "license": "BSD-2-Clause", 19 | "bugs": { 20 | "url": "https://github.com/mtharrison/hackernews/issues" 21 | }, 22 | "dependencies": { 23 | "request": "~2.27.0", 24 | "feedparser": "~0.16.2", 25 | "colors": "~0.6.2", 26 | "prompt": "~0.2.11" 27 | } 28 | } 29 | --------------------------------------------------------------------------------