diff --git a/app.js b/app.js index 879df11..745d78b 100644 --- a/app.js +++ b/app.js @@ -12,7 +12,8 @@ const { getCompleteTable, getGraph } = require('./lib/corona'); const { lookupCountry, htmlTemplate, footer } = require('./lib/helpers'); const { getLiveUpdates } = require('./lib/reddit.js'); const { getWorldoMetersTable } = require('./lib/worldoMeters.js'); -const { helpContent, countryNotFound } = require('./lib/constants'); +const { getUsaStats } = require('./lib/country/us.js'); +const { helpContent, countryNotFound, stateCountryNotFound } = require('./lib/constants'); const app = express(); const port = process.env.PORT || 3001; @@ -125,6 +126,26 @@ app.get('/help', (req, res) => { return res.send(chalk.green(helpContent)); }); +app.get('/states/:country', (req, res) => { + const { country } = req.params; + const isCurl = req.isCurl; + const format = req.query.format ? req.query.format : ''; + const minimal = req.query.minimal === 'true'; + const top = req.query.top ? Number(req.query.top) : 1000; + + const lookupObj = lookupCountry(country); + + if (!lookupObj) { + return res.status(404).send(stateCountryNotFound(isCurl)); + } + if (lookupObj.iso2 === 'US') { + return getUsaStats({ isCurl, minimal, top, format}) + .then(result => { + return res.send(result); + }).catch(error => errorHandler(error, req, res)); + } +}); + app.get('/:country', (req, res) => { const { country } = req.params; diff --git a/bin/index.js b/bin/index.js index 338566b..e798809 100755 --- a/bin/index.js +++ b/bin/index.js @@ -7,6 +7,7 @@ const { getCompleteTable, getGraph } = require('../lib/corona'); const { getCountryTable } = require('../lib/byCountry'); const { getWorldoMetersTable } = require('../lib/worldoMeters'); const { lookupCountry } = require('../lib/helpers'); +const { getUsaStats } = require('../lib/country/us'); const { argv } = yargs .command('$0 [country]', 'Tool to track COVID-19 statistics from terminal', yargs => @@ -68,12 +69,27 @@ const { argv } = yargs describe: 'Get graph', type: 'boolean', default: false, + }, + st: { + alias: 'states', + describe: 'Get state level data of country ', + type: 'string', } }) .strict() .help('help'); argv.countryCode = argv.country; +if (argv.states === 'US') { + getUsaStats(argv).then(result => { + console.log(result); + process.exit(1); + }).catch(error => { + console.error(error); + process.exit(0); + }); +} + if (argv.source === 1) { ( argv.country === 'ALL' diff --git a/changelog.md b/changelog.md index 9863037..2aa9b5f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,9 @@ # Changelog +## Version 0.9.1 + +* Added US states api `corona --states=US` + ## Version 0.9.0 * Changed default source to worldoMeters. i.e source 2 is now default diff --git a/lib/api.js b/lib/api.js index 1c220b5..ee11b7a 100644 --- a/lib/api.js +++ b/lib/api.js @@ -7,7 +7,6 @@ const NodeCache = require('node-cache'); const axios = require('axios'); -const { countryNameMap } = require('./constants'); const myCache = new NodeCache({ stdTTL: 100, checkperiod: 600 }); @@ -75,8 +74,8 @@ exports.getWorldoMetersData = async (countryCode = 'ALL') => { }); result.data.forEach(obj => { - obj.countryCode = countryNameMap[obj.country]; obj.confirmed = obj.cases; + obj.countryCode = obj.countryInfo.iso2 || ''; }); worldStats.casesPerOneMillion = (worldStats.cases / 7794).toFixed(2); worldStats.confirmed = worldStats.cases; @@ -89,3 +88,18 @@ exports.getWorldoMetersData = async (countryCode = 'ALL') => { myCache.set(key, returnObj, 60 * 15); return returnObj; }; + +exports.usaStats = async () => { + const key = 'usaStats'; + const cache = myCache.get(key); + + if (cache) { + console.log('cache', key); + return cache; + } + const result = await axios('https://corona.lmao.ninja/states'); + if (!result || !result.data) { + throw new Error('usa stats API failure'); + } + return result; +}; \ No newline at end of file diff --git a/lib/constants.js b/lib/constants.js index 75b14e5..028316a 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,201 +1,4 @@ const { htmlTemplate, footer } = require('./helpers'); -exports.countryNameMap = { - China: 'CN', - UK: 'GB', - Martinique: 'MQ', - Liechtenstein: 'LI', - 'Réunion': 'RE', - Ukraine: 'UA', - Honduras: 'HN', - Afghanistan: 'AF', - Bangladesh: 'BD', - Macao: 'MO', - Bolivia: 'BO', - Cuba: 'CU', - Netherlands: 'NL', - Jamaica: 'JM', - 'French Guiana': 'GF', - DRC: 'CD', - Cameroon: 'CM', - Maldives: 'MV', - Montenegro: 'ME', - Paraguay: 'PY', - Nigeria: 'NG', - Guam: 'GU', - 'French Polynesia': 'PF', - Austria: 'AT', - Ghana: 'GH', - Rwanda: 'RW', - Monaco: 'MC', - Gibraltar: 'GI', - Guatemala: 'GT', - 'Ivory Coast': 'CI', - Ethiopia: 'ET', - Togo: 'TG', - 'Trinidad and Tobago': 'TT', - Kenya: 'KE', - Belgium: 'BE', - Mauritius: 'MU', - 'Equatorial Guinea': 'GQ', - Kyrgyzstan: 'KG', - Mongolia: 'MN', - 'Puerto Rico': 'PR', - Seychelles: 'SC', - Tanzania: 'TZ', - Guyana: 'GY', - Aruba: 'AW', - Barbados: 'BB', - Norway: 'NO', - Mayotte: 'YT', - 'Cayman Islands': 'KY', - 'Curaçao': 'CW', - Bahamas: 'BS', - Congo: 'CD', - Gabon: 'GA', - Namibia: 'NA', - 'St. Barth': 'BL', - 'Saint Martin': 'MF', - 'U.S. Virgin Islands': 'VI', - Sweden: 'SE', - Sudan: 'SD', - Benin: 'BJ', - Bermuda: 'BM', - Bhutan: 'BT', - CAR: 'CF', - Greenland: 'GL', - Haiti: 'HT', - Liberia: 'LR', - Mauritania: 'MR', - 'New Caledonia': 'NC', - Denmark: 'DK', - 'Saint Lucia': 'LC', - Zambia: 'ZM', - Nepal: 'NP', - Angola: 'AO', - 'Antigua and Barbuda': 'AG', - 'Cabo Verde': 'CV', - Chad: 'TD', - Djibouti: 'DJ', - 'El Salvador': 'SV', - Fiji: 'FJ', - Japan: 'JP', - Gambia: 'GM', - Guinea: 'GN', - 'Vatican City': 'VA', - 'Isle of Man': 'IM', - Montserrat: 'MS', - Nicaragua: 'NI', - Niger: 'NE', - 'St. Vincent Grenadines': 'VC', - 'Sint Maarten': 'SX', - Somalia: 'SO', - Malaysia: 'MY', - Suriname: 'SR', - Eswatini: 'SZ', - Australia: 'AU', - Italy: 'IT', - Canada: 'CA', - Portugal: 'PT', - Czechia: 'CZ', - Israel: 'IL', - Brazil: 'BR', - Luxembourg: 'LU', - Ireland: 'IE', - Greece: 'GR', - Qatar: 'QA', - Pakistan: 'PK', - Iran: 'IR', - Finland: 'FI', - Poland: 'PL', - Turkey: 'TR', - Singapore: 'SG', - Chile: 'CL', - Iceland: 'IS', - Thailand: 'TH', - Slovenia: 'SI', - Indonesia: 'ID', - Bahrain: 'BH', - Spain: 'ES', - Romania: 'RO', - 'Saudi Arabia': 'SA', - Estonia: 'EE', - Ecuador: 'EC', - Egypt: 'EG', - Peru: 'PE', - Philippines: 'PH', - 'Hong Kong': 'HK', - India: 'IN', - Russia: 'RU', - Germany: 'DE', - Iraq: 'IQ', - Mexico: 'MX', - Lebanon: 'LB', - 'South Africa': 'ZA', - Kuwait: 'KW', - 'San Marino': 'SM', - UAE: 'AE', - Panama: 'PA', - Armenia: 'AM', - Taiwan: 'TW', - USA: 'US', - Argentina: 'AR', - Colombia: 'CO', - Slovakia: 'SK', - Serbia: 'RS', - Croatia: 'HR', - Bulgaria: 'BG', - Uruguay: 'UY', - Algeria: 'DZ', - 'Costa Rica': 'CR', - Latvia: 'LV', - France: 'FR', - Hungary: 'HU', - Vietnam: 'VN', - 'Faeroe Islands': 'FO', - Andorra: 'AD', - Brunei: 'BN', - Belarus: 'BY', - Jordan: 'JO', - Cyprus: 'CY', - 'Sri Lanka': 'LK', - Albania: 'AL', - 'S. Korea': 'KR', - 'Bosnia and Herzegovina': 'BA', - Morocco: 'MA', - Malta: 'MT', - 'North Macedonia': 'MK', - Moldova: 'MD', - Kazakhstan: 'KZ', - Lithuania: 'LT', - Oman: 'OM', - Cambodia: 'KH', - Palestine: 'PS', - Switzerland: 'CH', - Guadeloupe: 'GP', - Azerbaijan: 'AZ', - Georgia: 'GE', - Venezuela: 'VE', - Tunisia: 'TN', - 'New Zealand': 'NZ', - Senegal: 'SN', - 'Dominican Republic': 'DO', - 'Burkina Faso': 'BF', - Uzbekistan: 'UZ', - 'Madagascar': 'MG', - 'Uganda': 'UG', - 'Zimbabwe': 'ZW', - 'Dominica': 'DM', - 'Laos': 'LA', - 'Myanmar': 'MM', - 'Belize': 'BZ', - 'Eritrea': 'ER', - 'Grenada': 'GD', - 'Mozambique': 'MZ', - 'Papua New Guinea': 'PG', - 'Syria': 'SY', - 'Timor-Leste': 'TL', - 'Turks and Caicos': 'TC' -}; exports.helpContent = ` @@ -239,6 +42,19 @@ https://corona-stats.online/UK --------------------------------------------------------------------------------- +# State wise api (Only for US as of now) + +## Format: +https://corona-stats.online/states/[countryCode] +https://corona-stats.online/states/[countryName] + +## Example: From source 1 +https://corona-stats.online/us +https://corona-stats.online/USA?format=json +https://corona-stats.online/USA?minimal=true + +--------------------------------------------------------------------------------- + # Minimal Mode - remove the borders and padding from table ## Example: @@ -296,4 +112,16 @@ exports.countryNotFound = (isCurl) => { ${footer(new Date)} `; return isCurl ? body : htmlTemplate(body); +}; + +exports.stateCountryNotFound = (isCurl) => { + const body = ` + State wise api is only available for: + - US + Try: + /US or /USA + + ${footer(new Date)} + `; + return isCurl ? body : htmlTemplate(body); }; \ No newline at end of file diff --git a/lib/corona.js b/lib/corona.js index 2ec7b4c..be1cafa 100644 --- a/lib/corona.js +++ b/lib/corona.js @@ -79,7 +79,7 @@ exports.getGraph = async ({ countryCode = 'ALL', isCurl = true}) => { const confirmedGraph = asciichart.plot(confirmedByDay, graphConfig); const body = chalk.greenBright(confirmedGraph) - + chalk.cyanBright('\n\n' +padding + '22 Feb' + graphLength + '22 Mar') + '\n'; + + chalk.cyanBright('\n\n' +padding + '22 Feb' + graphLength + 'Today') + '\n'; if (!isCurl) { return htmlTemplate(body); diff --git a/lib/country/us.js b/lib/country/us.js new file mode 100644 index 0000000..60e5b4d --- /dev/null +++ b/lib/country/us.js @@ -0,0 +1,57 @@ +const Table = require('cli-table3'); +const chalk = require('chalk'); +const helpers = require('../helpers'); +const api = require('../api'); +const { cFormatter } = helpers; + + +const getUsaStatsHeaders = (emojis, secondColumnName) => { + const head = [ + 'Rank', + secondColumnName, + `Total Cases ${emojis ? ' ✅' : ''}`, + 'New Cases ▲', + `Total Deaths${emojis ? ' 😞' : ''}`, + `New Deaths ▲${emojis ? ' 😞' : ''}`, + `Active${emojis ? ' 😷' : ''}`, + + ]; + return head; +}; + + +exports.getUsaStats = async ({ + isCurl = true, + minimal = false, + top = 1000, + format, +}) => { + const secondColumnName = 'US States'; + const table = new Table({ + head: getUsaStatsHeaders(null, secondColumnName), + chars: helpers.getTableBorders(minimal), + style: helpers.getTableStyles(minimal), + }); + const { data } = await api.usaStats(); + if (format === 'json') { + return { data }; + } + + let rank = 1; + data.some(cd => { + const values = [ + cFormatter(cd.state , chalk.cyanBright), + cFormatter(cd.cases, chalk.green, 'right', true), + cFormatter(cd.todayCases, chalk.cyanBright, 'right', true, ' ▲'), + cFormatter(cd.deaths, chalk.whiteBright, 'right', true), + cFormatter(cd.todayDeaths, chalk.redBright, 'right', true, ' ▲'), + cFormatter(cd.active, chalk.blueBright , 'right', true), + ]; + table.push({ [rank++]: values }); + return rank === top + 1; + }); + + const lastUpdated = new Date(); + const ret = table.toString() + helpers.footer(lastUpdated); + return isCurl ? ret : helpers.htmlTemplate(ret); +}; \ No newline at end of file diff --git a/lib/helpers.js b/lib/helpers.js index e7be25e..218c712 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -171,8 +171,7 @@ ${chalk.greenBright('Twitter')}: ${chalk.blueBright('https://twitter.com/ekrysis ${chalk.magentaBright('Last Updated on:')} ${moment(lastUpdated).utc().format('DD-MMM-YYYY HH:MM')} UTC -${chalk.red.bold('UPDATE')}: ${chalk.blueBright('Source 2 is now default source')} -${chalk.red.bold('JHU Source 1 table')}: ${chalk.blueBright('https://corona-stats.online?source=1')} +${chalk.red.bold('US STATES API')}: ${chalk.blueBright('https://corona-stats.online/states/us')} ${chalk.red.bold('HELP')}: ${chalk.blueBright('https://corona-stats.online/help')} `; @@ -230,7 +229,6 @@ e.getTableHeadersV2 = (emojis, secondColumnName) => { ]; return head; }; - e.extraStats = (dataArr) => { return dataArr.map(obj => { return { diff --git a/package.json b/package.json index d3ad7ab..68d85bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coronavirus-tracker-cli", - "version": "0.9.0", + "version": "0.9.1", "description": "track conronavirus cases from cli", "repository": { "type": "git", diff --git a/readme.md b/readme.md index 817ac25..17802fd 100644 --- a/readme.md +++ b/readme.md @@ -38,11 +38,15 @@ curl https://corona-stats.online?source=2 # Filter by country /countryCode or /countryName -curl https://corona-stats.online/US +curl https://corona-stats.online/US curl https://corona-stats.online/italy curl https://corona-stats.online/uk?source=2 curl https://corona-stats.online/gb?source=1 +# State wise stats of country (Only for US as of now) + +curl https://corona-stats.online/US + # Only show top N countries curl https://corona-stats.online?top=20 @@ -91,6 +95,10 @@ corona -s=1 # Filter by country corona italy +# state wise stats (only for US as of now) +corona --states=US +corona --st=us + # Filter top N countries corona --top=10 corona -t=10