├── .gitignore ├── .npmignore ├── README.md ├── bin └── cli.js ├── index.js ├── package.json └── promise.js /.gitignore: -------------------------------------------------------------------------------- 1 | hosts.bak 2 | node_modules/ 3 | .diea/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | hosts.bak 2 | .diea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | hostx 2 | =========== 3 | 4 | 一条命令更新hosts,你懂的。 5 | 6 | 安装: 7 | 8 | npm install -g hostx 9 | 10 | 使用: 11 | 12 | hostx 13 | 14 | 指定一个在线的hosts列表更新 15 | 16 | hostx -u http://laod.cn/wp-content/uploads/2014/11/imouto.host_.txt 17 | 18 | 19 | 如果想清除已经更新的 hosts: 20 | 21 | hostx -c 22 | 23 | 查看帮助: 24 | 25 | hostx -h 26 | 27 | 28 | -------------------------------------------------------------------------------- /bin/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist').argv; 3 | var hostx = require('../index'); 4 | 5 | if (argv.c) { 6 | hostx.clear(); 7 | } 8 | else if (argv.h) { 9 | console.log( 10 | 'Usage: hostx [-u url] 更新hosts\n' + 11 | ' or: hostx -c 清除更新的hosts \n' + 12 | ' or: hostx -h 查看帮助 \n' 13 | ); 14 | } 15 | else { 16 | hostx.run(argv.u); 17 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by an.han on 15/1/20. 3 | */ 4 | 5 | var Promise = require('./promise'); 6 | var fs = require('fs'); 7 | var http = require('http'); 8 | var https = require('https'); 9 | 10 | 11 | var URLS = [ 12 | 'http://www.racalinux.cn/hosts.txt', 13 | 'https://github.com/racaljk/hosts/blob/master/hosts', 14 | //'https://raw.githubusercontent.com/zxdrive/imouto.host/master/imouto.host.txt', 15 | //'http://freedom.txthinking.com/hosts', 16 | //'http://laod.cn/wp-content/uploads/2014/11/imouto.host_.txt' 17 | ] 18 | 19 | var hostsFile = process.platform == 'win32' ? 'C:\\Windows\\System32\\drivers\\etc\\hosts' : '/etc/hosts'; 20 | var n = process.platform == 'win32' ? '\r\n' : '\n'; 21 | var group = '#==== hostx'; 22 | var groupReg = new RegExp(group + '[\n\r\n]([\\S\\s]*?)' + group, 'g'); 23 | 24 | var hostx = { 25 | 26 | status: 0, 27 | 28 | errors: 0, 29 | 30 | run: function (url) { 31 | var filter = this.filter.bind(this); 32 | var update = this.update.bind(this); 33 | var urls = url ? [url] : URLS; 34 | 35 | this.backup(); 36 | 37 | urls.forEach(function (url) { 38 | this.get(url).then(filter).then(update); 39 | }.bind(this)); 40 | }, 41 | 42 | update: function (hosts) { 43 | var oldHost = fs.readFileSync(hostsFile).toString(); 44 | var newHost = groupReg.test(oldHost) ? 45 | oldHost.replace(groupReg, group + n + hosts + n + group) : oldHost + n + group + n + hosts + n + group; 46 | 47 | fs.writeFile(hostsFile, newHost, this._callback('恭喜,更新 hosts 成功!')); 48 | }, 49 | 50 | filter: function (obj) { 51 | var host = '', 52 | url = obj.url, 53 | result = obj.result; 54 | 55 | if (/^https:\/\/github\.com/.test(url)) { 56 | var tds = result.match(/.+<\/td>/g); 57 | tds.forEach(function (td) { 58 | host += (td.replace(/<.+?>/g, '') + n); 59 | }); 60 | } 61 | else { 62 | host = result; 63 | } 64 | host = host.replace(/#.*?(\n|\r\n)/g, ''); 65 | return host 66 | }, 67 | 68 | get: function (url) { 69 | var self = this; 70 | var pm = new Promise(); 71 | var req = /^https/.test(url) ? https : http; 72 | req.get(url, function (res) { 73 | var result = ''; 74 | res.on('data', function (r) { 75 | result += r; 76 | }); 77 | res.on('end', function () { 78 | if (self.status == 0) { 79 | self.status = 1; 80 | pm.resolve({ 81 | url: url, 82 | result: result 83 | }); 84 | } 85 | }); 86 | }).on('error', function (e) { 87 | if (++self.errors == URLS.length && self.status == 0) { 88 | console.error('更新失败!'); 89 | process.exit(); 90 | } 91 | pm.reject(e); 92 | }); 93 | return pm; 94 | }, 95 | 96 | backup: function () { 97 | fs.writeFileSync('./hosts.bak', fs.readFileSync(hostsFile)); 98 | }, 99 | 100 | clear: function () { 101 | fs.writeFile(hostsFile, fs.readFileSync(hostsFile).toString().replace(groupReg, group + n + group), this._callback('hosts 清除成功!')); 102 | }, 103 | 104 | _callback: function (txt) { 105 | return function (err) { 106 | if (err) { 107 | console.error('权限不够!请修改hosts文件为可写入,或使用 sudo 身份运行此命令。'); 108 | } 109 | else { 110 | console.log(txt); 111 | } 112 | process.exit(); 113 | } 114 | } 115 | } 116 | 117 | module.exports = hostx; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hostx", 3 | "version": "0.1.1", 4 | "description": "update hosts", 5 | "main": "index.js", 6 | "bin": "bin/cli.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "hosts" 12 | ], 13 | "author": "韩安", 14 | "license": "ISC", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/hanan198501/hostx.git" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/hanan198501/hostx/issues" 21 | }, 22 | "dependencies": { 23 | "optimist": "^0.6.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /promise.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by an.han on 14/12/23. 3 | * ES6 Promise 类 4 | */ 5 | 6 | // status 7 | var PENDING = 0, 8 | FULFILLED = 1, 9 | REJECTED = 2; 10 | 11 | var Promise = function (fun) { 12 | var me = this, 13 | resolve = function (val) { 14 | me.resolve(val); 15 | }, 16 | reject = function (val) { 17 | me.reject(val); 18 | } 19 | me._status = PENDING; 20 | me._onFulfilled = null; 21 | me._onRejected = null; 22 | (typeof fun === 'function') && fun(resolve, reject); 23 | } 24 | 25 | var fn = Promise.prototype; 26 | 27 | fn.then = function (resolve, reject) { 28 | var pms = new Promise(); 29 | this._onFulfilled = function (val) { 30 | var ret = resolve ? resolve(val) : val; 31 | if (Promise.isPromise(ret)) { 32 | ret.then(function (val) { 33 | pms.resolve(val); 34 | }); 35 | } 36 | else { 37 | pms.resolve(ret); 38 | } 39 | }; 40 | this._onRejected = function (val) { 41 | var ret = reject ? reject(val) : val; 42 | pms.reject(ret); 43 | }; 44 | return pms; 45 | } 46 | 47 | fn.catch = function (reject) { 48 | return this.then(null, reject); 49 | } 50 | 51 | fn.resolve = function (val) { 52 | if (this._status === PENDING) { 53 | this._status = FULFILLED; 54 | this._onFulfilled && this._onFulfilled(val); 55 | } 56 | } 57 | 58 | fn.reject = function (val) { 59 | if (this._status === PENDING) { 60 | this._status = REJECTED; 61 | this._onRejected && this._onRejected(val); 62 | } 63 | } 64 | 65 | Promise.all = function (arr) { 66 | var pms = new Promise(); 67 | var len = arr.length, 68 | i = -1, 69 | count = 0, 70 | results = []; 71 | while (++i < len) { 72 | ~function (i) { 73 | arr[i].then( 74 | function (val) { 75 | results[i] = val; 76 | if (++count === len) { 77 | pms.resolve(results); 78 | } 79 | }, 80 | function (val) { 81 | pms.reject(val); 82 | } 83 | ); 84 | }(i); 85 | } 86 | return pms; 87 | } 88 | 89 | Promise.resolve = function (obj) { 90 | var ret; 91 | if (!Promise.isPromise(obj)) { 92 | ret = obj; 93 | obj = new Promise(); 94 | } 95 | setTimeout(function () { 96 | obj.resolve(ret); 97 | }); 98 | return obj; 99 | } 100 | 101 | Promise.reject = function (obj) { 102 | var ret; 103 | if (!Promise.isPromise(obj)) { 104 | ret = obj; 105 | obj = new Promise(); 106 | } 107 | setTimeout(function () { 108 | obj.reject(ret); 109 | }); 110 | return obj; 111 | } 112 | 113 | Promise.isPromise = function (obj) { 114 | return obj instanceof Promise; 115 | } 116 | 117 | 118 | module.exports = Promise; --------------------------------------------------------------------------------