Merge branch 'master' of https://git.frogeye.fr:8443/geoffrey/dotfiles
This commit is contained in:
commit
f94154c8f5
|
@ -1,3 +1,4 @@
|
||||||
#include ".Xresources.d/xft"
|
#include ".Xresources.d/xft"
|
||||||
#include ".Xresources.d/theme"
|
#include ".Xresources.d/theme"
|
||||||
#include ".Xresources.d/xterm"
|
#include ".Xresources.d/xterm"
|
||||||
|
#include ".Xresources.d/urxvt"
|
||||||
|
|
1
Xresources.d/.gitignore
vendored
Normal file
1
Xresources.d/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
theme
|
|
@ -1,36 +0,0 @@
|
||||||
! special
|
|
||||||
*.foreground: #f1ebeb
|
|
||||||
*.background: #272822
|
|
||||||
*.cursorColor: #f1ebeb
|
|
||||||
|
|
||||||
! black
|
|
||||||
*.color0: #48483e
|
|
||||||
*.color8: #76715e
|
|
||||||
|
|
||||||
! red
|
|
||||||
*.color1: #dc2566
|
|
||||||
*.color9: #fa2772
|
|
||||||
|
|
||||||
! green
|
|
||||||
*.color2: #8fc029
|
|
||||||
*.color10: #a7e22e
|
|
||||||
|
|
||||||
! yellow
|
|
||||||
*.color3: #d4c96e
|
|
||||||
*.color11: #e7db75
|
|
||||||
|
|
||||||
! blue
|
|
||||||
*.color4: #55bcce
|
|
||||||
*.color12: #66d9ee
|
|
||||||
|
|
||||||
! magenta
|
|
||||||
*.color5: #9358fe
|
|
||||||
*.color13: #ae82ff
|
|
||||||
|
|
||||||
! cyan
|
|
||||||
*.color6: #56b7a5
|
|
||||||
*.color14: #66efd5
|
|
||||||
|
|
||||||
! white
|
|
||||||
*.color7: #acada1
|
|
||||||
*.color15: #cfd0c2
|
|
55
Xresources.d/urxvt
Normal file
55
Xresources.d/urxvt
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
! Scrollback position
|
||||||
|
! TODO Does not work
|
||||||
|
|
||||||
|
! do not scroll with output
|
||||||
|
URxvt*scrollTtyOutput: false
|
||||||
|
|
||||||
|
! scroll in relation to buffer (with mouse scroll or Shift+Page Up)
|
||||||
|
URxvt*scrollWithBuffer: true
|
||||||
|
|
||||||
|
! scroll back to the bottom on keypress
|
||||||
|
URxvt*scrollTtyKeypress: true
|
||||||
|
|
||||||
|
|
||||||
|
! Scrollback buffer in secondary screen
|
||||||
|
! TODO Does not work
|
||||||
|
URxvt.secondaryScreen: 1
|
||||||
|
URxvt.secondaryScroll: 0
|
||||||
|
|
||||||
|
|
||||||
|
! No scroll bar
|
||||||
|
URxvt*scrollBar: false
|
||||||
|
|
||||||
|
|
||||||
|
! Font declaration
|
||||||
|
URxvt.font: xft:DejaVu Sans Mono for Powerline:size=12:antialias=true,xft:Symbola:size=12:antialias=true
|
||||||
|
|
||||||
|
! Font spacing
|
||||||
|
URxvt.letterSpace: 0
|
||||||
|
|
||||||
|
! Disable Ctrl+Shift default bindings
|
||||||
|
URxvt.iso14755: false
|
||||||
|
URxvt.iso14755_52: false
|
||||||
|
|
||||||
|
! Copy/Paste CLIPBOARD selection with Ctrl+Shift+C/V
|
||||||
|
URxvt.keysym.C-S-C: eval:selection_to_clipboard
|
||||||
|
URxvt.keysym.C-S-V: eval:paste_clipboard
|
||||||
|
|
||||||
|
|
||||||
|
! Extensions
|
||||||
|
URxvt.perl-ext-common: resize-font,bell-command,readline,selection
|
||||||
|
|
||||||
|
! Changing font size on the fly (extension: resize-font, package: urxvt-resize-font-git)
|
||||||
|
URxvt.keysym.C-KP_Subtract: resize-font:smaller
|
||||||
|
URxvt.keysym.C-KP_Add: resize-font:bigger
|
||||||
|
|
||||||
|
! Fake transparency (without compositing manager)
|
||||||
|
urxvt*transparent: true
|
||||||
|
urxvt*shading: 30
|
||||||
|
|
||||||
|
! True transparency (with compositing manager)
|
||||||
|
!urxvt*depth: 32
|
||||||
|
!urxvt*background: rgba:2700/2800/2200/c800
|
||||||
|
|
||||||
|
! Bell command (extension: bell-command)
|
||||||
|
URxvt.bell-command: play -n synth sine C5 sine E4 remix 1-2 fade 0.1 0.2 0.1 &> /dev/null
|
75
bashrc
75
bashrc
|
@ -12,11 +12,6 @@ export BROWSER=qutebrowser
|
||||||
|
|
||||||
# Some programs need those changes
|
# Some programs need those changes
|
||||||
export PATH="/usr/lib/ccache/bin/:$PATH"
|
export PATH="/usr/lib/ccache/bin/:$PATH"
|
||||||
GEM_HOME=$(ruby -e 'puts Gem.user_dir' 2> /dev/null)
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
GEM_PATH=$GEM_HOME
|
|
||||||
export PATH="$PATH:$GEM_HOME/bin"
|
|
||||||
fi
|
|
||||||
if [ -d /data/data/com.termux/ ]; then
|
if [ -d /data/data/com.termux/ ]; then
|
||||||
export PATH="$HOME/.termux/scripts:$HOME/.termux/bin:$PATH"
|
export PATH="$HOME/.termux/scripts:$HOME/.termux/bin:$PATH"
|
||||||
fi
|
fi
|
||||||
|
@ -44,8 +39,10 @@ alias dd='dd status=progress'
|
||||||
alias rm='rm -Iv --one-file-system'
|
alias rm='rm -Iv --one-file-system'
|
||||||
alias free='free -m'
|
alias free='free -m'
|
||||||
alias df='df -h'
|
alias df='df -h'
|
||||||
alias pacman='pacman --color auto'
|
|
||||||
alias dmesg='dmesg --ctime'
|
alias dmesg='dmesg --ctime'
|
||||||
|
alias ffmpeg='ffmpeg -hide_banner'
|
||||||
|
alias ffprobe='ffprobe -hide_banner'
|
||||||
|
alias ffplay='ffplay -hide_banner'
|
||||||
|
|
||||||
# Frequent mistakes
|
# Frequent mistakes
|
||||||
alias sl=ls
|
alias sl=ls
|
||||||
|
@ -62,17 +59,50 @@ alias po='eval $(proxy off)'
|
||||||
alias nw="sudo systemctl restart NetworkManager"
|
alias nw="sudo systemctl restart NetworkManager"
|
||||||
alias mc="machines"
|
alias mc="machines"
|
||||||
alias tracefiles="strace -f -t -e trace=file"
|
alias tracefiles="strace -f -t -e trace=file"
|
||||||
|
alias n='urxvtc &'
|
||||||
|
|
||||||
# Superseding commands with better ones if they are present
|
# Superseding commands with better ones if they are present
|
||||||
if which vim &> /dev/null; then
|
function _do_rank() { # executables... -- arguments...
|
||||||
alias vi='vim'
|
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
|
fi
|
||||||
if which gopass &> /dev/null; then
|
done
|
||||||
alias pass='gopass'
|
for ex in "$@"
|
||||||
fi
|
do
|
||||||
if which wakeonlan &> /dev/null; then
|
[ "$al" == "--" ] && break
|
||||||
alias wol='wakeonlan'
|
if -z "$list"
|
||||||
|
then
|
||||||
|
list=$ex
|
||||||
|
else
|
||||||
|
list=$list, $ex
|
||||||
fi
|
fi
|
||||||
|
done
|
||||||
|
echo "Not installed: $list"
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
# SHELL CUSTOMIZATION
|
||||||
|
|
||||||
|
@ -89,7 +119,8 @@ shopt -s hostcomplete
|
||||||
|
|
||||||
export HISTSIZE=100000
|
export HISTSIZE=100000
|
||||||
export HISTFILESIZE=${HISTSIZE}
|
export HISTFILESIZE=${HISTSIZE}
|
||||||
export HISTCONTROL=ignoreboth
|
export HISTCONTROL=ignorespace:erasedups
|
||||||
|
export HISTTIMEFORMAT="%y-%m-%d %H:%M:%S "
|
||||||
|
|
||||||
# PROMPT CUSTOMIZATION
|
# PROMPT CUSTOMIZATION
|
||||||
|
|
||||||
|
@ -104,16 +135,28 @@ export PS1="\[\e]2;\u@\h \w\a\]\[\e[0;37m\][\[\e[0;${col}m\]\u\[\e[0;37m\]@\[\e[
|
||||||
export PS2="> "
|
export PS2="> "
|
||||||
export PS3="+ "
|
export PS3="+ "
|
||||||
export PS4="- "
|
export PS4="- "
|
||||||
|
export PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}:${PWD}\007"'
|
||||||
|
|
||||||
# CUSTOM SCRIPTS
|
# CUSTOM SCRIPTS
|
||||||
|
|
||||||
export PATH="$HOME/.bin/:$HOME/.scripts/:$PATH"
|
export PATH="$HOME/.local/bin/:$HOME/.scripts/:$PATH"
|
||||||
[ -f ~/.gscripts/gprofile ] && source ~/.gscripts/gprofile
|
[ -f ~/.gscripts/gprofile ] && source ~/.gscripts/gprofile
|
||||||
|
|
||||||
# UTILITIES
|
# UTILITIES
|
||||||
|
|
||||||
|
# Theme
|
||||||
|
[ -f ~/.local/bin/colorSchemeApply ] && source ~/.local/bin/colorSchemeApply
|
||||||
|
[ -f ~/.local/bin/colorSchemeApplyFzf ] && source ~/.local/bin/colorSchemeApplyFzf
|
||||||
|
|
||||||
# Bash completion
|
# Bash completion
|
||||||
[ -f /etc/bash_completion ] && . /etc/bash_completion
|
[ -f /etc/bash_completion ] && source /etc/bash_completion
|
||||||
|
|
||||||
|
# Fuzzy matching all the way
|
||||||
|
export FZF_DEFAULT_OPTS="${FZF_DEFAULT_OPTS} --height 100% --layout=default"
|
||||||
|
export FZF_CTRL_T_OPTS="--preview '[[ -d {} ]] && ls -l --color=always {} || [[ \$(file --mime {}) =~ binary ]] && echo {} is a binary file || (highlight -O ansi -l {} || coderay {} || rougify {} || cat {}) 2> /dev/null | head -500'"
|
||||||
|
export FZF_COMPLETION_OPTS="${FZF_CTRL_T_OPTS}"
|
||||||
|
[ -f /usr/share/fzf/completion.bash ] && source /usr/share/fzf/completion.bash
|
||||||
|
[ -f /usr/share/fzf/key-bindings.bash ] && source /usr/share/fzf/key-bindings.bash
|
||||||
|
|
||||||
# Bad day mood-saver
|
# Bad day mood-saver
|
||||||
function fuck {
|
function fuck {
|
||||||
|
|
2
bin/.gitignore
vendored
2
bin/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
||||||
*
|
|
||||||
!.gitignore
|
|
|
@ -1,53 +0,0 @@
|
||||||
shadow = false;
|
|
||||||
no-dnd-shadow = true;
|
|
||||||
no-dock-shadow = true;
|
|
||||||
clear-shadow = true;
|
|
||||||
|
|
||||||
menu-opacity = 0.9;
|
|
||||||
inactive-opacity = 0.93;
|
|
||||||
active-opacity = 1;
|
|
||||||
alpha-step = 0.01;
|
|
||||||
inactive-dim = 0.0;
|
|
||||||
blur-background = false;
|
|
||||||
blur-kern = "3x3box";
|
|
||||||
|
|
||||||
fading = false;
|
|
||||||
fade-delta = 1;
|
|
||||||
fade-in-step = 0.03;
|
|
||||||
fade-out-step = 0.03;
|
|
||||||
fade-exclude = [ ];
|
|
||||||
|
|
||||||
backend = "xrender";
|
|
||||||
mark-wmwin-focused = true;
|
|
||||||
mark-ovredir-focused = true;
|
|
||||||
detect-rounded-corners = true;
|
|
||||||
detect-client-opacity = true;
|
|
||||||
unredir-if-possible = true;
|
|
||||||
refresh-rate = 0;
|
|
||||||
vsync = "none";
|
|
||||||
dbe = false;
|
|
||||||
paint-on-overlay = true;
|
|
||||||
focus-exclude = [ "class_g = 'Cairo-clock'" ];
|
|
||||||
detect-transient = true;
|
|
||||||
detect-client-leader = true;
|
|
||||||
invert-color-include = [ ];
|
|
||||||
glx-copy-from-front = false;
|
|
||||||
glx-swap-method = "undefined";
|
|
||||||
|
|
||||||
wintypes :
|
|
||||||
{
|
|
||||||
tooltip :
|
|
||||||
{
|
|
||||||
fade = true;
|
|
||||||
shadow = false;
|
|
||||||
opacity = 0.75;
|
|
||||||
focus = true;
|
|
||||||
};
|
|
||||||
fullscreen :
|
|
||||||
{
|
|
||||||
fade = true;
|
|
||||||
shadow = false;
|
|
||||||
opacity = 1;
|
|
||||||
focus = true;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,300 +1,63 @@
|
||||||
[global]
|
[global]
|
||||||
font = Cantarell 10
|
|
||||||
|
|
||||||
# Allow a small subset of html markup:
|
|
||||||
# <b>bold</b>
|
|
||||||
# <i>italic</i>
|
|
||||||
# <s>strikethrough</s>
|
|
||||||
# <u>underline</u>
|
|
||||||
#
|
|
||||||
# For a complete reference see
|
|
||||||
# <http://developer.gnome.org/pango/stable/PangoMarkupFormat.html>.
|
|
||||||
# If markup is not allowed, those tags will be stripped out of the
|
|
||||||
# message.
|
|
||||||
allow_markup = yes
|
|
||||||
|
|
||||||
# The format of the message. Possible variables are:
|
|
||||||
# %a appname
|
|
||||||
# %s summary
|
|
||||||
# %b body
|
|
||||||
# %i iconname (including its path)
|
|
||||||
# %I iconname (without its path)
|
|
||||||
# %p progress value if set ([ 0%] to [100%]) or nothing
|
|
||||||
# Markup is allowed
|
|
||||||
format = "%s %p\n%b"
|
|
||||||
|
|
||||||
# Sort messages by urgency.
|
|
||||||
sort = no
|
|
||||||
|
|
||||||
# Show how many messages are currently hidden (because of geometry).
|
|
||||||
indicate_hidden = yes
|
|
||||||
|
|
||||||
# Alignment of message text.
|
|
||||||
# Possible values are "left", "center" and "right".
|
|
||||||
alignment = left
|
alignment = left
|
||||||
|
always_run_script = true
|
||||||
# The frequency with wich text that is longer than the notification
|
browser = /usr/bin/qutebrowser
|
||||||
# window allows bounces back and forth.
|
class = Dunst
|
||||||
# This option conflicts with "word_wrap".
|
|
||||||
# Set to 0 to disable.
|
|
||||||
bounce_freq = 5
|
|
||||||
|
|
||||||
|
|
||||||
# Show age of message if message is older than show_age_threshold
|
|
||||||
# seconds.
|
|
||||||
# Set to -1 to disable.
|
|
||||||
show_age_threshold = 60
|
|
||||||
|
|
||||||
# Split notifications into multiple lines if they don't fit into
|
|
||||||
# geometry.
|
|
||||||
word_wrap = no
|
|
||||||
|
|
||||||
# Ignore newlines '\n' in notifications.
|
|
||||||
ignore_newline = no
|
|
||||||
|
|
||||||
|
|
||||||
# The geometry of the window:
|
|
||||||
# [{width}]x{height}[+/-{x}+/-{y}]
|
|
||||||
# The geometry of the message window.
|
|
||||||
# The height is measured in number of notifications everything else
|
|
||||||
# in pixels. If the width is omitted but the height is given
|
|
||||||
# ("-geometry x2"), the message window expands over the whole screen
|
|
||||||
# (dmenu-like). If width is 0, the window expands to the longest
|
|
||||||
# message displayed. A positive x is measured from the left, a
|
|
||||||
# negative from the right side of the screen. Y is measured from
|
|
||||||
# the top and down respectevly.
|
|
||||||
# The width can be negative. In this case the actual width is the
|
|
||||||
# screen width minus the width defined in within the geometry option.
|
|
||||||
geometry = "0x0-25+25"
|
|
||||||
|
|
||||||
# Shrink window if it's smaller than the width. Will be ignored if
|
|
||||||
# width is 0.
|
|
||||||
shrink = yes
|
|
||||||
|
|
||||||
# The transparency of the window. Range: [0; 100].
|
|
||||||
# This option will only work if a compositing windowmanager is
|
|
||||||
# present (e.g. xcompmgr, compiz, etc.).
|
|
||||||
transparency = 17
|
|
||||||
|
|
||||||
# Don't remove messages, if the user is idle (no mouse or keyboard input)
|
|
||||||
# for longer than idle_threshold seconds.
|
|
||||||
# Set to 0 to disable.
|
|
||||||
# default 120
|
|
||||||
idle_threshold = 120
|
|
||||||
|
|
||||||
# Which monitor should the notifications be displayed on.
|
|
||||||
monitor = 0
|
|
||||||
|
|
||||||
# Display notification on focused monitor. Possible modes are:
|
|
||||||
# mouse: follow mouse pointer
|
|
||||||
# keyboard: follow window with keyboard focus
|
|
||||||
# none: don't follow anything
|
|
||||||
#
|
|
||||||
# "keyboard" needs a windowmanager that exports the
|
|
||||||
# _NET_ACTIVE_WINDOW property.
|
|
||||||
# This should be the case for almost all modern windowmanagers.
|
|
||||||
#
|
|
||||||
# If this option is set to mouse or keyboard, the monitor option
|
|
||||||
# will be ignored.
|
|
||||||
follow = none
|
|
||||||
|
|
||||||
# Should a notification popped up from history be sticky or timeout
|
|
||||||
# as if it would normally do.
|
|
||||||
sticky_history = yes
|
|
||||||
|
|
||||||
# Maximum amount of notifications kept in history
|
|
||||||
history_length = 20
|
|
||||||
|
|
||||||
# Display indicators for URLs (U) and actions (A).
|
|
||||||
show_indicators = yes
|
|
||||||
|
|
||||||
# The height of a single line. If the height is smaller than the
|
|
||||||
# font height, it will get raised to the font height.
|
|
||||||
# This adds empty space above and under the text.
|
|
||||||
line_height = 0
|
|
||||||
|
|
||||||
# Draw a line of "separator_height" pixel height between two
|
|
||||||
# notifications.
|
|
||||||
# Set to 0 to disable.
|
|
||||||
separator_height = 1
|
|
||||||
|
|
||||||
# Padding between text and separator.
|
|
||||||
# padding = 8
|
|
||||||
padding = 8
|
|
||||||
|
|
||||||
# Horizontal padding.
|
|
||||||
horizontal_padding = 10
|
|
||||||
|
|
||||||
# Define a color for the separator.
|
|
||||||
# possible values are:
|
|
||||||
# * auto: dunst tries to find a color fitting to the background;
|
|
||||||
# * foreground: use the same color as the foreground;
|
|
||||||
# * frame: use the same color as the frame;
|
|
||||||
# * anything else will be interpreted as a X color.
|
|
||||||
separator_color = #2ECC71
|
|
||||||
|
|
||||||
# Print a notification on startup.
|
|
||||||
# This is mainly for error detection, since dbus (re-)starts dunst
|
|
||||||
# automatically after a crash.
|
|
||||||
startup_notification = false
|
|
||||||
|
|
||||||
# dmenu path.
|
|
||||||
dmenu = /usr/bin/dmenu -p dunst:
|
dmenu = /usr/bin/dmenu -p dunst:
|
||||||
|
ellipsize = middle
|
||||||
# Browser for opening urls in context menu.
|
follow = none
|
||||||
browser = firefox
|
font = DejaVu Sans 10
|
||||||
|
force_xinerama = false
|
||||||
# Align icons left/right/off
|
format = "<b>%s %p</b>\n%b"
|
||||||
|
frame_color = "#A6E22E"
|
||||||
|
frame_width = 3
|
||||||
|
geometry = "500x5-30+20"
|
||||||
|
hide_duplicate_count = false
|
||||||
|
history_length = 20
|
||||||
|
horizontal_padding = 8
|
||||||
|
icon_path = /usr/share/icons/gnome/256x256/actions/:/usr/share/icons/gnome/256x256/status/:/usr/share/icons/gnome/256x256/devices/
|
||||||
icon_position = left
|
icon_position = left
|
||||||
|
idle_threshold = 120
|
||||||
# Paths to default icons.
|
ignore_newline = no
|
||||||
icon_folders = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/
|
indicate_hidden = yes
|
||||||
|
line_height = 0
|
||||||
[frame]
|
markup = full
|
||||||
width = 1
|
max_icon_size = 48
|
||||||
color = "#2ECC71"
|
monitor = 0
|
||||||
|
notification_height = 0
|
||||||
|
padding = 8
|
||||||
|
separator_color = frame
|
||||||
|
separator_height = 2
|
||||||
|
show_age_threshold = 60
|
||||||
|
show_indicators = yes
|
||||||
|
shrink = no
|
||||||
|
sort = yes
|
||||||
|
stack_duplicates = true
|
||||||
|
startup_notification = false
|
||||||
|
sticky_history = yes
|
||||||
|
title = Dunst
|
||||||
|
transparency = 0
|
||||||
|
verbosity = mesg
|
||||||
|
word_wrap = yes
|
||||||
|
[experimental]
|
||||||
|
per_monitor_dpi = false
|
||||||
[shortcuts]
|
[shortcuts]
|
||||||
|
|
||||||
# Shortcuts are specified as [modifier+][modifier+]...key
|
|
||||||
# Available modifiers are "ctrl", "mod1" (the alt-key), "mod2",
|
|
||||||
# "mod3" and "mod4" (windows-key).
|
|
||||||
# Xev might be helpful to find names for keys.
|
|
||||||
|
|
||||||
# Close notification.
|
|
||||||
close = mod4+n
|
|
||||||
|
|
||||||
# Close all notifications.
|
|
||||||
# close_all = ctrl+shift+space
|
|
||||||
close_all = ctrl+mod4+n
|
close_all = ctrl+mod4+n
|
||||||
|
close = mod4+n
|
||||||
# Redisplay last message(s).
|
|
||||||
# On the US keyboard layout "grave" is normally above TAB and left
|
|
||||||
# of "1".
|
|
||||||
history = shift+mod4+n
|
|
||||||
|
|
||||||
# Context menu.
|
|
||||||
context = mod1+mod4+n
|
context = mod1+mod4+n
|
||||||
|
history = shift+mod4+n
|
||||||
[urgency_low]
|
[urgency_low]
|
||||||
# IMPORTANT: colors have to be defined in quotation marks.
|
background = "#272822"
|
||||||
# Otherwise the "#" and following would be interpreted as a comment.
|
foreground = "#F8F8F2"
|
||||||
background = "#000000"
|
frame_color = "#A6E22E"
|
||||||
foreground = "#888888"
|
|
||||||
timeout = 10
|
timeout = 10
|
||||||
|
|
||||||
[urgency_normal]
|
[urgency_normal]
|
||||||
background = "#000000"
|
background = "#272822"
|
||||||
foreground = "#ffffff"
|
foreground = "#F8F8F2"
|
||||||
|
frame_color = "#F4BF75"
|
||||||
timeout = 10
|
timeout = 10
|
||||||
|
|
||||||
[urgency_critical]
|
[urgency_critical]
|
||||||
background = "#900000"
|
background = "#272822"
|
||||||
foreground = "#ffffff"
|
foreground = "#F8F8F2"
|
||||||
|
frame_color = "#F92672"
|
||||||
timeout = 0
|
timeout = 0
|
||||||
|
|
||||||
|
|
||||||
# Every section that isn't one of the above is interpreted as a rules to
|
|
||||||
# override settings for certain messages.
|
|
||||||
# Messages can be matched by "appname", "summary", "body", "icon", "category",
|
|
||||||
# "msg_urgency" and you can override the "timeout", "urgency", "foreground",
|
|
||||||
# "background", "new_icon" and "format".
|
|
||||||
# Shell-like globbing will get expanded.
|
|
||||||
#
|
|
||||||
# SCRIPTING
|
|
||||||
# You can specify a script that gets run when the rule matches by
|
|
||||||
# setting the "script" option.
|
|
||||||
# The script will be called as follows:
|
|
||||||
# script appname summary body icon urgency
|
|
||||||
# where urgency can be "LOW", "NORMAL" or "CRITICAL".
|
|
||||||
#
|
|
||||||
# NOTE: if you don't want a notification to be displayed, set the format
|
|
||||||
# to "".
|
|
||||||
# NOTE: It might be helpful to run dunst -print in a terminal in order
|
|
||||||
# to find fitting options for rules.
|
|
||||||
|
|
||||||
#[espeak]
|
|
||||||
# summary = "*"
|
|
||||||
# script = dunst_espeak.sh
|
|
||||||
|
|
||||||
#[script-test]
|
|
||||||
# summary = "*script*"
|
|
||||||
# script = dunst_test.sh
|
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
# # This notification will not be displayed
|
|
||||||
# summary = "foobar"
|
|
||||||
# format = ""
|
|
||||||
|
|
||||||
#[signed_on]
|
|
||||||
# appname = Pidgin
|
|
||||||
# summary = "*signed on*"
|
|
||||||
# urgency = low
|
|
||||||
#
|
|
||||||
#[signed_off]
|
|
||||||
# appname = Pidgin
|
|
||||||
# summary = *signed off*
|
|
||||||
# urgency = low
|
|
||||||
#
|
|
||||||
#[says]
|
|
||||||
# appname = Pidgin
|
|
||||||
# summary = *says*
|
|
||||||
# urgency = critical
|
|
||||||
#
|
|
||||||
#[twitter]
|
|
||||||
# appname = Pidgin
|
|
||||||
# summary = *twitter.com*
|
|
||||||
# urgency = normal
|
|
||||||
#
|
|
||||||
#[Claws Mail]
|
|
||||||
# appname = claws-mail
|
|
||||||
# category = email.arrived
|
|
||||||
# urgency = normal
|
|
||||||
# background = "#2F899E"
|
|
||||||
# foreground = "#FFA247"
|
|
||||||
#
|
|
||||||
#[mute.sh]
|
|
||||||
# appname = mute
|
|
||||||
# category = mute.sound
|
|
||||||
# script = mute.sh
|
|
||||||
#
|
|
||||||
#[JDownloader]
|
|
||||||
# appname = JDownloader
|
|
||||||
# category = JD
|
|
||||||
# background = "#FFA247"
|
|
||||||
# foreground = "#FFFFFF"
|
|
||||||
#
|
|
||||||
#[newsbeuter]
|
|
||||||
# summary = *Feeds*
|
|
||||||
# background = "#A8EB41"
|
|
||||||
# foreground = "#FFFFFF"
|
|
||||||
#
|
|
||||||
[irc]
|
|
||||||
appname = weechat
|
|
||||||
timeout = 0
|
|
||||||
background = "#0033bb"
|
|
||||||
foreground = "#dddddd"
|
|
||||||
#
|
|
||||||
[weechat hl]
|
|
||||||
appname = weechat
|
|
||||||
category = weechat.HL
|
|
||||||
background = "#FF5C47"
|
|
||||||
foreground = "#FFFFFF"
|
|
||||||
#
|
|
||||||
[weechat pn]
|
|
||||||
appname = weechat
|
|
||||||
category = weechat.PM
|
|
||||||
background = "#D53B84"
|
|
||||||
foreground = "#FFFFFF"
|
|
||||||
#
|
|
||||||
#[CMUS]
|
|
||||||
# appname = CMUS
|
|
||||||
# category = cmus
|
|
||||||
# background = "#6C4AB7"
|
|
||||||
# foreground = "#FFE756"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# background = "#30AB70"
|
|
||||||
# foreground = "#F67245"
|
|
||||||
#
|
|
||||||
# vim: ft=cfg
|
|
||||||
|
|
7
config/i3/ashuffle
Executable file
7
config/i3/ashuffle
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
ashuffle
|
||||||
|
sleep 1
|
||||||
|
done
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
shopt -s nullglob globstar
|
shopt -s nullglob globstar
|
||||||
|
|
||||||
profile=$(echo -e "$(autorandr 2>&1 | cut -d' ' -f1)" | ~/.config/i3/dmenu_cmd -p "Default profile" "$@")
|
profile=$(echo -e "$(autorandr 2>&1 | cut -d' ' -f1)" | rofi -dmenu -p "Default profile" "$@")
|
||||||
|
|
||||||
[[ -n $profile ]] || exit
|
[[ -n $profile ]] || exit
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
shopt -s nullglob globstar
|
shopt -s nullglob globstar
|
||||||
|
|
||||||
profile=$(echo -e "common\nhorizontal\nvertical\n$(autorandr 2>&1 | cut -d' ' -f1)" | ~/.config/i3/dmenu_cmd -p "Load profile" "$@")
|
profile=$(echo -e "common\nhorizontal\nvertical\n$(autorandr 2>&1 | cut -d' ' -f1)" | rofi -dmenu -p "Load profile" "$@")
|
||||||
|
|
||||||
[[ -n $profile ]] || exit
|
[[ -n $profile ]] || exit
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
shopt -s nullglob globstar
|
shopt -s nullglob globstar
|
||||||
|
|
||||||
profile=$(echo -e "$(autorandr 2>&1 | cut -d' ' -f1)" | ~/.config/i3/dmenu_cmd -p "Remove profile" "$@")
|
profile=$(echo -e "$(autorandr 2>&1 | cut -d' ' -f1)" | rofi -dmenu -p "Remove profile" "$@")
|
||||||
|
|
||||||
[[ -n $profile ]] || exit
|
[[ -n $profile ]] || exit
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
shopt -s nullglob globstar
|
shopt -s nullglob globstar
|
||||||
|
|
||||||
profile=$(echo -e "$(autorandr 2>&1 | cut -d' ' -f1)" | ~/.config/i3/dmenu_cmd -p "Save profile" "$@")
|
profile=$(echo -e "$(autorandr 2>&1 | cut -d' ' -f1)" | rofi -dmenu -p "Save profile" "$@")
|
||||||
|
|
||||||
[[ -n $profile ]] || exit
|
[[ -n $profile ]] || exit
|
||||||
|
|
||||||
|
|
55
config/i3/batteryNotify
Executable file
55
config/i3/batteryNotify
Executable file
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
BATT="/sys/class/power_supply/BAT0"
|
||||||
|
LOW=10
|
||||||
|
CRIT=3
|
||||||
|
LASTSTATE="$HOME/.cache/batteryState"
|
||||||
|
|
||||||
|
function setState() { # state [...notify-send arguments]
|
||||||
|
state="$1"
|
||||||
|
last="$(cat "$LASTSTATE" 2> /dev/null)"
|
||||||
|
shift
|
||||||
|
|
||||||
|
echo "Battery state: $state"
|
||||||
|
|
||||||
|
if [ "$state" != "$last" ]
|
||||||
|
then
|
||||||
|
notify-send "$@"
|
||||||
|
echo "$state" > "$LASTSTATE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeState() {
|
||||||
|
acpiStatus="$(cat "$BATT/status")"
|
||||||
|
acpiCapacity="$(cat "$BATT/capacity")"
|
||||||
|
|
||||||
|
if [ "$acpiStatus" == "Discharging" ]
|
||||||
|
then
|
||||||
|
if [ $acpiCapacity -le $CRIT ]
|
||||||
|
then
|
||||||
|
setState "CRIT" -u critical -i battery-caution "Battery level is critical" "$acpiCapacity %"
|
||||||
|
elif [ $acpiCapacity -le $LOW ]
|
||||||
|
then
|
||||||
|
setState "LOW" -u critical -i battery-low "Battery level is low" "$acpiCapacity %"
|
||||||
|
else
|
||||||
|
setState "DISCHARGING" -i battery-good "Battery is discharging" "$acpiCapacity %"
|
||||||
|
fi
|
||||||
|
elif [ "$acpiStatus" == "Charging" ]
|
||||||
|
then
|
||||||
|
setState "CHARGING" -u normal -i battery-good-charging "Battery is charging" "$acpiCapacity %"
|
||||||
|
elif [ "$acpiStatus" == "Full" ]
|
||||||
|
then
|
||||||
|
setState "FULL" -u low -i battery-full-charged "Battery is full" "$acpiCapacity %"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$1" == "-d" ]
|
||||||
|
then
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
computeState
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
else
|
||||||
|
computeState
|
||||||
|
fi
|
|
@ -1,52 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
shopt -s nullglob
|
|
||||||
|
|
||||||
# We use this to make sure the cache files are sorted bytewise
|
|
||||||
LC_COLLATE=C
|
|
||||||
|
|
||||||
# Some people copy/paste huge swathes of text that could slow down dmenu
|
|
||||||
line_length_limit=500
|
|
||||||
|
|
||||||
declare -A selections
|
|
||||||
ordered_selections=()
|
|
||||||
|
|
||||||
files=("$HOME/.clipmenu/"*)
|
|
||||||
|
|
||||||
# We can't use `for ... in` here because we need to add files to
|
|
||||||
# ordered_selections from last to first -- that is, newest to oldest. Incoming
|
|
||||||
# clipboard entries have a ISO datetime prefixed to the front to aid in this.
|
|
||||||
for (( i=${#files[@]}-1; i>=0; i-- )); do
|
|
||||||
file=${files[$i]}
|
|
||||||
|
|
||||||
# We look for the first line matching regex /./ here because we want the
|
|
||||||
# first line that can provide reasonable context to the user. That is, if
|
|
||||||
# you have 5 leading lines of whitespace, displaying " (6 lines)" is much
|
|
||||||
# less useful than displaying "foo (6 lines)", where "foo" is the first
|
|
||||||
# line in the entry with actionable context.
|
|
||||||
first_line=$(sed -n '/./{p;q}' "$file" | cut -c1-"$line_length_limit")
|
|
||||||
lines=$(wc -l < "$file")
|
|
||||||
|
|
||||||
if (( lines > 1 )); then
|
|
||||||
first_line+=" ($lines lines)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ordered_selections+=("$first_line")
|
|
||||||
selections[$first_line]=$file
|
|
||||||
done
|
|
||||||
|
|
||||||
# It's okay to hardcode `-l 8` here as a sensible default without checking
|
|
||||||
# whether `-l` is also in "$@", because the way that dmenu works allows a later
|
|
||||||
# argument to override an earlier one. That is, if the user passes in `-l`, our
|
|
||||||
# one will be ignored.
|
|
||||||
chosen_line=$(printf '%s\n' "${ordered_selections[@]}" | uniq | $HOME/.config/i3/dmenu_cmd -l 8 -p "Copy" "$@")
|
|
||||||
|
|
||||||
[[ $chosen_line ]] || exit 1
|
|
||||||
|
|
||||||
for selection in clipboard primary; do
|
|
||||||
if type -p xsel >/dev/null 2>&1; then
|
|
||||||
xsel --logfile /dev/null -i --"$selection" < "${selections[$chosen_line]}"
|
|
||||||
else
|
|
||||||
xclip -sel "$selection" < "${selections[$chosen_line]}"
|
|
||||||
fi
|
|
||||||
done
|
|
|
@ -1,127 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
hr_msg() {
|
|
||||||
printf -- '\n--- %s ---\n\n' "$1" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
debug() {
|
|
||||||
if (( DEBUG )); then
|
|
||||||
printf '%s\n' "$@" >&2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
print_debug_info() {
|
|
||||||
# DEBUG comes from the environment
|
|
||||||
if ! (( DEBUG )); then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local msg="${1?}"
|
|
||||||
|
|
||||||
hr_msg "$msg"
|
|
||||||
|
|
||||||
hr_msg Environment
|
|
||||||
env | LC_ALL=C sort >&2
|
|
||||||
|
|
||||||
cgroup_path=/proc/$$/cgroup
|
|
||||||
|
|
||||||
if [[ -f $cgroup_path ]]; then
|
|
||||||
hr_msg cgroup
|
|
||||||
cat "$cgroup_path" >&2
|
|
||||||
else
|
|
||||||
hr_msg 'NO CGROUP'
|
|
||||||
fi
|
|
||||||
|
|
||||||
hr_msg 'Finished debug info'
|
|
||||||
}
|
|
||||||
|
|
||||||
print_debug_info 'Initialising'
|
|
||||||
|
|
||||||
cache_dir=$HOME/.clipmenu/
|
|
||||||
|
|
||||||
# It's ok that this only applies to the final directory.
|
|
||||||
# shellcheck disable=SC2174
|
|
||||||
mkdir -p -m0700 "$cache_dir"
|
|
||||||
|
|
||||||
declare -A last_data
|
|
||||||
declare -A last_filename
|
|
||||||
|
|
||||||
while sleep "${CLIPMENUD_SLEEP:-0.5}"; do
|
|
||||||
print_debug_info 'About to run selection'
|
|
||||||
|
|
||||||
for selection in clipboard primary; do
|
|
||||||
print_debug_info "About to do selection for '$selection'"
|
|
||||||
|
|
||||||
if type -p xsel >/dev/null 2>&1; then
|
|
||||||
debug 'Using xsel'
|
|
||||||
data=$(xsel --logfile /dev/null -o --"$selection"; printf x)
|
|
||||||
else
|
|
||||||
debug 'Using xclip'
|
|
||||||
data=$(xclip -o -sel "$selection"; printf x)
|
|
||||||
fi
|
|
||||||
|
|
||||||
debug "Data before stripping: $data"
|
|
||||||
|
|
||||||
# We add and remove the x so that trailing newlines are not stripped.
|
|
||||||
# Otherwise, they would be stripped by the very nature of how POSIX
|
|
||||||
# defines command substitution.
|
|
||||||
data=${data%x}
|
|
||||||
|
|
||||||
debug "Data after stripping: $data"
|
|
||||||
|
|
||||||
if [[ $data != *[^[:space:]]* ]]; then
|
|
||||||
debug "Skipping as clipboard is only blank"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${last_data[$selection]} == "$data" ]]; then
|
|
||||||
debug 'Skipping as last selection is the same as this one'
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If we were in the middle of doing a selection when the previous poll
|
|
||||||
# ran, then we may have got a partial clip.
|
|
||||||
possible_partial=${last_data[$selection]}
|
|
||||||
if [[ $possible_partial && $data == "$possible_partial"* ]]; then
|
|
||||||
debug "$possible_partial is a possible partial of $data"
|
|
||||||
debug "Removing ${last_filename[$selection]}"
|
|
||||||
rm -- "${last_filename[$selection]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
filename="$cache_dir/$(LC_ALL=C date +%F-%T.%N)"
|
|
||||||
|
|
||||||
last_data[$selection]=$data
|
|
||||||
last_filename[$selection]=$filename
|
|
||||||
|
|
||||||
debug "Writing $data to $filename"
|
|
||||||
printf '%s' "$data" > "$filename"
|
|
||||||
|
|
||||||
if ! (( NO_OWN_CLIPBOARD )) && [[ $selection != primary ]]; then
|
|
||||||
# Take ownership of the clipboard, in case the original application
|
|
||||||
# is unable to serve the clipboard request (due to being suspended,
|
|
||||||
# etc).
|
|
||||||
#
|
|
||||||
# Primary is excluded from the change of ownership as applications
|
|
||||||
# sometimes act up if clipboard focus is taken away from them --
|
|
||||||
# for example, urxvt will unhilight text, which is undesirable.
|
|
||||||
#
|
|
||||||
# We can't colocate this with the above copying code because
|
|
||||||
# https://github.com/cdown/clipmenu/issues/34 requires knowing if
|
|
||||||
# we would skip first.
|
|
||||||
if type -p xsel >/dev/null 2>&1; then
|
|
||||||
xsel --logfile /dev/null -o --"$selection" | xsel -i --"$selection"
|
|
||||||
else
|
|
||||||
xclip -o -sel "$selection" | xclip -i -sel "$selection"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! (( NO_TRANSFER_CLIPBOARD )) && [[ $selection != primary ]]; then
|
|
||||||
# Copy every clipboard content into primary clipboard
|
|
||||||
if type -p xsel >/dev/null 2>&1; then
|
|
||||||
xsel --logfile /dev/null -o --"$selection" | xsel -i --primary
|
|
||||||
else
|
|
||||||
xclip -o -sel "$selection" | xclip -i -sel primary
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
107
config/i3/config
107
config/i3/config
|
@ -19,11 +19,15 @@ hide_edge_borders both
|
||||||
#bindsym $mod+y border pixel 2
|
#bindsym $mod+y border pixel 2
|
||||||
#bindsym $mod+n border normal
|
#bindsym $mod+n border normal
|
||||||
|
|
||||||
|
# Compatibility layer for people coming from other backgrounds
|
||||||
|
bindsym Mod1+Tab exec --no-startup-id rofi -modi window -show window
|
||||||
|
bindsym Mod1+F2 exec --no-startup-id rofi -modi drun -show drun
|
||||||
|
bindsym Mod1+F4 kill
|
||||||
|
|
||||||
# Font for window titles. Will also be used by the bar unless a different font
|
# Font for window titles. Will also be used by the bar unless a different font
|
||||||
# is used in the bar {} block below.
|
# is used in the bar {} block below.
|
||||||
|
|
||||||
font pango:Source Code Pro 8
|
font pango:DejaVu Sans 8
|
||||||
font pango:DejaVu Sans Mono 8
|
|
||||||
font pango:Sans 8
|
font pango:Sans 8
|
||||||
|
|
||||||
# Use Mouse+$mod to drag floating windows
|
# Use Mouse+$mod to drag floating windows
|
||||||
|
@ -31,23 +35,19 @@ floating_modifier $mod
|
||||||
|
|
||||||
# kill focused window
|
# kill focused window
|
||||||
bindsym $mod+z kill
|
bindsym $mod+z kill
|
||||||
#bindsym Mod1+F4 kill
|
|
||||||
bindsym button2 kill
|
bindsym button2 kill
|
||||||
|
|
||||||
# start dmenu (a program launcher)
|
bindsym $mod+c exec --no-startup-id rofi-pass --last-used
|
||||||
bindsym $mod+F2 exec --no-startup-id ~/.config/i3/dmenu_run
|
bindsym $mod+asterisk exec --no-startup-id rofi -modi ssh -show ssh
|
||||||
bindsym Mod1+F2 exec --no-startup-id ~/.config/i3/dmenu_run
|
bindsym $mod+dollar exec --no-startup-id rofi -modi ssh -show ssh -ssh-command '{terminal} -e {ssh-client} {host} -t "sudo -s -E"'
|
||||||
|
bindsym $mod+Tab exec --no-startup-id rofi -modi window -show window
|
||||||
bindsym $mod+c exec --no-startup-id ~/.config/i3/passmenu --type
|
|
||||||
#bindsym $mod+x exec --no-startup-id ~/.config/i3/clipmenu
|
|
||||||
bindsym $mod+asterisk exec --no-startup-id ~/.config/i3/sshmenu
|
|
||||||
bindsym $mod+dollar exec --no-startup-id ~/.config/i3/sshmenu root
|
|
||||||
|
|
||||||
# start program launcher
|
# start program launcher
|
||||||
bindsym $mod+d exec --no-startup-id ~/.config/i3/dmenu_run
|
bindsym $mod+d exec --no-startup-id rofi -modi run -show run
|
||||||
|
bindsym $mod+Shift+d exec --no-startup-id rofi -modi drun -show drun
|
||||||
|
|
||||||
# Start Applications
|
# Start Applications
|
||||||
bindsym $mod+Return exec xterm
|
bindsym $mod+Return exec urxvtc
|
||||||
bindsym $mod+p exec thunar
|
bindsym $mod+p exec thunar
|
||||||
bindsym $mod+m exec qutebrowser --override-restore --backend=webengine
|
bindsym $mod+m exec qutebrowser --override-restore --backend=webengine
|
||||||
|
|
||||||
|
@ -57,11 +57,11 @@ bindsym XF86AudioLowerVolume exec pactl set-sink-mute @DEFAULT_SINK@ false; exec
|
||||||
bindsym XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ true
|
bindsym XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ true
|
||||||
bindsym $mod+F7 exec pactl suspend-sink @DEFAULT_SINK@ 1; exec pactl suspend-sink @DEFAULT_SINK@ 0
|
bindsym $mod+F7 exec pactl suspend-sink @DEFAULT_SINK@ 1; exec pactl suspend-sink @DEFAULT_SINK@ 0
|
||||||
# Re-synchronize bluetooth headset
|
# Re-synchronize bluetooth headset
|
||||||
bindsym $mod+F8 exec mpc prev
|
bindsym XF86AudioPrev exec mpc prev
|
||||||
bindsym $mod+F9 exec mpc toggle
|
bindsym XF86AudioPlay exec mpc toggle
|
||||||
bindsym $mod+F10 exec mpc next
|
bindsym XF86AudioNext exec mpc next
|
||||||
bindsym $mod+F11 exec xterm -e 'pacmixer'
|
bindsym $mod+F11 exec urxvtc -e 'pacmixer'
|
||||||
bindsym $mod+F12 exec xterm -e 'pacmixer'
|
bindsym $mod+F12 exec urxvtc -e 'pacmixer'
|
||||||
|
|
||||||
#Brightness control
|
#Brightness control
|
||||||
bindsym XF86MonBrightnessDown exec xbacklight -dec 20
|
bindsym XF86MonBrightnessDown exec xbacklight -dec 20
|
||||||
|
@ -144,19 +144,14 @@ set $WS10 10
|
||||||
|
|
||||||
# Workspace output
|
# Workspace output
|
||||||
workspace "$WS1" output LVDS1
|
workspace "$WS1" output LVDS1
|
||||||
workspace "$WS2" output VGA1
|
|
||||||
workspace "$WS2" output HDMI1
|
workspace "$WS2" output HDMI1
|
||||||
workspace "$WS3" output LVDS1
|
workspace "$WS3" output LVDS1
|
||||||
workspace "$WS4" output VGA1
|
|
||||||
workspace "$WS4" output HDMI1
|
workspace "$WS4" output HDMI1
|
||||||
workspace "$WS5" output LVDS1
|
workspace "$WS5" output LVDS1
|
||||||
workspace "$WS6" output VGA1
|
|
||||||
workspace "$WS6" output HDMI1
|
workspace "$WS6" output HDMI1
|
||||||
workspace "$WS7" output LVDS1
|
workspace "$WS7" output LVDS1
|
||||||
workspace "$WS8" output VGA1
|
|
||||||
workspace "$WS8" output HDMI1
|
workspace "$WS8" output HDMI1
|
||||||
workspace "$WS9" output LVDS1
|
workspace "$WS9" output LVDS1
|
||||||
workspace "$WS10" output VGA1
|
|
||||||
workspace "$WS10" output HDMI1
|
workspace "$WS10" output HDMI1
|
||||||
|
|
||||||
# switch to workspace
|
# switch to workspace
|
||||||
|
@ -245,6 +240,8 @@ for_window [class="qutebrowser"] layout tabbed
|
||||||
|
|
||||||
for_window [window_role="pop-up"] floating enable
|
for_window [window_role="pop-up"] floating enable
|
||||||
for_window [window_role="task_dialog"] floating enable
|
for_window [window_role="task_dialog"] floating enable
|
||||||
|
for_window [ title="^pdfpc.*" window_role="presenter" ] move to output left, fullscreen
|
||||||
|
for_window [ title="^pdfpc.*" window_role="presentation" ] move to output right, fullscreen
|
||||||
|
|
||||||
# switch to workspace with urgent window automatically
|
# switch to workspace with urgent window automatically
|
||||||
for_window [urgent=latest] focus
|
for_window [urgent=latest] focus
|
||||||
|
@ -335,24 +332,24 @@ mode "$mode_temp" {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Colors
|
# Colors
|
||||||
set $bg #272822
|
set_from_resource $background i3wm.background #272822
|
||||||
set $fg #f1ebeb
|
set_from_resource $foreground i3wm.foreground #f1ebeb
|
||||||
set $00 #48483e
|
set_from_resource $color00 i3wm.color0 #48483e
|
||||||
set $01 #dc2566
|
set_from_resource $color01 i3wm.color1 #dc2566
|
||||||
set $02 #8fc029
|
set_from_resource $color02 i3wm.color2 #8fc029
|
||||||
set $03 #d4c96e
|
set_from_resource $color03 i3wm.color3 #d4c96e
|
||||||
set $04 #55bcce
|
set_from_resource $color04 i3wm.color4 #55bcce
|
||||||
set $05 #9358fe
|
set_from_resource $color05 i3wm.color5 #9358fe
|
||||||
set $06 #56b7a5
|
set_from_resource $color06 i3wm.color6 #56b7a5
|
||||||
set $07 #acada1
|
set_from_resource $color07 i3wm.color7 #acada1
|
||||||
set $08 #76715e
|
set_from_resource $color08 i3wm.color8 #76715e
|
||||||
set $09 #fa2772
|
set_from_resource $color09 i3wm.color9 #fa2772
|
||||||
set $10 #a7e22e
|
set_from_resource $color10 i3wm.color10 #a7e22e
|
||||||
set $11 #e7db75
|
set_from_resource $color11 i3wm.color11 #e7db75
|
||||||
set $12 #66d9ee
|
set_from_resource $color12 i3wm.color12 #66d9ee
|
||||||
set $13 #ae82ff
|
set_from_resource $color13 i3wm.color13 #ae82ff
|
||||||
set $14 #66efd5
|
set_from_resource $color14 i3wm.color14 #66efd5
|
||||||
set $15 #cfd0c2
|
set_from_resource $color15 i3wm.color15 #cfd0c2
|
||||||
|
|
||||||
# Inactivity settings
|
# Inactivity settings
|
||||||
exec --no-startup-id xautolock -time 10 -locker 'xset dpms force standby' -killtime 1 -killer '$locker'
|
exec --no-startup-id xautolock -time 10 -locker 'xset dpms force standby' -killtime 1 -killer '$locker'
|
||||||
|
@ -361,26 +358,26 @@ bindsym $mod+F5 exec --no-startup-id xautolock -enable
|
||||||
|
|
||||||
|
|
||||||
# Autostart applications
|
# Autostart applications
|
||||||
exec --no-startup-id /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 # Password remembering
|
#exec --no-startup-id /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 # Password remembering
|
||||||
exec --no-startup-id gnome-keyring-daemon # Password remembering
|
#exec --no-startup-id gnome-keyring-daemon # Password remembering
|
||||||
|
exec --no-startup-id urxvtd -q -f # urxvt daemon
|
||||||
exec --no-startup-id numlockx on # Activate Num lock
|
exec --no-startup-id numlockx on # Activate Num lock
|
||||||
#exec --no-startup-id nm-applet # Network manager tray icon
|
exec --no-startup-id unclutter -root # Hide mouse cursor after some time
|
||||||
#exec --no-startup-id compton -b # Compositing manager
|
#exec --no-startup-id dunst # Notifications (handled by systemd)
|
||||||
exec --no-startup-id unclutter # Hide mouse cursor after some time
|
|
||||||
exec --no-startup-id dunst # Notifications
|
|
||||||
exec --no-startup-id keynav # Keyboard cursor controller
|
exec --no-startup-id keynav # Keyboard cursor controller
|
||||||
#exec --no-startup-id $HOME/.config/i3/clipmenud # Clipboard manager
|
#exec --no-startup-id mpd # Music Player Daemon (handled by systemd)
|
||||||
exec --no-startup-id mpd # Music Player Daemon
|
exec --no-startup-id ~/.config/i3/ashuffle # MPD Auto-refill
|
||||||
exec --no-startup-id autorandr --change # Screen configuration and everything that depends on it
|
exec --no-startup-id autorandr --change # Screen configuration and everything that depends on it
|
||||||
|
exec --no-startup-id ~/.config/i3/batteryNotify -d # Battery state notification
|
||||||
|
|
||||||
set $ignore #ff00000
|
set $ignore #ff00000
|
||||||
|
|
||||||
# Theme colors
|
# Theme colors
|
||||||
#class border backgr. text indicator child_border
|
#class border backgr. text indicator child_border
|
||||||
client.focused $02 $02 $bg $07 $10
|
client.focused $color02 $color02 $background $color08 $color10
|
||||||
client.focused_inactive $03 $03 $08 $15 $14
|
client.focused_inactive $color03 $color03 $color08 $color15 $color14
|
||||||
client.unfocused $08 $08 $fg $11 $00
|
client.unfocused $color08 $color08 $color07 $color11 $color00
|
||||||
client.urgent $01 $01 $fg $05 $09
|
client.urgent $color01 $color01 $color07 $foreground $color09
|
||||||
client.placeholder $ignore $06 $fg $ignore $14
|
client.placeholder $ignore $color06 $color07 $ignore $color14
|
||||||
|
|
||||||
client.background $15
|
client.background $color15
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
dmenu -fn 'DejaVu Sans Mono-10' -nb '#48483e' -nf '#f1ebeb' -sb '#8fc029' -sf '#272822' -l 8 -f "$@"
|
dmenu -fn 'DejaVu Sans Mono-10' -nb '#48483e' -nf '#f1ebeb' -sb '#8fc029' -sf '#272822' -i -l 8 -f "$@"
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
#!/usr/bin/env sh
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Remove SSH and GPG keys from keystores
|
||||||
|
ssh-add -D
|
||||||
|
echo RELOADAGENT | gpg-connect-agent
|
||||||
|
|
||||||
|
|
||||||
dm-tool lock
|
dm-tool lock
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
|
|
26
config/i3/multimediaKey
Executable file
26
config/i3/multimediaKey
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Send a key event to the current multimedia application or to MPD
|
||||||
|
|
||||||
|
# Currently since I did not found a way to test if a keystroke
|
||||||
|
# is grabbed by a windows or not, we test if MPD is playing
|
||||||
|
|
||||||
|
echo 8 "$1" "$2" "$(xdotool getactivewindow)" >> /tmp/dbg
|
||||||
|
|
||||||
|
if [ $# != 2 ]; then
|
||||||
|
echo "Usage: $0 KEY MPC_COMMAND"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $(mpc status | wc -l) -ne 1 ]; then
|
||||||
|
# If mpd is running
|
||||||
|
mpc $2
|
||||||
|
else
|
||||||
|
# If mpd is not running
|
||||||
|
# echo "$1" "$2" "$(xdotool getactivewindow)" >> /tmp/dbg
|
||||||
|
xdotool key --window $(xdotool getactivewindow) $1
|
||||||
|
echo xdotool key --window $(xdotool getactivewindow) $1 >> /tmp/dbg
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
shopt -s nullglob globstar
|
|
||||||
|
|
||||||
typeit=0
|
|
||||||
if [[ $1 == "--type" ]]; then
|
|
||||||
typeit=1
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
if PASS=$(which gopass 2> /dev/null); then
|
|
||||||
password_files="$($PASS ls --flat)"
|
|
||||||
elif PASS=$(which pass 2> /dev/null); then
|
|
||||||
prefix=${PASSWORD_STORE_DIR-~/.password-store}
|
|
||||||
password_files=( "$prefix"/**/*.gpg )
|
|
||||||
password_files=( "${password_files[@]#"$prefix"/}" )
|
|
||||||
password_files=( "${password_files[@]%.gpg}" )
|
|
||||||
else
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
password=$(printf '%s\n' "${password_files[@]}" | $HOME/.config/i3/dmenu_cmd -p "Passwords" "$@")
|
|
||||||
|
|
||||||
[[ -n $password ]] || exit
|
|
||||||
|
|
||||||
if [[ $typeit -eq 0 ]]; then
|
|
||||||
$PASS show -c "$password"
|
|
||||||
else
|
|
||||||
xdotool - <<<"type --clearmodifiers -- $($PASS show "$password" | head -n 1)"
|
|
||||||
fi
|
|
|
@ -1,9 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
if [ "$1" == 'root' ]; then
|
|
||||||
a=" (root)"
|
|
||||||
b="-t 'sudo -s'"
|
|
||||||
fi
|
|
||||||
machine=$(cat ~/.ssh/config | grep '^Host ' | cut -d ' ' -f 2 | grep -v '*' | sort | $HOME/.config/i3/dmenu_cmd -p "SSH$a to ")
|
|
||||||
if [ ! -z $machine ]; then
|
|
||||||
xterm -e "ssh $machine $b"
|
|
||||||
fi
|
|
|
@ -1,5 +0,0 @@
|
||||||
prefix=${PASSWORD_STORE_DIR-~/.password-store}
|
|
||||||
password_files=( "$prefix"/**/*.gpg )
|
|
||||||
password_files=( "${password_files[@]#"$prefix"/}" )
|
|
||||||
password_files=( "${password_files[@]%.gpg}" )
|
|
||||||
echo -e "${password_files[@]}"
|
|
34
config/khal/config
Normal file
34
config/khal/config
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[calendars]
|
||||||
|
[[calendars]]
|
||||||
|
path = ~/.vdirsyncer/calendars/*
|
||||||
|
type = discover
|
||||||
|
|
||||||
|
# [[birthdays]]
|
||||||
|
# type=birthdays
|
||||||
|
# path = ~/.vdirsyncer/contacts/contacts/
|
||||||
|
# color = light magenta
|
||||||
|
|
||||||
|
[locale]
|
||||||
|
timeformat = %H:%M
|
||||||
|
dateformat = %d/%m
|
||||||
|
longdateformat = %d/%m/%Y
|
||||||
|
datetimeformat = %d/%m %H:%M
|
||||||
|
longdatetimeformat = %d/%m/%Y %H:%M
|
||||||
|
local_timezone = Europe/Paris
|
||||||
|
|
||||||
|
[default]
|
||||||
|
default_calendar = "Personnel"
|
||||||
|
default_command = calendar
|
||||||
|
highlight_event_days = True
|
||||||
|
show_all_days = True
|
||||||
|
timedelta = 7d
|
||||||
|
|
||||||
|
[highlight_days]
|
||||||
|
|
||||||
|
[view]
|
||||||
|
agenda_day_format = "{bold}{name}, {date-long}{reset}"
|
||||||
|
agenda_event_format = "{calendar-color}{cancelled}{start-end-time-style} {title}{repeat-symbol} | {location}{reset}"
|
||||||
|
bold_for_light_color = False
|
||||||
|
event_format = "{calendar-color}{cancelled}{start}-{end} {title}{repeat-symbol} | {location}{reset}"
|
||||||
|
event_view_always_visible = True
|
||||||
|
frame = color
|
43
config/khard/khard.conf
Normal file
43
config/khard/khard.conf
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# example configuration file for khard version >= 0.11.0
|
||||||
|
# place it under $HOME/.config/khard/khard.conf
|
||||||
|
|
||||||
|
[addressbooks]
|
||||||
|
[[contacts]]
|
||||||
|
path = ~/.vdirsyncer/contacts/contacts/
|
||||||
|
|
||||||
|
[general]
|
||||||
|
debug = no
|
||||||
|
default_action = list
|
||||||
|
editor = vim
|
||||||
|
merge_editor = vimdiff
|
||||||
|
|
||||||
|
[contact table]
|
||||||
|
# display names by first or last name: first_name / last_name
|
||||||
|
display = first_name
|
||||||
|
# group by address book: yes / no
|
||||||
|
group_by_addressbook = no
|
||||||
|
# reverse table ordering: yes / no
|
||||||
|
reverse = no
|
||||||
|
# append nicknames to name column: yes / no
|
||||||
|
show_nicknames = no
|
||||||
|
# show uid table column: yes / no
|
||||||
|
show_uids = yes
|
||||||
|
# sort by first or last name: first_name / last_name
|
||||||
|
sort = last_name
|
||||||
|
# localize dates: yes / no
|
||||||
|
localize_dates = yes
|
||||||
|
|
||||||
|
[vcard]
|
||||||
|
# extend contacts with your own private objects
|
||||||
|
# these objects are stored with a leading "X-" before the object name in the vcard files
|
||||||
|
# every object label may only contain letters, digits and the - character
|
||||||
|
# example:
|
||||||
|
# private_objects = Jabber, Skype, Twitter
|
||||||
|
private_objects = Jabber, Skype, Twitter
|
||||||
|
# preferred vcard version: 3.0 / 4.0
|
||||||
|
preferred_version = 3.0
|
||||||
|
# Look into source vcf files to speed up search queries: yes / no
|
||||||
|
search_in_source_files = no
|
||||||
|
# skip unparsable vcard files: yes / no
|
||||||
|
skip_unparsable = no
|
||||||
|
|
3
config/nvim/init.vim
Normal file
3
config/nvim/init.vim
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
set runtimepath^=~/.vim runtimepath+=~/.vim/after
|
||||||
|
let &packpath = &runtimepath
|
||||||
|
source ~/.vimrc
|
10
config/offlineimap.py
Normal file
10
config/offlineimap.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#! /usr/bin/env python2
|
||||||
|
from subprocess import check_output
|
||||||
|
|
||||||
|
|
||||||
|
def get_pass(account):
|
||||||
|
return check_output("pass " + account, shell=True).splitlines()[0]
|
||||||
|
|
||||||
|
def beep():
|
||||||
|
check_output("play -n synth sine E4 sine A5 remix 1-2 fade 0.5 1.2 0.5 2", shell=True)
|
||||||
|
|
18
config/polybar/bbswitch
Executable file
18
config/polybar/bbswitch
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [ -f /proc/acpi/bbswitch ]
|
||||||
|
then
|
||||||
|
echo -n
|
||||||
|
state="$(grep -o '\w\+$' /proc/acpi/bbswitch)"
|
||||||
|
if [ "$state" == "ON" ]
|
||||||
|
then
|
||||||
|
echo ""
|
||||||
|
elif [ "$state" == "OFF" ]
|
||||||
|
then
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
echo "?"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
fi
|
|
@ -76,7 +76,7 @@ enable-ipc = true
|
||||||
inherit = bar/base
|
inherit = bar/base
|
||||||
|
|
||||||
modules-center = mpd
|
modules-center = mpd
|
||||||
modules-right = vpncheck eth wlan bbswitch xbacklight volume battery date
|
modules-right = mail todo vpncheck eth wlan bbswitch xbacklight volume battery shortdate
|
||||||
|
|
||||||
tray-position = right
|
tray-position = right
|
||||||
tray-padding = 2
|
tray-padding = 2
|
||||||
|
@ -84,7 +84,7 @@ tray-transparent = false
|
||||||
|
|
||||||
[bar/secondary]
|
[bar/secondary]
|
||||||
inherit = bar/base
|
inherit = bar/base
|
||||||
modules-right = cpu memory temperature vpncheck ethMore wlanMore filesystem bbswitch xbacklight volume date
|
modules-right = cpu memory temperature keystore vpncheck ethMore wlanMore filesystem linuxmismatch bbswitch xbacklight volume date
|
||||||
|
|
||||||
|
|
||||||
[module/filesystem]
|
[module/filesystem]
|
||||||
|
@ -176,12 +176,33 @@ toggle-off-foreground = #55
|
||||||
|
|
||||||
[module/bbswitch]
|
[module/bbswitch]
|
||||||
type = custom/script
|
type = custom/script
|
||||||
exec = grep -o '\w\+$' /proc/acpi/bbswitch
|
exec = ~/.config/polybar/bbswitch
|
||||||
exec-if = test -f /proc/acpi/bbswitch
|
|
||||||
interval = 5
|
interval = 5
|
||||||
prefix =
|
|
||||||
format-foreground = ${theme.redF}
|
format-foreground = ${theme.redF}
|
||||||
|
|
||||||
|
[module/todo]
|
||||||
|
type = custom/script
|
||||||
|
exec = ~/.config/polybar/todo
|
||||||
|
interval = 30
|
||||||
|
format-prefix =
|
||||||
|
format-foreground = ${theme.yellowF}
|
||||||
|
|
||||||
|
[module/mail]
|
||||||
|
type = custom/script
|
||||||
|
exec = cat ~/.cache/mutt/status
|
||||||
|
interval = 1
|
||||||
|
format-prefix =
|
||||||
|
format-foreground = ${theme.magentaF}
|
||||||
|
; format-background = ${theme.magentaB}
|
||||||
|
|
||||||
|
[module/linuxmismatch]
|
||||||
|
type = custom/script
|
||||||
|
exec = echo
|
||||||
|
exec-if = ~/.config/polybar/linuxmismatch
|
||||||
|
interval = 30
|
||||||
|
format-foreground = ${theme.yellowF}
|
||||||
|
; format-background = ${theme.yellowF}
|
||||||
|
|
||||||
[module/xbacklight]
|
[module/xbacklight]
|
||||||
type = internal/xbacklight
|
type = internal/xbacklight
|
||||||
output = ${env:display:LVDS1}
|
output = ${env:display:LVDS1}
|
||||||
|
@ -201,7 +222,7 @@ card = intel_backlight
|
||||||
|
|
||||||
[module/cpu]
|
[module/cpu]
|
||||||
type = internal/cpu
|
type = internal/cpu
|
||||||
interval = 0.5
|
interval = 1
|
||||||
format = <ramp-coreload>
|
format = <ramp-coreload>
|
||||||
format-foreground = ${theme.redF}
|
format-foreground = ${theme.redF}
|
||||||
ramp-coreload-0 = ▁
|
ramp-coreload-0 = ▁
|
||||||
|
@ -215,10 +236,17 @@ ramp-coreload-7 = █
|
||||||
|
|
||||||
[module/memory]
|
[module/memory]
|
||||||
type = internal/memory
|
type = internal/memory
|
||||||
interval = 2
|
interval = 1
|
||||||
format-foreground = ${theme.greenF}
|
format-foreground = ${theme.greenF}
|
||||||
label = %gb_free%
|
label = %gb_free%
|
||||||
|
|
||||||
|
[module/keystore]
|
||||||
|
type = custom/script
|
||||||
|
exec = ~/.config/polybar/keystore
|
||||||
|
; exec-if = pgrep openvpn
|
||||||
|
interval = 5
|
||||||
|
format-foreground = ${theme.greenF}
|
||||||
|
|
||||||
[module/vpncheck]
|
[module/vpncheck]
|
||||||
type = custom/script
|
type = custom/script
|
||||||
exec = echo
|
exec = echo
|
||||||
|
@ -229,7 +257,7 @@ format-foreground = ${theme.blueF}
|
||||||
[module/eth]
|
[module/eth]
|
||||||
type = internal/network
|
type = internal/network
|
||||||
interface = ${env:ethI:eth0}
|
interface = ${env:ethI:eth0}
|
||||||
interval = 1
|
interval = 5
|
||||||
|
|
||||||
format-connected = <label-connected>
|
format-connected = <label-connected>
|
||||||
label-connected = %local_ip%
|
label-connected = %local_ip%
|
||||||
|
@ -244,7 +272,7 @@ label-connected = ↑%upspeed% ↓%downspeed%
|
||||||
[module/wlan]
|
[module/wlan]
|
||||||
type = internal/network
|
type = internal/network
|
||||||
interface = ${env:wlanI:wlan0}
|
interface = ${env:wlanI:wlan0}
|
||||||
interval = 1
|
interval = 5
|
||||||
|
|
||||||
format-connected = <ramp-signal> <label-connected>
|
format-connected = <ramp-signal> <label-connected>
|
||||||
label-connected = %local_ip% %essid%
|
label-connected = %local_ip% %essid%
|
||||||
|
@ -281,6 +309,11 @@ format-foreground = ${theme.cyanF}
|
||||||
|
|
||||||
label = %date% %time%
|
label = %date% %time%
|
||||||
|
|
||||||
|
[module/shortdate]
|
||||||
|
inherit = module/date
|
||||||
|
date = " %d/%m"
|
||||||
|
|
||||||
|
|
||||||
[module/volume]
|
[module/volume]
|
||||||
type = internal/volume
|
type = internal/volume
|
||||||
|
|
||||||
|
@ -307,11 +340,12 @@ label-full =
|
||||||
|
|
||||||
format-charging = <ramp-capacity> <label-charging>
|
format-charging = <ramp-capacity> <label-charging>
|
||||||
format-charging-foreground = ${theme.yellowF}
|
format-charging-foreground = ${theme.yellowF}
|
||||||
|
format-charging-prefix =
|
||||||
label-charging = %percentage%% (%time%)
|
label-charging = %percentage%% (%time%)
|
||||||
|
|
||||||
format-discharging = <ramp-capacity> <label-discharging>
|
format-discharging = <ramp-capacity> <label-discharging>
|
||||||
format-discharging-foreground = ${self.format-charging-foreground}
|
format-discharging-foreground = ${self.format-charging-foreground}
|
||||||
format-discharging-background = ${theme.redB}
|
; format-discharging-background = ${theme.redB}
|
||||||
label-discharging = %percentage%% (%time%)
|
label-discharging = %percentage%% (%time%)
|
||||||
|
|
||||||
format-full-prefix = " "
|
format-full-prefix = " "
|
||||||
|
|
9
config/polybar/keystore
Executable file
9
config/polybar/keystore
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
output="$(ssh-add -l)"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo -n " "
|
||||||
|
echo "$output" | wc -l
|
||||||
|
fi
|
17
config/polybar/linuxmismatch
Executable file
17
config/polybar/linuxmismatch
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if ! which pacman &> /dev/null
|
||||||
|
then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
packageVersion=$(pacman -Q linux | cut -d' ' -f2)
|
||||||
|
runningVersion=$(uname -r)
|
||||||
|
|
||||||
|
if echo "$runningVersion" | grep "^$packageVersion" &> /dev/null
|
||||||
|
then
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
21
config/polybar/todo
Executable file
21
config/polybar/todo
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
CALDIR="$HOME/.vdirsyncer/currentCalendars"
|
||||||
|
|
||||||
|
function status() {
|
||||||
|
ls "$CALDIR" | while read account
|
||||||
|
do
|
||||||
|
displayname="$(cat "$CALDIR/$account/displayname")"
|
||||||
|
color="$(cat "$CALDIR/$account/color")"
|
||||||
|
nb="$(todo list "$displayname" | grep -v "^$" | wc -l)"
|
||||||
|
|
||||||
|
if [ $nb -gt 0 ]
|
||||||
|
then
|
||||||
|
echo -n " %{F$color}$nb%{F-}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Newline to tell polybar to update in any case
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
status
|
3
config/rofi/.gitignore
vendored
Normal file
3
config/rofi/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
theme.config
|
||||||
|
theme.rasi
|
||||||
|
|
8
config/rofi/config
Normal file
8
config/rofi/config
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include "theme.config"
|
||||||
|
rofi.theme: theme
|
||||||
|
rofi.cycle: true
|
||||||
|
rofi.case-sensitive: false
|
||||||
|
rofi.scroll-method: 0
|
||||||
|
rofi.show-match: true
|
||||||
|
rofi.lazy-grab: false
|
||||||
|
rofi.matching: fuzzy
|
1
config/systemd/user/default.target.wants/dunst.service
Symbolic link
1
config/systemd/user/default.target.wants/dunst.service
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
/usr/lib/systemd/user/dunst.service
|
1
config/systemd/user/default.target.wants/mbsync.timer
Symbolic link
1
config/systemd/user/default.target.wants/mbsync.timer
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
/home/geoffrey/.local/share/systemd/user/mbsync.timer
|
1
config/systemd/user/default.target.wants/mpd.service
Symbolic link
1
config/systemd/user/default.target.wants/mpd.service
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
/usr/lib/systemd/user/mpd.service
|
1
config/systemd/user/default.target.wants/offlineimap.service
Symbolic link
1
config/systemd/user/default.target.wants/offlineimap.service
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
/usr/lib/systemd/user/offlineimap.service
|
1
config/systemd/user/default.target.wants/syncthing.service
Symbolic link
1
config/systemd/user/default.target.wants/syncthing.service
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
/usr/lib/systemd/user/syncthing.service
|
1
config/systemd/user/timers.target.wants/vdirsyncer.timer
Symbolic link
1
config/systemd/user/timers.target.wants/vdirsyncer.timer
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
/usr/lib/systemd/user/vdirsyncer.timer
|
4
config/todoman/todoman.conf
Normal file
4
config/todoman/todoman.conf
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[main]
|
||||||
|
path = ~/.vdirsyncer/currentCalendars/*
|
||||||
|
default_list = Personnel
|
||||||
|
humanize = True
|
0
config/vdirsyncer/.dfrecur
Normal file
0
config/vdirsyncer/.dfrecur
Normal file
70
config/vdirsyncer/config
Normal file
70
config/vdirsyncer/config
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# An example configuration for vdirsyncer.
|
||||||
|
#
|
||||||
|
# Move it to ~/.vdirsyncer/config or ~/.config/vdirsyncer/config and edit it.
|
||||||
|
# Run `vdirsyncer --help` for CLI usage.
|
||||||
|
#
|
||||||
|
# Optional parameters are commented out.
|
||||||
|
# This file doesn't document all available parameters, see
|
||||||
|
# http://vdirsyncer.pimutils.org/ for the rest of them.
|
||||||
|
|
||||||
|
[general]
|
||||||
|
# A folder where vdirsyncer can store some metadata about each pair.
|
||||||
|
status_path = "~/.vdirsyncer/status/"
|
||||||
|
|
||||||
|
# # CARDDAV
|
||||||
|
[pair geoffrey_contacts]
|
||||||
|
# A `[pair <name>]` block defines two storages `a` and `b` that should be
|
||||||
|
# synchronized. The definition of these storages follows in `[storage <name>]`
|
||||||
|
# blocks. This is similar to accounts in OfflineIMAP.
|
||||||
|
a = "geoffrey_contacts_local"
|
||||||
|
b = "geoffrey_contacts_remote"
|
||||||
|
|
||||||
|
# Synchronize all collections that can be found.
|
||||||
|
# You need to run `vdirsyncer discover` if new calendars/addressbooks are added
|
||||||
|
# on the server.
|
||||||
|
|
||||||
|
collections = ["from a", "from b"]
|
||||||
|
|
||||||
|
# Synchronize the "display name" property into a local file (~/.contacts/displayname).
|
||||||
|
metadata = ["displayname"]
|
||||||
|
|
||||||
|
# To resolve a conflict the following values are possible:
|
||||||
|
# `null` - abort when collisions occur (default)
|
||||||
|
# `"a wins"` - assume a's items to be more up-to-date
|
||||||
|
# `"b wins"` - assume b's items to be more up-to-date
|
||||||
|
#conflict_resolution = null
|
||||||
|
|
||||||
|
[storage geoffrey_contacts_local]
|
||||||
|
# A storage references actual data on a remote server or on the local disk.
|
||||||
|
# Similar to repositories in OfflineIMAP.
|
||||||
|
type = "filesystem"
|
||||||
|
path = "~/.vdirsyncer/contacts/"
|
||||||
|
fileext = ".vcf"
|
||||||
|
|
||||||
|
[storage geoffrey_contacts_remote]
|
||||||
|
type = "carddav"
|
||||||
|
url = "https://dav.frogeye.fr/caldav.php/"
|
||||||
|
username = "geoffrey"
|
||||||
|
password.fetch = ["command", "sh", "-c", "cat ~/.config/vdirsyncer/pass"]
|
||||||
|
|
||||||
|
# CALDAV
|
||||||
|
[pair geoffrey_calendar]
|
||||||
|
a = "geoffrey_calendar_local"
|
||||||
|
b = "geoffrey_calendar_remote"
|
||||||
|
collections = ["from a", "from b"]
|
||||||
|
|
||||||
|
# Calendars also have a color property
|
||||||
|
metadata = ["displayname", "color"]
|
||||||
|
# conflict_resolution = "a wins"
|
||||||
|
# conflict_resolution = "b wins"
|
||||||
|
|
||||||
|
[storage geoffrey_calendar_local]
|
||||||
|
type = "filesystem"
|
||||||
|
path = "~/.vdirsyncer/calendars/"
|
||||||
|
fileext = ".ics"
|
||||||
|
|
||||||
|
[storage geoffrey_calendar_remote]
|
||||||
|
type = "caldav"
|
||||||
|
url = "https://dav.frogeye.fr/caldav.php/"
|
||||||
|
username = "geoffrey"
|
||||||
|
password.fetch = ["command", "sh", "-c", "cat ~/.config/vdirsyncer/pass"]
|
|
@ -8,3 +8,8 @@
|
||||||
default = matching
|
default = matching
|
||||||
[alias]
|
[alias]
|
||||||
git = !exec git
|
git = !exec git
|
||||||
|
[filter "lfs"]
|
||||||
|
clean = git-lfs clean -- %f
|
||||||
|
smudge = git-lfs smudge -- %f
|
||||||
|
process = git-lfs filter-process
|
||||||
|
required = true
|
||||||
|
|
2
profile
2
profile
|
@ -9,4 +9,4 @@
|
||||||
[ -f "$HOME/.config/linuxColors.sh" ] && . "$HOME/.config/linuxColors.sh"
|
[ -f "$HOME/.config/linuxColors.sh" ] && . "$HOME/.config/linuxColors.sh"
|
||||||
|
|
||||||
# Bashrc
|
# Bashrc
|
||||||
[ -f ~/.bashrc ] && . ~/.bashrc
|
[ -f ~/.bashrc ] && source ~/.bashrc
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
sudo kexec -l /boot/vmlinuz-linux --initrd=/boot/initramfs-linux.img --reuse-cmdlin
|
sudo kexec -l /boot/vmlinuz-linux --initrd=/boot/initramfs-linux.img --reuse-cmdline
|
||||||
sudo systemctl kexec
|
sudo systemctl kexec
|
||||||
|
|
44
scripts/changeColors
Executable file
44
scripts/changeColors
Executable file
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Fetchs colors from https://github.com/chriskempson/base16 templates
|
||||||
|
# and apply them into my configuration
|
||||||
|
|
||||||
|
scheme="$1"
|
||||||
|
if [ -z "$scheme" ]
|
||||||
|
then
|
||||||
|
echo Please specify a scheme
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# TODO Verify if scheme is known
|
||||||
|
|
||||||
|
# Shell (allows to use all colors in Vim while still having nice colors in the rest of the terminal)
|
||||||
|
curl "https://raw.githubusercontent.com/chriskempson/base16-shell/master/scripts/base16-${scheme}.sh" > ~/.local/bin/colorSchemeApply
|
||||||
|
chmod +x ~/.local/bin/colorSchemeApply
|
||||||
|
|
||||||
|
# Xressources (I'm not sure if this is really needed with shell overriding these but i3 load those resources)
|
||||||
|
curl "https://raw.githubusercontent.com/chriskempson/base16-xresources/master/xresources/base16-${scheme}-256.Xresources" > ~/.Xresources.d/theme
|
||||||
|
|
||||||
|
# Vim
|
||||||
|
echo -e "let base16colorspace=256\nset termguicolors\ncolorscheme base16-${scheme}" > ~/.vim/colorscheme.vim
|
||||||
|
|
||||||
|
# FZF
|
||||||
|
curl "https://raw.githubusercontent.com/nicodebo/base16-fzf/master/bash/base16-${scheme}.config" > ~/.local/bin/colorSchemeApplyFzf
|
||||||
|
chmod +x ~/.local/bin/colorSchemeApplyFzf
|
||||||
|
|
||||||
|
# qutebrowser
|
||||||
|
curl "https://raw.githubusercontent.com/theova/base16-qutebrowser/4a17eea8a39f722c2cee95fb44d4a87f5eb2518f/themes/base16-${scheme}.config.py" > ~/.config/qutebrowser/theme.py
|
||||||
|
|
||||||
|
# rofi
|
||||||
|
curl "https://raw.githubusercontent.com/0xdec/base16-rofi/master/themes/base16-${scheme}.rasi" > ~/.config/rofi/theme.rasi
|
||||||
|
curl "https://raw.githubusercontent.com/0xdec/base16-rofi/master/themes/base16-${scheme}.config" > ~/.config/rofi/theme.config
|
||||||
|
|
||||||
|
# TODO dunst (template online, but not to my liking)
|
||||||
|
# TODO bar (might change bar in the future, so...)
|
||||||
|
# TODO qutebrowser (need to fiddle with the config thing)
|
||||||
|
# TODO highlight (there IS a template but the colors look different from vim and mostly the same from when there's no config)
|
||||||
|
|
||||||
|
# Reload a bunch of things to make changes immediate
|
||||||
|
source ~/.bashrc
|
||||||
|
xrdb -load ~/.Xresources
|
||||||
|
i3-msg reload
|
213
scripts/compressPictureMovies
Executable file
213
scripts/compressPictureMovies
Executable file
|
@ -0,0 +1,213 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import coloredlogs
|
||||||
|
import progressbar
|
||||||
|
import time
|
||||||
|
import hashlib
|
||||||
|
import tempfile
|
||||||
|
import json
|
||||||
|
import statistics
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||||
|
log = logging.getLogger()
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
PICTURES_FOLDER = os.path.join(os.path.expanduser("~"), "Images")
|
||||||
|
ORIGINAL_FOLDER = os.path.join(os.path.expanduser("~"), ".ImagesOriginaux")
|
||||||
|
MOVIE_EXTENSIONS = ["mov", "avi", "mp4", "3gp", "webm", "mkv"]
|
||||||
|
OUTPUT_EXTENSION = "webm"
|
||||||
|
OUTPUT_FFMPEG_PARAMETERS = ["-c:v", "libvpx-vp9", "-crf", "30", "-b:v", "0"]
|
||||||
|
# OUTPUT_FFMPEG_PARAMETERS = ["-c:v", "libaom-av1", "-crf", "30", "-strict", "experimental", "-c:a", "libopus"]
|
||||||
|
DURATION_MAX_DEV = 1
|
||||||
|
|
||||||
|
|
||||||
|
def videoMetadata(filename):
|
||||||
|
assert os.path.isfile(filename)
|
||||||
|
cmd = ["ffmpeg", "-i", filename, "-f", "ffmetadata", "-"]
|
||||||
|
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||||
|
p.check_returncode()
|
||||||
|
metadataRaw = p.stdout
|
||||||
|
data = dict()
|
||||||
|
for metadataLine in metadataRaw.split(b'\n'):
|
||||||
|
# Skip empty lines
|
||||||
|
if not len(metadataLine):
|
||||||
|
continue
|
||||||
|
# Skip comments
|
||||||
|
if metadataLine.startswith(b';'):
|
||||||
|
continue
|
||||||
|
# Parse key-value
|
||||||
|
metadataLineSplit = metadataLine.split(b'=')
|
||||||
|
if len(metadataLineSplit) != 2:
|
||||||
|
log.warning("Unparsed metadata line: `{}`".format(metadataLine))
|
||||||
|
continue
|
||||||
|
key, val = metadataLineSplit
|
||||||
|
key = key.decode().lower()
|
||||||
|
val = val.decode()
|
||||||
|
data[key] = val
|
||||||
|
return data
|
||||||
|
|
||||||
|
def videoInfos(filename):
|
||||||
|
assert os.path.isfile(filename)
|
||||||
|
cmd = ["ffprobe", filename, "-print_format", "json", "-show_streams"]
|
||||||
|
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||||
|
p.check_returncode()
|
||||||
|
infosRaw = p.stdout
|
||||||
|
infos = json.loads(infosRaw)
|
||||||
|
return infos
|
||||||
|
|
||||||
|
from pprint import pprint
|
||||||
|
def streamDuration(stream):
|
||||||
|
if "duration" in stream:
|
||||||
|
return float(stream["duration"])
|
||||||
|
elif "sample_rate" in stream and "nb_frames" in stream:
|
||||||
|
return int(stream["nb_frames"]) / int(stream["sample_rate"])
|
||||||
|
elif "tags" in stream and "DURATION" in stream["tags"]:
|
||||||
|
durRaw = stream["tags"]["DURATION"]
|
||||||
|
durSplit = durRaw.split(":")
|
||||||
|
assert len(durSplit) == 3
|
||||||
|
durSplitFloat = [float(a) for a in durSplit]
|
||||||
|
hours, minutes, seconds = durSplitFloat
|
||||||
|
return (hours * 60 + minutes) * 60 + seconds
|
||||||
|
else:
|
||||||
|
raise KeyError("Can't find duration information in stream")
|
||||||
|
|
||||||
|
def videoDuration(filename):
|
||||||
|
# TODO Doesn't work with VP8 / webm
|
||||||
|
infos = videoInfos(filename)
|
||||||
|
durations = [streamDuration(stream) for stream in infos["streams"]]
|
||||||
|
dev = statistics.stdev(durations)
|
||||||
|
assert dev <= DURATION_MAX_DEV, "Too much deviation ({} s)".format(dev)
|
||||||
|
return sum(durations)/len(durations)
|
||||||
|
|
||||||
|
|
||||||
|
todos = set()
|
||||||
|
totalSize = 0
|
||||||
|
totalDuration = 0
|
||||||
|
|
||||||
|
# Walk folders
|
||||||
|
log.info("Listing files in {}".format(PICTURES_FOLDER))
|
||||||
|
allVideos = list()
|
||||||
|
for root, dirs, files in os.walk(PICTURES_FOLDER):
|
||||||
|
# If folder is in ORIGINAL_FOLDER, skip it
|
||||||
|
if root.startswith(ORIGINAL_FOLDER):
|
||||||
|
continue
|
||||||
|
# Iterate over files
|
||||||
|
for inputName in files:
|
||||||
|
# If the file is not a video, skip it
|
||||||
|
inputNameBase, inputExt = os.path.splitext(inputName)
|
||||||
|
inputExt = inputExt[1:].lower()
|
||||||
|
if inputExt not in MOVIE_EXTENSIONS:
|
||||||
|
continue
|
||||||
|
|
||||||
|
allVideos.append((root, inputName))
|
||||||
|
|
||||||
|
log.info("Analyzing videos")
|
||||||
|
for root, inputName in progressbar.progressbar(allVideos):
|
||||||
|
inputNameBase, inputExt = os.path.splitext(inputName)
|
||||||
|
inputExt = inputExt[1:].lower()
|
||||||
|
|
||||||
|
# Generates all needed filepaths
|
||||||
|
## Found file
|
||||||
|
inputFull = os.path.join(root, inputName)
|
||||||
|
inputRel = os.path.relpath(inputFull, PICTURES_FOLDER)
|
||||||
|
## Original file
|
||||||
|
originalFull = os.path.join(ORIGINAL_FOLDER, inputRel)
|
||||||
|
originalRel = inputRel
|
||||||
|
assert not os.path.isfile(originalFull), originalFile + " exists"
|
||||||
|
|
||||||
|
## Compressed file
|
||||||
|
outputFull = os.path.join(root, inputNameBase + "." + OUTPUT_EXTENSION)
|
||||||
|
|
||||||
|
# If the extension is the same of the output one
|
||||||
|
if inputExt == OUTPUT_EXTENSION:
|
||||||
|
# Read the metadata of the video
|
||||||
|
meta = videoMetadata(inputFull)
|
||||||
|
|
||||||
|
# If it has the field with the original file
|
||||||
|
if 'original' in meta:
|
||||||
|
# Skip file
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
assert not os.path.isfile(outputFull), outputFull + " exists"
|
||||||
|
|
||||||
|
|
||||||
|
size = os.stat(inputFull).st_size
|
||||||
|
try:
|
||||||
|
duration = videoDuration(inputFull)
|
||||||
|
except Exception as e:
|
||||||
|
log.warning("Can't determine duration of {}, skipping".format(inputFull))
|
||||||
|
log.debug(e, exc_info=True)
|
||||||
|
continue
|
||||||
|
|
||||||
|
todo = (inputFull, originalFull, outputFull, size, duration)
|
||||||
|
|
||||||
|
totalDuration += duration
|
||||||
|
totalSize += size
|
||||||
|
todos.add(todo)
|
||||||
|
|
||||||
|
log.info("Converting {} videos ({})".format(len(todos), datetime.timedelta(seconds=totalDuration)))
|
||||||
|
|
||||||
|
# From https://stackoverflow.com/a/3431838
|
||||||
|
def sha256(fname):
|
||||||
|
hash_sha256 = hashlib.sha256()
|
||||||
|
with open(fname, "rb") as f:
|
||||||
|
for chunk in iter(lambda: f.read(131072), b""):
|
||||||
|
hash_sha256.update(chunk)
|
||||||
|
return hash_sha256.hexdigest()
|
||||||
|
|
||||||
|
# Progress bar things
|
||||||
|
totalDataSize = progressbar.widgets.DataSize()
|
||||||
|
totalDataSize.variable = 'max_value'
|
||||||
|
barWidgets = [progressbar.widgets.DataSize(), ' of ', totalDataSize, ' ', progressbar.widgets.Bar(), ' ', progressbar.widgets.FileTransferSpeed(), ' ', progressbar.widgets.AdaptiveETA()]
|
||||||
|
bar = progressbar.DataTransferBar(max_value=totalSize, widgets=barWidgets)
|
||||||
|
bar.start()
|
||||||
|
processedSize = 0
|
||||||
|
|
||||||
|
|
||||||
|
for inputFull, originalFull, outputFull, size, duration in todos:
|
||||||
|
tmpfile = tempfile.mkstemp(prefix="compressPictureMovies", suffix="."+OUTPUT_EXTENSION)[1]
|
||||||
|
try:
|
||||||
|
# Calculate the sum of the original file
|
||||||
|
checksum = sha256(inputFull)
|
||||||
|
|
||||||
|
# Initiate a conversion in a temporary file
|
||||||
|
originalRel = os.path.relpath(originalFull, ORIGINAL_FOLDER)
|
||||||
|
originalContent = "{} {}".format(originalRel, checksum)
|
||||||
|
metadataCmd = ["-metadata", 'original="{}"'.format(originalContent)]
|
||||||
|
cmd = ["ffmpeg", "-hide_banner", "-y", "-i", inputFull] + OUTPUT_FFMPEG_PARAMETERS + metadataCmd + [tmpfile]
|
||||||
|
p = subprocess.run(cmd)
|
||||||
|
p.check_returncode()
|
||||||
|
|
||||||
|
# Verify the durartion of the new file
|
||||||
|
newDuration = videoDuration(tmpfile)
|
||||||
|
dev = statistics.stdev((duration, newDuration))
|
||||||
|
assert dev < DURATION_MAX_DEV, "Too much deviation in duration"
|
||||||
|
|
||||||
|
# Move the original to the corresponding original folder
|
||||||
|
originalDir = os.path.dirname(originalFull)
|
||||||
|
os.makedirs(originalDir, exist_ok=True)
|
||||||
|
shutil.move(inputFull, originalFull)
|
||||||
|
|
||||||
|
# Move the converted file in place of the original
|
||||||
|
shutil.move(tmpfile, outputFull)
|
||||||
|
except Exception as e:
|
||||||
|
log.error("Couldn't process file {}".format(inputFull))
|
||||||
|
log.error(e, exc_info=True)
|
||||||
|
try:
|
||||||
|
os.unlink(tmpfile)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
# Progress bar things
|
||||||
|
processedSize += size
|
||||||
|
bar.update(processedSize)
|
||||||
|
bar.finish()
|
||||||
|
|
||||||
|
|
||||||
|
# TODO Iterate over the already compressed videos to assert the originals are
|
||||||
|
# in their correct place, else move them
|
|
@ -167,10 +167,13 @@ function altInst {
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function systemdUserUnit {
|
||||||
|
systemctl enable "$1"
|
||||||
|
systemctl start "$1"
|
||||||
|
}
|
||||||
|
|
||||||
# Common CLI
|
# Common CLI
|
||||||
|
|
||||||
.Xresources.d/configure
|
|
||||||
|
|
||||||
# Utils
|
# Utils
|
||||||
inst coreutils man openssl-tool grep sed sh tar
|
inst coreutils man openssl-tool grep sed sh tar
|
||||||
|
@ -180,14 +183,15 @@ if [ $TERMUX == 1 ]; then
|
||||||
inst tsu
|
inst tsu
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
inst moreutils screen ncdu lsof htop proxytunnel pv curl wget sshfs netcat mosh bash-completion rsync pwgen
|
inst moreutils screen ncdu lsof htop proxytunnel pv curl wget netcat mosh bash-completion rsync pwgen fzf highlight
|
||||||
|
# TODO Test those who are on Debian machines and those who aren't
|
||||||
if [ $ARCH == 1 ]; then
|
if [ $ARCH == 1 ]; then
|
||||||
inst bash-completion
|
inst bash-completion tldr
|
||||||
altInst gopass
|
altInst gopass
|
||||||
else
|
else
|
||||||
inst pass
|
inst pass
|
||||||
wget -qO ~/.bin/ https://raw.githubusercontent.com/pepa65/tldr-bash-client/master/tldr
|
wget -qO ~/.local/bin/ https://raw.githubusercontent.com/pepa65/tldr-bash-client/master/tldr
|
||||||
chmod +x ~/.bin/tldr
|
chmod +x ~/.local/bin/tldr
|
||||||
fi
|
fi
|
||||||
tldr -u
|
tldr -u
|
||||||
if [[ $ARCH == 1 && $ADMIN == 1 ]]; then
|
if [[ $ARCH == 1 && $ADMIN == 1 ]]; then
|
||||||
|
@ -222,33 +226,14 @@ if [ $DEBIAN == 1 ]; then
|
||||||
else
|
else
|
||||||
inst ctags
|
inst ctags
|
||||||
fi
|
fi
|
||||||
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
|
vim +PlugUpgrade +PlugUpdate +PlugInstall +qall
|
||||||
vim +PluginInstall +qall
|
|
||||||
|
|
||||||
# YouCompleteMe (vim plugin)
|
|
||||||
if [ $ARCH == 1 ] && [ $ADMIN == 1 ]; then
|
|
||||||
if [ $EXTRA == 1 ]; then
|
|
||||||
altInst vim-youcompleteme-git
|
|
||||||
else
|
|
||||||
altInst vim-youcompleteme-core-git
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [ $DEBIAN == 1 || $TERMUX == 1 ]; then
|
|
||||||
inst python-dev python3-dev cmake
|
|
||||||
fi
|
|
||||||
YCM_ARGS=""
|
|
||||||
if [ $TERMUX != 1 ]; then
|
|
||||||
YCM_ARGS="$YCM_ARGS --clang-completer --tern-completer"
|
|
||||||
fi
|
|
||||||
|
|
||||||
python $HOME/.vim/bundle/YouCompleteMe/install.py $YCM_ARGS
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Common GUI
|
# Common GUI
|
||||||
|
|
||||||
if [ $GUI == 1 ]; then
|
if [ $GUI == 1 ]; then
|
||||||
|
.Xresources.d/configure
|
||||||
|
|
||||||
# Desktop manager
|
# Desktop manager
|
||||||
inst i3 i3lock dunst unclutter xautolock feh numlockx scrot xterm xclip
|
inst i3 i3lock dunst unclutter xautolock feh numlockx scrot rxvt-unicode xclip
|
||||||
curl "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/a8386aae19e200ddb0f6845b5feeee5eb7013687/fonts/fontawesome-webfont.ttf" > ~/.local/share/fonts/fontawesome-webfont.ttf
|
curl "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/a8386aae19e200ddb0f6845b5feeee5eb7013687/fonts/fontawesome-webfont.ttf" > ~/.local/share/fonts/fontawesome-webfont.ttf
|
||||||
if [ $ARCH == 1 ]; then
|
if [ $ARCH == 1 ]; then
|
||||||
inst xorg-xinit
|
inst xorg-xinit
|
||||||
|
@ -259,6 +244,9 @@ if [ $GUI == 1 ]; then
|
||||||
inst debhelper cmake libxcb-icccm4-dev libxcb-image0-dev libxcb-randr0-dev libx11-dev libxcb1-dev libxcb-util-dev libx11-xcb-dev linux-libc-dev libboost-dev x11proto-core-dev libxcb-ewmh-dev libxft-dev libasound2-dev libiw-dev libmpdclient-dev xcb-proto python-xcbgen libxcb-xkb-dev i3-wm libcairo2-dev libxcb-xrm-dev
|
inst debhelper cmake libxcb-icccm4-dev libxcb-image0-dev libxcb-randr0-dev libx11-dev libxcb1-dev libxcb-util-dev libx11-xcb-dev linux-libc-dev libboost-dev x11proto-core-dev libxcb-ewmh-dev libxft-dev libasound2-dev libiw-dev libmpdclient-dev xcb-proto python-xcbgen libxcb-xkb-dev i3-wm libcairo2-dev libxcb-xrm-dev
|
||||||
# TODO Figure which one are really needed
|
# TODO Figure which one are really needed
|
||||||
#inst libasound2 libc6 libgcc1 libiw30 libmpdclient2 libstdc++6 libx11-6 libx11-xcb1 libxcb-ewmh2 libxcb-icccm4 libxcb-randr0 libxcb-xkb1 libxcb1 libxft2
|
#inst libasound2 libc6 libgcc1 libiw30 libmpdclient2 libstdc++6 libx11-6 libx11-xcb1 libxcb-ewmh2 libxcb-icccm4 libxcb-randr0 libxcb-xkb1 libxcb1 libxft2
|
||||||
|
# ↓ really needed
|
||||||
|
inst libcairo2-dev libxcb-xkb-dev libxcb-randr0-dev xcb-proto libxcb-image0-dev libxcb-icccm4-dev libxcb-ewmh-dev libxcb-util0-dev python-xcbgen
|
||||||
|
|
||||||
TMP=$(mktemp -d)
|
TMP=$(mktemp -d)
|
||||||
git clone --branch 3.0.5 --recursive https://github.com/jaagr/polybar $TMP
|
git clone --branch 3.0.5 --recursive https://github.com/jaagr/polybar $TMP
|
||||||
mkdir $TMP/build
|
mkdir $TMP/build
|
||||||
|
@ -266,7 +254,7 @@ if [ $GUI == 1 ]; then
|
||||||
cmake ..
|
cmake ..
|
||||||
make -j`nproc`
|
make -j`nproc`
|
||||||
strip bin/polybar
|
strip bin/polybar
|
||||||
mv bin/polybar ~/.bin/
|
mv bin/polybar ~/.local/bin/
|
||||||
rm -rf $TMP
|
rm -rf $TMP
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -299,10 +287,10 @@ if [ $GUI == 1 ]; then
|
||||||
if [ $ARCH == 1 ]; then
|
if [ $ARCH == 1 ]; then
|
||||||
altInst sct
|
altInst sct
|
||||||
elif [ $TERMUX != 1 ]; then
|
elif [ $TERMUX != 1 ]; then
|
||||||
if [ ! -f $HOME/.bin/sct ]; then
|
if [ ! -f $HOME/.local/bin/sct ]; then
|
||||||
TMP=$(mktemp /tmp/XXXXXXXXXX.c)
|
TMP=$(mktemp /tmp/XXXXXXXXXX.c)
|
||||||
wget https://gist.githubusercontent.com/ajnirp/208c03d3aa7f02c743d2/raw/55bf3eed25739173d8be57b5179ed5542cf40ed6/sct.c -O $TMP
|
wget https://gist.githubusercontent.com/ajnirp/208c03d3aa7f02c743d2/raw/55bf3eed25739173d8be57b5179ed5542cf40ed6/sct.c -O $TMP
|
||||||
cc $TMP --std=c99 -lX11 -lXrandr -o $HOME/.bin/sct
|
cc $TMP --std=c99 -lX11 -lXrandr -o $HOME/.local/bin/sct
|
||||||
rm $TMP
|
rm $TMP
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -315,20 +303,28 @@ if [ $GUI == 1 ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [ $EXTRA == 1 ]; then
|
if [ $EXTRA == 1 ]; then
|
||||||
# Extra dev
|
# Extra dev
|
||||||
inst cmake clang llvm npm
|
inst cmake clang llvm npm
|
||||||
|
inst python-rope
|
||||||
|
|
||||||
# Extra CLI
|
# Extra CLI
|
||||||
inst ffmpeg youtube-dl optipng syncthing ccache
|
inst ffmpeg youtube-dl optipng syncthing ccache mutt
|
||||||
|
systemdUserUnit syncthing.service
|
||||||
if [ $ARCH == 1 ]; then
|
if [ $ARCH == 1 ]; then
|
||||||
inst jq
|
inst jq
|
||||||
altInst pdftk translate-shell git-lfs js-beautify insect visidata-git
|
altInst pdftk translate-shell git-lfs js-beautify insect visidata-git
|
||||||
|
|
||||||
|
# Orga
|
||||||
|
# TODO For others
|
||||||
|
inst vdirsyncer khard
|
||||||
|
altInst khal todoman offlineimap
|
||||||
|
systemdUserUnit vdirsyncer.timer
|
||||||
else
|
else
|
||||||
# translate-shell
|
# translate-shell
|
||||||
curl -L git.io/trans > ~/.bin/trans
|
curl -L git.io/trans > ~/.local/bin/trans
|
||||||
chmod +x ~/.bin/trans
|
chmod +x ~/.local/bin/trans
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Extra GUI
|
# Extra GUI
|
||||||
|
@ -337,7 +333,7 @@ if [ $EXTRA == 1 ]; then
|
||||||
|
|
||||||
if [ $ARCH == 1 ]; then
|
if [ $ARCH == 1 ]; then
|
||||||
inst simplescreenrecorder
|
inst simplescreenrecorder
|
||||||
altInst pacmixer xcursor-menda-git menda-themes-git menda-maia-icon-theme vimpc-git mpc
|
altInst pacmixer xcursor-menda-git menda-themes-git menda-maia-icon-theme vimpc-git mpc ashuffle-git
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -31,6 +31,8 @@ apt upgrade
|
||||||
# (needed for install-prefs)
|
# (needed for install-prefs)
|
||||||
apt install coreutils
|
apt install coreutils
|
||||||
apt install grep
|
apt install grep
|
||||||
|
# Used by some of my termux scripts
|
||||||
|
apt install jq
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
touch ~/.hushlogin
|
touch ~/.hushlogin
|
||||||
|
|
|
@ -52,7 +52,7 @@ function _machines-api {
|
||||||
wget $MACHINES_API/$route --content-on-error --quiet --output-document=- "$@"
|
wget $MACHINES_API/$route --content-on-error --quiet --output-document=- "$@"
|
||||||
result=$?
|
result=$?
|
||||||
if [ $result != 0 ]; then
|
if [ $result != 0 ]; then
|
||||||
echo "[ERROR] wget returned $result..."
|
echo "[ERROR] wget returned $result..." 1>&2;
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ function _machines-pubFromCrt {
|
||||||
function _machines-verifyCertificate {
|
function _machines-verifyCertificate {
|
||||||
return
|
return
|
||||||
if openssl verify $MACHINES_CONFIG/machines.crt | grep -v 'error 18' | grep 'error' --quiet; then
|
if openssl verify $MACHINES_CONFIG/machines.crt | grep -v 'error 18' | grep 'error' --quiet; then
|
||||||
echo "[ERROR] Invalid certificate"
|
echo "[ERROR] Invalid certificate" 1>&2;
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ function _machines-ensurePub {
|
||||||
if [ $? == 1 ]; then
|
if [ $? == 1 ]; then
|
||||||
mv $CERT_FILE $MACHINES_CONFIG/machines.crt &> /dev/null
|
mv $CERT_FILE $MACHINES_CONFIG/machines.crt &> /dev/null
|
||||||
else
|
else
|
||||||
echo "[ERROR] Certificate rejected."
|
echo "[ERROR] Certificate rejected." 1>&2;
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -105,7 +105,7 @@ function _machines-ensurePub {
|
||||||
|
|
||||||
function _machines-ensureAdmin {
|
function _machines-ensureAdmin {
|
||||||
if [ ! -f $MACHINES_CONFIG/machines.key ]; then
|
if [ ! -f $MACHINES_CONFIG/machines.key ]; then
|
||||||
echo "[ERROR] You need have to have the private key to do that"
|
echo "[ERROR] You need have to have the private key to do that" 1>&2;
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -127,6 +127,10 @@ function _machines-getAkey { # network
|
||||||
SIGN_FILE=$(mktemp)
|
SIGN_FILE=$(mktemp)
|
||||||
_machines-api akey/$1 > $KEY_FILE
|
_machines-api akey/$1 > $KEY_FILE
|
||||||
_machines-api akey/$1?signature > $SIGN_FILE
|
_machines-api akey/$1?signature > $SIGN_FILE
|
||||||
|
md5sum $KEY_FILE &1>&2;
|
||||||
|
md5sum $SIGN_FILE &1>&2;
|
||||||
|
md5sum $MACHINES_CONFIG/machines.pub &1>&2;
|
||||||
|
|
||||||
openssl dgst -sha256 -verify $MACHINES_CONFIG/machines.pub -signature $SIGN_FILE $KEY_FILE &> /dev/null
|
openssl dgst -sha256 -verify $MACHINES_CONFIG/machines.pub -signature $SIGN_FILE $KEY_FILE &> /dev/null
|
||||||
if [ $? == 0 ]; then
|
if [ $? == 0 ]; then
|
||||||
cat $KEY_FILE
|
cat $KEY_FILE
|
||||||
|
@ -147,7 +151,7 @@ function _machines-updateAkey {
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
cat $MYKEY_FILE
|
cat $MYKEY_FILE
|
||||||
echo "[ERROR] Authorized keys are not properly signed"
|
echo "[ERROR] Authorized keys are not properly signed" 1>&2;
|
||||||
rm $MYKEY_FILE
|
rm $MYKEY_FILE
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -368,12 +372,13 @@ function machines_update-all {
|
||||||
machines_machine_list | while read machine; do
|
machines_machine_list | while read machine; do
|
||||||
echo "Updating $machine..."
|
echo "Updating $machine..."
|
||||||
ssh $machine 'machines update' &
|
ssh $machine 'machines update' &
|
||||||
|
ssh $machine 'cd .dotfiles && git pull' &
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
function machines_regen-keys {
|
function machines_regen-keys {
|
||||||
if [[ -e $MACHINES_CONFIG/machines.key || -e $MACHINES_CONFIG/machines.pub || -e $MACHINES_CONFIG/machines.crt ]]; then
|
if [[ -e $MACHINES_CONFIG/machines.key || -e $MACHINES_CONFIG/machines.pub || -e $MACHINES_CONFIG/machines.crt ]]; then
|
||||||
echo "[ERROR] Please delete the pem files manually to prove you know what you're doing."
|
echo "[ERROR] Please delete the pem files manually to prove you know what you're doing." 1>&2;
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
openssl genrsa -out $MACHINES_CONFIG/machines.key 4096
|
openssl genrsa -out $MACHINES_CONFIG/machines.key 4096
|
||||||
|
@ -389,7 +394,7 @@ function machines_regen-keys {
|
||||||
|
|
||||||
function machines_setup {
|
function machines_setup {
|
||||||
if [ -e $MACHINES_CONFIG/this.name ]; then
|
if [ -e $MACHINES_CONFIG/this.name ]; then
|
||||||
echo "[ERROR] This machine is already set up"
|
echo "[ERROR] This machine is already set up" 1>&2;
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,8 @@ if (latex) {
|
||||||
|
|
||||||
// Conversion
|
// Conversion
|
||||||
htmlString = marked(markdownString, {
|
htmlString = marked(markdownString, {
|
||||||
renderer: renderer
|
renderer: renderer,
|
||||||
|
breaks: false
|
||||||
});
|
});
|
||||||
// fullHtmlString = htmlString;
|
// fullHtmlString = htmlString;
|
||||||
fullHtmlString = template.replace('%BODY%', () => { return htmlString });
|
fullHtmlString = template.replace('%BODY%', () => { return htmlString });
|
||||||
|
|
628
scripts/mel
Executable file
628
scripts/mel
Executable file
|
@ -0,0 +1,628 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
Meh mail client
|
||||||
|
A dumb Python scripts that leverages notmuch, mbsync, and msmtp
|
||||||
|
to become a fully-functional extremly-opinonated mail client.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# TODO Features
|
||||||
|
# TODO Implement initial command set
|
||||||
|
# TODO Lockfiles for write operations on mail files (mbsync, tags→maildir operations)
|
||||||
|
# TODO OPTI Lockfile per account and process everything in parallel (if implemented, this
|
||||||
|
# should be optional since while it may speed up the mail fetching process, its multi-threading
|
||||||
|
# nature would cause a lot of cache flushes and be not very efficient on battery)
|
||||||
|
# TODO Handle true character width
|
||||||
|
# TODO IMAP IDLE watches?
|
||||||
|
# TODO GPG
|
||||||
|
# TODO (only then) Refactor
|
||||||
|
# TODO OOP-based
|
||||||
|
# TODO Merge file with melConf
|
||||||
|
|
||||||
|
# DEBUG Small perf profiler
|
||||||
|
import time
|
||||||
|
perf_dict = dict()
|
||||||
|
perf_last = time.perf_counter()
|
||||||
|
def perfstep(name):
|
||||||
|
t = time.perf_counter()
|
||||||
|
global perf_last
|
||||||
|
global perf_dict
|
||||||
|
diff = t - perf_last
|
||||||
|
if name not in perf_dict:
|
||||||
|
perf_dict[name] = 0
|
||||||
|
perf_dict[name] += diff
|
||||||
|
perf_last = time.perf_counter()
|
||||||
|
|
||||||
|
|
||||||
|
import notmuch
|
||||||
|
import logging
|
||||||
|
import coloredlogs
|
||||||
|
import colorama
|
||||||
|
import datetime
|
||||||
|
import os
|
||||||
|
import progressbar
|
||||||
|
import argparse
|
||||||
|
import configparser
|
||||||
|
import base64
|
||||||
|
import shutil
|
||||||
|
import argparse
|
||||||
|
import xdg.BaseDirectory
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import html
|
||||||
|
import re
|
||||||
|
import email.parser
|
||||||
|
|
||||||
|
perfstep("import")
|
||||||
|
|
||||||
|
ACCOUNTS = dict()
|
||||||
|
ALIASES = set()
|
||||||
|
db = None
|
||||||
|
config = None
|
||||||
|
|
||||||
|
def notmuch_new():
|
||||||
|
close_database()
|
||||||
|
log.info("Indexing mails")
|
||||||
|
notmuchConfigPath = os.path.expanduser("~/.notmuchrc") # TODO Better
|
||||||
|
cmd = ["notmuch", "--config", notmuchConfigPath, "new"]
|
||||||
|
log.debug(" ".join(cmd))
|
||||||
|
subprocess.run(cmd)
|
||||||
|
|
||||||
|
def list_folders():
|
||||||
|
storagePath = os.path.realpath(os.path.expanduser(config["GENERAL"]["storage"]))
|
||||||
|
folders = list()
|
||||||
|
for account in ACCOUNTS.keys():
|
||||||
|
storagePathAccount = os.path.join(storagePath, account)
|
||||||
|
for root, dirs, files in os.walk(storagePathAccount):
|
||||||
|
if "cur" not in dirs or "new" not in dirs or "tmp" not in dirs:
|
||||||
|
continue
|
||||||
|
assert root.startswith(storagePath)
|
||||||
|
path = root[len(storagePath):]
|
||||||
|
pathSplit = path.split('/')
|
||||||
|
if pathSplit[0] == '':
|
||||||
|
pathSplit = pathSplit[1:]
|
||||||
|
folders.append(tuple(pathSplit))
|
||||||
|
return folders
|
||||||
|
|
||||||
|
def open_database(write=False):
|
||||||
|
global db
|
||||||
|
mode = notmuch.Database.MODE.READ_WRITE if write else notmuch.Database.MODE.READ_ONLY
|
||||||
|
if db:
|
||||||
|
if db.mode == mode:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
log.info("Current database not in required mode, closing")
|
||||||
|
close_database()
|
||||||
|
log.info("Opening database in mode {}".format(mode))
|
||||||
|
dbPath = os.path.realpath(os.path.expanduser(config["GENERAL"]["storage"]))
|
||||||
|
db = notmuch.Database(mode=mode, path=dbPath)
|
||||||
|
|
||||||
|
def close_database():
|
||||||
|
global db
|
||||||
|
if db:
|
||||||
|
log.info("Closing database")
|
||||||
|
db.close()
|
||||||
|
db = None
|
||||||
|
|
||||||
|
def generate_aliases():
|
||||||
|
for name in config.sections():
|
||||||
|
if not name.islower():
|
||||||
|
continue
|
||||||
|
section = config[name]
|
||||||
|
ALIASES.add(section["from"])
|
||||||
|
if "alternatives" in section:
|
||||||
|
for alt in section["alternatives"].split(";"):
|
||||||
|
ALIASES.add(alt)
|
||||||
|
ACCOUNTS[name] = section
|
||||||
|
|
||||||
|
|
||||||
|
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):]
|
||||||
|
pathSplit = path.split('/')
|
||||||
|
mailbox = pathSplit[1]
|
||||||
|
assert mailbox in ACCOUNTS
|
||||||
|
state = pathSplit[-1]
|
||||||
|
folder = tuple(pathSplit[2:-1])
|
||||||
|
assert state in {'cur', 'tmp', 'new'}
|
||||||
|
return (mailbox, folder, state)
|
||||||
|
|
||||||
|
MAILBOX_COLORS = dict()
|
||||||
|
|
||||||
|
def get_mailbox_color(mailbox):
|
||||||
|
if mailbox not in MAILBOX_COLORS:
|
||||||
|
colorStr = config[mailbox]["color"]
|
||||||
|
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')
|
||||||
|
|
||||||
|
WIDTH_FIXED = 31
|
||||||
|
WIDTH_RATIO_DEST_SUBJECT = 0.3
|
||||||
|
ISATTY = sys.stdout.isatty()
|
||||||
|
destWidth = None
|
||||||
|
subjectWidth = None
|
||||||
|
def compute_line_format():
|
||||||
|
if ISATTY:
|
||||||
|
columns, rows = shutil.get_terminal_size((80, 20))
|
||||||
|
remain = columns - WIDTH_FIXED - 1
|
||||||
|
global destWidth, subjectWidth
|
||||||
|
destWidth = int(remain * WIDTH_RATIO_DEST_SUBJECT)
|
||||||
|
subjectWidth = remain - destWidth
|
||||||
|
else:
|
||||||
|
destWidth = None
|
||||||
|
subjectWidth = None
|
||||||
|
|
||||||
|
def clip_text(size, text):
|
||||||
|
if size is None:
|
||||||
|
return text
|
||||||
|
l = len(text)
|
||||||
|
if l == size:
|
||||||
|
return text
|
||||||
|
elif l > size:
|
||||||
|
return text[:size-1] + '…'
|
||||||
|
elif l < size:
|
||||||
|
return text + " " * (size - l)
|
||||||
|
|
||||||
|
|
||||||
|
def print_msg(msg):
|
||||||
|
if not destWidth:
|
||||||
|
compute_line_format()
|
||||||
|
|
||||||
|
sep = " " if ISATTY else "\t"
|
||||||
|
line = ""
|
||||||
|
tags = set(msg.get_tags())
|
||||||
|
mailbox, folder, state = get_location(msg)
|
||||||
|
if ISATTY:
|
||||||
|
line += get_mailbox_color(mailbox)
|
||||||
|
|
||||||
|
# UID
|
||||||
|
uid = None
|
||||||
|
for tag in tags:
|
||||||
|
if tag.startswith('tuid'):
|
||||||
|
uid = tag[4:]
|
||||||
|
assert isUID(uid), uid
|
||||||
|
line += uid
|
||||||
|
|
||||||
|
# Date
|
||||||
|
line += sep
|
||||||
|
date = datetime.datetime.fromtimestamp(msg.get_date())
|
||||||
|
line += format_date(date)
|
||||||
|
|
||||||
|
# Icons
|
||||||
|
line += sep
|
||||||
|
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', '?', 'S', 'D', ' ')
|
||||||
|
tags2col1('attachment', 'encrypted', 'E', 'A', 'E', ' ')
|
||||||
|
tags2col1('unread', 'flagged', '!', 'U', 'F', ' ')
|
||||||
|
tags2col1('sent', 'replied', '?', '↑', '↪', ' ')
|
||||||
|
|
||||||
|
if 'sent' in tags:
|
||||||
|
dest = msg.get_header("to")
|
||||||
|
else:
|
||||||
|
dest = msg.get_header("from")
|
||||||
|
line += sep
|
||||||
|
line += clip_text(destWidth, dest)
|
||||||
|
|
||||||
|
# Subject
|
||||||
|
line += sep
|
||||||
|
subject = msg.get_header("subject")
|
||||||
|
line += clip_text(subjectWidth, subject)
|
||||||
|
|
||||||
|
if ISATTY:
|
||||||
|
line += colorama.Style.RESET_ALL
|
||||||
|
print(line)
|
||||||
|
|
||||||
|
|
||||||
|
def retag_msg(msg):
|
||||||
|
mailbox, folder, state = get_location(msg)
|
||||||
|
|
||||||
|
# Search-friendly folder name
|
||||||
|
slugFolderList = list()
|
||||||
|
for f, fold in [(f, folder[f]) for f in range(len(folder))]:
|
||||||
|
if f == 0 and len(folder) > 1 and fold == "INBOX":
|
||||||
|
continue
|
||||||
|
slugFolderList.append(fold.upper())
|
||||||
|
slugFolder = tuple(slugFolderList)
|
||||||
|
|
||||||
|
tags = set(msg.get_tags())
|
||||||
|
def tag_if(tag, condition):
|
||||||
|
if condition and tag not in tags:
|
||||||
|
msg.add_tag(tag)
|
||||||
|
elif not condition and tag in tags:
|
||||||
|
msg.remove_tag(tag)
|
||||||
|
expeditor = extract_email(msg.get_header('from'))
|
||||||
|
|
||||||
|
tag_if('inbox', slugFolder[0] == 'INBOX')
|
||||||
|
tag_if('spam', slugFolder[0] == 'JUNK' or slugFolder[0] == 'SPAM')
|
||||||
|
tag_if('deleted', slugFolder[0] == 'TRASH')
|
||||||
|
tag_if('draft', slugFolder[0] == 'DRAFTS')
|
||||||
|
tag_if('sent', expeditor in ALIASES)
|
||||||
|
tag_if('unprocessed', False)
|
||||||
|
|
||||||
|
# UID
|
||||||
|
uid = msg.get_header("X-TUID")
|
||||||
|
assert isUID(uid)
|
||||||
|
uidtag = 'tuid{}'.format(uid)
|
||||||
|
# Remove eventual others UID
|
||||||
|
for tag in tags:
|
||||||
|
if tag.startswith('tuid') and tag != uidtag:
|
||||||
|
msg.remove_tag(tag)
|
||||||
|
msg.add_tag(uidtag)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def extract_email(field):
|
||||||
|
try:
|
||||||
|
sta = field.index('<')
|
||||||
|
sto = field.index('>')
|
||||||
|
return field[sta+1:sto]
|
||||||
|
except ValueError:
|
||||||
|
return field
|
||||||
|
|
||||||
|
def applyMsgs(queryStr, action, *args, showProgress=False, write=False, closeDb=True, **kwargs):
|
||||||
|
open_database(write=write)
|
||||||
|
|
||||||
|
log.info("Querying {}".format(queryStr))
|
||||||
|
query = notmuch.Query(db, queryStr)
|
||||||
|
query.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
|
||||||
|
|
||||||
|
elements = query.search_messages()
|
||||||
|
nbMsgs = query.count_messages()
|
||||||
|
|
||||||
|
iterator = progressbar.progressbar(elements, max_value=nbMsgs) if showProgress else elements
|
||||||
|
|
||||||
|
log.info("Executing {}".format(action))
|
||||||
|
for msg in iterator:
|
||||||
|
if write:
|
||||||
|
msg.freeze()
|
||||||
|
|
||||||
|
action(msg, *args, **kwargs)
|
||||||
|
|
||||||
|
if write:
|
||||||
|
msg.thaw()
|
||||||
|
msg.tags_to_maildir_flags()
|
||||||
|
|
||||||
|
if closeDb:
|
||||||
|
close_database()
|
||||||
|
|
||||||
|
return nbMsgs
|
||||||
|
|
||||||
|
# def update_polybar_status():
|
||||||
|
def update_polybar_status(*args, **kwargs):
|
||||||
|
log.info("Updating polybar status")
|
||||||
|
accountsList = sorted(ACCOUNTS.keys())
|
||||||
|
print(accountsList)
|
||||||
|
open_database()
|
||||||
|
statusArr = []
|
||||||
|
for account in accountsList:
|
||||||
|
queryStr = 'folder:/{}/ and tag:unread'.format(account)
|
||||||
|
query = notmuch.Query(db, queryStr)
|
||||||
|
nbMsgs = query.count_messages()
|
||||||
|
if nbMsgs < 1:
|
||||||
|
continue
|
||||||
|
color = config[account]['color']
|
||||||
|
statusAccStr = '%{F' + color + '}' + str(nbMsgs) + '%{F-}'
|
||||||
|
statusArr.append(statusAccStr)
|
||||||
|
close_database()
|
||||||
|
statusStr = ('_' + ' '.join(statusArr)) if len(statusArr) else '\n'
|
||||||
|
statusPath = os.path.expanduser("~/.cache/mutt/status") # TODO Better
|
||||||
|
with open(statusPath, 'w') as f:
|
||||||
|
f.write(statusStr)
|
||||||
|
# statusPath = os.path.expanduser("~/.cache/mel/polybarstatus") # TODO Better
|
||||||
|
|
||||||
|
def notify_msg(msg):
|
||||||
|
log.info("Sending notification for {}".format(msg))
|
||||||
|
subject = msg.get_header("subject")
|
||||||
|
expd = msg.get_header("from")
|
||||||
|
account, _, _ = get_location(msg)
|
||||||
|
|
||||||
|
summary = '{} (<i>{}</i>)'.format(html.escape(expd), account)
|
||||||
|
body = html.escape(subject)
|
||||||
|
cmd = ["notify-send", "-u", "low", "-i", "mail-message-new", summary, body]
|
||||||
|
print(' '.join(cmd))
|
||||||
|
subprocess.run(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def notify_all(*args, **kwargs):
|
||||||
|
open_database()
|
||||||
|
nbMsgs = applyMsgs('tag:unread and tag:unprocessed', notify_msg)
|
||||||
|
if nbMsgs > 0:
|
||||||
|
log.info("Playing notification sound ({} new message(s))".format(nbMsgs))
|
||||||
|
cmd = ["play", "-n", "synth", "sine", "E4", "sine", "A5", "remix", "1-2", "fade", "0.5", "1.2", "0.5", "2"]
|
||||||
|
subprocess.run(cmd)
|
||||||
|
close_database()
|
||||||
|
|
||||||
|
def isUID(uid):
|
||||||
|
return isinstance(uid, str) and len(uid) == 12 and re.match('^[a-zA-Z0-9+/]{12}$', uid)
|
||||||
|
|
||||||
|
# From https://stackoverflow.com/a/312464
|
||||||
|
def chunks(l, n):
|
||||||
|
"""Yield successive n-sized chunks from l."""
|
||||||
|
for i in range(0, len(l), n):
|
||||||
|
yield l[i:i + n]
|
||||||
|
|
||||||
|
def apply_msgs_input(argmessages, action, write=False):
|
||||||
|
if not len(argmessages):
|
||||||
|
fromStdin = not sys.stdin.isatty()
|
||||||
|
else:
|
||||||
|
fromStdin = len(argmessages) == 1 and argmessages == '-'
|
||||||
|
|
||||||
|
messages = list()
|
||||||
|
if fromStdin:
|
||||||
|
for line in sys.stdin:
|
||||||
|
uid = line[:12]
|
||||||
|
if not isUID(uid):
|
||||||
|
log.error("Not an UID: {}".format(uid))
|
||||||
|
continue
|
||||||
|
messages.append(uid)
|
||||||
|
else:
|
||||||
|
for uids in argmessages:
|
||||||
|
if len(uids) > 12:
|
||||||
|
log.warn("Might have forgotten some spaces between the UIDs. Don't worry, I'll split them for you")
|
||||||
|
for uid in chunks(uids, 12):
|
||||||
|
if not isUID(uid):
|
||||||
|
log.error("Not an UID: {}".format(uid))
|
||||||
|
continue
|
||||||
|
messages.append(uid)
|
||||||
|
|
||||||
|
for message in messages:
|
||||||
|
queryStr = 'tag:tuid{}'.format(message)
|
||||||
|
nbMsgs = applyMsgs(queryStr, action, write=write, closeDb=False)
|
||||||
|
if nbMsgs < 1:
|
||||||
|
log.error("Couldn't execute function for message {}".format(message))
|
||||||
|
close_database()
|
||||||
|
|
||||||
|
def format_header_value(val):
|
||||||
|
return val.replace('\n', '').replace('\t', '').strip()
|
||||||
|
|
||||||
|
# From https://stackoverflow.com/a/1094933
|
||||||
|
def sizeof_fmt(num, suffix='B'):
|
||||||
|
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
|
||||||
|
if abs(num) < 1024.0:
|
||||||
|
return "%3.1f %s%s" % (num, unit, suffix)
|
||||||
|
num /= 1024.0
|
||||||
|
return "%.1f %s%s" % (num, 'Yi', suffix)
|
||||||
|
|
||||||
|
PART_MULTI_FORMAT = colorama.Fore.BLUE + '{nb} {indent}+ {typ}' + colorama.Style.RESET_ALL
|
||||||
|
PART_LEAF_FORMAT = colorama.Fore.BLUE + '{nb} {indent}→ {desc} ({typ}; {size})' + colorama.Style.RESET_ALL
|
||||||
|
def show_parts_tree(part, lvl=0, nb=1):
|
||||||
|
indent = lvl * '\t'
|
||||||
|
typ = part.get_content_type()
|
||||||
|
if part.is_multipart():
|
||||||
|
print(PART_MULTI_FORMAT.format(nb=nb, indent=indent, typ=typ))
|
||||||
|
payl = part.get_payload()
|
||||||
|
size = 1
|
||||||
|
for obj in payl:
|
||||||
|
size += show_parts_tree(obj, lvl=lvl+1, nb=nb+size)
|
||||||
|
return size
|
||||||
|
else:
|
||||||
|
size = len(part.get_payload(decode=True))
|
||||||
|
desc = part.get('Content-Description', '<no description>')
|
||||||
|
print(PART_LEAF_FORMAT.format(nb=nb, indent=indent, typ=typ, desc=desc, size=sizeof_fmt(size)))
|
||||||
|
return 1
|
||||||
|
|
||||||
|
INTERESTING_HEADERS = ["Date", "From", "Subject", "To", "Cc", "Message-Id"]
|
||||||
|
HEADER_FORMAT = colorama.Fore.BLUE + colorama.Style.BRIGHT + '{}:' + colorama.Style.NORMAL + ' {}' + colorama.Style.RESET_ALL
|
||||||
|
def read_msg(msg):
|
||||||
|
# Parse
|
||||||
|
filename = msg.get_filename()
|
||||||
|
parser = email.parser.BytesParser()
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
|
mail = parser.parse(f)
|
||||||
|
|
||||||
|
# Debug
|
||||||
|
global a
|
||||||
|
a = mail
|
||||||
|
|
||||||
|
# Defects
|
||||||
|
if len(mail.defects):
|
||||||
|
log.warn("Defects found in the mail:")
|
||||||
|
for defect in mail.defects:
|
||||||
|
log.warn(mail.defects)
|
||||||
|
|
||||||
|
|
||||||
|
# Headers
|
||||||
|
for key in INTERESTING_HEADERS:
|
||||||
|
val = mail.get(key)
|
||||||
|
if val:
|
||||||
|
val = format_header_value(val)
|
||||||
|
print(HEADER_FORMAT.format(key, val))
|
||||||
|
# TODO Show all headers
|
||||||
|
# TODO BONUS Highlight failed verifications
|
||||||
|
|
||||||
|
show_parts_tree(mail)
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Show text/plain
|
||||||
|
for part in mail.walk():
|
||||||
|
if part.get_content_type() == "text/plain":
|
||||||
|
payl = part.get_payload(decode=True)
|
||||||
|
print(payl.decode())
|
||||||
|
|
||||||
|
|
||||||
|
perfstep("definitions")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Main arguments
|
||||||
|
parser = argparse.ArgumentParser(description="Meh mail client")
|
||||||
|
selectedVerbosityLevels = ["DEBUG", "INFO", "WARNING", "ERROR", "FATAL"]
|
||||||
|
parser.add_argument('-v', '--verbosity', choices=selectedVerbosityLevels, default='WARNING', help="Verbosity of log messages")
|
||||||
|
# parser.add_argument('-n', '--dry-run', action='store_true', help="Don't do anything") # DEBUG
|
||||||
|
defaultConfigFile = os.path.join(xdg.BaseDirectory.xdg_config_home, 'mel', 'accounts.conf')
|
||||||
|
parser.add_argument('-c', '--config', default=defaultConfigFile, help="Accounts config file")
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(help="Action to execute")
|
||||||
|
|
||||||
|
## List messages
|
||||||
|
|
||||||
|
def func_default(args):
|
||||||
|
applyMsgs('tag:inbox', print_msg)
|
||||||
|
parser.set_defaults(func=func_default)
|
||||||
|
|
||||||
|
# inbox (default)
|
||||||
|
def func_inbox(args):
|
||||||
|
queryStr = 'tag:unread' if args.only_unread else 'tag:inbox'
|
||||||
|
applyMsgs(queryStr, print_msg)
|
||||||
|
|
||||||
|
parserInbox = subparsers.add_parser("inbox", help="Show unread, unsorted and flagged messages")
|
||||||
|
parserInbox.add_argument('-u', '--only-unread', action='store_true', help="Show unread messages only")
|
||||||
|
# TODO Make this more relevant
|
||||||
|
parserInbox.set_defaults(func=func_inbox)
|
||||||
|
|
||||||
|
|
||||||
|
# list folder [--recurse]
|
||||||
|
## List actions
|
||||||
|
|
||||||
|
|
||||||
|
# flag msg...
|
||||||
|
def func_flag(args):
|
||||||
|
def flag_msg(msg):
|
||||||
|
msg.add_tag('flagged')
|
||||||
|
apply_msgs_input(args.message, flag_msg, write=True)
|
||||||
|
parserFlag = subparsers.add_parser("flag", help="Mark messages as flagged")
|
||||||
|
parserFlag.add_argument('message', nargs='*', help="Messages")
|
||||||
|
parserFlag.set_defaults(func=func_flag)
|
||||||
|
|
||||||
|
|
||||||
|
# unflag msg...
|
||||||
|
def func_unflag(args):
|
||||||
|
def unflag_msg(msg):
|
||||||
|
msg.remove_tag('flagged')
|
||||||
|
apply_msgs_input(args.message, unflag_msg, write=True)
|
||||||
|
parserUnflag = subparsers.add_parser("unflag", help="Mark messages as not-flagged")
|
||||||
|
parserUnflag.add_argument('message', nargs='*', help="Messages")
|
||||||
|
parserUnflag.set_defaults(func=func_unflag)
|
||||||
|
|
||||||
|
|
||||||
|
# delete msg...
|
||||||
|
# spam msg...
|
||||||
|
# move dest msg...
|
||||||
|
## Read message
|
||||||
|
|
||||||
|
|
||||||
|
# read msg [--html] [--plain] [--browser]
|
||||||
|
def func_read(args):
|
||||||
|
apply_msgs_input(args.message, read_msg)
|
||||||
|
parserRead = subparsers.add_parser("read", help="Read message")
|
||||||
|
parserRead.add_argument('message', nargs=1, help="Messages")
|
||||||
|
parserRead.set_defaults(func=func_read)
|
||||||
|
|
||||||
|
|
||||||
|
# attach msg [id] [--save] (list if no id, xdg-open else)
|
||||||
|
## Redaction
|
||||||
|
# new account
|
||||||
|
# reply msg [--all]
|
||||||
|
## Folder management
|
||||||
|
# tree [folder]
|
||||||
|
# mkdir folder
|
||||||
|
# rmdir folder (prevent if folder isn't empty (mail/subfolder))
|
||||||
|
# (yeah that should do)
|
||||||
|
## Meta
|
||||||
|
# setup (interactive thing maybe)
|
||||||
|
|
||||||
|
|
||||||
|
# fetch (mbsync, notmuch new, retag, notify; called by greater gods)
|
||||||
|
def func_fetch(args):
|
||||||
|
# Fetch mails
|
||||||
|
log.info("Fetching mails")
|
||||||
|
mbsyncConfigPath = os.path.expanduser("~/.mbsyncrc") # TODO Better
|
||||||
|
cmd = ["mbsync", "--config", mbsyncConfigPath, "--all"]
|
||||||
|
subprocess.run(cmd)
|
||||||
|
|
||||||
|
# Index new mails
|
||||||
|
notmuch_new()
|
||||||
|
|
||||||
|
# Notify
|
||||||
|
notify_all()
|
||||||
|
update_polybar_status()
|
||||||
|
|
||||||
|
# Tag new mails
|
||||||
|
applyMsgs('tag:unprocessed', retag_msg, showProgress=True, write=True)
|
||||||
|
|
||||||
|
parserFetch = subparsers.add_parser("fetch", help="Fetch mail, tag them, and run notifications")
|
||||||
|
parserFetch.set_defaults(func=func_fetch)
|
||||||
|
|
||||||
|
|
||||||
|
## Debug
|
||||||
|
# debug (various)
|
||||||
|
def func_expose(args):
|
||||||
|
# And leave the door open
|
||||||
|
def expose_msg(a):
|
||||||
|
global msg
|
||||||
|
msg = a
|
||||||
|
applyMsgs('tag:tuidyviU45m6flff', expose_msg, closeDb=False)
|
||||||
|
def func_debug(args):
|
||||||
|
from pprint import pprint
|
||||||
|
pprint(list_folders())
|
||||||
|
parserDebug = subparsers.add_parser("debug", help="Who know what this holds...")
|
||||||
|
parserDebug.set_defaults(verbosity='DEBUG')
|
||||||
|
parserDebug.set_defaults(func=func_debug)
|
||||||
|
|
||||||
|
# retag (all or unprocessed)
|
||||||
|
def func_retag(args):
|
||||||
|
applyMsgs('*', retag_msg, showProgress=True, write=True)
|
||||||
|
parserRetag = subparsers.add_parser("retag", help="Retag all mails (when you changed configuration)")
|
||||||
|
parserRetag.set_defaults(func=func_retag)
|
||||||
|
|
||||||
|
# all
|
||||||
|
def func_all(args):
|
||||||
|
applyMsgs('*', print_msg)
|
||||||
|
|
||||||
|
parserAll = subparsers.add_parser("all", help="Show ALL messages")
|
||||||
|
parserAll.set_defaults(func=func_all)
|
||||||
|
|
||||||
|
# Init
|
||||||
|
args = parser.parse_args()
|
||||||
|
perfstep("parse_args")
|
||||||
|
|
||||||
|
colorama.init()
|
||||||
|
coloredlogs.install(level=args.verbosity, fmt='%(levelname)s %(message)s')
|
||||||
|
log = logging.getLogger()
|
||||||
|
|
||||||
|
log.info("Loading config {}".format(args.config))
|
||||||
|
if not os.path.isfile(args.config):
|
||||||
|
log.fatal("Config file not found: {}".format(args.config))
|
||||||
|
sys.exit(1)
|
||||||
|
# TODO Create it, maybe?
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read(args.config)
|
||||||
|
|
||||||
|
generate_aliases()
|
||||||
|
perfstep("config")
|
||||||
|
|
||||||
|
if args.func:
|
||||||
|
log.info("Executing function {}".format(args.func))
|
||||||
|
args.func(args)
|
||||||
|
|
||||||
|
perfstep("exec")
|
||||||
|
|
||||||
|
# DEBUG
|
||||||
|
sys.exit(0)
|
||||||
|
for kv in sorted(perf_dict.items(), key=lambda p: p[1]):
|
||||||
|
log.debug("{1:.6f} {0}".format(*kv))
|
227
scripts/melConf
Executable file
227
scripts/melConf
Executable file
|
@ -0,0 +1,227 @@
|
||||||
|
#!/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 Signature file
|
||||||
|
# TODO Write ~/.mail/[mailbox]/color file if required by sth?
|
||||||
|
# TODO Fix IMAPS with mbsync
|
||||||
|
|
||||||
|
configPath = os.path.join(os.path.expanduser('~'), '.config', 'mel', 'accounts.conf')
|
||||||
|
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read(configPath)
|
||||||
|
|
||||||
|
storageFull = os.path.realpath(os.path.expanduser(config["GENERAL"]["storage"]))
|
||||||
|
config["GENERAL"]["storage"] = storageFull
|
||||||
|
|
||||||
|
SERVER_DEFAULTS = {
|
||||||
|
"imap": {"port": 143, "starttls": True},
|
||||||
|
"smtp": {"port": 587, "starttls": True},
|
||||||
|
}
|
||||||
|
SERVER_ITEMS = {"host", "port", "user", "pass", "starttls"}
|
||||||
|
|
||||||
|
# Reading sections
|
||||||
|
accounts = dict()
|
||||||
|
mails = set()
|
||||||
|
|
||||||
|
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]
|
||||||
|
|
||||||
|
mails.add(section["from"])
|
||||||
|
if "alternatives" in section:
|
||||||
|
for alt in section["alternatives"].split(";"):
|
||||||
|
mails.add(alt)
|
||||||
|
|
||||||
|
data["account"] = name
|
||||||
|
data["storage"] = os.path.join(config['GENERAL']['storage'], name)
|
||||||
|
data["storageInbox"] = os.path.join(data["storage"], "INBOX")
|
||||||
|
accounts[name] = data
|
||||||
|
|
||||||
|
general = dict()
|
||||||
|
section = config["GENERAL"]
|
||||||
|
for key in section.keys():
|
||||||
|
general[key] = section[key]
|
||||||
|
general["main"] = accounts[general["main"]]
|
||||||
|
|
||||||
|
|
||||||
|
# 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 {account}]
|
||||||
|
localrepository = {account}-local
|
||||||
|
remoterepository = {account}-remote
|
||||||
|
autorefresh = 0.5
|
||||||
|
quick = 10
|
||||||
|
utf8foldernames = yes
|
||||||
|
postsynchook = ~/.mutt/postsync
|
||||||
|
|
||||||
|
[Repository {account}-local]
|
||||||
|
type = Maildir
|
||||||
|
localfolders = {storage}
|
||||||
|
|
||||||
|
[Repository {account}-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 {account}
|
||||||
|
Host {imaphost}
|
||||||
|
Port {imapport}
|
||||||
|
User {imapuser}
|
||||||
|
Pass "{imappassEscaped}"
|
||||||
|
{secconf}
|
||||||
|
|
||||||
|
IMAPStore {account}-remote
|
||||||
|
Account {account}
|
||||||
|
|
||||||
|
MaildirStore {account}-local
|
||||||
|
Subfolders Verbatim
|
||||||
|
Path {storage}/
|
||||||
|
Inbox {storageInbox}/
|
||||||
|
|
||||||
|
Channel {account}
|
||||||
|
Master :{account}-remote:
|
||||||
|
Slave :{account}-local:
|
||||||
|
Patterns *
|
||||||
|
Create Both
|
||||||
|
SyncState *
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
mbsyncStr = ""
|
||||||
|
for name, account in accounts.items():
|
||||||
|
if account["imapstarttls"]:
|
||||||
|
secconf = "SSLType STARTTLS"
|
||||||
|
else:
|
||||||
|
secconf = "SSLType IMAPS"
|
||||||
|
if "certificate" in account:
|
||||||
|
secconf += "\nCertificateFile {certificate}".format(**account)
|
||||||
|
imappassEscaped = account["imappass"].replace("\\", "\\\\")
|
||||||
|
mbsyncStr += MBSYNC_ACCOUNT.format(**account, secconf=secconf, imappassEscaped=imappassEscaped)
|
||||||
|
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 {account}
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
# notmuch
|
||||||
|
NOTMUCH_BEGIN = """[database]
|
||||||
|
path={storage}
|
||||||
|
|
||||||
|
[user]
|
||||||
|
name={main[name]}
|
||||||
|
primary_email={main[from]}
|
||||||
|
other_email={other_email}
|
||||||
|
|
||||||
|
[new]
|
||||||
|
tags=unprocessed;unread;
|
||||||
|
ignore=
|
||||||
|
|
||||||
|
[search]
|
||||||
|
exclude_tags=deleted;spam;
|
||||||
|
|
||||||
|
[maildir]
|
||||||
|
synchronize_flags=true
|
||||||
|
|
||||||
|
[crypto]
|
||||||
|
gpg_path=gpg
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
other_email = mails.copy()
|
||||||
|
other_email.remove(general["main"]["from"])
|
||||||
|
other_email = ";".join(other_email)
|
||||||
|
notmuchStr = NOTMUCH_BEGIN.format(**general, other_email=other_email)
|
||||||
|
msbsyncFilepath = os.path.join(os.path.expanduser('~'), '.notmuchrc')
|
||||||
|
with open(msbsyncFilepath, 'w') as f:
|
||||||
|
f.write(notmuchStr)
|
||||||
|
|
39
scripts/musiqueBof
Executable file
39
scripts/musiqueBof
Executable file
|
@ -0,0 +1,39 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import logging
|
||||||
|
import coloredlogs
|
||||||
|
|
||||||
|
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||||
|
log = logging.getLogger()
|
||||||
|
|
||||||
|
MUSICS_FOLDER = os.path.join(os.path.expanduser("~"), "Musique")
|
||||||
|
BOF_FOLDER = os.path.join(os.path.expanduser("~"), ".MusiqueBof")
|
||||||
|
|
||||||
|
for f in sys.argv[1:]:
|
||||||
|
src = os.path.realpath(f)
|
||||||
|
if not os.path.isfile(src):
|
||||||
|
log.error("{} does not exists".format(src))
|
||||||
|
continue
|
||||||
|
|
||||||
|
srcBase = None
|
||||||
|
if src.startswith(MUSICS_FOLDER):
|
||||||
|
srcBase = MUSICS_FOLDER
|
||||||
|
dstBase = BOF_FOLDER
|
||||||
|
elif src.startswith(BOF_FOLDER):
|
||||||
|
srcBase = BOF_FOLDER
|
||||||
|
dstBase = MUSIC_FOLDER
|
||||||
|
else:
|
||||||
|
log.error("{} not in any music folder".format(src))
|
||||||
|
continue
|
||||||
|
|
||||||
|
common = os.path.relpath(src, srcBase)
|
||||||
|
dst = os.path.join(dstBase, common)
|
||||||
|
dstFolder = os.path.dirname(dst)
|
||||||
|
|
||||||
|
log.info("{} → {}".format(src, dst))
|
||||||
|
os.makedirs(dstFolder, exist_ok=True)
|
||||||
|
shutil.move(src, dst)
|
||||||
|
|
|
@ -146,20 +146,26 @@ do
|
||||||
|
|
||||||
done <<< "$(find "$dir" -type f -iname "*.png")"
|
done <<< "$(find "$dir" -type f -iname "*.png")"
|
||||||
|
|
||||||
# SVG (requires svgo)
|
# # SVG (requires scour)
|
||||||
while read image
|
# while read image
|
||||||
do
|
# do
|
||||||
if [ -z "$image" ]; then continue; fi
|
# if [ -z "$image" ]; then continue; fi
|
||||||
echo Processing $image
|
# 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)
|
# NOTE Explicitely disabled since:
|
||||||
cp "$image" "$temp"
|
# - I only have ~50 MiB of SVG in TOTAL
|
||||||
svgo --quiet --config $HOME/.config/optiSvgo.yml "$temp"
|
# - Most conversions are not image losseless
|
||||||
echo "→ Optimize done"
|
# - Even when they are losseless, they are mostly worthless
|
||||||
|
# - I might want to keep editor data and/or ids for some of them
|
||||||
replaceImg "$temp" "$image"
|
# So rather use scour explicitely when needed
|
||||||
|
|
||||||
done <<< "$(find "$dir" -type f -iname "*.svg")"
|
|
||||||
|
|
||||||
cleandev
|
cleandev
|
||||||
|
|
||||||
|
|
4
scripts/pdfpages
Executable file
4
scripts/pdfpages
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
# From https://stackoverflow.com/a/14736593
|
||||||
|
pdftk "$1" dump_data | grep NumberOfPages | awk '{print $2}'
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# Moves a file to another place and put a symbolic link in place
|
# Moves a file to another place and put a symbolic link in place
|
||||||
|
|
||||||
function proxy_help {
|
function rep_help {
|
||||||
echo "Usage: $0 SOURCE DEST"
|
echo "Usage: $0 SOURCE DEST"
|
||||||
echo
|
echo
|
||||||
echo "Arguments:"
|
echo "Arguments:"
|
||||||
|
@ -17,9 +17,9 @@ ln -s "$2" "$1"
|
||||||
# MAIN
|
# MAIN
|
||||||
command="$1"
|
command="$1"
|
||||||
shift
|
shift
|
||||||
if type "proxy_$command" &> /dev/null; then
|
if type "rep_$command" &> /dev/null; then
|
||||||
"proxy_$command" "$@"
|
"rep_$command" "$@"
|
||||||
else
|
else
|
||||||
proxy_help
|
rep_help
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
68
scripts/replayGain
Executable file
68
scripts/replayGain
Executable file
|
@ -0,0 +1,68 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Normalisation is done at the default of each program,
|
||||||
|
# which is usually -89.0 dB
|
||||||
|
|
||||||
|
import os
|
||||||
|
import coloredlogs
|
||||||
|
import logging
|
||||||
|
import r128gain
|
||||||
|
import sys
|
||||||
|
|
||||||
|
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||||
|
log = logging.getLogger()
|
||||||
|
|
||||||
|
# TODO Remove debug
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
FORCE = '-f' in sys.argv
|
||||||
|
if FORCE:
|
||||||
|
sys.argv.remove('-f')
|
||||||
|
SOURCE_FOLDER = os.path.realpath(sys.argv[1]) if len(sys.argv) >= 2 else os.path.join(os.path.expanduser("~"), "Musique")
|
||||||
|
|
||||||
|
def isMusic(f):
|
||||||
|
ext = os.path.splitext(f)[1][1:].lower()
|
||||||
|
return ext in r128gain.AUDIO_EXTENSIONS
|
||||||
|
|
||||||
|
# Get album paths
|
||||||
|
log.info("Listing albums and tracks")
|
||||||
|
albums = set()
|
||||||
|
singleFiles = set()
|
||||||
|
for root, dirs, files in os.walk(SOURCE_FOLDER):
|
||||||
|
|
||||||
|
relRoot = os.path.relpath(root, SOURCE_FOLDER)
|
||||||
|
|
||||||
|
head, tail = os.path.split(relRoot)
|
||||||
|
# 1 component in the path: save files path as single
|
||||||
|
if not len(head):
|
||||||
|
for f in files:
|
||||||
|
if isMusic(f):
|
||||||
|
fullPath = os.path.join(root, f)
|
||||||
|
singleFiles.add(fullPath)
|
||||||
|
head, tail = os.path.split(head)
|
||||||
|
if len(head):
|
||||||
|
continue
|
||||||
|
# 2 components in the path: save album path
|
||||||
|
albums.add(root)
|
||||||
|
|
||||||
|
log.info("Processing single files")
|
||||||
|
# r128gain.process(list(singleFiles), album_gain=False, skip_tagged=not FORCE, report=True)
|
||||||
|
for album in albums:
|
||||||
|
albumName = os.path.relpath(album, SOURCE_FOLDER)
|
||||||
|
log.info("Processing album {}".format(albumName))
|
||||||
|
|
||||||
|
musicFiles = set()
|
||||||
|
for root, dirs, files in os.walk(album):
|
||||||
|
for f in files:
|
||||||
|
if isMusic(f):
|
||||||
|
fullPath = os.path.join(root, f)
|
||||||
|
musicFiles.add(fullPath)
|
||||||
|
|
||||||
|
# print(musicFiles)
|
||||||
|
if not len(musicFiles):
|
||||||
|
continue
|
||||||
|
r128gain.process(list(musicFiles), album_gain=True, skip_tagged=not FORCE, report=True)
|
||||||
|
print("==============================")
|
||||||
|
|
||||||
|
|
||||||
|
|
2
scripts/rms
Executable file
2
scripts/rms
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
find . -name "*.sync-conflict-*" -delete
|
17
scripts/tagCreatorPhotos
Executable file
17
scripts/tagCreatorPhotos
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import piexif
|
||||||
|
|
||||||
|
assert len(sys.argv) >= 3, "Usage {} CREATOR FILENAMES...".format(sys.argv[0])
|
||||||
|
creator = sys.argv[1]
|
||||||
|
filenames = sys.argv[2:]
|
||||||
|
|
||||||
|
for filename in filenames:
|
||||||
|
assert os.path.isfile(filename)
|
||||||
|
exifDict = piexif.load(filename)
|
||||||
|
exifDict['0th'][piexif.ImageIFD.Copyright] = creator.encode()
|
||||||
|
exifBytes = piexif.dump(exifDict)
|
||||||
|
piexif.insert(exifBytes, filename)
|
||||||
|
|
121
scripts/updateCompressedMusic
Executable file
121
scripts/updateCompressedMusic
Executable file
|
@ -0,0 +1,121 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import progressbar
|
||||||
|
import logging
|
||||||
|
import coloredlogs
|
||||||
|
|
||||||
|
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||||
|
log = logging.getLogger()
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
SOURCE_FOLDER = os.path.join(os.path.expanduser("~"), "Musique")
|
||||||
|
OUTPUT_FOLDER = os.path.join(os.path.expanduser("~"), ".MusiqueCompressed")
|
||||||
|
CONVERSIONS = {"flac": "opus"}
|
||||||
|
FORBIDDEN_EXTENSIONS = ["jpg", "pdf", "ffs_db"]
|
||||||
|
FORGIVEN_FILENAMES = ["cover.jpg"]
|
||||||
|
IGNORED_EMPTY_FOLDER = [".stfolder"]
|
||||||
|
|
||||||
|
# TODO FEAT Make the directory structure the same as the base one and
|
||||||
|
# remove IGNORED_EMPTY_FOLDER variable
|
||||||
|
|
||||||
|
# Listing files
|
||||||
|
log.info("Listing files")
|
||||||
|
sourceFiles = dict()
|
||||||
|
for root, dirs, files in os.walk(SOURCE_FOLDER):
|
||||||
|
for f in files:
|
||||||
|
fullPath = os.path.join(root, f)
|
||||||
|
path = os.path.relpath(fullPath, SOURCE_FOLDER)
|
||||||
|
sourceFiles[path] = os.path.getctime(fullPath)
|
||||||
|
|
||||||
|
outputFiles = dict()
|
||||||
|
for root, dirs, files in os.walk(OUTPUT_FOLDER):
|
||||||
|
for f in files:
|
||||||
|
fullPath = os.path.join(root, f)
|
||||||
|
path = os.path.relpath(fullPath, OUTPUT_FOLDER)
|
||||||
|
outputFiles[path] = os.path.getctime(fullPath)
|
||||||
|
|
||||||
|
# Sorting files
|
||||||
|
remainingConversions = dict()
|
||||||
|
extraFiles = set(outputFiles.keys())
|
||||||
|
|
||||||
|
|
||||||
|
def convertPath(path):
|
||||||
|
filename, extension = os.path.splitext(path)
|
||||||
|
extension = extension[1:].lower()
|
||||||
|
# If the extension isn't allowed
|
||||||
|
if extension in FORBIDDEN_EXTENSIONS:
|
||||||
|
basename = os.path.basename(path)
|
||||||
|
# And the filename is not an exception
|
||||||
|
if basename not in FORGIVEN_FILENAMES:
|
||||||
|
# This file shouldn't be copied nor converted
|
||||||
|
return False
|
||||||
|
# If this needs a conversion
|
||||||
|
elif extension in CONVERSIONS:
|
||||||
|
extension = CONVERSIONS[extension]
|
||||||
|
return filename + "." + extension
|
||||||
|
# In all other case, this is a simple copy
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
log.info("Determining action over {} files".format(len(sourceFiles)))
|
||||||
|
for sourceFile in sourceFiles:
|
||||||
|
outputFile = convertPath(sourceFile)
|
||||||
|
# If the file should not be converted, do nothing
|
||||||
|
if outputFile == False:
|
||||||
|
continue
|
||||||
|
# If the file already has something as an output
|
||||||
|
elif outputFile in outputFiles:
|
||||||
|
extraFiles.remove(outputFile)
|
||||||
|
# If the output file is newer than the source file, do not initiate a
|
||||||
|
# conversion
|
||||||
|
if outputFiles[outputFile] >= sourceFiles[sourceFile]:
|
||||||
|
continue
|
||||||
|
# If the file needs to be converted, do it
|
||||||
|
remainingConversions[sourceFile] = outputFile
|
||||||
|
|
||||||
|
log.debug("{} actions will need to be taken".format(len(remainingConversions)))
|
||||||
|
log.info("Copying files that do not require a conversion")
|
||||||
|
conversions = set()
|
||||||
|
for sourceFile in remainingConversions:
|
||||||
|
outputFile = remainingConversions[sourceFile]
|
||||||
|
|
||||||
|
# Creating folder if it doesn't exists
|
||||||
|
fullOutputFile = os.path.join(OUTPUT_FOLDER, outputFile)
|
||||||
|
fullOutputDir = os.path.dirname(fullOutputFile)
|
||||||
|
os.makedirs(fullOutputDir, exist_ok=True)
|
||||||
|
|
||||||
|
# Converting
|
||||||
|
fullSourceFile = os.path.join(SOURCE_FOLDER, sourceFile)
|
||||||
|
if sourceFile == outputFile:
|
||||||
|
log.debug('{} → {}'.format(fullSourceFile, fullOutputFile))
|
||||||
|
if os.path.isfile(fullOutputFile):
|
||||||
|
os.remove(fullOutputFile)
|
||||||
|
os.link(fullSourceFile, fullOutputFile)
|
||||||
|
else:
|
||||||
|
conversions.add((fullSourceFile, fullOutputFile))
|
||||||
|
|
||||||
|
log.info("Removing extra files")
|
||||||
|
for extraFile in extraFiles:
|
||||||
|
fullExtraFile = os.path.join(OUTPUT_FOLDER, extraFile)
|
||||||
|
log.debug('× {}'.format(fullExtraFile))
|
||||||
|
os.remove(fullExtraFile)
|
||||||
|
|
||||||
|
log.info("Listing files that will be converted")
|
||||||
|
for fullSourceFile, fullOutputFile in conversions:
|
||||||
|
log.debug('{} ⇒ {}'.format(fullSourceFile, fullOutputFile))
|
||||||
|
|
||||||
|
log.info("Converting files")
|
||||||
|
for fullSourceFile, fullOutputFile in progressbar.progressbar(conversions):
|
||||||
|
cmd = ["ffmpeg", "-y", "-i", fullSourceFile, "-c:a", "libopus",
|
||||||
|
"-movflags", "+faststart", "-b:a", "128k", "-vbr", "on",
|
||||||
|
"-compression_level", "10", fullOutputFile]
|
||||||
|
subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
|
|
||||||
|
# Removing empty dirs
|
||||||
|
for root, dirs, files in os.walk(OUTPUT_FOLDER):
|
||||||
|
if not dirs and not files:
|
||||||
|
dirBasename = os.path.basename(root)
|
||||||
|
if dirBasename not in IGNORED_EMPTY_FOLDER:
|
||||||
|
os.rmdir(root)
|
3
scripts/updatedate
Executable file
3
scripts/updatedate
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
echo ssh "$1" sudo date --set="'$(date -R)'"
|
20
scripts/vidcmp
Executable file
20
scripts/vidcmp
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Compresses video using FFMPEG using
|
||||||
|
# FFMPEG's reasonable default settings
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
files = sys.argv[1:]
|
||||||
|
|
||||||
|
remove = False
|
||||||
|
if '-r' in files:
|
||||||
|
files.remove('-r')
|
||||||
|
remove = True
|
||||||
|
|
||||||
|
for f in files:
|
||||||
|
print(os.path.splitext(f))
|
||||||
|
|
||||||
|
|
BIN
terminfo/a/alacritty
Normal file
BIN
terminfo/a/alacritty
Normal file
Binary file not shown.
BIN
terminfo/a/alacritty-256color
Normal file
BIN
terminfo/a/alacritty-256color
Normal file
Binary file not shown.
BIN
terminfo/r/rxvt-unicode
Normal file
BIN
terminfo/r/rxvt-unicode
Normal file
Binary file not shown.
BIN
terminfo/r/rxvt-unicode-256color
Normal file
BIN
terminfo/r/rxvt-unicode-256color
Normal file
Binary file not shown.
6
termux/scripts/tsu
Executable file
6
termux/scripts/tsu
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/data/data/com.termux/files/usr/bin/env bash
|
||||||
|
|
||||||
|
# Force the passing of the environment variables on LineageOS where the --preserve-environment
|
||||||
|
# option on the su binary doesn't seem to work well
|
||||||
|
|
||||||
|
/data/data/com.termux/files/usr/bin/tsu -s "$(env | sed "s/^\([^=]\+\)=\(.*\)/\1='\2'/" | tr '\n' ' ') $(which bash)"
|
|
@ -8,7 +8,7 @@ LOGFILE="$HOME/.local/log/syncthing.log"
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
printf "Starting Syncthing: "
|
printf "Starting Syncthing: "
|
||||||
sudo start-stop-daemon -p "$PIDFILE" -x syncthing -S -b -N 5 -m -- -logfile="$LOGFILE"
|
sudo start-stop-daemon -p "$PIDFILE" -x syncthing -S -b -N 5 -m -- -logfile="$LOGFILE" -home ~/.config/syncthing
|
||||||
echo "OK"
|
echo "OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
vimpcrc
1
vimpcrc
|
@ -5,3 +5,4 @@ map ° D:browse<C-M>A:shuffle<C-M>:play<C-M>:playlist<C-M>
|
||||||
set songformat {%a - %b: %t}|{%f}$E$R $H[$H%l$H]$H
|
set songformat {%a - %b: %t}|{%f}$E$R $H[$H%l$H]$H
|
||||||
set libraryformat %n \| {%t}|{%f}$E$R $H[$H%l$H]$H
|
set libraryformat %n \| {%t}|{%f}$E$R $H[$H%l$H]$H
|
||||||
set ignorecase
|
set ignorecase
|
||||||
|
set sort library
|
||||||
|
|
195
vimrc
195
vimrc
|
@ -5,56 +5,69 @@ set nocompatible
|
||||||
filetype off
|
filetype off
|
||||||
|
|
||||||
""" PLUGINS MANAGEMENT """
|
""" PLUGINS MANAGEMENT """
|
||||||
" Voir :h vundle
|
|
||||||
|
|
||||||
set rtp+=~/.vim/bundle/Vundle.vim
|
" NOTE 18-06-24 Got rid of Vundle in favor of vim-plug (why: more recent, supports
|
||||||
call vundle#begin()
|
" Neovim, simpler). Commented out plugins that seemed useless, feel free to
|
||||||
Plugin 'gmarik/Vundle.vim'
|
" uncomment them again if you need to
|
||||||
|
|
||||||
Plugin 'L9'
|
" Auto-install vim-plug
|
||||||
Plugin 'rstacruz/sparkup', {'rtp': 'vim/'}
|
if empty(glob('~/.vim/autoload/plug.vim'))
|
||||||
Plugin 'tomasr/molokai'
|
silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs
|
||||||
"Bundle 'Shougo/neosnippet'
|
\ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
|
||||||
"Bundle 'Shougo/neosnippet-snippets'
|
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
|
||||||
Plugin 'tpope/vim-surround'
|
endif
|
||||||
Plugin 'tpope/vim-fugitive'
|
|
||||||
Plugin 'tpope/vim-repeat'
|
|
||||||
Plugin 'tpope/tpope-vim-abolish'
|
|
||||||
Plugin 'vim-airline/vim-airline'
|
|
||||||
Plugin 'vim-airline/vim-airline-themes'
|
|
||||||
Plugin 'airblade/vim-gitgutter'
|
|
||||||
Plugin 'ctrlpvim/ctrlp.vim'
|
|
||||||
Plugin 'mbbill/undotree'
|
|
||||||
Plugin 'xolox/vim-misc'
|
|
||||||
Plugin 'xolox/vim-easytags'
|
|
||||||
Plugin 'majutsushi/tagbar'
|
|
||||||
Plugin 'wellle/targets.vim'
|
|
||||||
Plugin 'Chiel92/vim-autoformat'
|
|
||||||
" Plugin 'Valloric/YouCompleteMe'
|
|
||||||
Plugin 'artur-shaik/vim-javacomplete2'
|
|
||||||
Plugin 'tomtom/tcomment_vim'
|
|
||||||
Plugin 'Shougo/denite.nvim'
|
|
||||||
Plugin 'tomlion/vim-solidity'
|
|
||||||
Plugin 'godlygeek/tabular'
|
|
||||||
|
|
||||||
call vundle#end() " required
|
" Plugin definition
|
||||||
filetype plugin indent on " required
|
call plug#begin()
|
||||||
|
|
||||||
|
" Plug 'L9'
|
||||||
|
" Plug 'rstacruz/sparkup', {'rtp': 'vim/'}
|
||||||
|
Plug 'chriskempson/base16-vim'
|
||||||
|
Plug 'tpope/vim-surround'
|
||||||
|
" Plug 'tpope/vim-fugitive'
|
||||||
|
" Plug 'tpope/vim-repeat'
|
||||||
|
Plug 'tpope/tpope-vim-abolish'
|
||||||
|
Plug 'vim-airline/vim-airline'
|
||||||
|
Plug 'vim-airline/vim-airline-themes'
|
||||||
|
Plug 'airblade/vim-gitgutter'
|
||||||
|
Plug 'mbbill/undotree'
|
||||||
|
Plug 'xolox/vim-misc' " Required for 'xolox/vim-easytags'
|
||||||
|
Plug 'xolox/vim-easytags'
|
||||||
|
Plug 'majutsushi/tagbar'
|
||||||
|
Plug 'wellle/targets.vim'
|
||||||
|
Plug 'Chiel92/vim-autoformat'
|
||||||
|
Plug 'tomtom/tcomment_vim'
|
||||||
|
" Plug 'Shougo/denite.nvim'
|
||||||
|
" Plug 'tomlion/vim-solidity'
|
||||||
|
" Plug 'godlygeek/tabular'
|
||||||
|
" Plug 'jrozner/vim-antlr'
|
||||||
|
"
|
||||||
|
" Plug 'maralla/completor.vim'
|
||||||
|
if has('nvim')
|
||||||
|
Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' }
|
||||||
|
else
|
||||||
|
Plug 'Shougo/deoplete.nvim'
|
||||||
|
Plug 'roxma/nvim-yarp'
|
||||||
|
Plug 'roxma/vim-hug-neovim-rpc'
|
||||||
|
endif
|
||||||
|
Plug 'zchee/deoplete-jedi'
|
||||||
|
|
||||||
|
Plug 'python-mode/python-mode', { 'branch': 'develop' }
|
||||||
|
Plug 'junegunn/fzf', {'do': './install --bin'}
|
||||||
|
Plug 'junegunn/fzf.vim'
|
||||||
|
Plug 'ervandew/supertab'
|
||||||
|
Plug 'dpelle/vim-LanguageTool'
|
||||||
|
Plug 'terryma/vim-smooth-scroll'
|
||||||
|
|
||||||
|
call plug#end()
|
||||||
|
|
||||||
|
""" COMPLETOR """
|
||||||
|
|
||||||
|
let g:deoplete#enable_at_startup = 1
|
||||||
|
|
||||||
""" UNDOTREE """
|
""" UNDOTREE """
|
||||||
|
|
||||||
nmap <F7> :UndotreeToggle<CR>:UndotreeFocus<CR>
|
nmap <F7> :UndotreeToggle<CR>
|
||||||
|
|
||||||
""" CTRLP """
|
|
||||||
|
|
||||||
let g:ctrlp_custom_ignore = {
|
|
||||||
\ 'dir': '\v([\/]\.(git|hg|svn)|log|node_modules|bower_components|__pycache__|vendor|output|buildroot|doc)$',
|
|
||||||
\ 'file': '\v\.(exe|so|dll|o|pyc)$',
|
|
||||||
\ 'link': 'SOME_BAD_SYMBOLIC_LINKS',
|
|
||||||
\ }
|
|
||||||
|
|
||||||
let g:ctrlp_map = '<c-p>'
|
|
||||||
let g:ctrlp_cmd = 'CtrlPMixed'
|
|
||||||
map <a-p> :CtrlPMRUFiles<CR>
|
|
||||||
|
|
||||||
""" TAGBAR """
|
""" TAGBAR """
|
||||||
|
|
||||||
|
@ -71,27 +84,65 @@ let g:airline#extensions#tabline#enabled = 1
|
||||||
let g:airline_section_a = airline#section#create(['mode'])
|
let g:airline_section_a = airline#section#create(['mode'])
|
||||||
let g:airline_section_b = airline#section#create(['branch', 'hunks'])
|
let g:airline_section_b = airline#section#create(['branch', 'hunks'])
|
||||||
let g:airline_section_z = airline#section#create(['%B', '@', '%l', ':', '%c'])
|
let g:airline_section_z = airline#section#create(['%B', '@', '%l', ':', '%c'])
|
||||||
let g:airline_theme = 'wombat'
|
let g:airline_theme = 'base16_monokai'
|
||||||
|
|
||||||
""" YOUCOMPLETEME """
|
|
||||||
|
|
||||||
" let g:ycm_global_ycm_extra_conf = '~/.config/ycm_extra_conf.py'
|
|
||||||
let g:ycm_global_ycm_extra_conf = '/usr/share/vim/vimfiles/third_party/ycmd/cpp/ycm/.ycm_extra_conf.py'
|
|
||||||
let g:ycm_server_python_interpreter = '/usr/bin/python2'
|
|
||||||
|
|
||||||
nmap gTi :YcmCompleter GoToInclude<CR>
|
|
||||||
nmap gTc :YcmCompleter GoToDeclaration<CR>
|
|
||||||
nmap gTf :YcmCompleter GoToDefinition<CR>
|
|
||||||
nmap gt :YcmCompleter GoTo<CR>
|
|
||||||
nmap gT :YcmCompleter GoToImprecise<CR>
|
|
||||||
nmap gTr :YcmCompleter GoToReference<CR>
|
|
||||||
|
|
||||||
""" AUTOFORMAT """
|
""" AUTOFORMAT """
|
||||||
nmap <F3> :Autoformat<CR>
|
nmap <F3> :Autoformat<CR>
|
||||||
|
|
||||||
""" JAVACOMPLETE """
|
""" PYMODE """
|
||||||
|
|
||||||
|
let g:pymode_virtualenv = 1
|
||||||
|
let g:pymode_lint_ignore = ["W0401"]
|
||||||
|
let g:pymode_lint_cwindow = 0
|
||||||
|
|
||||||
|
" TODO Even with magic pymod_motion complains about the option `magic&` being not set :/
|
||||||
|
let g:pymode_motion = 0
|
||||||
|
set magic
|
||||||
|
|
||||||
|
""" FZF """
|
||||||
|
|
||||||
|
let g:fzf_layout = { 'down': '~100%' }
|
||||||
|
let g:fzf_colors =
|
||||||
|
\ { 'fg': ['fg', 'Normal'],
|
||||||
|
\ 'bg': ['bg', 'Normal'],
|
||||||
|
\ 'hl': ['fg', 'Comment'],
|
||||||
|
\ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
|
||||||
|
\ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],
|
||||||
|
\ 'hl+': ['fg', 'Statement'],
|
||||||
|
\ 'info': ['fg', 'PreProc'],
|
||||||
|
\ 'border': ['fg', 'Ignore'],
|
||||||
|
\ 'prompt': ['fg', 'Conditional'],
|
||||||
|
\ 'pointer': ['fg', 'Exception'],
|
||||||
|
\ 'marker': ['fg', 'Keyword'],
|
||||||
|
\ 'spinner': ['fg', 'Label'],
|
||||||
|
\ 'header': ['fg', 'Comment'] }
|
||||||
|
|
||||||
|
nmap gF :Files<CR>
|
||||||
|
nmap gf :GFiles<CR>
|
||||||
|
nmap gb :Buffers<CR>
|
||||||
|
nmap gL :Lines<CR>
|
||||||
|
nmap gl :BLines<CR>
|
||||||
|
nmap gT :Tags<CR>
|
||||||
|
nmap gt :BTags<CR>
|
||||||
|
nmap gm :Marks<CR>
|
||||||
|
nmap gw :Windows<CR>
|
||||||
|
nmap gh :History<CR>
|
||||||
|
nmap gH :History:<CR>
|
||||||
|
nmap gS :History/<CR>
|
||||||
|
nmap gs :Snippets<CR>
|
||||||
|
|
||||||
|
" TODO `gd` → go to tag matching selected word, or show a list with that
|
||||||
|
" of tags pre-filtered with that word
|
||||||
|
|
||||||
|
""" SUPERTAB """
|
||||||
|
|
||||||
|
let g:SuperTabDefaultCompletionType = "<c-n>" " Go down when completing
|
||||||
|
let g:SuperTabContextDefaultCompletionType = "<c-n>"
|
||||||
|
|
||||||
|
""" LanguageTool """
|
||||||
|
|
||||||
|
let g:languagetool_jar = "/usr/share/java/languagetool/languagetool-commandline.jar"
|
||||||
|
|
||||||
autocmd FileType java setlocal omnifunc=javacomplete#Complete
|
|
||||||
|
|
||||||
""" VIM SETTINGS """
|
""" VIM SETTINGS """
|
||||||
|
|
||||||
|
@ -125,11 +176,9 @@ set updatetime=250
|
||||||
|
|
||||||
set cursorcolumn
|
set cursorcolumn
|
||||||
|
|
||||||
syntax enable
|
set splitbelow
|
||||||
|
|
||||||
set background=dark
|
syntax enable
|
||||||
colorscheme molokai
|
|
||||||
let g:molokai_original = 1
|
|
||||||
|
|
||||||
" From http://stackoverflow.com/a/5004785/2766106
|
" From http://stackoverflow.com/a/5004785/2766106
|
||||||
set list
|
set list
|
||||||
|
@ -140,10 +189,16 @@ filetype on
|
||||||
filetype plugin on
|
filetype plugin on
|
||||||
filetype indent on
|
filetype indent on
|
||||||
|
|
||||||
|
set wildmode=longest,list
|
||||||
|
set showcmd
|
||||||
|
|
||||||
" Put plugins and dictionaries in this dir (also on Windows)
|
" Put plugins and dictionaries in this dir (also on Windows)
|
||||||
let vimDir = '$HOME/.vim'
|
let vimDir = '$HOME/.vim'
|
||||||
let &runtimepath.=','.vimDir
|
let &runtimepath.=','.vimDir
|
||||||
|
|
||||||
|
" theme
|
||||||
|
source $HOME/.vim/colorscheme.vim
|
||||||
|
|
||||||
" Keep undo history across sessions by storing it in a file
|
" Keep undo history across sessions by storing it in a file
|
||||||
if has('persistent_undo')
|
if has('persistent_undo')
|
||||||
let myUndoDir = expand(vimDir . '/undodir')
|
let myUndoDir = expand(vimDir . '/undodir')
|
||||||
|
@ -159,11 +214,19 @@ endif
|
||||||
cmap w!! w !sudo tee > /dev/null %
|
cmap w!! w !sudo tee > /dev/null %
|
||||||
|
|
||||||
imap jk <Esc>
|
imap jk <Esc>
|
||||||
imap mù <Esc>
|
vmap <Enter> <Esc>
|
||||||
map <Enter> o<Esc>
|
|
||||||
|
nmap <Enter> o<Esc>
|
||||||
nmap <C-H> :bp<CR>
|
nmap <C-H> :bp<CR>
|
||||||
nmap <C-L> :bn<CR>
|
nmap <C-L> :bn<CR>
|
||||||
|
if has('nvim')
|
||||||
|
" nmap <C-K> 20k
|
||||||
|
" nmap <C-J> 20j
|
||||||
|
noremap <silent> <C-K> :call smooth_scroll#up(20, 5, 1)<CR>
|
||||||
|
noremap <silent> <C-J> :call smooth_scroll#down(20, 5, 1)<CR>
|
||||||
|
else
|
||||||
nmap <C-K> kkkkkkkkkkkkkkkkkkkkk
|
nmap <C-K> kkkkkkkkkkkkkkkkkkkkk
|
||||||
nmap <C-J> jjjjjjjjjjjjjjjjjjjjj
|
nmap <C-J> jjjjjjjjjjjjjjjjjjjjj
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue