⚡ add bin (scripts)
This commit is contained in:
parent
075f2deaf0
commit
b54b08442a
9
.config/uurc
Normal file
9
.config/uurc
Normal file
@ -0,0 +1,9 @@
|
||||
#! /usr/bin/
|
||||
uu_w_alias="wttr.in/${1:-prague}?M"
|
||||
uu_w_is_raw=0
|
||||
uu_h_alias="cheat.sh/$1"
|
||||
uu_h_is_raw=0
|
||||
uu_surl_alias="tinyurl.com/api-create.php?url=$1"
|
||||
uu_surl_is_raw=1
|
||||
uu_ip_alias="ifconfig.co/json"
|
||||
uu_ip_is_raw=1
|
76
bin/bw-ftp.js
Executable file
76
bin/bw-ftp.js
Executable file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */
|
||||
$.is_fatal= true;
|
||||
const css= echo.css`
|
||||
.code, .url{ color: lightblue; }
|
||||
.code::before, .code::after{ content: "\`"; }
|
||||
`;
|
||||
testRequirements();
|
||||
$.api()
|
||||
.version("2023-03-21")
|
||||
.describe([
|
||||
"Small utility to find out FTP url with credentials using Bitwarden CLI.",
|
||||
echo.format("The idea is to use saved login %cusername%c, %cpassword%c and %curl%c.",
|
||||
css.code, css.unset, css.code, css.unset, css.code, css.unset)
|
||||
])
|
||||
.command("get [name]", "Get url with credentials.")
|
||||
.alias("item")
|
||||
.option("--copy", echo.format("Uses %cxclip -selection clipboard%c.", css.code))
|
||||
.action(get)
|
||||
.command("list", echo.format("List all %cftp-*%c.", css.code))
|
||||
.option("--json", "Print output in JSON format.")
|
||||
.action(list)
|
||||
.parse();
|
||||
|
||||
async function get(name, { copy: is_copy= false }){
|
||||
if(!name)
|
||||
name= await $.read({
|
||||
"-p": "Name",
|
||||
completions: list({ is_internal: true }).map(o=> o.name)
|
||||
});
|
||||
const item= s.$().run`bw get item ${name}`;
|
||||
if(!item.trim())
|
||||
$.error(`No record found for ${name}.`);
|
||||
|
||||
const { uris, username, password }= item
|
||||
.xargs(JSON.parse)
|
||||
.login;
|
||||
const url= urlFromUris(uris).replace('://', `://${username}:${password}@`);
|
||||
if(!is_copy){
|
||||
echo(url);
|
||||
$.exit(0);
|
||||
}
|
||||
s.echo(url).run`xclip -selection clipboard 2>1 > /dev/null`;
|
||||
$.exit(0);
|
||||
}
|
||||
function list({ json= false, is_internal= false }){
|
||||
const list= s.$().run`bw list items --search="ftp"`
|
||||
.xargs(JSON.parse)
|
||||
.filter(o=> o.name.startsWith("ftp-"))
|
||||
.map(({ name, note, login: { uris } })=> ({ name, url: urlFromUris(uris), note }))
|
||||
.filter(o=> o.url);
|
||||
if(is_internal)
|
||||
return list;
|
||||
if(json)
|
||||
$.exit(0, echo(JSON.stringify(list)));
|
||||
|
||||
list.forEach(pipe(
|
||||
line=> echo.format(line),
|
||||
t=> t.replaceAll("\n", " ").slice(2, -2),
|
||||
echo
|
||||
));
|
||||
$.exit(0);
|
||||
}
|
||||
|
||||
function urlFromUris(uris){ return uris.find(o=> o.uri)?.uri; }
|
||||
|
||||
function testRequirements(){
|
||||
if(!s.which("bw"))
|
||||
$.error([
|
||||
echo.format("The %cbw%c utility has not been found.", css.code),
|
||||
echo.format("Please install it using %cnpm i @bitwarden/cli --location=global%c.", css.code),
|
||||
echo.format("Respectively, follow the instructions at %chttps://github.com/bitwarden/clients/tree/master/apps/cli", css.url)
|
||||
].join("\n"));
|
||||
}
|
||||
// vim: set tabstop=4 shiftwidth=4 textwidth=250 noexpandtab :
|
||||
// vim>60: set foldmethod=indent foldlevel=1 foldnestmax=2:
|
82
bin/chrome-autoinspect.mjs
Executable file
82
bin/chrome-autoinspect.mjs
Executable file
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */
|
||||
const css= echo.css`
|
||||
.url{ color: lightblue; }
|
||||
.code { font-style: italic; }
|
||||
.code::before, .code::after { content: "\`"; }
|
||||
`;
|
||||
$.api()
|
||||
.version("2023-03-23")
|
||||
.describe([
|
||||
echo.format("This is small utility around %cchrome-remote-interface%c¹ to auto open inspect for cordova apps.", css.code),
|
||||
echo.format("[1] %chttps://github.com/cyrus-and/chrome-remote-interface", css.url)
|
||||
])
|
||||
.command("open", "This open browser and after 30secs enable auto inspect openning.", true)
|
||||
.option("--browser, -B", "Browser exec. Use one of supported browsers, such as chrome, chromium, opera, edge, …", "chromium")
|
||||
.option("--port, -P", "Chanhe debugging port", 9222)
|
||||
.action(async function({ browser, port }){
|
||||
s.runA`${browser} --remote-debugging-port=${port}`;
|
||||
const { setTimeout }= await import("node:timers/promises");
|
||||
await setTimeout(30_000);
|
||||
await register();
|
||||
$.exit(0);
|
||||
})
|
||||
.command("enable", "Enable auto inspect openning for already running browser.")
|
||||
.action(async function(){
|
||||
await register();
|
||||
$.exit(0);
|
||||
})
|
||||
.parse();
|
||||
|
||||
async function register(){
|
||||
const { default: CDP } = await import($.xdg.globalPackage`chrome-remote-interface`);
|
||||
let client;
|
||||
try{
|
||||
await CDP.New();
|
||||
client= await CDP();
|
||||
const { Network, Page, Runtime }= client;
|
||||
await Network.enable();
|
||||
await Page.enable();
|
||||
await Page.navigate({url: 'chrome://inspect/#devices'});
|
||||
await Page.loadEventFired();
|
||||
await Runtime.evaluate({ expression: `const debugCordova= (${autoRunCordovaAppInspect.toString()})();` });
|
||||
} finally {
|
||||
if(!client) return;
|
||||
return await client.close();
|
||||
}
|
||||
}
|
||||
|
||||
function autoRunCordovaAppInspect(){
|
||||
const { filter, map }= Array.prototype;
|
||||
let /* filters */
|
||||
device_filter, app_filter, last_state;
|
||||
const /* get elements */
|
||||
devicesElements= ()=> filter.call(document.getElementsByClassName("device"), el=> el.id!=="device:localhost"),
|
||||
getApp= el=> el.getElementsByClassName("browser-name")[0].textContent,
|
||||
appTest= browser_candidate_el=> getApp(browser_candidate_el).indexOf(app_filter)!==-1,
|
||||
browsersElements= wrapper_el=> wrapper_el.getElementsByClassName("browser"),
|
||||
actionElementFilter= wrapper_el=> filter.call(wrapper_el.getElementsByClassName("action"), el=> el.textContent==="inspect")[0];
|
||||
|
||||
function run(){
|
||||
const device= !device_filter ? (d=> d&&d[d.length-1])(devicesElements()) : filter.call(devicesElements(), el=> el.id===device_filter)[0];
|
||||
if(!device) return false;
|
||||
const app= !app_filter ? (a=> a&&a[a.length-1])(browsersElements(device)) : filter.call(browsersElements(document), appTest)[0];
|
||||
if(!app) return false;
|
||||
const { id }= app;
|
||||
if(last_state===id) return false;
|
||||
last_state= id;
|
||||
const action= actionElementFilter(app);
|
||||
if(!action) return false;
|
||||
action.click();
|
||||
}
|
||||
const observer= new MutationObserver(run);
|
||||
observer.observe(document.getElementById("devices-list"), { childList: true, subtree: true })
|
||||
return {
|
||||
/* Set string to filter, typically app id or ip */
|
||||
setApp: _app_filter=> app_filter= _app_filter,
|
||||
/* Apply only for given device (see debugCordova.devices). */
|
||||
setDevice: _device_filter=> device_filter= _device_filter,
|
||||
get apps(){ return map.call(browsersElements(document), getApp); },
|
||||
get devices(){ return map.call(devicesElements(), el=> el.id); }
|
||||
};
|
||||
}
|
418
bin/github-releases.js
Executable file
418
bin/github-releases.js
Executable file
@ -0,0 +1,418 @@
|
||||
#!/usr/bin/env node
|
||||
/* jshint esversion: 8,-W097, -W040, node: true, expr: true, undef: true */
|
||||
const /* dependencies */
|
||||
[ fs, readline, https, { spawn } ]= [ "fs", "readline", "https", "child_process" ].map(p=> require(p));
|
||||
const /* helper for coloring console | main program params */
|
||||
colors= { e: "\x1b[38;2;252;76;76m", s: "\x1b[38;2;76;252;125m", w: "\x1b[33m", R: "\x1b[0m", y: "\x1b[38;2;200;190;90m", g: "\x1b[38;2;150;150;150m" },
|
||||
info= {
|
||||
name: __filename.slice(__filename.lastIndexOf("/")+1, __filename.lastIndexOf(".")),
|
||||
version: "1.2.1",
|
||||
description: "Helper for working with “packages” stored in GitHub releases.",
|
||||
config: `${__filename.slice(0, __filename.lastIndexOf("."))}.json`,
|
||||
folder: __filename.slice(0, __filename.lastIndexOf("/")+1),
|
||||
commands: [
|
||||
{
|
||||
cmd: "help", args: [ "--help", "-h" ],
|
||||
desc: "Shows this text"
|
||||
},
|
||||
{
|
||||
cmd: "config", args: [ "--config" ],
|
||||
desc: "Opens config file in terminal editor (defaults to vim)"
|
||||
},
|
||||
{
|
||||
cmd: "check", args: [ "--check", "-c" ],
|
||||
desc: "Shows/checks updates for registered packages"
|
||||
},
|
||||
{
|
||||
cmd: "update", args: [ "--update", "-u" ], param: "group",
|
||||
desc: "Installs lates versions of registered packages"
|
||||
},
|
||||
{
|
||||
cmd: "uninstall", args: [ "--uninstall", "-u" ], param: "package",
|
||||
desc: "Deletes downloaded file and moves package to the 'skip' group"
|
||||
},
|
||||
{
|
||||
cmd: "register", args: [ "--register", "--change" ], param: "package",
|
||||
desc: "Add package infos to internal list to be able installing/updating"
|
||||
},
|
||||
{
|
||||
cmd: "remove", args: [ "--remove" ], param: "package",
|
||||
desc: ([
|
||||
"Uninstall package if needed (see `-u`)",
|
||||
"And remove it from internal list (see `--config`)"
|
||||
]).join(". ")
|
||||
}
|
||||
],
|
||||
params: {
|
||||
group: ([
|
||||
"You can label each package to update only choosen one",
|
||||
"There are sereved options:",
|
||||
" - '' (empty): these packages are includes in all groups",
|
||||
" - 'all': in case of `--update` process all packages (except skipped)",
|
||||
" - 'skip': these packages are “uninstalled”",
|
||||
" No updates will be downloaded",
|
||||
"Group can be setted via '--register'"
|
||||
]).join(". "),
|
||||
package: ([
|
||||
"Represents package identificator, it is in fact GitHub repository path",
|
||||
"So, it schould be in the form `username/repository`"
|
||||
]).join(". ")
|
||||
}
|
||||
};
|
||||
printMain();
|
||||
const current= getCurrent(process.argv.slice(2));
|
||||
(function main_(){
|
||||
const { cmd }= current.command;
|
||||
if(!cmd) return Promise.resolve("No arguments (use `--help` for showing all oprions).");
|
||||
switch(cmd){
|
||||
case "help": return Promise.resolve(printHelp());
|
||||
case "config": return vim_(info.config);
|
||||
}
|
||||
const config= getConfig();
|
||||
switch(cmd){
|
||||
case "register": return register_(config);
|
||||
}
|
||||
if(!config.packages) return Promise.resolve("No packages yet!");
|
||||
switch(cmd){
|
||||
case "check": return check_(config);
|
||||
case "update": return update_(config);
|
||||
case "uninstall":
|
||||
case "remove":
|
||||
return uninstall_(cmd, config);
|
||||
}
|
||||
})()
|
||||
.then(function(message){
|
||||
if(message)
|
||||
log(1, `Operation '${current.command.cmd}' successfull: @s_${message}`);
|
||||
process.exit();
|
||||
})
|
||||
.catch(error);
|
||||
|
||||
async function uninstall_(cmd, config){
|
||||
const progress= [
|
||||
[ "Deleting file", "not needed" ],
|
||||
[ "Check out from updates", "yes" ],
|
||||
[ "Remove from packages list", "no" ]
|
||||
];
|
||||
const pkg_name= current.param;
|
||||
const pkg_index= config.packages.findIndex(({ repository })=> repository===pkg_name);
|
||||
if(pkg_index===-1) return "nothing to do (maybe typo)";
|
||||
|
||||
const pkg= config.packages[pkg_index];
|
||||
const { downloads }= pkg;
|
||||
if(downloads&&fs.existsSync(downloads)){
|
||||
try{ fs.unlinkSync(downloads); progress[0][1]= "done"; }
|
||||
catch (_){ progress[0][1]= colors.e+"error, try manually – "+downloads; }
|
||||
}
|
||||
Reflect.deleteProperty(pkg, "last_update");
|
||||
Reflect.set(pkg, "group", "skip");
|
||||
progress[1][1]= "done";
|
||||
if(cmd!=="remove") return gotoEnd();
|
||||
|
||||
const y= await promt_(`Are you realy want to remove package ${pkg.repository} (yes/no)`, "no");
|
||||
if(y!=="yes") return gotoEnd();
|
||||
|
||||
config.packages.splice(pkg_index, 1);
|
||||
progress[2][1]= "done";
|
||||
return gotoEnd();
|
||||
|
||||
function gotoEnd(){
|
||||
const o= progress.reduce((o, [ k, v ])=> Reflect.set(o, k, v)&&o, {});
|
||||
logSection(" ", pkg_name, o);
|
||||
save(config);
|
||||
}
|
||||
}
|
||||
function vim_(file){ return new Promise(function(resolve, reject){
|
||||
const cmd= spawn((process.env.EDITOR||"vim")+(process.platform==="win32"?".bat":""), [ file ], { stdio: 'inherit' });
|
||||
cmd.on('exit', e=> e ? reject("Editor error, try manually: "+file) : resolve("OK"));
|
||||
});}
|
||||
async function update_(config){
|
||||
const filter= current.param;
|
||||
const is_all= filter==="all";
|
||||
let updates= [];
|
||||
log(1, "Collecting packages to download:");
|
||||
for(const [
|
||||
i, { repository, last_update, group, file_name, exec, downloaded, tag_name_regex }
|
||||
] of Object.entries(config.packages)){
|
||||
if(group==="skip") continue;
|
||||
if(!is_all&&group&&filter!==group) continue;
|
||||
|
||||
const { tag_name, published_at, html_url, assets_url }= await githubRelease_(repository, tag_name_regex);
|
||||
const status= packageStatus(last_update, published_at);
|
||||
if(status!==3) continue;
|
||||
|
||||
const assets= await downloadJSON_(repository, assets_url);
|
||||
if(!assets.length){
|
||||
console.log(" Nothing to download: Visit "+html_url);
|
||||
continue;
|
||||
}
|
||||
|
||||
const options= assets.map(({ name, download_count, size })=>
|
||||
`${name} | size: ${Math.round(size/1048576)}MB | downloads: ${download_count}`);
|
||||
logSection(" ", " "+repository, {
|
||||
"Version": tag_name,
|
||||
"Url": html_url
|
||||
});
|
||||
logSection(" ", " Available assets:", options);
|
||||
const choose= await promt_(" Choose (empty for skip)", "");
|
||||
if(choose==="") continue;
|
||||
|
||||
const { browser_download_url: url, name: remote_name, size }= assets[choose];
|
||||
updates.push({
|
||||
index: i,
|
||||
file_name, exec, downloaded,
|
||||
repository, version: tag_name, last_update: published_at,
|
||||
url, remote_name, size
|
||||
});
|
||||
}
|
||||
if(!updates.length){
|
||||
log(2, "No packages in "+`group ${filter} needs updates.`);
|
||||
return Promise.resolve("nothing to update");
|
||||
}
|
||||
log(1, "Downloading:");
|
||||
return applySequentially_(updates, async function(todo){
|
||||
const to= todo.file_name ? info.folder+todo.file_name : (
|
||||
todo.downloaded ? todo.downloaded : info.folder+todo.remote_name);
|
||||
const d= await downloadFile_(to, todo);
|
||||
return Object.assign(todo, d);
|
||||
})
|
||||
.then(function(dones){
|
||||
log(1, "Finalizing:");
|
||||
let e= 0;
|
||||
for(const nth of dones){
|
||||
if(!nth.success){
|
||||
e+= 1;
|
||||
log(2, `${nth.repository}: @e_${nth.message}`);
|
||||
continue;
|
||||
}
|
||||
Object.assign(config.packages[nth.index], registerDownloads(nth));
|
||||
}
|
||||
save(config);
|
||||
const { length }= dones;
|
||||
const msg= `updated ${length-e} of ${length} packages.`;
|
||||
return e ? Promise.reject(msg) : Promise.resolve(msg);
|
||||
});
|
||||
}
|
||||
function registerDownloads({ repository, last_update, message: downloads, exec, version }){
|
||||
let msg= colors.s+"OK";
|
||||
if(exec==="yes"){
|
||||
try{ fs.chmodSync(downloads, 0o755); }
|
||||
catch(e){ msg= colors.e+"try manual `chmod+x` for '"+downloads+"'"; }
|
||||
}
|
||||
log(2, `${repository}: ${msg}`);
|
||||
return { last_update, downloads, version };
|
||||
}
|
||||
async function check_({ packages }){
|
||||
let updates= 0, skipped= 0;
|
||||
for(const { repository, name, version, last_update, group, tag_name_regex } of packages){
|
||||
const { tag_name, published_at }= await githubRelease_(repository, tag_name_regex);
|
||||
const status= packageStatus(last_update, published_at);
|
||||
updates+= status===3;
|
||||
const skip= group==="skip";
|
||||
skipped+= skip;
|
||||
log(2, `@g_${repository} [${group}]: `+( !version ? "not installed" : packageStatusText(status, skip) ));
|
||||
}
|
||||
const u= updates-skipped;
|
||||
const s= skipped ? ` (inc. skipped: ${updates})` : "";
|
||||
return (!u ? "" : colors.w)+u+" update(s) available"+s;
|
||||
}
|
||||
async function register_(config){
|
||||
const { param: repository }= current;
|
||||
if(!Reflect.has(config, "packages")) Reflect.set(config, "packages", []);
|
||||
const packages= Reflect.get(config, "packages");
|
||||
let local_id= packages.findIndex(p=> p.repository===repository);
|
||||
if(local_id===-1)
|
||||
local_id= packages.push({ repository })-1;
|
||||
const local= config.packages[local_id];
|
||||
const remote= await githubRepo_(repository) || {};
|
||||
|
||||
log(1, "Registering: "+repository);
|
||||
const spaces= " ";
|
||||
local.name= await promt_(spaces+"Name", local.name || remote.name || "");
|
||||
if(!local.description) local.description= remote.description;
|
||||
logLines(2, [
|
||||
"@g_Group info:",
|
||||
"- you can update specific packages by using their group name",
|
||||
"- There some reserved options:",
|
||||
" - '' (empty): will be included in all groups",
|
||||
" - 'skip': will be always skipped"
|
||||
]);
|
||||
local.group= await promt_(spaces+"Group", local.group || "");
|
||||
local.file_name= await promt_(spaces+"File Name", local.file_name || local.name.toLowerCase().replace(/\s/g, "-") || "");
|
||||
local.exec= await promt_(spaces+"Make executable (yes/no)", local.exec || "no");
|
||||
save(config);
|
||||
return `${repository}: saved`;
|
||||
}
|
||||
function packageStatusText(status, skip){
|
||||
const s= skip ? colors.R+"skipped – "+colors.g : "";
|
||||
switch(status){
|
||||
case 0: return s+"nothing to compare";
|
||||
case 1: return s+"@s_up-to-date";
|
||||
case 2: return s+"newer";
|
||||
case 3: return s+"@e_outdated/not instaled";
|
||||
}
|
||||
}
|
||||
function packageStatus(local, remote){
|
||||
if(!remote) return 0;
|
||||
if(!local) return 3;
|
||||
if(remote===local) return 1;
|
||||
return 2+(local<remote);
|
||||
}
|
||||
function logSection(spaces, name, data){
|
||||
console.log(spaces+name);
|
||||
for(const [ key, value ] of Object.entries(data))
|
||||
console.log(spaces.repeat(2)+colors.g+key+": "+value.replace(/@(\w)_/g, (_, m)=> colors[m])+colors.R);
|
||||
}
|
||||
function githubRelease_(repository, tag_name_regex= ""){
|
||||
return downloadJSON_(repository, "https://api.github.com/repos/"+repository+"/releases")
|
||||
.then(data=> data.find(function find({ draft, published_at, tag_name }){
|
||||
if(draft||!published_at) return false;
|
||||
if(!tag_name_regex) return true;
|
||||
return (new RegExp(tag_name_regex, 'g')).test(tag_name);
|
||||
})||{});
|
||||
}
|
||||
function githubRepo_(repository){ return downloadJSON_(repository, "https://api.github.com/repos/"+repository); }
|
||||
function promt_(q, def){
|
||||
const rl= readline.createInterface({ input: process.stdin, output: process.stdout });
|
||||
return new Promise(function(resolve){
|
||||
rl.question(q+": ", a=> { rl.close(); resolve(a); });
|
||||
rl.write(def);
|
||||
});
|
||||
}
|
||||
function getConfig(){
|
||||
let config;
|
||||
try{ config= JSON.parse(fs.readFileSync(info.config)); }
|
||||
catch(e){ config= {}; log(1, "@w_Missing or corrupted config file. Creates empty one."); }
|
||||
return config;
|
||||
}
|
||||
function save(config){
|
||||
return fs.writeFileSync(info.config, JSON.stringify(config, null, " "));
|
||||
}
|
||||
function getCurrent(args){
|
||||
let command, command_arg, param;
|
||||
const hasArg= arg=> ({ args })=> args.includes(arg);
|
||||
for(let i=0, { length }= args, arg; i<length; i++){
|
||||
arg= args[i];
|
||||
if(!command){
|
||||
command= info.commands.find(hasArg(arg));
|
||||
command_arg= arg;
|
||||
continue;
|
||||
}
|
||||
if(!command.param||typeof param!=="undefined")
|
||||
break;
|
||||
param= arg;
|
||||
}
|
||||
if(!command)
|
||||
command= { cmd: "" };
|
||||
if(command.param&&typeof param==="undefined")
|
||||
return error(`Missign arguments for '${command_arg}'.`);
|
||||
return { command, param };
|
||||
}
|
||||
function downloadJSON_(repository, url){
|
||||
return downloadText_(url)
|
||||
.then(function(data){
|
||||
try{
|
||||
const response= JSON.parse(data);
|
||||
if(Reflect.has(response, "message")) throw new Error(response.message);
|
||||
return Promise.resolve(JSON.parse(data));
|
||||
} catch(e){
|
||||
log(1, "Received data: "+data);
|
||||
log(1, "@e_"+e);
|
||||
return Promise.reject(`JSON from '${repository}' failed.`);
|
||||
}
|
||||
});
|
||||
}
|
||||
function downloadText_(url){
|
||||
return get_(url)
|
||||
.then(function(response){ return new Promise(function(resolve){
|
||||
let data= "";
|
||||
response.on("data", chunk=> data+= chunk);
|
||||
response.on("end", ()=> resolve(data));
|
||||
}); });
|
||||
}
|
||||
function downloadFile_(to, { url, repository, size }){
|
||||
const file= fs.createWriteStream(to);
|
||||
return get_(url)
|
||||
.then(r=> get_(r.headers.location))
|
||||
.then(function(response){ return new Promise(function(resolve){
|
||||
let progress= 0, pc_prev= 0, avg= 0;
|
||||
const start= new Date();
|
||||
const i= setInterval(function(){
|
||||
readline.clearLine(process.stdout);
|
||||
const pc= (100*progress/size).toFixed(2);
|
||||
if(!pc_prev) pc_prev= pc;
|
||||
else {
|
||||
avg= ((100-pc)/(60*(pc-pc_prev))).toFixed(2);
|
||||
pc_prev= 0;
|
||||
}
|
||||
const running= ((new Date()-start)/60000).toFixed(2);
|
||||
log(2, repository+": "+pc+"%"+` (end in ~${avg} mins, running ${running} mins)`);
|
||||
readline.moveCursor(process.stdout, 0, -1);
|
||||
}, 500);
|
||||
response.on('data', function(chunk){
|
||||
file.write(chunk);
|
||||
progress+= chunk.length;
|
||||
});
|
||||
response.on('end', function(){
|
||||
clearInterval(i);
|
||||
readline.clearLine(process.stdout);
|
||||
log(2, repository+": @s_OK");
|
||||
file.close(()=> resolve({ success: 1, message: to })); /* close() is async, call cb after close completes. */
|
||||
});
|
||||
}); })
|
||||
.catch(({ message })=> {
|
||||
fs.unlink(to); // Delete the file async. (But we don't check the result)
|
||||
return { success: 0, message };
|
||||
});
|
||||
}
|
||||
function get_(url){ return new Promise(function(resolve, reject){
|
||||
https.get(
|
||||
url,
|
||||
{ headers: { 'Cache-Control': 'no-cache', 'User-Agent': 'node' } },
|
||||
resolve
|
||||
).on("error", reject);
|
||||
});}
|
||||
function applySequentially_(input, pF){
|
||||
const data= [];
|
||||
let p= pF(input[0]);
|
||||
const tie= nth=> result_mth=> ( data.push(result_mth), pF(input[nth]) );
|
||||
for(let i= 1, { length }= input; i<length; i++)
|
||||
p= p.then(tie(i));
|
||||
return p.then(o=> (data.push(o), data));
|
||||
}
|
||||
function error(message){
|
||||
const help_text= `@w_See help using '${info.commands[0].args[0]}'.`;
|
||||
log(1, `@e_Error: ${message} ${help_text}`);
|
||||
return process.exit(1);
|
||||
}
|
||||
function printMain(){
|
||||
const { name, version, description }= info;
|
||||
log(1, `@w_${name}@${version}`);
|
||||
log(1, description);
|
||||
const cmds= info.commands.map(({args})=> args[0].replace("--", "")).join(", ");
|
||||
log(1, `@w_Usage: ${name} --[cmd] [param]`);
|
||||
log(2, `…cmd: ${cmds}`);
|
||||
log(2, "…param: Based on cmd\n");
|
||||
}
|
||||
function printHelp(){
|
||||
log(1, "@s_Help:");
|
||||
log(2, "Commands:");
|
||||
info.commands.forEach(({ args, param, desc })=> {
|
||||
const args_text= args.join("|");
|
||||
param= param ? " "+param : "";
|
||||
log(3, `@g_${args_text}@R_${param}`);
|
||||
logLines(4, desc);
|
||||
});
|
||||
log(2, "Params:");
|
||||
for(const [ param, desc ] of Object.entries(info.params)){
|
||||
log(3, `@g_${param}`);
|
||||
logLines(4, desc);
|
||||
}
|
||||
}
|
||||
function log(tab, text){
|
||||
return console.log(" ".repeat(tab)+text.replace(/@(\w)_/g, (_, m)=> colors[m])+colors.R);
|
||||
}
|
||||
function logLines(tab, multiline_text){
|
||||
if(!Array.isArray(multiline_text)) multiline_text= multiline_text.split(/(?<=\.) /g);
|
||||
return log(tab, multiline_text.join("\n"+" ".repeat(tab)));
|
||||
}
|
216
bin/github-releases.json
Normal file
216
bin/github-releases.json
Normal file
@ -0,0 +1,216 @@
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"repository": "shiftkey/desktop",
|
||||
"name": "GitHub Desktop",
|
||||
"group": "dev",
|
||||
"file_name": "github-desktop",
|
||||
"exec": "yes",
|
||||
"description": "Fork of GitHub Desktop to support various Linux distributions",
|
||||
"last_update": "2023-12-20T15:25:06Z",
|
||||
"downloads": "/home/jaandrle/bin/github-desktop",
|
||||
"version": "release-3.3.6-linux3"
|
||||
},
|
||||
{
|
||||
"repository": "jaandrle/jaaCSS-cli",
|
||||
"name": "jaaCSS",
|
||||
"description": "EXPERIMENT – Helper for managing functional CSS classes",
|
||||
"group": "dev",
|
||||
"file_name": "jaaCSS.js",
|
||||
"exec": "yes",
|
||||
"downloads": "/home/jaandrle/bin/jaaCSS.js",
|
||||
"version": "v1.3.2",
|
||||
"last_update": "2022-09-02T13:33:16Z"
|
||||
},
|
||||
{
|
||||
"repository": "th-ch/youtube-music",
|
||||
"name": "youtube-music",
|
||||
"description": "YouTube Music Desktop App bundled with custom plugins (and built-in ad blocker / downloader)",
|
||||
"group": "nondev",
|
||||
"file_name": "youtube-music",
|
||||
"exec": "yes",
|
||||
"last_update": "2024-01-05T14:44:27Z",
|
||||
"downloads": "/home/jaandrle/bin/youtube-music",
|
||||
"version": "v3.2.2"
|
||||
},
|
||||
{
|
||||
"repository": "ArchGPT/insomnium",
|
||||
"name": "insomnium",
|
||||
"description": "Insomnium is a fast local API testing tool that is privacy-focused and 100% local. For testing GraphQL, REST, WebSockets and gRPC. This is a fork of Kong/insomnia",
|
||||
"group": "dev",
|
||||
"file_name": "insomnium",
|
||||
"exec": "yes",
|
||||
"last_update": "2023-11-13T10:03:28Z",
|
||||
"downloads": "/home/jaandrle/bin/insomnium",
|
||||
"tag_name_regex": "core@.*",
|
||||
"version": "core@0.2.3-a"
|
||||
},
|
||||
{
|
||||
"repository": "Kong/insomnia",
|
||||
"name": "insomnia",
|
||||
"description": "The open-source, cross-platform API client for GraphQL, REST, and gRPC.",
|
||||
"group": "skip",
|
||||
"file_name": "insomnia",
|
||||
"exec": "yes",
|
||||
"last_update": "2023-10-16T10:03:28Z",
|
||||
"downloads": "/home/jaandrle/bin/insomnia",
|
||||
"tag_name_regex": "core@.*",
|
||||
"version": "core@8.3.0"
|
||||
},
|
||||
{
|
||||
"repository": "rvpanoz/luna",
|
||||
"name": "luna",
|
||||
"description": "Manage npm dependencies through a modern UI.",
|
||||
"group": "skip",
|
||||
"file_name": "luna",
|
||||
"exec": "yes"
|
||||
},
|
||||
{
|
||||
"repository": "angela-d/wifi-channel-watcher",
|
||||
"name": "wifi-channel-watcher",
|
||||
"group": "skip",
|
||||
"file_name": "wifi-channel-watcher",
|
||||
"exec": "no",
|
||||
"description": "Monitor channel usage of neighboring routers & get an alert if your active channel is not optimal.\tTroubleshoot wifi without lifting a finger!"
|
||||
},
|
||||
{
|
||||
"repository": "vinceliuice/Tela-circle-icon-theme",
|
||||
"name": "Tela-circle-icon-theme",
|
||||
"description": "Tela-circle-icon-theme",
|
||||
"group": "themes",
|
||||
"file_name": "tela-circle-icon-theme.zip",
|
||||
"last_update": "2021-07-19T14:12:05Z",
|
||||
"exec": "no"
|
||||
},
|
||||
{
|
||||
"repository": "AppImage/AppImageKit",
|
||||
"name": "AppImageKit",
|
||||
"group": "skip",
|
||||
"file_name": "appimagekit",
|
||||
"exec": "yes",
|
||||
"description": "Package desktop applications as AppImages that run on common Linux-based operating systems, such as RHEL, CentOS, openSUSE, SLED, Ubuntu, Fedora, debian and derivatives. Join #AppImage on irc.freenode.net"
|
||||
},
|
||||
{
|
||||
"repository": "dynobo/normcap",
|
||||
"name": "NormCap",
|
||||
"description": "OCR powered screen-capture tool to capture information instead of images",
|
||||
"group": "nondev",
|
||||
"file_name": "normcap",
|
||||
"exec": "yes",
|
||||
"last_update": "2023-12-12T22:23:37Z",
|
||||
"downloads": "/home/jaandrle/bin/normcap",
|
||||
"version": "v0.5.2"
|
||||
},
|
||||
{
|
||||
"repository": "upscayl/upscayl",
|
||||
"name": "upscayl",
|
||||
"description": "🆙 Upscayl - Free and Open Source AI Image Upscaler for Linux, MacOS and Windows built with Linux-First philosophy.",
|
||||
"group": "nondev",
|
||||
"file_name": "upscayl",
|
||||
"exec": "yes",
|
||||
"last_update": "2024-01-16T09:54:25Z",
|
||||
"downloads": "/home/jaandrle/bin/upscayl",
|
||||
"version": "v2.9.8"
|
||||
},
|
||||
{
|
||||
"repository": "RasmusLindroth/tut",
|
||||
"name": "tut",
|
||||
"description": "TUI for Mastodon with vim inspired keys",
|
||||
"group": "nondev",
|
||||
"file_name": "tut",
|
||||
"exec": "yes",
|
||||
"last_update": "2023-01-26T17:48:00Z",
|
||||
"downloads": "/home/jaandrle/bin/tut",
|
||||
"version": "2.0.1"
|
||||
},
|
||||
{
|
||||
"repository": "sunner/ChatALL",
|
||||
"name": "ChatALL",
|
||||
"description": " Concurrently chat with ChatGPT, Bing Chat, bard, Alpaca, Vincuna, Claude, ChatGLM, MOSS, iFlytek Spark, ERNIE and more, discover the best answers",
|
||||
"group": "skip",
|
||||
"file_name": "chatall",
|
||||
"exec": "yes",
|
||||
"last_update": "2023-09-30T14:08:00Z",
|
||||
"downloads": "/home/jaandrle/bin/chatall",
|
||||
"version": "v1.50.73"
|
||||
},
|
||||
{
|
||||
"repository": "jaandrle/bs",
|
||||
"name": "bs",
|
||||
"description": "The simplest possible build system using executables",
|
||||
"group": "dev",
|
||||
"file_name": "bs",
|
||||
"exec": "yes",
|
||||
"last_update": "2023-06-30T07:48:58Z",
|
||||
"downloads": "/home/jaandrle/bin/bs",
|
||||
"version": "v0.7.3"
|
||||
},
|
||||
{
|
||||
"repository": "h3poteto/fedistar",
|
||||
"name": "Fedistar",
|
||||
"description": "Multi-column Mastodon, Pleroma, and Friendica client for desktop",
|
||||
"group": "nondev",
|
||||
"file_name": "fedistar",
|
||||
"exec": "yes",
|
||||
"last_update": "2024-01-29T10:29:58Z",
|
||||
"downloads": "/home/jaandrle/bin/fedistar",
|
||||
"version": "v1.8.3"
|
||||
},
|
||||
{
|
||||
"repository": "ollama/ollama",
|
||||
"name": "ollama",
|
||||
"description": "Get up and running with Llama 2 and other large language models locally",
|
||||
"group": "ai",
|
||||
"file_name": "ollama",
|
||||
"exec": "yes",
|
||||
"last_update": "2024-01-26T18:19:36Z",
|
||||
"downloads": "/home/jaandrle/bin/ollama",
|
||||
"version": "v0.1.22"
|
||||
},
|
||||
{
|
||||
"repository": "neovim/neovim",
|
||||
"name": "neovim",
|
||||
"tag_name_regex": "v.*",
|
||||
"description": "Vim-fork focused on extensibility and usability",
|
||||
"group": "dev-test",
|
||||
"file_name": "nvim",
|
||||
"exec": "yes",
|
||||
"downloads": "/home/jaandrle/bin/nvim",
|
||||
"version": "v0.9.5",
|
||||
"last_update": "2023-12-30T13:31:47Z"
|
||||
},
|
||||
{
|
||||
"repository": "viarotel-org/escrcpy",
|
||||
"name": "Escrcpy",
|
||||
"description": "📱 Graphical Scrcpy to display and control Android, devices powered by Electron. | 使用图形化的 Scrcpy 显示和控制您的 Android 设备,由 Electron 驱动。",
|
||||
"group": "dev",
|
||||
"file_name": "escrcpy",
|
||||
"exec": "yes",
|
||||
"last_update": "2023-12-27T01:18:21Z",
|
||||
"downloads": "/home/jaandrle/bin/escrcpy",
|
||||
"version": "v1.16.8"
|
||||
},
|
||||
{
|
||||
"repository": "drovp/drovp",
|
||||
"name": "drovp",
|
||||
"description": "Desktop app for encoding, converting, upscaling, and much more.",
|
||||
"group": "dev-test",
|
||||
"file_name": "drovp",
|
||||
"exec": "yes",
|
||||
"last_update": "2023-12-06T11:30:02Z",
|
||||
"downloads": "/home/jaandrle/bin/drovp",
|
||||
"version": "0.8.0"
|
||||
},
|
||||
{
|
||||
"repository": "janhq/jan",
|
||||
"name": "Jan",
|
||||
"description": "Jan is an open source alternative to ChatGPT that runs 100% offline on your computer",
|
||||
"group": "ai",
|
||||
"file_name": "jan",
|
||||
"exec": "yes",
|
||||
"last_update": "2024-01-29T05:19:22Z",
|
||||
"downloads": "/home/jaandrle/bin/jan",
|
||||
"version": "v0.4.5"
|
||||
}
|
||||
]
|
||||
}
|
8
bin/jsconfig.json
Normal file
8
bin/jsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"include": [
|
||||
"/home/jaandrle/.nvm/versions/node/v18.18.0/lib/node_modules/nodejsscript/index.d.ts",
|
||||
"./*.mjs",
|
||||
"./*.js",
|
||||
"chrome-autoinspect.mjs"
|
||||
]
|
||||
}
|
19
bin/nocodb.mjs
Executable file
19
bin/nocodb.mjs
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */
|
||||
const url_api= "https://nocodb.jaandrle.cz/api/v1/db/data/v1/Linky/Linky";
|
||||
$.api()
|
||||
.command("add-md")
|
||||
.action(async function addMd(){
|
||||
const { clipboard }= $;
|
||||
const [ title, url ]= clipboard.split("](");
|
||||
|
||||
const res= await fetch(url_api, {
|
||||
body: JSON.stringify({ Popis: title.slice(1), Url: url.slice(0, -1) }),
|
||||
headers: { "xc-token": "Js7Qu0oT_wTmGJDFKlIZEBhwk87WF0L1wLmQO01F",
|
||||
"accept": "application/json", "Content-Type": "application/json"
|
||||
},
|
||||
method: "post"
|
||||
}).then(res=>res.json());
|
||||
echo(res);
|
||||
})
|
||||
.parse();
|
9
bin/onedrive
Executable file
9
bin/onedrive
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
if [[ $(mount | grep OneDrive) ]]; then
|
||||
fusermount -uz ~/Vzdálené/OneDrive
|
||||
notify-send -i system-file-manager "OneDrive disk ODPOJEN"
|
||||
else
|
||||
rclone --vfs-cache-mode full mount "onedrive": ~/Vzdálené/OneDrive &
|
||||
dolphin ~/Vzdálené/OneDrive/ &
|
||||
notify-send -i system-file-manager "OneDrive disk PŘIPOJEN"
|
||||
fi
|
71
bin/piper.mjs
Executable file
71
bin/piper.mjs
Executable file
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */
|
||||
const p_home= $.xdg.home`Applications/piper/`
|
||||
const p_models= p_home+"models/"
|
||||
|
||||
$.api("", true)
|
||||
.version("2023-05-31")
|
||||
.describe([
|
||||
"This is a wrapper around the piper CLI.",
|
||||
"It allows you to get the list of available models, or to simplify `piper` callings.",
|
||||
"",
|
||||
"Visit: https://github.com/rhasspy/piper",
|
||||
"Original help:",
|
||||
...s.$().run`${p_home}piper --help`.stderr.split("\n").filter(Boolean).map(l=> "\t"+l)
|
||||
])
|
||||
.option("--models", "prints available models")
|
||||
.option("--model, -m", "chooses voice model by it's index or by text search (full name)")
|
||||
.option("--input_file, -I", "path to input text file (defaults to stdin)")
|
||||
.action(function main({
|
||||
models: is_models,
|
||||
model= 0,
|
||||
input_file,
|
||||
_,
|
||||
...pass
|
||||
}){
|
||||
if(is_models){
|
||||
models()
|
||||
.forEach(l=> echo(l));
|
||||
echo(helpTextModels("…for more models"))
|
||||
$.exit(0);
|
||||
}
|
||||
model= getModel(model);
|
||||
pass= Object.entries(pass)
|
||||
.map(([ name, value ])=> `${name.length > 1 ? "--" : "-"}${name} '${value}'`)
|
||||
.join(" ");
|
||||
const o= s.run(`echo ${text(input_file)} | ${p_home}piper --model ${model} ${pass}`);
|
||||
$.exit(o.code);
|
||||
})
|
||||
.parse();
|
||||
|
||||
function text(input_file){
|
||||
const candidate= input_file ? s.cat(input_file).stdout : $.stdin.text();
|
||||
if(typeof candidate!=="string")
|
||||
$.error("Missing input text file or piped text. Use `--help` for more information.");
|
||||
return "'"+candidate.trim().replaceAll("\n", "\t — \t").replaceAll("'", "\"")+"'";
|
||||
}
|
||||
function getModel(identifier){
|
||||
const candidate= typeof identifier==="number" ?
|
||||
models()[identifier] :
|
||||
models().find(l=> l.includes(identifier));
|
||||
if(!candidate)
|
||||
$.error([
|
||||
`Model identifier '${identifier}' seems not to matching any existing model.`,
|
||||
"Try `--models` to see all available models."
|
||||
].join("\n"));
|
||||
return candidate.slice(candidate.indexOf(" ")+1);
|
||||
}
|
||||
function models(){
|
||||
const out= s.ls(`${p_models}*.onnx`)
|
||||
.map((l, n)=> `${n}: ${l}`);
|
||||
if(!out.length)
|
||||
$.error(helpTextModels("No available models."));
|
||||
return out;
|
||||
}
|
||||
function helpTextModels(...text_initial){
|
||||
return [
|
||||
...text_initial,
|
||||
"Visits https://github.com/rhasspy/piper",
|
||||
"and download/extract model(s) into "+p_models
|
||||
].join("\n");
|
||||
}
|
10
bin/pocket-sh-add.sh
Executable file
10
bin/pocket-sh-add.sh
Executable file
@ -0,0 +1,10 @@
|
||||
[ ! -r ~/.config/pocketshaddrc ] && echo "\`~/.config/pocketshaddrc\` not found" && exit 1
|
||||
. ~/.config/pocketshaddrc
|
||||
|
||||
curl -sS -X POST \
|
||||
-F "url=$1" \
|
||||
-F "title=$2" \
|
||||
-F "consumer_key=$CONSUMER_KEY" \
|
||||
-F "access_token=$ACCESS_TOKEN" \
|
||||
https://getpocket.com/v3/add \
|
||||
> /dev/null
|
80
bin/socky.mjs
Executable file
80
bin/socky.mjs
Executable file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */
|
||||
|
||||
$.api("")
|
||||
.version("2023-08-11")
|
||||
.command("textInImage [file]", "Generovat obrázek s textem pro sdílení na sociálních sítích.")
|
||||
.alias("tii")
|
||||
.option("--pointsize", "Text size", "62")
|
||||
.option("--gravity", "`convert -list gravity`", "Center")
|
||||
.option("--text", "Text")
|
||||
.action(textInImage)
|
||||
.command("textSplit <file>", "Rozdělit text dle zadaného limitu.")
|
||||
.alias("ts")
|
||||
.option("--limit", "Počet znaků kde text rozdělovat.", 500)
|
||||
.option("--counter", "Prepend counter, set no. of chars of counter.", 5)
|
||||
.option("--text", "Text")
|
||||
.action(textSplit)
|
||||
.parse();
|
||||
|
||||
function textSplit(file, { limit, counter, text }){
|
||||
limit= parseInt(limit) - parseInt(counter);
|
||||
const words= getText(file, text).split(" ");
|
||||
let buffer= [], i= -1, chars= limit;
|
||||
for(const word of words){
|
||||
const { length }= word;
|
||||
if((chars+length) < limit){
|
||||
chars+= ( is_empty ? 0 : 1 ) + length;
|
||||
buffer[i].end= i;
|
||||
continue;
|
||||
}
|
||||
chars= 0;
|
||||
i+= 1;
|
||||
buffer[i]= { start: i };
|
||||
}
|
||||
const { length }= buffer;
|
||||
echo(buffer.map(function({ start, end }, i){
|
||||
return (i+1)+"/"+length+" "+words.slice(start, end).join(" ");
|
||||
}).join("\n============\n"));
|
||||
$.exit(0);
|
||||
}
|
||||
function textInImage(file, { text, gravity, pointsize }){
|
||||
text= getText(file, text);
|
||||
const output= !file ? "textInImage.png" : (({ pathname: p })=> p.slice(1, p.lastIndexOf(".")+1)+"png")(new URL(file, "file://"));
|
||||
const round_corners= [ //https://9to5answer.com/rounding-corners-of-pictures-with-imagemagick
|
||||
"\\(",
|
||||
"+clone -alpha extract",
|
||||
"-draw 'fill black polygon 0,0 0,15 15,0 fill white circle 15,15 15,0'",
|
||||
"\\( +clone -flip \\) -compose Multiply -composite",
|
||||
"\\( +clone -flop \\) -compose Multiply -composite",
|
||||
"\\) -alpha off -compose CopyOpacity -composite",
|
||||
].join(" ");
|
||||
s.run([
|
||||
"convert",
|
||||
"\\(",
|
||||
"-size ::size::",
|
||||
"-pointsize ::pointsize::",
|
||||
"-fill ::fill:: -background ::background::",
|
||||
"-gravity ::gravity::",
|
||||
"-family ::family:: -weight Bold",
|
||||
"-bordercolor ::background:: -border 5%",
|
||||
"caption:::text::",
|
||||
"\\)",
|
||||
round_corners,
|
||||
"::output::"
|
||||
].join(" "), {
|
||||
fill: "whitesmoke",
|
||||
background: "#2b2b2b",
|
||||
size: "1024x512",
|
||||
family: "Ubuntu Mono",
|
||||
output, text, gravity, pointsize
|
||||
});
|
||||
$.exit(0);
|
||||
}
|
||||
function getText(file, text){
|
||||
if(file && s.test("-f", file))
|
||||
return s.cat(file).toString();
|
||||
if(!text)
|
||||
return $.stdin.text().trim();
|
||||
return text;
|
||||
}
|
119
bin/uu
Executable file
119
bin/uu
Executable file
@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
this="${0##*/}"
|
||||
version="2022-07-27"
|
||||
config_file="$HOME/.config/${this}rc"
|
||||
[ ! -t 0 ] && exo-open --launch TerminalEmulator -- -e "$this $*" && exit 0
|
||||
|
||||
arg=${1:---help}
|
||||
if [[ "$arg" = "--completion-bash" ]]; then
|
||||
echo "_${this}_completion(){
|
||||
local cur=\"\${COMP_WORDS[COMP_CWORD]}\"
|
||||
local com_basic=\"--alias --help --version --tips\"
|
||||
local com_urls=\"cht.sh wttr.in rate.sx qrenco.de ifconfig.co\"
|
||||
if [[ \$COMP_CWORD != 1 ]]; then
|
||||
local com_web=\"\"
|
||||
case \"\${COMP_WORDS[1]}\" in
|
||||
--raw)
|
||||
COMPREPLY=( \$(compgen -W \"\$com_urls \$com_basic\" -- \"\$cur\" ) )
|
||||
return 0;
|
||||
;;
|
||||
--alias)
|
||||
COMPREPLY=( \$(compgen -W \"? + -\" -- \"\$cur\" ) )
|
||||
return 0;
|
||||
;;
|
||||
wttr.in)
|
||||
local com_web+=\"moon m u M 0 1 2 A F n q Q T\"
|
||||
;;
|
||||
ifconfig.co)
|
||||
local com_web+=\"json\"
|
||||
;;
|
||||
cht.sh)
|
||||
local com_web+=\"\$(compgen -c)\"
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=( \$(compgen -W \":help \$com_web\" -- \"\$cur\" ) )
|
||||
return 0;
|
||||
fi
|
||||
|
||||
COMPREPLY=( \$(compgen -W \"--raw \$com_urls \$com_basic\" -- \"\$cur\" ) )
|
||||
}
|
||||
complete -o bashdefault -o default -F _${this}_completion ${this}
|
||||
"
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
_echo(){ [[ $is_raw == 1 ]] && echo -e "$1" || echo "$1" | less -R -S; }
|
||||
[[ "$arg" = "--raw" ]] && is_raw=1 && command shift && arg=${1:---help} || is_raw=0
|
||||
|
||||
if [[ "$arg" = "--help" ]]; then
|
||||
_echo "\
|
||||
$this@v$version – URL UTILS
|
||||
This is helper around \`curl\` to run web-based commands such as 'wttr.in', 'cht.sh', …
|
||||
Usage:
|
||||
$this [--raw] BASE_URL [PARAMS]
|
||||
$this [--raw] --[help|version|tips]
|
||||
$this [--raw] --alias NAME +|-|? FULL_URL
|
||||
|
||||
Options:
|
||||
--raw – no output using \`less\`
|
||||
--alias – you can also use vars '\\\$1', …
|
||||
PARAMS – parameters to be concatenated with BASE_URL with '/' or '?'/'&' when parameter starts with '?' … se below
|
||||
Examples:
|
||||
$this cht.sh/less $this cht.sh less
|
||||
$this wttr.in/prague?M&n $this wttr.in prague ?M ?n
|
||||
$this --raw ident.me/json | jq
|
||||
Config file:
|
||||
$config_file
|
||||
"
|
||||
exit 0
|
||||
fi
|
||||
[[ "$arg" = "--version" ]] && echo "$version" && exit 0
|
||||
if [[ "$arg" = "--tips" ]]; then
|
||||
_echo "\
|
||||
cht.sh – The only cheat sheet you need Unified access to the best community driven documentation repositories of the world.
|
||||
wttr.in – Weather report
|
||||
rate.sx – show exchange rates for cryptocurrencies
|
||||
qrenco.de
|
||||
ifconfig.co
|
||||
https://github.com/chubin/awesome-console-services/tree/65e8e897c9c5a2ec013747dd9f1acc03c8573fe7
|
||||
"
|
||||
exit 0
|
||||
fi
|
||||
command shift
|
||||
|
||||
if [[ "$arg" == "--alias" ]]; then
|
||||
alias_name="${1:-[^_]*}"
|
||||
[[ $alias_name == *.* ]] && echo "Alias should not contains '.'" && exit 1
|
||||
case "$2" in
|
||||
"+")
|
||||
out=$(grep -v -e "uu_${alias_name}_alias=" -e "uu_${alias_name}_is_raw=" $config_file)
|
||||
out="$out\nuu_${alias_name}_alias=\"$3\""
|
||||
out="$out\nuu_${alias_name}_is_raw=$is_raw"
|
||||
echo -e "$out" > $config_file
|
||||
exit 0
|
||||
;;
|
||||
"-") echo -e "$(grep -v -e "uu_${alias_name}_alias=" -e "uu_${alias_name}_is_raw=" $config_file)" > $config_file || echo "No aliases yet"; exit 0;;
|
||||
*) grep -e "uu_${alias_name}_alias=" -e "uu_${alias_name}_is_raw=" $config_file || echo "No aliases yet"; exit 0;;
|
||||
esac
|
||||
exit 1
|
||||
fi
|
||||
|
||||
args=""
|
||||
if [[ $arg != *.* ]]; then
|
||||
. $config_file
|
||||
is_raw_name=uu_${arg}_is_raw
|
||||
is_raw=${!is_raw_name}
|
||||
|
||||
[[ -z $is_raw ]] && echo "No alias '$arg' found." && exit 1
|
||||
arg_name=uu_${arg}_alias
|
||||
arg=${!arg_name}
|
||||
else
|
||||
for p in "$@"; do
|
||||
[[ $p == "?"* ]] \
|
||||
&& args+=" --data-urlencode ${p:1} " \
|
||||
|| arg+="/$p"
|
||||
done
|
||||
fi
|
||||
out=$(curl -fGsS -H 'Accept-Language: cs' $args --compressed $arg || echo 'Curl error, see terminal error output.')
|
||||
_echo "$out"
|
159
bin/§ai-commit.mjs
Executable file
159
bin/§ai-commit.mjs
Executable file
@ -0,0 +1,159 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */
|
||||
$.is_fatal= true;
|
||||
const token_file= "~/.config/openai.token";
|
||||
let token;
|
||||
const gitmoji_list= {
|
||||
build: "building_construction",
|
||||
chore: "bricks",
|
||||
ci: "construction_worker",
|
||||
docs: "memo",
|
||||
feat: "sparkles",
|
||||
fix: "bug",
|
||||
perf: "zap",
|
||||
refactor: "recycle",
|
||||
revert: "rewind",
|
||||
style: "art",
|
||||
test: "white_check_mark"
|
||||
};
|
||||
const git3moji_list= {
|
||||
build: "tv",
|
||||
chore: "tv",
|
||||
ci: "tv",
|
||||
docs: "abc",
|
||||
feat: "zap",
|
||||
fix: "bug",
|
||||
perf: "zap",
|
||||
refactor: "cop",
|
||||
style: "zap",
|
||||
test: "cop"
|
||||
};
|
||||
const conventional_desc= [
|
||||
"Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)",
|
||||
"Other changes that don't modify src or test files",
|
||||
"Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)",
|
||||
"Documentation only changes",
|
||||
"A new feature",
|
||||
"A bug Fix",
|
||||
"A code change that improves performance",
|
||||
"A code change that neither fixes a bug nor adds a feature",
|
||||
"Reverts a previous commit",
|
||||
"Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)",
|
||||
"Adding missing tests or correcting existing tests"
|
||||
];
|
||||
|
||||
$.api("", true)
|
||||
.version("2024-02-19")
|
||||
.describe([
|
||||
"Utility to use ChatGPT to generate a commit message from COMMIT_EDITMSG file.",
|
||||
`Don't forget to set the token in ${token_file} file.`,
|
||||
"",
|
||||
"Conventional/gitmoji commits should follow https://www.conventionalcommits.org/en/v1.0.0/ (https://github.com/pvdlg/conventional-commit-types).",
|
||||
"For the gitmoji the <type> uses emojis as follows:",
|
||||
...Object.entries(gitmoji_list).map(( v, i )=> echo.format("%c"+v[0]+` (${v[1]}): ${conventional_desc[i]}`, "display: list-item")),
|
||||
...Object.entries(git3moji_list).map(( v, i )=> echo.format("%c"+v[0]+` (${v[1]}): ${conventional_desc[i]}`, "display: list-item"))
|
||||
])
|
||||
.option("--format, -f", [ "Use one of the following formats to generate the commit message: [regular (default), conventional, gitmoji, git3moji]",
|
||||
"For gitmoji see: https://gitmoji.dev/"
|
||||
])
|
||||
.action(async function({ format= "regular" }= {}){
|
||||
const question= questionChatGPT(format);
|
||||
const response= (await pipe(
|
||||
()=> s.cat("./.git/COMMIT_EDITMSG"),
|
||||
s=> s.slice(s.indexOf("diff --git")),
|
||||
diffToChunks(3900-545), //the worst scenario of ★ +new lines
|
||||
ch=> ch.map(pipe( question, requestCommitMessage )),
|
||||
ch=> Promise.all(ch)
|
||||
)())
|
||||
.map(pipe(
|
||||
j=> j.choices[0].text.trim(),
|
||||
t=> t.match(/\[[^\]]*\]/) ?? convertToJSONArray(t),
|
||||
JSON.parse,
|
||||
format==="regular" ? i=> i : i=> gitmoji(i, format==="git3moji"),
|
||||
a=> a.join("\n")
|
||||
))
|
||||
.join("\n\n");
|
||||
echo(response);
|
||||
$.exit(0);
|
||||
})
|
||||
.parse();
|
||||
|
||||
function diffToChunks(max_tokens){ return function(input){
|
||||
if(input.length < max_tokens)
|
||||
return [ input ];
|
||||
|
||||
return input.split(/(?=diff --git)/g)
|
||||
.flatMap(function(input){
|
||||
if(input.length < max_tokens)
|
||||
return [ input ];
|
||||
|
||||
const [ file, ...diffs ]= input.split(/\n(?=@@)/g);
|
||||
if(file.includes("new file"))
|
||||
return [ file ];
|
||||
return diffs
|
||||
.filter(chunk=> chunk.length < max_tokens)
|
||||
.reduce(function(chunks, chunk){
|
||||
const i= chunks.length-1;
|
||||
if(chunks[i].length + chunk.length < max_tokens-1)
|
||||
chunks[i]+= "\n"+chunk;
|
||||
else
|
||||
chunks.push(file+"\n"+chunk);
|
||||
return chunks;
|
||||
}, [ file ])
|
||||
.filter(chunk=> chunk.length < max_tokens);
|
||||
});
|
||||
}; }
|
||||
function convertToJSONArray(text){
|
||||
const arr= text.split("\n")
|
||||
.filter(line=> line.trim().match(/^[1-3]\. /))
|
||||
.map(line=> line.slice(3))
|
||||
.map(line => line.startsWith('"') ? line : "\"" + ( "'`".slice("").includes(line[0]) ? line.slice(1, -1) : line ) + "\"");
|
||||
return `[${arr.join(", ")}]`;
|
||||
}
|
||||
function questionChatGPT(format){ return function(diff){
|
||||
const msg= [
|
||||
[
|
||||
"I would like to ask you to act like a git commit message writer.",
|
||||
"I will enter a git diff, and your job is to convert it into a useful commit message and make 3 options as JSON array.",
|
||||
"Do not preface the commit with anything, use a concise, precise, present-tense, complete sentence.",
|
||||
"The length should be fewer than 50 characters if possible.",
|
||||
].join(" ") //340chars★
|
||||
];
|
||||
if(format!=="regular")
|
||||
msg.push(
|
||||
[
|
||||
"It should follow the conventional commits.",
|
||||
"The format is <type in lowercase>: <description>.",
|
||||
"A type can be one of the following: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, or test.",
|
||||
].join(" ") //203chars★
|
||||
);
|
||||
msg.push("", diff);
|
||||
return msg.join("\n");
|
||||
}; }
|
||||
function gitmoji(candidates, is_three= false){
|
||||
return candidates.map(message=> message.trim().replace(/^[^:]*:/, toGitmoji));
|
||||
|
||||
function toGitmoji(name){
|
||||
const candidate= ( is_three ? git3moji_list : gitmoji_list )[name.slice(0, -1)];
|
||||
return !candidate ? name : `:${candidate}:`;
|
||||
}
|
||||
}
|
||||
function requestCommitMessage(prompt){
|
||||
if(!token) token= s.cat(token_file).stdout.trim();
|
||||
const model= "text-davinci-003";
|
||||
return fetch(`https://api.openai.com/v1/engines/${model}/completions`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer "+token
|
||||
},
|
||||
body: JSON.stringify({
|
||||
max_tokens: 1000,
|
||||
temperature: 0.1,
|
||||
prompt
|
||||
}),
|
||||
signal: AbortSignal.timeout(10000)
|
||||
}).then(r=> r.json());
|
||||
}
|
||||
// vim: set tabstop=4 shiftwidth=4 textwidth=250 noexpandtab :
|
||||
// vim>60: set foldmethod=indent foldlevel=1 foldnestmax=2:
|
26
bin/§awk
Executable file
26
bin/§awk
Executable file
@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
this="${0##*/}"
|
||||
USAGE="\
|
||||
usage: $this [<awk_args>] <field_no>
|
||||
Ex: getent passwd | grep andy | $this -F: 5
|
||||
Ex: echo \"A B\" | $this 2
|
||||
"
|
||||
err(){ echo -e "$USAGE" >&2; exit 1; }
|
||||
|
||||
[[ $# -eq 0 ]] && err
|
||||
# bail if the *last* argument isn't a number (source:
|
||||
# http://stackoverflow.com/a/808740)
|
||||
last=${@:(-1)}
|
||||
if ! [ $last -eq $last ] &>/dev/null; then
|
||||
echo "_awk! Last argument (awk field) must be numeric." >&2
|
||||
err
|
||||
fi
|
||||
|
||||
if [ $# -gt 1 ]; then
|
||||
# Source:
|
||||
# http://www.cyberciti.biz/faq/linux-unix-bsd-apple-osx-bash-get-last-argument/
|
||||
rest=${@:1:$(( $# - 1 ))}
|
||||
else
|
||||
rest='' # just to be sure
|
||||
fi
|
||||
awk $rest "{ print \$$last }"
|
34
bin/§battery
Executable file
34
bin/§battery
Executable file
@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
version="2022-01-25"
|
||||
this="${0##*/}"
|
||||
USAGE="\
|
||||
$this@v$version
|
||||
Wrapper around 'upower' to show battery info(s).
|
||||
Usage: $this --[help|all|oneline|notify]
|
||||
|
||||
'oneline' [Default] prints 'status | time | percentage'
|
||||
'notify' sends 'oneline' to 'notify-send'
|
||||
'all' prints 'upower -i'
|
||||
'help' prints this text
|
||||
"
|
||||
arg=${1:---oneline}
|
||||
if [[ "$arg" = "--help" ]]; then
|
||||
echo -e "$USAGE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
batt_name=`upower -e | grep 'BAT'`
|
||||
batt_info=`upower -i $batt_name`
|
||||
if [[ "$arg" = "--all" ]]; then
|
||||
echo -e "$batt_info"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
batt_oneline=`echo "$batt_info" | grep -E "state|percentage|to\ full|to\ empty" | §awk -F: 2 | sed 's/^ *//g' | tr -s '\n' '|' | sed 's/|$/\n/' | sed 's/|/ | /g'`
|
||||
if [[ "$arg" = "--oneline" ]]; then
|
||||
echo -e "$batt_oneline"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
icon=`echo "$batt_info" | grep "icon-name" | §awk -F\' 2`
|
||||
notify-send --icon=$icon "Battery" "$batt_oneline"
|
6
bin/§calc
Executable file
6
bin/§calc
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
function _echo(){
|
||||
[ -t 0 ] && echo "$1" && exit
|
||||
notify-send -i kcalc "$1" && exit
|
||||
}
|
||||
_echo `python3 -c 'import sys; print(eval(" ".join(sys.argv[1:])))' "$*"`
|
60
bin/§cordova-release.mjs
Executable file
60
bin/§cordova-release.mjs
Executable file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, style, fetch, cyclicLoop */
|
||||
import { join as pathJoin } from "path";
|
||||
import { platform } from "process";
|
||||
const config_path= $.xdg.data`package_global.json`;
|
||||
|
||||
$.is_fatal= true;
|
||||
$.api("[name]", true)
|
||||
.version("2022-10-06")
|
||||
.describe([
|
||||
"Release cordova app with saved data in: "+config_path+".",
|
||||
"This should be JSON file with `cordova_keys_store` key/object:",
|
||||
`{"cordova_keys_store": { "NAME": { "path": "", "password": "", "alias": "" } }}`,
|
||||
"You can lists all saved options (NAME), when you run without arguments." ])
|
||||
.option("--noclear", "Skipping cleaning existing apk files.")
|
||||
.action(function main(name, { noclear }){
|
||||
if(!name){
|
||||
echo("Available options:");
|
||||
pipe(getConfig, Object.keys, a=> "- "+a.join("\n- "), echo)();
|
||||
$.exit(0);
|
||||
}
|
||||
const /* runtime arguments and cwd */
|
||||
{ path, password, alias }= getConfigFor(name),
|
||||
cwd= process.cwd(),
|
||||
platform_android= toDirPath( cwd, "platforms", "android" ),
|
||||
platform_build= !s.test("-e", toDirPath(platform_android, "app")) ? toDirPath(platform_android, "build") : toDirPath(platform_android, "app", "build"),
|
||||
apk_dir= toDirPath(platform_build, "outputs", "apk"),
|
||||
key_path= pathJoin(cwd, "keystore.jks"),
|
||||
process_clear= !noclear && !s.test("-e", toDirPath(platform_android, "app"));
|
||||
|
||||
$.configAssign({ verbose: true, fatal: true });
|
||||
if(process_clear) s.rm("-Rf", apk_dir+"*");
|
||||
s.cp(path, key_path);
|
||||
s.run("cordova" + ( platform==="win32" ? ".cmd" : "" ) + " ::args::",
|
||||
{ args: [ "build", "--release", "android", "--",'--keystore=keystore.jks', "--storePassword="+password, "--password="+password, "--alias="+alias ] });
|
||||
s.rm(key_path);// cordova si to uklada a uz potom bez nej nelze buildit vubec
|
||||
s.rm(platform_android+"release-signing.properties");
|
||||
$.exit(0);
|
||||
})
|
||||
.parse(process.argv);
|
||||
|
||||
function toDirPath(...path){ return pathJoin(...path)+"/"; }
|
||||
function getConfigFor(name){
|
||||
const config= getConfig();
|
||||
if(Object.hasOwn(config, name))
|
||||
return config[name];
|
||||
|
||||
$.error(`Name '${name}' not found, use one of: `+Object.keys(config));
|
||||
}
|
||||
function getConfig(){
|
||||
if(!s.test("-f", config_path))
|
||||
$.error("No config file found! Tested file path: "+config_path);
|
||||
try{
|
||||
const config= s.cat(config_path).xargs(JSON.parse).cordova_keys_store;
|
||||
if(!Object.keys(config).length) throw new Error();
|
||||
return config;
|
||||
} catch(e){
|
||||
$.error("Unsupported config file: "+config_path+"! Use `--help` for more information.");
|
||||
}
|
||||
}
|
61
bin/§extract
Executable file
61
bin/§extract
Executable file
@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
this="${0##*/}"
|
||||
this_version="2021-03-14"
|
||||
while read; do printf '%s\n' "$REPLY"
|
||||
done <<-EOF
|
||||
$this ($this_version) <andrle.jan@centrum.cz>
|
||||
Utility for extracting archives into folder with the same name.
|
||||
|
||||
EOF
|
||||
err() {
|
||||
printf >&2 "Error: $*\n"
|
||||
exit 1
|
||||
}
|
||||
|
||||
ARC="$1"
|
||||
[[ ! -z "$ARC" ]] || ARC="--help"
|
||||
|
||||
if [[ "$ARC" = "--help" ]]; then
|
||||
while read; do printf '%s\n' "$REPLY"
|
||||
done <<-EOF
|
||||
Usage: $this [file|--help|]
|
||||
[--help|] - show this text
|
||||
[file] - path to file for extracting
|
||||
Supported formats (used utilities):
|
||||
EOF
|
||||
sed -n 42,52p $0 | sed -e 's/^/ /'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
[[ -f $ARC ]] || err $"'$ARC' does not exist"
|
||||
|
||||
ARC_name_ext="${ARC##*/}"
|
||||
ARC="$(readlink -f "$ARC")"
|
||||
ARC_name="${ARC_name_ext%.*}"
|
||||
|
||||
mkdir "$ARC_name" || err $"Directory '$ARC_name' can not be created"
|
||||
[[ -d $ARC_name ]] || err $"Directory '$ARC_name' does not exist"
|
||||
[[ -w $ARC_name ]] || err $"Permission denied: '$ARC_name' is not writable"
|
||||
|
||||
cd "$ARC_name"
|
||||
case "$ARC" in
|
||||
*.tar.bz2) tar xjf "$ARC" ;;
|
||||
*.tar.gz) tar xzf "$ARC" ;;
|
||||
*.bz2) bunzip2 "$ARC" ;;
|
||||
*.rar) unrar e "$ARC" ;;
|
||||
*.gz) gunzip "$ARC" ;;
|
||||
*.tar) tar xf "$ARC" ;;
|
||||
*.tbz2) tar xjf "$ARC" ;;
|
||||
*.tgz) tar xzf "$ARC" ;;
|
||||
*.zip) unzip "$ARC" ;;
|
||||
*.epub) unzip "$ARC" ;;
|
||||
*.docx) unzip "$ARC" ;;
|
||||
*.xmlx) unzip "$ARC" ;;
|
||||
*.pptx) unzip "$ARC" ;;
|
||||
*.Z) uncompress "$ARC" ;;
|
||||
*.7z) 7z x "$ARC" ;;
|
||||
*.eml) munpack -t "$ARC" ;;
|
||||
*) err $"'$ARC' cannot be extracted by $this" ;;
|
||||
esac
|
||||
|
||||
# sudo apt install mpack
|
94
bin/§mail.mjs
Executable file
94
bin/§mail.mjs
Executable file
@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, style, fetch, cyclicLoop, xdg, $ */
|
||||
import { basename } from "path";
|
||||
const app= {
|
||||
name: basename(process.argv[1]),
|
||||
version: "2022-09-28",
|
||||
cmd: $.xdg.home`.local/bin/himalaya`,
|
||||
configs: $.xdg.config`himalaya/`,
|
||||
modificator: "§"
|
||||
};
|
||||
const chars= { "&AOE-": "á", "&AWE-": "š", "&ARs-": "ě" };
|
||||
let argv_arr= argvArr();
|
||||
|
||||
if("help"===argv_arr.toString().replaceAll("-", "")){ //#region
|
||||
echo([ `${app.name}@${app.version}`,
|
||||
`This is small wrapper around 'himalaya' fixing coding errors and provide better 'read'. (Use § for calling himalaya directly)`,
|
||||
"" ].join("\n"));
|
||||
s.run(app.cmd+" --help");
|
||||
$.exit(0); //#endregion
|
||||
}
|
||||
if("version"===argv_arr.toString().replaceAll("-", "")){//#region
|
||||
echo(`${app.name} ${app.version}`);
|
||||
s.run(app.cmd+" --version");
|
||||
$.exit(0);//#endregion
|
||||
}
|
||||
if("completion,bash"===argv_arr.toString()){//#region
|
||||
const completion= s.run(app.cmd+" ::argv_arr::", { argv_arr });
|
||||
echo(completion.toString().replace("himalaya)", `himalaya|${app.name})`));
|
||||
echo(`alias ${app.name}-inbox="§mail § | less -R -S"`);
|
||||
echo(`complete -F _himalaya -o bashdefault -o default ${app.name}`);
|
||||
$.exit(0);//#endregion
|
||||
}
|
||||
(async function main(){
|
||||
if(argv_arr.indexOf(app.modificator)!==-1) await runH(argv_arr.filter(l=> l!==app.modificator));
|
||||
|
||||
argv_arr= argv_arr.filter(str=> str!==app.modificator);
|
||||
if(argv_arr.indexOf("list")!==-1){
|
||||
argv_arr.push("-w", process.stdout.columns);
|
||||
await runH(argv_arr);
|
||||
}
|
||||
if(argv_arr.indexOf("read")!==-1){
|
||||
const email= $.xdg.temp`/himalaya-read.eml`;
|
||||
argv_arr.push("-h", "From", "-h", "Subject");
|
||||
await s.$().runA(app.cmd+" ::argv_arr::", { argv_arr }).pipe(s=> s.to(email));
|
||||
await s.runA`vim ${email}`.pipe(process.stdout);
|
||||
$.exit(0);
|
||||
}
|
||||
|
||||
if(argv_arr[0] && argv_arr[0]!=="--rofi") await runH(argv_arr);
|
||||
|
||||
const template_path= app.configs+"template-inbox.json";
|
||||
if(!s.test("-f", template_path)) await runH([]);
|
||||
|
||||
const out= await pipe(
|
||||
f=> s.cat(f).xargs(JSON.parse),
|
||||
argv_arr.indexOf('--rofi')===-1 ? templateRead : templateRofi,
|
||||
a=> Promise.all(a)
|
||||
)(template_path);
|
||||
for(const l of out){
|
||||
if(typeof l=="string"&&!l.indexOf("%c===\n")) echo(l, "unset:all", "color:magenta");
|
||||
else echo(l);
|
||||
}
|
||||
$.exit(0);
|
||||
})();
|
||||
|
||||
function templateRofi(lines){
|
||||
return lines.filter(line=> line.type!=="text")
|
||||
.map(line=>
|
||||
s.$().runA(app.cmd+" ::value:: -w 120", line)
|
||||
.then(data=> data.toString().split("\n")
|
||||
.filter(l=> l)
|
||||
.map(line=> line.replaceAll("✷ ", "* "))
|
||||
.map(line_result=> line_result+" │ "+line.label)
|
||||
.join("\n"))
|
||||
);
|
||||
}
|
||||
function templateRead(lines){
|
||||
argv_arr.push("-w", process.stdout.columns);
|
||||
return lines.map(line=> line.type==="text" ?
|
||||
Promise.resolve("%c===\n%c"+line.value) :
|
||||
s.$().runA(app.cmd+" ::value:: ::argv_arr::", { value: line.value, argv_arr })
|
||||
);
|
||||
}
|
||||
|
||||
function argvArr(){
|
||||
const _chars= Object.entries(chars).reduce((acc, [ key, val ])=> Reflect.set(acc, val, key) && acc, {});
|
||||
return process.argv.slice(2).map(str=> str.replace(new RegExp(`(${Object.keys(_chars).join("|")})`, "g"), l=> _chars[l]));
|
||||
}
|
||||
async function runH(args){
|
||||
const result= await s.runA(app.cmd+" ::args::", { args }).pipe(process.stdout);
|
||||
$.exit(result.exitCode);
|
||||
}
|
||||
// vim: set tabstop=4 shiftwidth=4 textwidth=250 noexpandtab ft=javascript :
|
||||
// vim>60: set foldmethod=marker foldmarker=#region,#endregion :
|
71
bin/§software
Executable file
71
bin/§software
Executable file
@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
this="${0##*/}"
|
||||
this_version="2021-12-01"
|
||||
err() { printf >&2 "Error: $*\n"; exit 1; }
|
||||
log() { printf ":: $* ::\n"; }
|
||||
|
||||
if [ ! -t 0 ]; then
|
||||
exo-open --launch TerminalEmulator -- -e "$this $*"
|
||||
exit
|
||||
fi
|
||||
action="${1:---help}"
|
||||
if [[ "$action" = "--help" ]]; then
|
||||
while read; do printf '%s\n' "$REPLY"
|
||||
done <<-EOF
|
||||
$this ($this_version) <andrle.jan@centrum.cz>
|
||||
Utility for updating my packages managers such as \`npm\`, \`apt\`, \`github-releases\` …
|
||||
|
||||
Usage: $this --[help|check|update] [basic|dangerous]
|
||||
[default] --help: show this text
|
||||
--check: check updates
|
||||
--update: update all
|
||||
--list: list of packages managers
|
||||
|
||||
modificators:
|
||||
[default] basic: checks/updates regular packages managers
|
||||
dangerous: ↘+also \`pip\`
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$action" = "--list" ]]; then
|
||||
echo npm
|
||||
echo github-releases.js
|
||||
echo _vim_plugins – updates only
|
||||
echo snap – updates only
|
||||
echo flatpak – updates only
|
||||
echo pip [dangerous]
|
||||
exit 0
|
||||
fi
|
||||
modificator="${2:-basic}"
|
||||
if [[ "$action" = "--check" ]]; then
|
||||
log "npm outdated --global (for update use: \`npm update --global\`)"
|
||||
npm outdated --global
|
||||
[[ "${?}" = "0" ]] && echo "> all up-to.date"
|
||||
log "github-releases.js --check (for update use for example: \`github-releases.js --update all\`)"
|
||||
github-releases.js --check
|
||||
if [[ ! "$modificator" = "basic" ]]; then
|
||||
log "pip list --outdated"
|
||||
pip list --outdated
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$action" = "--update" ]]; then
|
||||
log "npm update --global"
|
||||
npm update --global
|
||||
log "github-releases.js --update all"
|
||||
github-releases.js --update all
|
||||
log "_vim_plugins --update"
|
||||
_vim_plugins --update
|
||||
log "snap refresh --list"
|
||||
snap refresh --list
|
||||
log "flatpak update"
|
||||
flatpak update
|
||||
if [[ ! "$modificator" = "basic" ]]; then
|
||||
log "pip list --outdated --format=freeze | grep -v '^\\-e' | cut -d = -f 1 | xargs -n1 pip install -U --user"
|
||||
pip list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 pip install -U --user
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
err "Wrong arguments (use \`--help\`)"
|
22
bin/§trans.mjs
Executable file
22
bin/§trans.mjs
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 8,-W097, -W040, node: true, expr: true, undef: true *//* global echo, $, pipe, s, style, fetch, cyclicLoop */
|
||||
$.is_fatal= true;
|
||||
$.api("<lang>")
|
||||
.version("2022-09-23")
|
||||
.describe("This is just wrapper around 'trans' cli utility.")
|
||||
.option("-b", "Turn off '-b' parametrer for 'trans' which is give by this script.")
|
||||
.option("-c", "Redirect into clipboard ('| xclip -selection clipboard')")
|
||||
.example("2en pes → 'trans cs:en -b pes'")
|
||||
.example("en -b dog → 'trans en:cs dog'")
|
||||
.action(function main(lang, { _: query, c: to_clipboard, b: to_long }){
|
||||
query= [ `"${query.join(" ").replaceAll('"', '\\"')}"` ];
|
||||
if(!to_long) query.unshift('-b');
|
||||
query.unshift(lang[0]==="2" ? lang.replace("2", "cs:") : ( lang.indexOf(":")!==-1 ? lang : lang+":cs" ));
|
||||
query.push('-no-ansi');
|
||||
|
||||
const result= s.$().run("trans "+query.join(" "));
|
||||
if(!to_clipboard) return echo(result.toString());
|
||||
result.runA("xclip -selection clipboard 2> /dev/null 1> /dev/null")
|
||||
.then($.exit.bind(null, 0)).catch($.exit.bind(null, 1));
|
||||
})
|
||||
.parse(process.argv);
|
58
bin/§ubuntu-info
Executable file
58
bin/§ubuntu-info
Executable file
@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
this="${0##*/}"
|
||||
this_version="2021-01-22"
|
||||
USAGE="\
|
||||
$this@v$this_version
|
||||
Wrapper around '/etc/os-release' to show Ubuntu (like) os info.
|
||||
Usage: $this --[help|all|raw]
|
||||
|
||||
'all' [default] prints all infos
|
||||
'pick' prints only given key (default key is 'DESCRIPTION')
|
||||
'raw' cats '/etc/os-release'
|
||||
'help' prints this text
|
||||
|
||||
Examples:
|
||||
$this --all
|
||||
$this --pick NAME
|
||||
$this --pick VERSION_NAME
|
||||
$this --all | grep NAME
|
||||
"
|
||||
arg=${1:---all}
|
||||
if [[ "$arg" = "--help" ]]; then
|
||||
echo -e "$USAGE"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$arg" = "--raw" ]]; then
|
||||
cat /etc/os-release
|
||||
exit 0
|
||||
fi
|
||||
|
||||
. /etc/os-release
|
||||
out="ID=$ID"
|
||||
out="${out}\nDESCRIPTION=$PRETTY_NAME"
|
||||
case "$ID" in
|
||||
neon) out="${out}\nNAME=$NAME (${VARIANT:-User Edition})"
|
||||
out="${out}\nVERSION=$VERSION ($VERSION_ID)"
|
||||
;;
|
||||
*) out="${out}\nNAME=$NAME"
|
||||
out="${out}\nVERSION=$VERSION"
|
||||
;;
|
||||
esac
|
||||
out="${out}\nVERSION_NICK=$UBUNTU_CODENAME"
|
||||
codename=`grep $(lsb_release -rs) /usr/share/python-apt/templates/Ubuntu.info | grep -m 1 "Description: Ubuntu " | cut -d "'" -f2`
|
||||
out="${out}\nVERSION_NAME=$codename"
|
||||
# http://www.releases.ubuntu.com/jammy/
|
||||
out="${out}\nLIKE=$ID_LIKE"
|
||||
out="${out}\n`grep URL /etc/os-release | sed 's/^\([A-Z_]*\)_URL/URL_\1/'`"
|
||||
|
||||
if [[ "$arg" = "--all" ]]; then
|
||||
echo -e "$out"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$arg" = "--pick" ]]; then
|
||||
echo -e `echo -e "$out" | grep "\b${2:-DESCRIPTION}\b" | cut -d = -f 2-`
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Wrong argument, see '--help'."
|
||||
exit 1
|
3
bin/§vim_cache_clean
Executable file
3
bin/§vim_cache_clean
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
find ~/.vim/undodir/ -maxdepth 1 -mindepth 1 -type f -mtime +180 -delete
|
||||
find ~/.vim/view/ -maxdepth 1 -mindepth 1 -type f -mtime +180 -delete
|
281
bin/§vim_plugins.mjs
Executable file
281
bin/§vim_plugins.mjs
Executable file
@ -0,0 +1,281 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */
|
||||
//TODO: save options!?
|
||||
$.is_fatal= true;
|
||||
const dirs= { vim_root: $.xdg.home`.vim` };
|
||||
Object.assign(dirs, {
|
||||
pack: dirs.vim_root+"/pack/",
|
||||
bundle: dirs.vim_root+"/bundle/",
|
||||
one_files: dirs.vim_root+"/bundle/__one_files/plugin/" });
|
||||
const file_one_file= dirs.bundle+"one_file.json";
|
||||
const runResToArr= pipe( s.$().run, ({ stderr, stdout })=> stdout+stderr, o=> o.split("\n"));
|
||||
const css= echo.css`
|
||||
.code{ color: yellow; }
|
||||
.code::before, .code::after{ content: "\`"; }
|
||||
.url{ color: lightblue; }
|
||||
.bold{ color: magenta; }
|
||||
`;
|
||||
|
||||
$.api()
|
||||
.version("2023-04-18")
|
||||
.describe([
|
||||
"Utility for managing vim plugins “native” way. It uses two types:",
|
||||
`- “old” way (${f("bundle", css.code)}): inspiration from ${f("https://shapeshed.com/vim-packages/", css.url)}`,
|
||||
`- vim8 native package managing (${f("pack", css.code)}): see for example ${f("https://shapeshed.com/vim-packages/", css.url)}`
|
||||
])
|
||||
.command("path <type>", [ "Prints paths for given package type",
|
||||
"Use (‘S’ is alias for this script name):",
|
||||
"- "+f("cd `S path bundle`", css.code),
|
||||
"- "+f("cd `S path one_files`", css.code),
|
||||
"- "+f("cd `S path pack`", css.code)
|
||||
])
|
||||
.action(function(type){ echo(dirs[type]); $.exit(0); })
|
||||
.command("clone <type> <url>", [ "Add/install new package.",
|
||||
`Use ${f("bundle", css.code )}/${f("pack", css.code)} to specify the package ${f("type", css.code)}.`,
|
||||
`The ${f("url", css.url)} should be a URL to the script itself or url of the git repository or github repository in the form of ${f("username/reponame", css.url)}.`
|
||||
])
|
||||
.alias("C")
|
||||
.option("--target, -t [target]", `In case of ${f("pack", css.code)} type, specify the target sub-directory (typically/defaults ${f("start", css.code)}).`)
|
||||
.option("--branch, -b [branch]", `In case of ${f("git", css.bold)} repository, specify the branch if it is different from default one.`)
|
||||
.action(function(type, url, options){
|
||||
switch(type){
|
||||
case "bundle": return addBundle(url);
|
||||
case "pack": return addPack(url, options);
|
||||
}
|
||||
echo("Nothing todo, check given arguments (compare to `--help`):", { type, url, options });
|
||||
$.exit(1);
|
||||
})
|
||||
.command("remove <type> <path>", [ "Remove/uninstall package.",
|
||||
`As ${f("type", css.bold)}/${f("path", css.bold)} use output printed by ${f("list", css.code)} command.`
|
||||
])
|
||||
.alias("R").alias("rm")
|
||||
.action(function(type, path){
|
||||
switch(type){
|
||||
case "bundle": return removeBundle(path);
|
||||
case "pack": return removePack(path);
|
||||
}
|
||||
echo("Nothing todo, check given arguments (compare to `--help`):", { type, path });
|
||||
$.exit(1);
|
||||
})
|
||||
.command("list", "List all plugins paths/url/… (based on option).")
|
||||
.alias("L").alias("ls")
|
||||
.option("--type, -t [type]", `Defaults to list of paths (${f("paths", css.code)}). Use ${f("repos", css.code)} to show plugins origin.`)
|
||||
.example("list")
|
||||
.example("list --type paths")
|
||||
.example("list --type repos")
|
||||
.action(actionList)
|
||||
.command("export", "List all plugins in the form that can be imported by this Utility.")
|
||||
.action(actionList.bind(null, { type: "json" }))
|
||||
.command("status", "Loops through all installed plugins and shows overall status.")
|
||||
.alias("S")
|
||||
.action(actionStatus)
|
||||
.command("pull", "Loops through all installed plugins and updates them.")
|
||||
.alias("P").alias("update")
|
||||
.action(actionUpdate)
|
||||
.parse();
|
||||
|
||||
function removePack(path){
|
||||
s.cd(dirs.pack);
|
||||
s.$("-V").rm("-rf", path);
|
||||
const root= dirs.pack+path.split("/")[0];
|
||||
const { code, stdout }= s.$().find(root+"/*/*");
|
||||
if(!code) echo(stdout);
|
||||
else if(s.test("-d", root))
|
||||
s.$("-V").rm("-rf", root);
|
||||
$.exit(0);
|
||||
}
|
||||
function removeBundle(path){
|
||||
const is_onefile= dirs.one_files.endsWith(path.split("/").slice(0, 2).join("/")+"/");
|
||||
const name= path.slice(path.lastIndexOf("/")+1);
|
||||
s.cd(dirs.bundle);
|
||||
if(is_onefile){
|
||||
s.rm("-f", path);
|
||||
pipe( s.cat, JSON.parse, f=> f.filter(u=> !u.endsWith(name)), JSON.stringify, s.echo )
|
||||
(file_one_file).to(file_one_file);
|
||||
} else {
|
||||
s.run`git submodule deinit -f ${path}`;
|
||||
s.run`git rm ${path}`;
|
||||
s.rm("-rf", ".git/modules/"+path);
|
||||
}
|
||||
const type= is_onefile ? "file" : "repo";
|
||||
s.run`git commit --all -m "Remove ${type}: ${name}"`;
|
||||
$.exit(0);
|
||||
}
|
||||
async function addBundle(url){
|
||||
const is_onefile= url.endsWith(".vim");
|
||||
if(!is_onefile)
|
||||
url= gitUrl(url);
|
||||
const name= url.split(/[\/\.]/g).at(is_onefile ? -2 : -1);
|
||||
s.cd(dirs.bundle);
|
||||
if(is_onefile){
|
||||
const file= await fetch(url).then(r=> r.text());
|
||||
s.echo(file).to(dirs.one_files+name+".vim");
|
||||
const log= new Set(s.cat(file_one_file).xargs(JSON.parse));
|
||||
log.add(url);
|
||||
s.echo(JSON.stringify([ ...log ])).to(file_one_file);
|
||||
} else {
|
||||
s.run`git submodule init`;
|
||||
s.run`git submodule add ${url}`;
|
||||
}
|
||||
s.run`git add .`;
|
||||
const type= is_onefile ? "file" : "repo";
|
||||
s.run`git commit -m "Added ${type}: ${name}"`;
|
||||
$.exit(0);
|
||||
}
|
||||
/** @param {string} url @param {{ target: "start", branch?: string }} options */
|
||||
function addPack(url, { target= "start", branch }){
|
||||
url= gitUrl(url);
|
||||
const author= url.split(/[:\/]/).at(-2);
|
||||
const path= dirs.pack+author+"/"+target;
|
||||
s.mkdir("-p", path);
|
||||
s.cd(path);
|
||||
branch= !branch ? "" : `-b ${branch}`;
|
||||
s.run`git clone ${branch} --single-branch ${url} --depth 1`;
|
||||
$.exit(0);
|
||||
}
|
||||
function gitUrl(url_candidate){
|
||||
if(url_candidate.endsWith(".git"))
|
||||
return url_candidate;
|
||||
return "git@github.com:"+url_candidate;
|
||||
}
|
||||
async function actionUpdate(){
|
||||
const css= echo.css`
|
||||
.success{ color: lightgreen; }
|
||||
.success::before{ content: "✓ "; }
|
||||
`;
|
||||
updateRepo(dirs.bundle, getBundle());
|
||||
const todo= getOneFilesUrls();
|
||||
const progress= echoProgress(todo.length, "Downloaded one-file plugins");
|
||||
await Promise.all(todo.map(function(url, i){
|
||||
return fetch(url).then(r=> {
|
||||
progress.update(i, url);
|
||||
return r.text();
|
||||
}).then(f=> s.echo(f).to(dirs.one_files+fileName(url)));
|
||||
}));
|
||||
echo("One-file plugin(s) updated.");
|
||||
s.cd(dirs.bundle).$().run`git commit -m "Update"`;
|
||||
updateRepo(dirs.pack, getPack());
|
||||
|
||||
$.exit(0);
|
||||
|
||||
function updateRepo(dir, paths){
|
||||
echo(dir);
|
||||
const progress= echoProgress(paths.length, "Pulling");
|
||||
const todo= paths.map(function(p, i){
|
||||
progress.update(i, p);
|
||||
return pull(p);
|
||||
}).filter(isUpToDate);
|
||||
if(!todo.length)
|
||||
return echo("%cAll up-to-date!", css.success);
|
||||
todo.forEach(([ p, result ])=> echo("%c"+p+"\n", css.success, result.join("\n")));
|
||||
}
|
||||
function pull(p){
|
||||
s.cd(p);
|
||||
return [ p, runResToArr("git pull") ];
|
||||
}
|
||||
function isUpToDate([ _, result ]){
|
||||
return result[0]===" Already up-to-date.";
|
||||
}
|
||||
}
|
||||
function actionList({ type= "paths" }){
|
||||
if("paths"===type){
|
||||
echo("%cbundle", css.bold, dirs.bundle);
|
||||
getOneFiles().forEach(echoPath);
|
||||
getBundle().forEach(echoPath);
|
||||
|
||||
echo("%cpack", css.bold, dirs.pack);
|
||||
getPack().forEach(echoPath);
|
||||
$.exit(0);
|
||||
}
|
||||
const progress= echoProgress(3, "Collecting plugins urls");
|
||||
progress.update(0, dirs.bundle);
|
||||
const urls_bundle= getBundle().map(getRepo);
|
||||
progress.update(1, dirs.bundle);
|
||||
const urls_onefiles= getOneFilesUrls();
|
||||
progress.update(2, dirs.pack);
|
||||
const urls_pack= getPack().map(getRepo);
|
||||
|
||||
if("repos"===type){
|
||||
const echoUrl= pipe(
|
||||
u=> u.replace("git@github.com:", "https://github.com/"),
|
||||
u=> f(u, css.url),
|
||||
echo
|
||||
)
|
||||
echo("%cbundle", css.bold, dirs.bundle);
|
||||
urls_bundle.forEach(echoUrl);
|
||||
echo("%cbundle", css.bold, dirs.one_files);
|
||||
urls_onefiles.forEach(echoUrl);
|
||||
echo("%cpack", css.bold, dirs.pack);
|
||||
urls_pack.forEach(echoUrl);
|
||||
}
|
||||
if("json"===type){ //TODO: save options!?
|
||||
const o= {};
|
||||
o.bundle= urls_bundle;
|
||||
o.one_files= urls_onefiles;
|
||||
o.pack= urls_pack;
|
||||
echo(JSON.stringify(o));
|
||||
}
|
||||
$.exit(0);
|
||||
|
||||
function getRepo(p){ s.cd(p); return runResToArr("git remote -v")[0].split(/\s+/g)[1]; }
|
||||
}
|
||||
function actionStatus(){
|
||||
const css= echo.css`
|
||||
.success { color: lightgreen; }
|
||||
.success::before { content: "✓ "; }
|
||||
`;
|
||||
check(dirs.bundle, getBundle());
|
||||
echo("Onefiles plugins are not supported yet");
|
||||
check(dirs.pack, getPack());
|
||||
$.exit(0);
|
||||
|
||||
function check(root, repos){
|
||||
echo(root);
|
||||
const progress= echoProgress(repos.length);
|
||||
const results= repos.flatMap(function(p, i){
|
||||
progress.update(i, p);
|
||||
s.cd(p);
|
||||
const result= runResToArr("git fetch --dry-run --verbose")
|
||||
.filter(l=> !l ? false : l.startsWith("From") || (!l.startsWith(" = [up-to-date]") && !l.startsWith("POST") ));
|
||||
if(result.length===1) return [];
|
||||
return [ [ p, result.join("\n") ] ];
|
||||
});
|
||||
if(!results.length)
|
||||
return echo("%cup-to-date", css.success);
|
||||
results.forEach(([ p, l ])=> {
|
||||
echoPath(p);
|
||||
echo(l);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
import { relative } from 'node:path';
|
||||
function echoPath(path){ return echo(formatPath(path)); }
|
||||
function formatPath(path){
|
||||
const type= path.startsWith(dirs.bundle) ? "bundle" : "pack";
|
||||
return echo.format("%c"+relative(dirs[type], path), "color:lightblue");
|
||||
}
|
||||
import { stdout } from 'node:process';
|
||||
function echoProgress(length, message_start= "Working"){
|
||||
if(typeof stdout.isTTY === "undefined") return { update(){} };
|
||||
|
||||
const css= echo.css`
|
||||
.progress { color: lightblue; }
|
||||
`;
|
||||
echo.use("-R", `${message_start} (%c0/${length}%c)`, css.progress);
|
||||
return {
|
||||
update(i, status){
|
||||
const s= status ? `: ${status}` : "";
|
||||
return echo.use("-R", `${message_start} (%c${i+1}/${length}%c)${s}`, css.progress);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getPack(){ return s.ls(dirs.pack).flatMap(f=> s.find(dirs.pack+f+"/start/*/")[0]).filter(Boolean); }
|
||||
function getBundle(){ return s.cd(dirs.bundle).grep("path", ".gitmodules").split("\n").filter(Boolean).map(l=> dirs.bundle+l.split(" = ")[1]); }
|
||||
function getOneFiles(){ return s.find(dirs.one_files+"*"); }
|
||||
function getOneFilesUrls(){ return s.cat(file_one_file).xargs(JSON.parse); }
|
||||
|
||||
function fileName(url){ return url.split("/").pop(); }
|
||||
/** Quick formating of one piece of text. */
|
||||
function f(text, css){ return echo.format("%c"+text, css); }
|
44
bin/§wallpaper_BIOTD.mjs
Executable file
44
bin/§wallpaper_BIOTD.mjs
Executable file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env node
|
||||
/* jshint esversion: 6,-W097, -W040, browser: true, expr: true, undef: true */
|
||||
import { readFileSync, writeFileSync, createWriteStream } from "fs";
|
||||
import { get } from "https";
|
||||
import { homedir } from "os";
|
||||
|
||||
const url_main= "https://www.bing.com";
|
||||
const folder= homedir()+"/Obrázky/Bing Image Of The Day/";
|
||||
|
||||
get_(url_main+"/HPImageArchive.aspx?format=js&idx=0&n=2&mkt=cs-CZ")
|
||||
.then(res=> {
|
||||
let body= "";
|
||||
res.on("data", chunk=> body+= chunk);
|
||||
res.on("end", ()=> pipe(data, update)(body));
|
||||
})
|
||||
.catch(e=> console.error(String(e)));
|
||||
|
||||
function update(data){
|
||||
if(data===null) return false;
|
||||
Promise.allSettled(data.map(({ url, copyright }, id)=> getImage_(url, id ? "prev" : "now", copyright)))
|
||||
.then(res=> {
|
||||
let template= readFileSync(folder+"index_template.html").toString();
|
||||
writeFileSync(folder+"index.html", res.reduce((out, { status, value })=> status==="rejected" ? out : out.replace(`::${value.name}::`, value.description), template));
|
||||
})
|
||||
.catch(e=> console.error(String(e)));
|
||||
}
|
||||
function getImage_(url, name, desc){
|
||||
const description= desc.replace("(©", "<br>(©");
|
||||
return get_(url_main+url)
|
||||
.then(res=> {
|
||||
const fs= createWriteStream(folder+name+'.jpg');
|
||||
res.pipe(fs);
|
||||
return new Promise(res=> fs.on("finish", ()=> {
|
||||
fs.close();
|
||||
res({ name, description });
|
||||
}));
|
||||
});
|
||||
}
|
||||
function data(body){
|
||||
try { return JSON.parse(body).images; }
|
||||
catch (_) { return null; }
|
||||
}
|
||||
function get_(url){ return new Promise(function(res,rej){ get(url, res).on("error", rej); }); }
|
||||
function pipe(...f){ return Array.prototype.reduce.bind(f, (acc, f)=> f(acc)); }
|
20
bin/§wolframalpha.mjs
Executable file
20
bin/§wolframalpha.mjs
Executable file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env nodejsscript
|
||||
/* jshint esversion: 8,-W097, -W040, node: true, expr: true, undef: true *//* global echo, $, pipe, s, style, fetch, cyclicLoop */
|
||||
$.is_fatal= true;
|
||||
$.api("<...query_array>", true)
|
||||
.version("v2022-09-23")
|
||||
.describe([
|
||||
"This is just redirection to [WolframAlpha](https://www.wolframalpha.com/) site.",
|
||||
"Use the same expressions as on web page."
|
||||
])
|
||||
.example("linear fit {1.3, 2.2},{2.1, 5.8},{3.7, 10.2},{4.2, 11.8}")
|
||||
.example("polynomial fit {1,2},{2,3.1},{3,3.9}")
|
||||
.example("Fit[{{1,2},{2,3.1},{3,3.9}}, {1,x}, x]")
|
||||
.action(function main(first, { _: query_array= [] }){
|
||||
query_array.unshift(first);
|
||||
echo("Opening:");
|
||||
echo("https://www.wolframalpha.com/input/?i="+encodeURI(query_array.join(" ")).replace(/\+/g, '%2B'))
|
||||
.xargs(s.runA, "exo-open --launch WebBrowser {}")
|
||||
.then($.exit.bind(null, 0)).catch($.exit.bind(null, 1));
|
||||
})
|
||||
.parse();
|
Loading…
Reference in New Issue
Block a user