UNPKG

@jinxedbuffer/cfkit

Version:

cfkit is a CLI tool for competitive programming leveraging Codeforces API.

143 lines (130 loc) 4.53 kB
import ora from "ora"; import {CACHE_TIMEOUT_MINUTES, getCache, setCache} from "../helpers/cache-manager.js"; import {fetchJSONFromAPI} from "../api/request.js"; import moment from "moment"; import inquirer from "inquirer"; import Table from "cli-table3"; import {consoleWidth, dataColMaxWidth, keyColMaxWidth} from "../helpers/terminal-utils.js"; import open from "open"; export const blog = async function (cmd) { const spinner = ora('Fetching blogs').start(); const url = `https://codeforces.com/api/user.blogEntries?handle=${cmd.user}`; let blogs; const _cache = getCache(`blogs-${cmd.user}`); if (_cache && (_cache.timestamp + CACHE_TIMEOUT_MINUTES * 60 * 1000) > Date.now()) { blogs = _cache.data; } else { try { const res = await fetchJSONFromAPI(url); blogs = res.result; setCache(`blogs-${cmd.user}`, blogs); } catch (e) { spinner.fail(' Failed to fetch blogs'); console.error(e); return; } } if (blogs.length === 0) { spinner.fail(` No blogs found`); } else { spinner.stop(); displayBlogsMenu(cmd, blogs); } } const displayBlogsMenu = function (cmd, blogs) { const width = process.stdout.columns; const maxIdLength = Math.max(...blogs.map(b => b.id.toString().length)); const maxTimeLength = Math.max(...blogs.map(b => moment.duration(b.modificationTimeSeconds - (Date.now() / 1000), 's').humanize(true).length)); const choices = blogs.map((b) => { const id = `# ${b.id}`.padEnd(maxIdLength + 2, ' '); const time = (moment.duration(b.modificationTimeSeconds - (Date.now() / 1000), 's').humanize(true)).toString().padEnd(maxTimeLength, ' '); const title = b.title.replace(/<\/?[^>]+(>|$)/g, "").slice(0, width - maxIdLength - maxTimeLength - 10); return { name: `${id}${time}${title}`, value: b } }) inquirer.prompt([ { type: 'list', name: 'blog', message: ' Choose a blog', choices: choices, } ]) .then((answers) => { printBlog(answers.blog, () => displayBlogsMenu(cmd, blogs)); }) .catch((e) => { if (!e.message.includes('force closed')) { console.error(e); } }); } const printBlog = function (b, back) { const table = new Table({ colWidths: [keyColMaxWidth, ((consoleWidth - (keyColMaxWidth + 3)) < dataColMaxWidth ? (consoleWidth - (keyColMaxWidth + 3)) : dataColMaxWidth)], wordWrap: true }); const timePosted = moment.duration(b.creationTimeSeconds - (Date.now() / 1000), 's').humanize(true); const timeModified = moment.duration(b.modificationTimeSeconds - (Date.now() / 1000), 's').humanize(true); table.push( [{colSpan: 2, hAlign: "center", content: `Blog # ${b.id}`}], ['Title', b.title.replace(/<\/?[^>]+(>|$)/g, "")], ['Author', b.authorHandle], ['Posted', timePosted], ['Last modified', timeModified], ['Popularity', b.rating], ['Tags', (b.tags.length !== 0) ? b.tags.join(', ') : "N/A"], ); console.log(table.toString()); chooser(b, back); } const chooser = function (b, back) { const choices = [ { name: "Open in browser", value: "browserOpen" }, { name: "Back", value: "back" }, { name: "Exit", value: "exit" } ]; inquirer .prompt([ { type: 'list', name: 'options', message: ' Choose an option', choices: choices, }, ]) .then((answers) => { switch (answers.options) { case 'browserOpen': { open(`https://codeforces.com/blog/entry/${b.id}`) .then(() => chooser(b, back)) .catch((e) => { console.error(e); }); break; } case 'back': { back(); break; } default: { process.exit(0); } } }).catch(e => { if (!e.message.includes('force closed')) { console.error(e); } }); }