Things
This commit is contained in:
parent
fe27b3b960
commit
86bc146125
|
@ -22,7 +22,7 @@ URxvt*scrollBar: false
|
|||
|
||||
|
||||
! Font declaration
|
||||
URxvt.font: xft:DejaVu Sans Mono for Powerline:size=12:antialias=true
|
||||
URxvt.font: xft:DejaVu Sans Mono for Powerline:size=12:antialias=true,xft:Symbola:size=12:antialias=true
|
||||
|
||||
! Font spacing
|
||||
URxvt.letterSpace: 0
|
||||
|
|
60
bashrc
60
bashrc
|
@ -43,6 +43,9 @@ alias rm='rm -Iv --one-file-system'
|
|||
alias free='free -m'
|
||||
alias df='df -h'
|
||||
alias dmesg='dmesg --ctime'
|
||||
alias ffmpeg='ffmpeg -hide_banner'
|
||||
alias ffprobe='ffprobe -hide_banner'
|
||||
alias ffplay='ffplay -hide_banner'
|
||||
|
||||
# Frequent mistakes
|
||||
alias sl=ls
|
||||
|
@ -62,31 +65,48 @@ alias tracefiles="strace -f -t -e trace=file"
|
|||
alias n='urxvtc &'
|
||||
|
||||
# Superseding commands with better ones if they are present
|
||||
function vi() {
|
||||
if which vim &> /dev/null; then
|
||||
alias vi='vim'
|
||||
function _do_rank() { # executables... -- arguments...
|
||||
for ex in "$@"
|
||||
do
|
||||
[ "$ex" == "--" ] && break
|
||||
if which "$ex" &> /dev/null
|
||||
then
|
||||
for al in "$@"
|
||||
do
|
||||
shift
|
||||
[ "$al" == "--" ] && break
|
||||
alias "$al"="$ex"
|
||||
done
|
||||
"$ex" "$@"
|
||||
return $?
|
||||
fi
|
||||
vim "$@"
|
||||
}
|
||||
function pass() {
|
||||
if which gopass &> /dev/null; then
|
||||
alias pass='gopass'
|
||||
done
|
||||
for ex in "$@"
|
||||
do
|
||||
[ "$al" == "--" ] && break
|
||||
if -z "$list"
|
||||
then
|
||||
list=$ex
|
||||
else
|
||||
list=$list, $ex
|
||||
fi
|
||||
gopass "$@"
|
||||
done
|
||||
echo "Not installed: $list"
|
||||
}
|
||||
function wol() {
|
||||
if which wakeonlan &> /dev/null; then
|
||||
alias wol='wakeonlan'
|
||||
fi
|
||||
wakeonlan "$@"
|
||||
}
|
||||
function mutt() {
|
||||
if which neomutt &> /dev/null; then
|
||||
alias mutt='neomutt'
|
||||
fi
|
||||
neomutt "$@"
|
||||
|
||||
function _install_rank() { # executables...
|
||||
for ex in "$@"
|
||||
do
|
||||
list=$@
|
||||
alias "$ex"="_do_rank $list --"
|
||||
done
|
||||
}
|
||||
|
||||
_install_rank nvim vim vi
|
||||
_install_rank gopass pass
|
||||
_install_rank wakeonlan wol
|
||||
_install_rank neomutt mutt
|
||||
|
||||
# SHELL CUSTOMIZATION
|
||||
|
||||
complete -cf sudo
|
||||
|
|
141
scripts/mel
Executable file
141
scripts/mel
Executable file
|
@ -0,0 +1,141 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Meh mail client
|
||||
"""
|
||||
|
||||
import notmuch
|
||||
import logging
|
||||
import coloredlogs
|
||||
import colorama
|
||||
import datetime
|
||||
import os
|
||||
import progressbar
|
||||
import time
|
||||
|
||||
colorama.init()
|
||||
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||
log = logging.getLogger()
|
||||
|
||||
log.debug("Loading database")
|
||||
|
||||
db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE)
|
||||
# TODO Open read-only when needed
|
||||
|
||||
log.debug("Database loaded")
|
||||
|
||||
def get_location(msg):
|
||||
path = msg.get_filename()
|
||||
path = os.path.dirname(path)
|
||||
base = db.get_path()
|
||||
assert path.startswith(base)
|
||||
path = path[len(base):]
|
||||
_, mailbox, folder, state = path.split('/')
|
||||
assert state in {'cur', 'tmp', 'new'}
|
||||
return (mailbox, folder, state)
|
||||
|
||||
MAILBOX_COLORS = dict()
|
||||
|
||||
def get_mailbox_color(mailbox):
|
||||
if mailbox not in MAILBOX_COLORS:
|
||||
colorfile = os.path.join(db.get_path(), mailbox, 'color')
|
||||
assert os.path.isfile(colorfile)
|
||||
with open(colorfile, 'r') as f:
|
||||
colorStr = f.read()
|
||||
colorStr = colorStr[1:] if colorStr[0] == '#' else colorStr
|
||||
R = int(colorStr[0:2], 16)
|
||||
G = int(colorStr[2:4], 16)
|
||||
B = int(colorStr[4:6], 16)
|
||||
MAILBOX_COLORS[mailbox] = '\x1b[38;2;{};{};{}m'.format(R, G, B)
|
||||
return MAILBOX_COLORS[mailbox]
|
||||
|
||||
def format_date(date):
|
||||
now = datetime.datetime.now()
|
||||
midnight = datetime.datetime(year=now.year, month=now.month, day=now.day)
|
||||
if date > midnight:
|
||||
return date.strftime('%H:%M:%S')
|
||||
else:
|
||||
return date.strftime('%d/%m/%y')
|
||||
|
||||
|
||||
def print_msg(msg):
|
||||
line = ""
|
||||
tags = set(msg.get_tags())
|
||||
mailbox, folder, state = get_location(msg)
|
||||
line += get_mailbox_color(mailbox)
|
||||
|
||||
# Date
|
||||
date = datetime.datetime.fromtimestamp(msg.get_date())
|
||||
line += format_date(date)
|
||||
|
||||
# Icons
|
||||
line += " "
|
||||
def tags2col1(tag1, tag2, both, first, second, none):
|
||||
nonlocal line
|
||||
if tag1 in tags:
|
||||
if tag2 in tags:
|
||||
line += both
|
||||
else:
|
||||
line += first
|
||||
else:
|
||||
if tag2 in tags:
|
||||
line += second
|
||||
else:
|
||||
line += none
|
||||
|
||||
tags2col1('spam', 'draft', '??', '💥', '📝', ' ')
|
||||
tags2col1('attachment', 'encrypted', '🔐', '📎', '🔑', ' ')
|
||||
tags2col1('unread', 'flagged', '🏁', '🏳 ', '🏴', ' ')
|
||||
tags2col1('sent', 'replied', '?', '↑', '↪', ' ')
|
||||
|
||||
# TODO To: / From:
|
||||
|
||||
# Subject
|
||||
line += " "
|
||||
line += msg.get_header("subject")
|
||||
line += colorama.Style.RESET_ALL
|
||||
print(line)
|
||||
|
||||
|
||||
def retag_msg(msg):
|
||||
msg.freeze()
|
||||
mailbox, folder, state = get_location(msg)
|
||||
|
||||
# Search-friendly folder name
|
||||
if folder.startswith('INBOX.'):
|
||||
folder = folder[6:]
|
||||
folder = folder.upper()
|
||||
|
||||
msg.remove_all_tags()
|
||||
if folder.startswith('JUNK') or folder.startswith('SPAM'):
|
||||
msg.add_tag('spam')
|
||||
if folder.startswith('DRAFT'):
|
||||
msg.add_tag('draft')
|
||||
if folder.startswith('INBOX'):
|
||||
msg.add_tag('inbox')
|
||||
|
||||
# TODO 'sent' tag
|
||||
|
||||
# Save
|
||||
msg.thaw()
|
||||
msg.tags_to_maildir_flags()
|
||||
|
||||
|
||||
def applyMsgs(queryStr, function, useProgressbar=False):
|
||||
query = notmuch.Query(db, queryStr)
|
||||
query.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
|
||||
msgs = query.search_messages()
|
||||
if useProgressbar:
|
||||
nbMsgs = query.count_messages()
|
||||
iterator = progressbar.progressbar(msgs, max_value=nbMsgs)
|
||||
else:
|
||||
iterator = msgs
|
||||
for msg in iterator:
|
||||
function(msg)
|
||||
|
||||
applyMsgs('tag:inbox', print_msg)
|
||||
# applyMsgs('tag:spam', print_msg)
|
||||
# applyMsgs('tag:unread', print_msg)
|
||||
# applyMsgs('from:geoffrey@frogeye.fr', print_msg)
|
||||
|
||||
# applyMsgs('*', retag_msg, useProgressbar=True)
|
176
scripts/melConf
Executable file
176
scripts/melConf
Executable file
|
@ -0,0 +1,176 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Meh mail client conf generator for other things
|
||||
"""
|
||||
|
||||
import configparser
|
||||
import os
|
||||
import sys
|
||||
|
||||
# TODO Find config file from XDG
|
||||
# TODO Alias adresses
|
||||
# TODO Signature file
|
||||
# TODO Write ~/.mail/[mailbox]/color file if required by sth?
|
||||
# Certificate file
|
||||
|
||||
configPath = os.path.join(os.path.expanduser('~'), '.config', 'mel.conf')
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(configPath)
|
||||
|
||||
SERVER_DEFAULTS = {
|
||||
"imap": {"port": 143, "starttls": True},
|
||||
"smtp": {"port": 587, "starttls": True},
|
||||
}
|
||||
SERVER_ITEMS = {"host", "port", "user", "pass", "starttls"}
|
||||
|
||||
# Reading sections
|
||||
accounts = dict()
|
||||
|
||||
for name in config.sections():
|
||||
if not name.islower():
|
||||
continue
|
||||
section = config[name]
|
||||
|
||||
data = dict()
|
||||
for server in SERVER_DEFAULTS.keys():
|
||||
for item in SERVER_ITEMS:
|
||||
key = server + item
|
||||
try:
|
||||
val = section.get(key) or section.get(item) or SERVER_DEFAULTS[server][item]
|
||||
except KeyError:
|
||||
raise KeyError("{}.{}".format(name, key))
|
||||
|
||||
if isinstance(val, str):
|
||||
if val == "True":
|
||||
val = True
|
||||
elif val == "False":
|
||||
val = False
|
||||
elif val.isnumeric():
|
||||
val = int(val)
|
||||
data[key] = val
|
||||
|
||||
for key in section.keys():
|
||||
if key in SERVER_ITEMS:
|
||||
continue
|
||||
data[key] = section[key]
|
||||
|
||||
data["name"] = name
|
||||
data["storage"] = os.path.join(config['GLOBAL']['storage'], name)
|
||||
data["storageInbox"] = os.path.join(data["storage"], "INBOX")
|
||||
storageFull = os.path.expanduser(data["storage"])
|
||||
os.makedirs(storageFull, exist_ok=True)
|
||||
accounts[name] = data
|
||||
|
||||
# OfflineIMAP
|
||||
|
||||
OFFLINEIMAP_BEGIN = """[general]
|
||||
# List of accounts to be synced, separated by a comma.
|
||||
accounts = {}
|
||||
maxsyncaccounts = {}
|
||||
stocktimeout = 60
|
||||
pythonfile = ~/.config/offlineimap.py
|
||||
|
||||
[mbnames]
|
||||
enabled = yes
|
||||
filename = ~/.mutt/mailboxes
|
||||
header = "mailboxes "
|
||||
peritem = "+%(accountname)s/%(foldername)s"
|
||||
sep = " "
|
||||
footer = "\\n"
|
||||
|
||||
"""
|
||||
|
||||
OFFLINEIMAP_ACCOUNT = """[Account {name}]
|
||||
localrepository = {name}-local
|
||||
remoterepository = {name}-remote
|
||||
autorefresh = 0.5
|
||||
quick = 10
|
||||
utf8foldernames = yes
|
||||
postsynchook = ~/.mutt/postsync
|
||||
|
||||
[Repository {name}-local]
|
||||
type = Maildir
|
||||
localfolders = {storage}
|
||||
|
||||
[Repository {name}-remote]
|
||||
type = IMAP
|
||||
{secconf}
|
||||
keepalive = 60
|
||||
holdconnectionopen = yes
|
||||
remotehost = {imaphost}
|
||||
remoteport = {imapport}
|
||||
remoteuser = {imapuser}
|
||||
remotepass = {imappass}
|
||||
|
||||
"""
|
||||
|
||||
offlineIMAPstr = OFFLINEIMAP_BEGIN.format(','.join(accounts), len(accounts))
|
||||
for name, account in accounts.items():
|
||||
if account["imapstarttls"]:
|
||||
secconf = "ssl = no"
|
||||
else:
|
||||
secconf = "sslcacertfile = /etc/ssl/certs/ca-certificates.crt"
|
||||
offlineIMAPstr += OFFLINEIMAP_ACCOUNT.format(**account, secconf=secconf)
|
||||
# TODO Write
|
||||
|
||||
# mbsync
|
||||
MBSYNC_ACCOUNT = """IMAPAccount {name}
|
||||
Host {imaphost}
|
||||
User {imapuser}
|
||||
Pass "{imappass}"
|
||||
{secconf}
|
||||
|
||||
IMAPStore {name}-remote
|
||||
Account {name}
|
||||
|
||||
MaildirStore {name}-local
|
||||
Subfolders Verbatim
|
||||
Path {storage}/
|
||||
Inbox {storageInbox}/
|
||||
|
||||
Channel {name}
|
||||
Master :{name}-remote:
|
||||
Slave :{name}-local:
|
||||
Patterns *
|
||||
Create Both
|
||||
SyncState *
|
||||
|
||||
"""
|
||||
|
||||
mbsyncStr = ""
|
||||
for name, account in accounts.items():
|
||||
if account["imapstarttls"]:
|
||||
secconf = "SSLType STARTTLS"
|
||||
else:
|
||||
secconf = "SSLType IMAPS"
|
||||
mbsyncStr += MBSYNC_ACCOUNT.format(**account, secconf=secconf)
|
||||
msbsyncFilepath = os.path.join(os.path.expanduser('~'), '.mbsyncrc')
|
||||
with open(msbsyncFilepath, 'w') as f:
|
||||
f.write(mbsyncStr)
|
||||
|
||||
# msmtp
|
||||
MSMTP_BEGIN = """defaults
|
||||
protocol smtp
|
||||
auth on
|
||||
tls_trust_file /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
"""
|
||||
|
||||
MSMTP_ACCOUNT = """account {name}
|
||||
from {from}
|
||||
user {smtpuser}
|
||||
password {smtppass}
|
||||
host {smtphost}
|
||||
port {smtpport}
|
||||
tls on
|
||||
|
||||
"""
|
||||
|
||||
msmtpStr = MSMTP_BEGIN
|
||||
for name, account in accounts.items():
|
||||
msmtpStr += MSMTP_ACCOUNT.format(**account)
|
||||
msbsyncFilepath = os.path.join(os.path.expanduser('~'), '.msmtprc')
|
||||
with open(msbsyncFilepath, 'w') as f:
|
||||
f.write(msmtpStr)
|
|
@ -146,20 +146,26 @@ do
|
|||
|
||||
done <<< "$(find "$dir" -type f -iname "*.png")"
|
||||
|
||||
# SVG (requires svgo)
|
||||
while read image
|
||||
do
|
||||
if [ -z "$image" ]; then continue; fi
|
||||
echo Processing $image
|
||||
# # SVG (requires scour)
|
||||
# while read image
|
||||
# do
|
||||
# if [ -z "$image" ]; then continue; fi
|
||||
# echo Processing $image
|
||||
#
|
||||
# temp=$(mktemp --suffix .svg)
|
||||
# scour --quiet "$image" "$temp" --no-line-breaks
|
||||
# echo "→ Optimize done"
|
||||
#
|
||||
# replaceImg "$temp" "$image"
|
||||
#
|
||||
# done <<< "$(find "$dir" -type f -iname "*.svg")"
|
||||
|
||||
temp=$(mktemp --suffix .svg)
|
||||
cp "$image" "$temp"
|
||||
svgo --quiet --config $HOME/.config/optiSvgo.yml "$temp"
|
||||
echo "→ Optimize done"
|
||||
|
||||
replaceImg "$temp" "$image"
|
||||
|
||||
done <<< "$(find "$dir" -type f -iname "*.svg")"
|
||||
# NOTE Explicitely disabled since:
|
||||
# - I only have ~50 MiB of SVG in TOTAL
|
||||
# - Most conversions are not image losseless
|
||||
# - Even when they are losseless, they are mostly worthless
|
||||
# - I might want to keep editor data and/or ids for some of them
|
||||
# So rather use scour explicitely when needed
|
||||
|
||||
cleandev
|
||||
|
||||
|
|
Loading…
Reference in a new issue