Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: 2.1
orbs:
node: circleci/[email protected]
jobs:
build-and-test:
executor:
name: node/default
steps:
- checkout
- node/with-cache:
steps:
- run: npm install
workflows:
build-and-test:
jobs:
- build-and-test
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ This simple application offers you the following features...
* Optimized application.
* Fast response time (~< 100ms).
* Simple layout and easy to understand.
* By country query (```/country```).
* By country query.
* e.g. (```/country```).
* Windows CMD support.
* e.g. (```/cmd``` or ```/cmd/country```).
* Plain or Basic version.
* e.g. (```/plain``` or ```/plain/country```) or (```/basic```, ```/basic/country```).

_More features coming soon..._

Expand Down Expand Up @@ -87,10 +92,8 @@ If you're facing a problem in using COVID-19 Tracker CLI please let me know by c

## To Do

* CI (CircleCI)
* Local Version
* Add Static Version
* Official Logo
* Sample Usage (gif)
* Add HTTP Headers (currently F)
* More Code Refactor! (I guess I know what I'm doing now... for sure)
Expand Down Expand Up @@ -155,7 +158,6 @@ COVID-19 Tracker CLI is licensed under MIT - <https://opensource.org/licenses/MI
## Related Projects

* <https://github.com/sagarkarira/coronavirus-tracker-cli>
* <https://github.com/ahmadawais/corona-cli>

## Resources

Expand Down
45 changes: 45 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,31 @@ app.get('/', async (req, res, next) => {
return next();
});

// for cmd and powershell
app.get(['/plain','/cmd','/basic'], async (req, res, next) => {
const userAgent = req.headers['user-agent'],
api = await axios.get(`${apiBaseURL}/all`),
data = api.data;
if (util.isCommandline(userAgent)) {
await res.send(covid19.plainglobaltracker(
data.cases, data.deaths,
data.recovered, data.updated
));
return null;
}
return next();
});

// help options
app.get(['/help','/manual'], async (req, res, next) => {
const userAgent = req.headers['user-agent'];
if (util.isCommandline(userAgent)) {
await res.send(covid19.help());
return null;
}
return next();
});

// by country route for covid19 tracker
app.get('/:country', async (req, res, next) => {
const userAgent = req.headers['user-agent'],
Expand All @@ -50,6 +75,26 @@ app.get('/:country', async (req, res, next) => {
return next();
});

// by country route for covid19 tracker
app.get(['/plain/:country','/cmd/:country','/basic/:country'], async (req, res, next) => {
const userAgent = req.headers['user-agent'],
countryData = req.params.country,
api = await axios.get(`${apiBaseURL}/countries/${countryData}`),
all = await axios.get(`${apiBaseURL}/all`),
u = all.data,
d = api.data;
if (util.isCommandline(userAgent)) {
await res.send(covid19.plaincountrytracker(
d.country, d.cases, d.todayCases,
d.deaths, d.todayDeaths, d.recovered,
d.active, d.critical, d.casesPerOneMillion,
u.updated
));
return null;
}
return next();
});

app.get('*', (req, res) => res.send(`
Sorry, CLI version is only available at the moment...
\n
Expand Down
144 changes: 122 additions & 22 deletions lib/cli/index.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,46 @@
/* eslint-disable no-await-in-loop */

const style = require('ansi-styles'),
const color = require('ansi-styles'),
fs = require('fs'),
table3 = require('cli-table3');

// ansi style and colors
// ansi colors

const
// table color
tblclr = (border) => {return cyan(border);},
// normal ansi colors
white = (txt) => {return style.white.open+txt+style.white.close;},
black = (txt) => {return style.black.open+txt+style.black.close;},
green = (txt) => {return style.green.open+txt+style.green.close;},
cyan = (txt) => {return style.cyan.open+txt+style.cyan.close;},
magenta = (txt) => {return style.magenta.open+txt+style.magenta.close;},
yellow = (txt) => {return style.yellow.open+txt+style.yellow.close;},
red = (txt) => {return style.red.open+txt+style.red.close;},
white = (txt) => {return color.white.open+txt+color.white.close;},
black = (txt) => {return color.black.open+txt+color.black.close;},
green = (txt) => {return color.green.open+txt+color.green.close;},
cyan = (txt) => {return color.cyan.open+txt+color.cyan.close;},
magenta = (txt) => {return color.magenta.open+txt+color.magenta.close;},
yellow = (txt) => {return color.yellow.open+txt+color.yellow.close;},
red = (txt) => {return color.red.open+txt+color.red.close;},
// bright ansi colors
cyanBright = (txt) => {return style.cyanBright.open+txt+style.cyanBright.close;},
magentaBright = (txt) => {return style.magentaBright.open+txt+style.magentaBright.close;},
redBright = (txt) => {return style.redBright.open+txt+style.redBright.close;},
cyanBright = (txt) => {return color.cyanBright.open+txt+color.cyanBright.close;},
magentaBright = (txt) => {return color.magentaBright.open+txt+color.magentaBright.close;},
redBright = (txt) => {return color.redBright.open+txt+color.redBright.close;},
greenBright = (txt) => {return color.greenBright.open+txt+color.greenBright.close;},
// background ansi color
cyanBG = (txt) => {return style.bgCyan.open+txt+style.bgCyan.close;};
cyanBG = (txt) => {return color.bgCyan.open+txt+color.bgCyan.close;},
// horizontal line
line = '-'.repeat(60);


// package.json information
const pkg = JSON.parse(fs.readFileSync('package.json'));
const say = JSON.parse(fs.readFileSync('./lib/sayings/threads.json'));

// random sayings
const randomSay = () => {
let random = Math.floor(Math.random() * say.length);
return say[random];
};

// format data
const formatNumber = (num) => {
return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
const formatNumber = (value) => {
return value.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
};

// time data
Expand Down Expand Up @@ -66,6 +76,27 @@ const source = 'Source: https://www.worldometers.info/coronavirus/',
sourceCountry = {colSpan:5,content:source},
repoCountry = {colSpan:5,content:repo};

// help menu
exports.help = () => {
const manual = `
${line}
COVID-19 Tracker CLI v${pkg.version} by Waren Gonzaga
${line}

/country or /code ......... by country query
ex. /philippines or /ph

/cmd ...................... if using CMD

/plain or /basic .......... if your cli does not support ansi encoding

${line}

"${randomSay()}"
`;
return manual+plainfooter;
};

// covid19 global tracker
exports.covid19globaltracker = (c, d, r, u) => {
const cases = c, deaths = d, recovered = r, asof = new Date(u),
Expand All @@ -80,34 +111,93 @@ exports.covid19globaltracker = (c, d, r, u) => {
[formatNumber(cases), formatNumber(deaths), formatNumber(recovered), mortalityPercentage.toFixed(2), recoveredPercentage.toFixed(2)],
[sourceGlobal],[repoGlobal]
);
return table.toString()+'\n'+footer;
return table.toString()+'\n\n'+' '+'"'+green(randomSay())+'"'+footer;
};

// covid19 country tracker
exports.covid19countrytracker = (n, c, tC, d, tD, r, a, cl, cPOM, u) => {
const name = n, cases = c, todayCases = tC,
deaths = d, todayDeaths = tD, recovered = r,
active = a, critical = cl, casesPerOneMillion = cPOM,
mortalityPercentage = (d/c)*100, recoveredPercentage = (r/c)*100,
mortalityPercentage = (d/c)*100, recoveryPercentage = (r/c)*100,
asof = new Date(u);
table = new table3({
head: [{colSpan:5,content:white('COVID-19 Tracker CLI v'+pkg.version+' - '+name+' Update')}],
chars: borders
});
table.push(
[{colSpan:5,content:yellow('As of '+asof.toLocaleString()+' [Date:'+currentdate+']')}],
[magenta('Cases'), red('Deaths'), green('Recovered'), cyan('Active'), cyanBright('Cases Per Million')],
[magenta('Cases'), red('Deaths'), green('Recovered'), cyan('Active'), cyanBright('Cases/Million')],
[formatNumber(cases), formatNumber(deaths), formatNumber(recovered), formatNumber(active), formatNumber(casesPerOneMillion)],
[magentaBright('Today Cases'), redBright('Today Deaths'), redBright('Critical'), red('Mortality %'), green('Recovered %')],
[formatNumber(todayCases), formatNumber(todayDeaths), formatNumber(critical), mortalityPercentage.toFixed(2), recoveredPercentage.toFixed(2)],
[magentaBright('Today Cases'), redBright('Today Deaths'), redBright('Critical'), red('Mortality %'), greenBright('Recovery %')],
[formatNumber(todayCases), formatNumber(todayDeaths), formatNumber(critical), mortalityPercentage.toFixed(2), recoveryPercentage.toFixed(2)],
[sourceCountry],[repoCountry]
);
return table.toString()+'\n'+footer;
return table.toString()+'\n\n'+' '+'"'+green(randomSay())+'"'+footer;
};

exports.plainglobaltracker = (c, d, r, u) => {
const cases = c, deaths = d, recovered = r, asof = new Date(u),
mortalityPercentage = (d/c)*100, recoveredPercentage = (r/c)*100;

const visual = `
${line}
COVID-19 Tracker CLI v${pkg.version} - Global Update
${line}
As of ${asof.toLocaleString()} [Date: ${currentdate}]
${line}
Cases | ${formatNumber(cases)}
Deaths | ${formatNumber(deaths)}
Mortality % | ${mortalityPercentage.toFixed(2)}
Recovered | ${formatNumber(recovered)}
Recovery % | ${recoveredPercentage.toFixed(2)}
${line}
${source}
${line}
${repo}
${line}

"${randomSay()}"
`;
return visual+plainfooter;
};

exports.plaincountrytracker = (n, c, tC, d, tD, r, a, cl, cPOM, u) => {
const name = n, cases = c, todayCases = tC,
deaths = d, todayDeaths = tD, recovered = r,
active = a, critical = cl, casesPerOneMillion = cPOM,
mortalityPercentage = (d/c)*100, recoveredPercentage = (r/c)*100,
asof = new Date(u);

const visual = `
${line}
COVID-19 Tracker CLI v${pkg.version} - ${name} Update
${line}
As of ${asof.toLocaleString()} [Date: ${currentdate}]
${line}
Cases | ${formatNumber(cases)}
Today Cases | ${formatNumber(todayCases)}
Deaths | ${formatNumber(deaths)}
Today Deaths | ${formatNumber(todayDeaths)}
Critical | ${formatNumber(critical)}
Mortality % | ${mortalityPercentage.toFixed(2)}
Recovered | ${formatNumber(recovered)}
Recovery % | ${recoveredPercentage.toFixed(2)}
Active | ${formatNumber(active)}
Cases/Million | ${formatNumber(casesPerOneMillion)}
${line}
${source}
${line}
${repo}
${line}

"${randomSay()}"
`;
return visual+plainfooter;
};

// cli footer
const footer = `
Always wash your hands, stay safe...

---
Love this project? Please consider buying me a cup of coffee!
Expand All @@ -116,3 +206,13 @@ const footer = `
---
Follow ${cyanBG(black('@warengonzaga'))} for more updates!
\n`;

// cli plain footer
const plainfooter = `
---
Love this project? Please consider buying me a cup of coffee!
[ warengonzaga.com/buymeacoffee ]

---
Follow [ @warengonzaga ] for more updates!
\n`;
22 changes: 22 additions & 0 deletions lib/sayings/threads.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
"Always wash your hands, stay safe!",
"Stay healthy, stay at home...",
"Play online games with your friends",
"Stay on your home!",
"Avoid fake news...",
"Eat healthy foods, sleep on time",
"We will survive!",
"Code with Love by Waren",
"COVID-19 is a serious matter",
"Don't touch your face! wash your hands",
"Social distancing is real...",
"Developer from Philippines",
"Support open-source!",
"A cup of coffee will keep this project updated",
"Can you send some coffee to the developer?",
"Stay at home, play games instead...",
"Uninstall 2020, virus detected!",
"Always wear a mask when you go outside",
"Watch news to keep updated!",
"Support the developer, buy him a coffee!"
]
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "covid19-tracker-cli",
"version": "2.1.0",
"version": "2.5.0",
"description": "Track COVID-19 cases from command line interface",
"main": "app.js",
"scripts": {
Expand Down