nix: Make nix the root
Which means now I'll have to think about real prefixes in commit names.
This commit is contained in:
parent
550eed06e0
commit
ee178b7d57
190 changed files with 5 additions and 6 deletions
50
unprocessed/Zeal/Zeal.conf
Normal file
50
unprocessed/Zeal/Zeal.conf
Normal file
|
@ -0,0 +1,50 @@
|
|||
[General]
|
||||
check_for_update=true
|
||||
hide_on_close=false
|
||||
minimize_to_systray=false
|
||||
show_systray_icon=true
|
||||
start_minimized=false
|
||||
|
||||
[content]
|
||||
custom_css_file=
|
||||
dark_mode=false
|
||||
default_fixed_font_size=13
|
||||
default_font_family=serif
|
||||
default_font_size=16
|
||||
disable_ad=false
|
||||
external_link_policy=@Variant(\0\0\0\x7f\0\0\0)Zeal::Core::Settings::ExternalLinkPolicy\0\0\0\0\0)
|
||||
fixed_font_family=DejaVu Sans Mono
|
||||
highlight_on_navigate=true
|
||||
minimum_font_size=0
|
||||
sans_serif_font_family=DejaVu Sans
|
||||
serif_font_family=DejaVu Serif
|
||||
smooth_scrolling=false
|
||||
|
||||
[docsets]
|
||||
path=/home/geoffrey/.cache/dash_docsets
|
||||
|
||||
[global_shortcuts]
|
||||
show=
|
||||
|
||||
[internal]
|
||||
install_id=a2353684-8909-4ac3-8ad5-b8d8a7e9292a
|
||||
version=0.6.1
|
||||
|
||||
[proxy]
|
||||
authenticate=false
|
||||
host=
|
||||
password=
|
||||
port=0
|
||||
type=1
|
||||
username=
|
||||
|
||||
[search]
|
||||
fuzzy_search_enabled=false
|
||||
|
||||
[state]
|
||||
splitter_geometry=@ByteArray(\0\0\0\xff\0\0\0\x1\0\0\0\x2\0\0\x1\0\0\0\x4\xb0\0\xff\xff\xff\xff\x1\0\0\0\x1\0)
|
||||
toc_splitter_state=@ByteArray()
|
||||
window_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\a\x80\0\0\0\x12\0\0\f\x7f\0\0\x3\xeb\0\0\a\x80\0\0\0\x12\0\0\f\x7f\0\0\x3\xeb\0\0\0\0\0\0\0\0\x5\0\0\0\a\x80\0\0\0\x12\0\0\f\x7f\0\0\x3\xeb)
|
||||
|
||||
[tabs]
|
||||
open_new_tab_after_active=false
|
1
unprocessed/config/automatrop/.gitignore
vendored
Normal file
1
unprocessed/config/automatrop/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
self_name
|
10
unprocessed/config/automatrop/README.md
Normal file
10
unprocessed/config/automatrop/README.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Automatrop
|
||||
|
||||
Because I'm getting tired of too many bash scripts and yet using Ansible seems
|
||||
overkill at the same time.
|
||||
|
||||
## Dependencies
|
||||
|
||||
```bash
|
||||
ansible-galaxy install mnussbaum.base16-builder-ansible
|
||||
```
|
9
unprocessed/config/automatrop/ansible.cfg
Normal file
9
unprocessed/config/automatrop/ansible.cfg
Normal file
|
@ -0,0 +1,9 @@
|
|||
[defaults]
|
||||
inventory=hosts
|
||||
roles_path=roles
|
||||
interpreter_python=auto
|
||||
library=plugins/modules
|
||||
|
||||
[ssh_connection]
|
||||
pipelining = True # does not work with requiretty in /etc/sudoers
|
||||
ssh_args=-o ForwardAgent=yes # no need for installing/configuring/unlocking SSH/GPG keys on the host to be able to git clone extensions
|
34
unprocessed/config/automatrop/group_vars/all
Normal file
34
unprocessed/config/automatrop/group_vars/all
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Default values
|
||||
|
||||
# If you have root access on the machine (via sudo)
|
||||
root_access: no
|
||||
|
||||
# Display server (no, "x11", "wayland")
|
||||
display_server: no
|
||||
|
||||
# What development work will I do on this machine
|
||||
dev_stuffs: []
|
||||
|
||||
# Install software that is rarely used
|
||||
software_full: no
|
||||
|
||||
# Which additional software to install
|
||||
software_snippets: []
|
||||
|
||||
# If the computer has a battery and we want to use it
|
||||
has_battery: no
|
||||
|
||||
# Activate numlock by default
|
||||
auto_numlock: no
|
||||
|
||||
# Machine has SSH key to access git.frogeye.fr
|
||||
has_forge_access: no
|
||||
|
||||
# Wether to permit /home/$USER to be encrypted
|
||||
# with stacked filesystem encryption
|
||||
encrypt_home_stacked_fs: no
|
||||
|
||||
# Which extensions to load
|
||||
extensions: []
|
||||
|
||||
# TODO Make role/playbook defaults instead
|
|
@ -0,0 +1,30 @@
|
|||
root_access: yes
|
||||
display_server: "x11"
|
||||
dev_stuffs:
|
||||
- ansible
|
||||
- docker
|
||||
- network
|
||||
- nix
|
||||
- perl
|
||||
- php
|
||||
- python
|
||||
- shell
|
||||
- sql
|
||||
software_full: yes
|
||||
has_battery: yes
|
||||
auto_numlock: yes
|
||||
has_forge_access: yes
|
||||
extensions:
|
||||
- g
|
||||
- gh
|
||||
x11_screens:
|
||||
# nvidia-xrun
|
||||
# - HDMI-0
|
||||
# - eDP-1-1
|
||||
# mesa + nouveau
|
||||
# - HDMI-1-3
|
||||
# - eDP1
|
||||
# mesa + nvidia
|
||||
- HDMI-1-0
|
||||
- eDP1
|
||||
max_video_height: 1440
|
|
@ -0,0 +1,14 @@
|
|||
root_access: no
|
||||
display_server: "x11"
|
||||
dev_stuffs:
|
||||
- shell
|
||||
- network
|
||||
- ansible
|
||||
- perl
|
||||
- python
|
||||
extensions:
|
||||
- gh
|
||||
x11_screens:
|
||||
- HDMI-1
|
||||
- HDMI-2
|
||||
base16_scheme: solarized-light
|
|
@ -0,0 +1,16 @@
|
|||
root_access: yes
|
||||
display_server: "x11"
|
||||
dev_stuffs:
|
||||
- shell
|
||||
- network
|
||||
- ansible
|
||||
- python
|
||||
has_battery: yes
|
||||
encrypt_home_stacked_fs: yes
|
||||
extensions:
|
||||
- g
|
||||
- gh
|
||||
x11_screens:
|
||||
- DP-1
|
||||
- eDP-1
|
||||
max_video_height: 720
|
4
unprocessed/config/automatrop/hosts
Normal file
4
unprocessed/config/automatrop/hosts
Normal file
|
@ -0,0 +1,4 @@
|
|||
curacao.geoffrey.frogeye.fr
|
||||
# triffle.geoffrey.frogeye.fr
|
||||
pindakaas.geoffrey.frogeye.fr
|
||||
gho.geoffrey.frogeye.fr ansible_host=localhost ansible_port=2222
|
15
unprocessed/config/automatrop/playbooks/default.yml
Normal file
15
unprocessed/config/automatrop/playbooks/default.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Default
|
||||
hosts: all
|
||||
roles:
|
||||
- role: system
|
||||
tags: system
|
||||
when: root_access
|
||||
- role: dotfiles
|
||||
tags: dotfiles
|
||||
- role: termux
|
||||
tags: termux
|
||||
when: termux
|
||||
- role: extensions
|
||||
tags: extensions
|
||||
# TODO Dependencies
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
- name: Install dotfiles
|
||||
ansible.builtin.command: "{{ ansible_user_dir }}/.dotfiles/config/scripts/dotfiles install"
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
- name: Install dotfiles repository
|
||||
ansible.builtin.git:
|
||||
repo: "{% if has_forge_access %}git@git.frogeye.fr:{% else %}https://git.frogeye.fr/{% endif %}geoffrey/dotfiles.git"
|
||||
dest: "{{ ansible_user_dir }}/.dotfiles"
|
||||
update: true
|
||||
notify: install dotfiles
|
||||
tags: dotfiles_repo
|
||||
# TODO Put actual dotfiles in a subdirectory of the repo, so we don't have to put everything in config
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
- name: Load extensions
|
||||
ansible.builtin.include_role:
|
||||
name: geoffreyfrogeye.{{ extension }}automatrop.entry
|
||||
loop: "{{ extensions }}"
|
||||
loop_control:
|
||||
loop_var: extension
|
||||
tags: always
|
||||
|
||||
- name: Configure extensions rc sourcing
|
||||
ansible.builtin.template:
|
||||
src: extrc.sh.j2
|
||||
dest: "{{ ansible_user_dir }}/.config/shell/extrc"
|
||||
mode: u=rw,g=r,o=r
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
{% for extension in extensions %}
|
||||
trysource ~/.config/{{ extension }}scripts/{{ extension }}profile
|
||||
{% endfor %}
|
||||
{# TODO Rename profile as rc, and add env #}
|
||||
{# TODO Put in non-linked path #}
|
|
@ -0,0 +1,2 @@
|
|||
[Service]
|
||||
ExecStartPre=/bin/sh -c 'setleds +num < /dev/%I'
|
|
@ -0,0 +1,5 @@
|
|||
Section "Device"
|
||||
Identifier "Intel Graphics"
|
||||
Driver "intel"
|
||||
Option "Backlight" "intel_backlight"
|
||||
EndSection
|
|
@ -0,0 +1,15 @@
|
|||
Section "InputClass"
|
||||
Identifier "joystick catchall"
|
||||
MatchIsJoystick "on"
|
||||
MatchDevicePath "/dev/input/event*"
|
||||
Driver "joystick"
|
||||
Option "StartKeysEnabled" "False" #Disable mouse
|
||||
Option "StartMouseEnabled" "False" #support
|
||||
EndSection
|
||||
# Same thing for DualShock 4 touchpad
|
||||
Section "InputClass"
|
||||
Identifier "ds4-touchpad"
|
||||
Driver "libinput"
|
||||
MatchProduct "Wireless Controller Touchpad"
|
||||
Option "Ignore" "True"
|
||||
EndSection
|
|
@ -0,0 +1,10 @@
|
|||
- name: Reload systemd daemon
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
listen: systemd changed
|
||||
become: true
|
||||
|
||||
- name: Warn about changed Panfrost config
|
||||
ansible.builtin.debug:
|
||||
msg: The Panfrost display driver configuration was changed, but needs a reboot to be applied.
|
||||
listen: panfrost config changed
|
70
unprocessed/config/automatrop/roles/system/tasks/main.yml
Normal file
70
unprocessed/config/automatrop/roles/system/tasks/main.yml
Normal file
|
@ -0,0 +1,70 @@
|
|||
# Xorg configuration
|
||||
|
||||
- name: Check if there is Intel backlight
|
||||
ansible.builtin.stat:
|
||||
path: /sys/class/backlight/intel_backlight
|
||||
register: intel_backlight
|
||||
when: display_server == 'x11'
|
||||
|
||||
- name: Install Intel video drivers (Arch based)
|
||||
community.general.pacman:
|
||||
name: xf86-video-intel
|
||||
# state: "{{ intel_backlight.stat.exists }}"
|
||||
state: present
|
||||
become: true
|
||||
when: display_server == 'x11' and intel_backlight.stat.exists and arch_based
|
||||
# TODO With software role? Would permit other distributions
|
||||
|
||||
- name: Configure Xorg Intel backlight
|
||||
ansible.builtin.copy:
|
||||
src: xorg/intel_backlight.conf
|
||||
dest: "{{ item }}/20-intel_backlight.conf"
|
||||
become: true
|
||||
when: display_server == 'x11' and intel_backlight.stat.exists
|
||||
loop: "{{ xorg_common_config_dirs }}"
|
||||
|
||||
- name: Configure Xorg joystick behaviour
|
||||
ansible.builtin.copy:
|
||||
src: xorg/joystick.conf
|
||||
dest: "{{ item }}/50-joystick.conf"
|
||||
become: true
|
||||
when: display_server == 'x11'
|
||||
loop: "{{ xorg_common_config_dirs }}"
|
||||
|
||||
- name: List modules we're using
|
||||
ansible.builtin.slurp:
|
||||
src: /proc/modules
|
||||
register: modules
|
||||
when: display_server
|
||||
# Not sure the module will be loaded in early setup stages though
|
||||
|
||||
- name: Make panfrost use OpenGL 3.3
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/environment
|
||||
line: PAN_MESA_DEBUG="gl3"
|
||||
regexp: ^#? ?PAN_MESA_DEBUG=
|
||||
become: true
|
||||
when: display_server and using_panfrost
|
||||
vars:
|
||||
using_panfrost: "{{ 'panfrost' in (modules.content | b64decode) }}"
|
||||
notify: panfrost config changed
|
||||
|
||||
# Numlock on boot
|
||||
|
||||
- name: Set numlock on boot
|
||||
ansible.builtin.copy:
|
||||
src: getty.service
|
||||
dest: /etc/systemd/system/getty@.service.d/override.conf
|
||||
become: true
|
||||
notify:
|
||||
- systemd changed
|
||||
when: auto_numlock
|
||||
|
||||
- name: Unset numlock on boot
|
||||
ansible.builtin.file:
|
||||
path: /etc/systemd/system/getty@.service.d/override.conf
|
||||
state: absent
|
||||
become: true
|
||||
notify:
|
||||
- systemd changed
|
||||
when: not auto_numlock
|
29
unprocessed/config/automatrop/roles/termux/tasks/main.yml
Normal file
29
unprocessed/config/automatrop/roles/termux/tasks/main.yml
Normal file
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
- name: Create Termux directory
|
||||
ansible.builtin.file:
|
||||
state: directory
|
||||
path: "{{ ansible_user_dir }}/.termux"
|
||||
mode: u=rwx,g=rx,o=rx
|
||||
# TODO This is a dotfiles directory.
|
||||
# Make it not install unless it's Termux
|
||||
|
||||
- name: Silence Termux login message
|
||||
ansible.builtin.file:
|
||||
state: file
|
||||
path: "{{ ansible_user_dir }}/.hushlogin"
|
||||
mode: u=rw,g=r,o=r
|
||||
|
||||
# https://github.com/kdrag0n/base16-termux/blob/master/templates/default.mustache
|
||||
- name: Download base16 theme for Termux
|
||||
ansible.builtin.copy:
|
||||
content: "{{ base16_schemes['schemes'][base16_scheme]['termux']['colors']['base16-' + base16_scheme + '.properties'] }}"
|
||||
dest: "{{ ansible_env.HOME }}/.termux/colors.properties"
|
||||
mode: u=rw,g=r,o=r
|
||||
tags:
|
||||
- color
|
||||
|
||||
# TODO
|
||||
# Upgrade
|
||||
# If root:
|
||||
# $ apt install tsu
|
||||
# $ echo '/system/bin/mount -o remount,rw /; ln -s /data/data/com.termux/files/usr /usr; /system/bin/mount -o remount,ro /' | tsu
|
|
@ -0,0 +1,44 @@
|
|||
[general]
|
||||
status_path = "~/.cache/vdirsyncer/status/"
|
||||
|
||||
{% for config in configs %}
|
||||
|
||||
# CarDAV
|
||||
|
||||
[pair geoffrey_contacts]
|
||||
a = "geoffrey_contacts_local"
|
||||
b = "geoffrey_contacts_remote"
|
||||
collections = ["from a", "from b"]
|
||||
metadata = ["displayname"]
|
||||
|
||||
[storage geoffrey_contacts_local]
|
||||
type = "filesystem"
|
||||
path = "~/.cache/vdirsyncer/contacts/"
|
||||
fileext = ".vcf"
|
||||
|
||||
[storage geoffrey_contacts_remote]
|
||||
type = "carddav"
|
||||
url = "https://cloud.frogeye.fr/remote.php/dav"
|
||||
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"]
|
||||
metadata = ["displayname", "color"]
|
||||
|
||||
[storage geoffrey_calendar_local]
|
||||
type = "filesystem"
|
||||
path = "~/.cache/vdirsyncer/calendars/"
|
||||
fileext = ".ics"
|
||||
|
||||
[storage geoffrey_calendar_remote]
|
||||
type = "caldav"
|
||||
url = "https://cloud.frogeye.fr/remote.php/dav"
|
||||
username = "geoffrey"
|
||||
password.fetch = ["command", "sh", "-c", "cat ~/.config/vdirsyncer/pass"]
|
||||
|
||||
{% endfor %}
|
0
unprocessed/config/autorandr/.dfrecur
Normal file
0
unprocessed/config/autorandr/.dfrecur
Normal file
4
unprocessed/config/autorandr/bg
Normal file
4
unprocessed/config/autorandr/bg
Normal file
|
@ -0,0 +1,4 @@
|
|||
# https://i.imgur.com/yVtVucs.jpg # Doctor Who Series 11
|
||||
# Derivate of these ones https://wallpapers.wallhaven.cc/wallpapers/full/wallhaven-230622.png
|
||||
# https://geoffrey.frogeye.fr/files/backgrounds/VertBleu.png
|
||||
https://geoffrey.frogeye.fr/files/backgrounds/BleuVert.png
|
32
unprocessed/config/autorandr/postswitch
Executable file
32
unprocessed/config/autorandr/postswitch
Executable file
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
# From https://stackoverflow.com/a/246128
|
||||
|
||||
# Relaunch the bars
|
||||
# i3-msg exec ~/.config/polybar/launch.sh
|
||||
# TODO Make something better with that
|
||||
i3-msg exec ~/.config/lemonbar/launch.sh
|
||||
|
||||
# Resize background
|
||||
BGDIR="$HOME/.cache/background"
|
||||
mkdir -p "$BGDIR"
|
||||
|
||||
list="$DIR/bg"
|
||||
url="$(cat "$list" | sed -e 's/#.*$//' -e 's/ \+$//' -e '/^$/d' | sort -R | head -1)"
|
||||
|
||||
hash="$(printf "$url" | md5sum | cut -f1 -d' ')"
|
||||
filepath="$BGDIR/$hash"
|
||||
|
||||
if [ ! -e "$filepath" ]; then
|
||||
wget -c "$url" -O "$filepath"
|
||||
fi
|
||||
|
||||
feh --no-fehbg --bg-fill "$filepath"
|
||||
|
||||
# Make i3 distribute the workspaces on all screens
|
||||
monitors_json="$(xrandr --listmonitors | tail -n+2 | awk '{ print $4 }' | sed 's|.\+|"\0"|' | tr '\n' ',')"
|
||||
automatrop -e '{"x11_screens":['"$monitors_json"']}' --tags i3
|
||||
|
||||
# TODO Make sure it goes from left to right
|
||||
# Either with the "main" display or using the geometry data
|
26
unprocessed/config/j4status/config
Normal file
26
unprocessed/config/j4status/config
Normal file
|
@ -0,0 +1,26 @@
|
|||
[Plugins]
|
||||
Output=i3bar
|
||||
Input=nm;pulseaudio;upower;time
|
||||
Order=nm;pulseaudio;upower;time
|
||||
|
||||
[Time]
|
||||
Zones=Europe/Paris;
|
||||
|
||||
[PulseAudio]
|
||||
#Actions=raise
|
||||
|
||||
[NetworkManager]
|
||||
Interfaces=enp3s0;wlp2s0
|
||||
HideUnavailable=true
|
||||
|
||||
[Override pulseaudio:auto_null]
|
||||
Label=🔊
|
||||
|
||||
[Override nm-wifi:wlp2s0]
|
||||
Label=📶
|
||||
|
||||
[Override time:Europe/Paris]
|
||||
Label=🕗
|
||||
|
||||
[Override upower-battery:BAT0]
|
||||
Label=🔋
|
34
unprocessed/config/khal/config
Normal file
34
unprocessed/config/khal/config
Normal file
|
@ -0,0 +1,34 @@
|
|||
[calendars]
|
||||
[[calendars]]
|
||||
path = ~/.cache/vdirsyncer/calendars/*
|
||||
type = discover
|
||||
|
||||
# [[birthdays]]
|
||||
# type=birthdays
|
||||
# path = ~/.cache/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
unprocessed/config/khard/khard.conf
Normal file
43
unprocessed/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 = ~/.cache/vdirsyncer/contacts/contacts/
|
||||
|
||||
[general]
|
||||
debug = no
|
||||
default_action = list
|
||||
editor = nvim
|
||||
merge_editor = nvim
|
||||
|
||||
[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
|
||||
|
24
unprocessed/config/linuxColors.sh
Normal file
24
unprocessed/config/linuxColors.sh
Normal file
|
@ -0,0 +1,24 @@
|
|||
#!/bin/sh
|
||||
if [ "$TERM" = "linux" ]; then
|
||||
/bin/echo -e "
|
||||
\e]P048483e
|
||||
\e]P1dc2566
|
||||
\e]P28fc029
|
||||
\e]P3d4c96e
|
||||
\e]P455bcce
|
||||
\e]P59358fe
|
||||
\e]P656b7a5
|
||||
\e]P7acada1
|
||||
\e]P876715e
|
||||
\e]P9fa2772
|
||||
\e]PAa7e22e
|
||||
\e]PBe7db75
|
||||
\e]PC66d9ee
|
||||
\e]PDae82ff
|
||||
\e]PE66efd5
|
||||
\e]PFcfd0c2
|
||||
"
|
||||
# get rid of artifacts
|
||||
# clear
|
||||
fi
|
||||
|
10
unprocessed/config/offlineimap.py
Normal file
10
unprocessed/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)
|
||||
|
5
unprocessed/config/optiSvgo.yml
Normal file
5
unprocessed/config/optiSvgo.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
plugins:
|
||||
- mergePaths : false
|
||||
- convertTransform : false
|
||||
- cleanupNumericValues : false
|
||||
|
11
unprocessed/config/polybar/bars.ini
Normal file
11
unprocessed/config/polybar/bars.ini
Normal file
|
@ -0,0 +1,11 @@
|
|||
[bar/base]
|
||||
monitor = ${env:display}
|
||||
bottom = true
|
||||
|
||||
[bar/primary]
|
||||
inherit = bar/base
|
||||
modules-right = date
|
||||
|
||||
[bar/secondary]
|
||||
inherit = bar/base
|
||||
modules-right = date
|
18
unprocessed/config/polybar/bbswitch
Executable file
18
unprocessed/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
|
390
unprocessed/config/polybar/config
Normal file
390
unprocessed/config/polybar/config
Normal file
|
@ -0,0 +1,390 @@
|
|||
;=====================================================
|
||||
;
|
||||
; To learn more about how to configure Polybar
|
||||
; go to https://github.com/jaagr/polybar
|
||||
;
|
||||
; The README contains alot of information
|
||||
;
|
||||
;=====================================================
|
||||
|
||||
[theme]
|
||||
foreground = #f1ebeb
|
||||
background = #272822
|
||||
blackB = #48483e
|
||||
blackF = #76715e
|
||||
redB = #dc2566
|
||||
redF = #fa2772
|
||||
greenB = #8fc029
|
||||
greenF = #a7e22e
|
||||
yellowB = #d4c96e
|
||||
yellowF = #e7db75
|
||||
blueB = #55bcce
|
||||
blueF = #66d9ee
|
||||
magentaB = #9358fe
|
||||
magentaF = #ae82ff
|
||||
cyanB = #56b7a5
|
||||
cyanF = #66efd5
|
||||
whiteB = #acada1
|
||||
whiteF = #cfd0c2
|
||||
|
||||
[colors]
|
||||
background = ${theme.blackB}
|
||||
foreground = ${theme.foreground}
|
||||
|
||||
[bar/base]
|
||||
monitor = ${env:display:LVDS1}
|
||||
width = 100%
|
||||
height = 20
|
||||
fixed-center = false
|
||||
|
||||
background = ${colors.background}
|
||||
foreground = ${colors.foreground}
|
||||
|
||||
line-size = 0
|
||||
|
||||
border-size = 0
|
||||
border-color = ${colors.background}
|
||||
|
||||
padding-left = 2
|
||||
padding-right = 2
|
||||
|
||||
module-margin-left = 1
|
||||
module-margin-right = 1
|
||||
|
||||
font-0 = "DejaVu Sans:size=10;0"
|
||||
font-1 = "DejaVuSansMono Nerd Font Mono:pixelsize=10;0"
|
||||
|
||||
modules-left = i3
|
||||
|
||||
;wm-restack = bspwm
|
||||
wm-restack = i3
|
||||
|
||||
;override-redirect = true
|
||||
|
||||
;scroll-up = bspwm-desknext
|
||||
;scroll-down = bspwm-deskprev
|
||||
|
||||
;scroll-up = i3wm-wsnext
|
||||
;scroll-down = i3wm-wsprev
|
||||
|
||||
bottom = true
|
||||
|
||||
enable-ipc = true
|
||||
|
||||
[bar/primary]
|
||||
inherit = bar/base
|
||||
|
||||
modules-center = mpd
|
||||
; modules-right = cpu memory temperature mail todo vpncheck eth wlan bbswitch xbacklight volume battery shortdate
|
||||
modules-right = cpu memory temperature mail vpncheck eth wlan bbswitch xbacklight volume battery shortdate
|
||||
|
||||
tray-position = right
|
||||
tray-padding = 2
|
||||
tray-transparent = false
|
||||
|
||||
[bar/secondary]
|
||||
inherit = bar/base
|
||||
modules-right = cpu memory temperature keystore vpncheck ethMore wlanMore filesystem linuxmismatch bbswitch xbacklight volume date
|
||||
|
||||
|
||||
[module/filesystem]
|
||||
type = internal/fs
|
||||
interval = 25
|
||||
|
||||
mount-0 = /
|
||||
mount-1 = /home
|
||||
|
||||
label-mounted-foreground = ${theme.magentaB}
|
||||
label-mounted = %{F#ae81ff}%mountpoint%%{F-} %free%
|
||||
label-unmounted =
|
||||
|
||||
[module/i3]
|
||||
type = internal/i3
|
||||
pin-workspaces = true
|
||||
strip-wsnumbers = false
|
||||
index-sort = true
|
||||
enable-click = true
|
||||
enable-scroll = true
|
||||
wrapping-scroll = false
|
||||
reverse-scroll = true
|
||||
fuzzy-match = false
|
||||
|
||||
ws-icon-0 = "1;"
|
||||
ws-icon-1 = "2;"
|
||||
ws-icon-2 = "3;"
|
||||
ws-icon-3 = "4;"
|
||||
ws-icon-4 = "5;▲"
|
||||
ws-icon-5 = "6;▲"
|
||||
ws-icon-6 = "7;"
|
||||
ws-icon-7 = "8;"
|
||||
ws-icon-8 = "9;"
|
||||
ws-icon-9 = "10;"
|
||||
ws-icon-default = ?
|
||||
|
||||
format = <label-state> <label-mode>
|
||||
|
||||
label-mode = %mode%
|
||||
label-mode-padding = 2
|
||||
label-mode-background = ${theme.redB}
|
||||
|
||||
label-focused = %index% %icon%
|
||||
label-focused-foreground = ${theme.background}
|
||||
label-focused-background = ${theme.greenB}
|
||||
label-focused-padding = 2
|
||||
|
||||
label-unfocused = ${self.label-focused}
|
||||
label-unfocused-padding = ${self.label-focused-padding}
|
||||
|
||||
label-visible = ${self.label-focused}
|
||||
label-visible-padding = ${self.label-focused-padding}
|
||||
label-visible-foreground = ${theme.greenF}
|
||||
|
||||
label-urgent = ${self.label-focused}
|
||||
label-urgent-padding = ${self.label-focused-padding}
|
||||
label-urgent-foreground = ${theme.foreground}
|
||||
label-urgent-background = ${theme.redB}
|
||||
|
||||
[module/mpd]
|
||||
type = internal/mpd
|
||||
; format-online = <icon-prev> <icon-seekb> <icon-stop> <toggle> <icon-seekf> <icon-next> <icon-repeat> <icon-random> <bar-progress> <label-time> <label-song>
|
||||
format-online = <icon-prev> <icon-seekb> <icon-stop> <toggle> <icon-seekf> <icon-next> <icon-repeat> <icon-random> <label-time> <label-song>
|
||||
format-playing = ${self.format-online}
|
||||
format-paused = ${self.format-online}
|
||||
format-stopped = <toggle>
|
||||
|
||||
label-song = %title% - %artist%
|
||||
label-song-maxlen = 35
|
||||
label-song-ellipsis = true
|
||||
|
||||
label-time = %elapsed%/%total%
|
||||
|
||||
label-offline =
|
||||
|
||||
icon-play =
|
||||
icon-pause =
|
||||
icon-stop =
|
||||
icon-prev =
|
||||
icon-next =
|
||||
icon-seekb =
|
||||
icon-seekf =
|
||||
icon-random =
|
||||
icon-repeat =
|
||||
icon-repeatone = 1
|
||||
|
||||
toggle-on-foreground = ${theme.foreground}
|
||||
toggle-off-foreground = #55
|
||||
|
||||
[module/bbswitch]
|
||||
type = custom/script
|
||||
exec = ~/.config/polybar/bbswitch
|
||||
interval = 5
|
||||
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]
|
||||
type = internal/xbacklight
|
||||
output = ${env:display:LVDS1}
|
||||
enable-scroll = true
|
||||
format = <ramp>
|
||||
ramp-0 = 🌕
|
||||
ramp-1 = 🌔
|
||||
ramp-2 = 🌓
|
||||
ramp-3 = 🌒
|
||||
ramp-4 = 🌑
|
||||
format-foreground = ${theme.redF}
|
||||
|
||||
[module/backlight-acpi]
|
||||
inherit = module/xbacklight
|
||||
type = internal/backlight
|
||||
card = intel_backlight
|
||||
|
||||
[module/cpu]
|
||||
type = internal/cpu
|
||||
interval = 1
|
||||
format = <ramp-coreload>
|
||||
format-foreground = ${theme.redF}
|
||||
ramp-coreload-0 = ▁
|
||||
ramp-coreload-1 = ▂
|
||||
ramp-coreload-2 = ▃
|
||||
ramp-coreload-3 = ▄
|
||||
ramp-coreload-4 = ▅
|
||||
ramp-coreload-5 = ▆
|
||||
ramp-coreload-6 = ▇
|
||||
ramp-coreload-7 = █
|
||||
|
||||
[module/memory]
|
||||
type = internal/memory
|
||||
interval = 1
|
||||
format-foreground = ${theme.greenF}
|
||||
label = %gb_free%
|
||||
|
||||
[module/keystore]
|
||||
type = custom/script
|
||||
exec = ~/.config/polybar/keystore
|
||||
; exec-if = pgrep openvpn
|
||||
interval = 5
|
||||
format-foreground = ${theme.greenF}
|
||||
|
||||
[module/vpncheck]
|
||||
type = custom/script
|
||||
exec = echo
|
||||
exec-if = pgrep openvpn
|
||||
interval = 5
|
||||
format-foreground = ${theme.blueF}
|
||||
|
||||
[module/eth]
|
||||
type = internal/network
|
||||
interface = ${env:ethI:eth0}
|
||||
interval = 5
|
||||
|
||||
format-connected = <label-connected>
|
||||
label-connected = %local_ip%
|
||||
format-connected-foreground = ${theme.blueF}
|
||||
|
||||
format-disconnected =
|
||||
|
||||
[module/ethMore]
|
||||
inherit = module/eth
|
||||
label-connected = ↑%upspeed% ↓%downspeed%
|
||||
|
||||
[module/wlan]
|
||||
type = internal/network
|
||||
interface = ${env:wlanI:wlan0}
|
||||
interval = 5
|
||||
|
||||
format-connected = <ramp-signal> <label-connected>
|
||||
label-connected = %local_ip% %essid%
|
||||
format-connected-foreground = ${theme.cyanF}
|
||||
|
||||
format-disconnected =
|
||||
|
||||
ramp-signal-0 = ▁
|
||||
ramp-signal-1 = ▂
|
||||
ramp-signal-2 = ▃
|
||||
ramp-signal-3 = ▄
|
||||
ramp-signal-4 = ▅
|
||||
ramp-signal-5 = ▆
|
||||
ramp-signal-6 = ▇
|
||||
ramp-signal-7 = █
|
||||
|
||||
animation-packetloss-0 =
|
||||
animation-packetloss-1 =
|
||||
animation-packetloss-framerate = 500
|
||||
|
||||
[module/wlanMore]
|
||||
inherit = module/wlan
|
||||
label-connected = ↑%upspeed% ↓%downspeed%
|
||||
|
||||
[module/date]
|
||||
type = internal/date
|
||||
interval = 1
|
||||
|
||||
date = " %d/%m/%Y"
|
||||
time = %H:%M:%S
|
||||
|
||||
format = <label>
|
||||
format-foreground = ${theme.cyanF}
|
||||
|
||||
label = %date% %time%
|
||||
|
||||
[module/shortdate]
|
||||
inherit = module/date
|
||||
date = " %d/%m"
|
||||
|
||||
|
||||
[module/volume]
|
||||
type = internal/volume
|
||||
|
||||
master-soundcard = default
|
||||
format-volume = <ramp-volume> <label-volume>
|
||||
format-volume-foreground = ${theme.greenF}
|
||||
|
||||
label-muted =
|
||||
label-muted-foreground = #66
|
||||
format-muted-foreground = ${self.format-volume-foreground}
|
||||
|
||||
ramp-volume-0 =
|
||||
ramp-volume-1 =
|
||||
ramp-volume-2 =
|
||||
|
||||
[module/battery]
|
||||
type = internal/battery
|
||||
battery = BAT0
|
||||
adapter = ADP0
|
||||
full-at = 100
|
||||
time-format = %H:%M
|
||||
|
||||
label-full =
|
||||
|
||||
format-charging = <ramp-capacity> <label-charging>
|
||||
format-charging-foreground = ${theme.yellowF}
|
||||
format-charging-prefix =
|
||||
label-charging = %percentage%% (%time%)
|
||||
|
||||
format-discharging = <ramp-capacity> <label-discharging>
|
||||
format-discharging-foreground = ${self.format-charging-foreground}
|
||||
; format-discharging-background = ${theme.redB}
|
||||
label-discharging = %percentage%% (%time%)
|
||||
|
||||
format-full-prefix = " "
|
||||
format-full-foreground = ${self.format-charging-foreground}
|
||||
|
||||
ramp-capacity-0 =
|
||||
ramp-capacity-1 =
|
||||
ramp-capacity-2 =
|
||||
ramp-capacity-3 =
|
||||
ramp-capacity-4 =
|
||||
|
||||
[module/temperature]
|
||||
type = internal/temperature
|
||||
thermal-zone = 2
|
||||
warn-temperature = 70
|
||||
|
||||
format = <ramp> <label>
|
||||
format-foreground = ${theme.yellowB}
|
||||
label = %temperature%
|
||||
|
||||
format-warn = <ramp> <label-warn>
|
||||
format-warn-foreground = ${self.format-foreground}
|
||||
format-warn-background = ${theme.redB}
|
||||
label-warn = %temperature%
|
||||
|
||||
ramp-0 =
|
||||
ramp-1 =
|
||||
ramp-2 =
|
||||
ramp-3 =
|
||||
|
||||
[settings]
|
||||
screenchange-reload = true
|
||||
;compositing-background = xor
|
||||
;compositing-background = screen
|
||||
;compositing-foreground = source
|
||||
;compositing-border = over
|
||||
|
||||
[global/wm]
|
||||
margin-top = 5
|
||||
margin-bottom = 5
|
||||
|
||||
; vim:ft=dosini
|
2
unprocessed/config/polybar/config.ini
Normal file
2
unprocessed/config/polybar/config.ini
Normal file
|
@ -0,0 +1,2 @@
|
|||
include-file = modules.ini
|
||||
include-file = bars.ini
|
9
unprocessed/config/polybar/keystore
Executable file
9
unprocessed/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
|
28
unprocessed/config/polybar/launch.sh
Executable file
28
unprocessed/config/polybar/launch.sh
Executable file
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Terminate already running bar instances
|
||||
killall -q polybar
|
||||
|
||||
# Wait until the processes have been shut down
|
||||
while pgrep -x polybar >/dev/null; do sleep 1; done
|
||||
|
||||
# Getting some vars
|
||||
primary=$(xrandr | grep primary | head -1 | cut -d' ' -f1)
|
||||
export ethI=$(/bin/ls /sys/class/net/ | grep ^enp* | head -1)
|
||||
export wlanI=$(/bin/ls /sys/class/net/ | grep ^wl* | head -1)
|
||||
|
||||
# Launch bar for each display
|
||||
polybar -m | cut -d':' -f1 | while read display
|
||||
do
|
||||
export display=$display
|
||||
if [ "$display" == "$primary" ]
|
||||
then
|
||||
bar="primary"
|
||||
else
|
||||
bar="secondary"
|
||||
fi
|
||||
polybar -q $bar -c ~/.config/polybar/config.ini &
|
||||
done
|
||||
|
||||
echo "Bars launched..."
|
||||
|
17
unprocessed/config/polybar/linuxmismatch
Executable file
17
unprocessed/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
|
||||
|
3
unprocessed/config/polybar/modules.ini
Normal file
3
unprocessed/config/polybar/modules.ini
Normal file
|
@ -0,0 +1,3 @@
|
|||
[module/date]
|
||||
type = internal/date
|
||||
date = %m-%d %H:%M:%S
|
21
unprocessed/config/polybar/todo
Executable file
21
unprocessed/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
|
6
unprocessed/config/scripts/adb_backup_extract
Executable file
6
unprocessed/config/scripts/adb_backup_extract
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Make sur eto install zlib-flate from the qpdf package
|
||||
# Works on unencrypted only
|
||||
|
||||
tail -c +25 "$1" | zlib-flate -uncompress | tar xvf -
|
18
unprocessed/config/scripts/arch-kexec
Executable file
18
unprocessed/config/scripts/arch-kexec
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
# Set variables
|
||||
name="${1:-linux}"
|
||||
kernel="/boot/vmlinuz-$name"
|
||||
initrd="/boot/initramfs-$name.img"
|
||||
|
||||
# Test if required files are present
|
||||
[ -f $kernel ]
|
||||
[ -f $initrd ]
|
||||
command -v kexec &> /dev/null
|
||||
|
||||
# Configure the next kernel to load
|
||||
sudo kexec -l $kernel --initrd=$initrd --reuse-cmdline
|
||||
# Gracefully restart on the next kernel
|
||||
sudo systemctl kexec
|
12
unprocessed/config/scripts/cudarun
Executable file
12
unprocessed/config/scripts/cudarun
Executable file
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z $DISPLAY ]
|
||||
then
|
||||
sudo tee /proc/acpi/bbswitch <<< ON
|
||||
"$@"
|
||||
rmmod nvidia_uvm
|
||||
rmmod nvidia
|
||||
sudo tee /proc/acpi/bbswitch <<< OFF
|
||||
else
|
||||
PATH="/opt/cuda/bin:$PATH" LD_LIBRARY_PATH="/opt/cuda/lib64:$LD_LIBRARY_PATH" VBLANK=0 VGL_READBACK=pbo optirun -c yuv "$@"
|
||||
fi
|
8
unprocessed/config/scripts/dafont
Executable file
8
unprocessed/config/scripts/dafont
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Downloads a font from dafont.com and
|
||||
# extracts it in the user's font dir
|
||||
|
||||
wget "http://dl.dafont.com/dl/?f=$1" -O /tmp/dafont.zip
|
||||
unzip /tmp/dafont.zip -d ~/.local/share/fonts -x *.txt
|
||||
rm -rf /tmp/dafont.zip
|
455
unprocessed/config/scripts/debloc
Executable file
455
unprocessed/config/scripts/debloc
Executable file
|
@ -0,0 +1,455 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Installs Debian packages on a Debian system
|
||||
# with no root access, in the user home
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
# Verifications
|
||||
|
||||
if [[ -z $DEBIAN_MIRROR && ! -f /etc/apt/sources.list ]]; then
|
||||
echo "Unable to find a mirror. Try setting DEBIAN_MIRROR (see help)."
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z $DEBIAN_DB && ! $(which apt &> /dev/null) ]]; then
|
||||
echo "Unable to find a database for packages to install. Try setting DEBIAN_DB (see help)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Overrides
|
||||
|
||||
[ -z $DEBLOC_PREFIX ] && DEBLOC_PREFIX=$(dpkg --print-architecture)
|
||||
[ -z $DEBLOC_DB ] && DEBLOC_DB=${XDG_CONFIG_HOME:-$HOME/.config}/debloc/$DEBLOC_PREFIX
|
||||
[ -z $DEBLOC_ROOT ] && DEBLOC_ROOT=$HOME/.debloc/$DEBLOC_PREFIX
|
||||
DEBLOC_LD=$DEBLOC_ROOT/ld
|
||||
|
||||
if [ -z "$DEBIAN_MIRROR" ]; then
|
||||
DEBIAN_MIRROR="$(cat /etc/apt/sources.list | grep '^deb ' | grep main | grep -v backports)"
|
||||
DEBIAN_MIRROR="$(echo -e "$DEBIAN_MIRROR" | cut -d ' ' -f 2 | sed 's/\/$//' | sort | uniq)"
|
||||
fi
|
||||
|
||||
# Preparation
|
||||
|
||||
mkdir -p $DEBLOC_DB &> /dev/null
|
||||
mkdir -p $DEBLOC_ROOT &> /dev/null
|
||||
|
||||
# PRIVATE FUNCTIONS
|
||||
|
||||
# Tell if a package exists
|
||||
function _debloc-exists { # package
|
||||
if [[ -n $DEBIAN_DB && -f $DEBIAN_DB ]]; then
|
||||
grep "^Package: $1\$" $DEBIAN_DB --quiet
|
||||
else
|
||||
LANG=C apt-cache show $1 &> /dev/null
|
||||
fi
|
||||
if [ $? == 0 ]; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Return the real package associated with a virtual package
|
||||
# If not a virtual package, return the input
|
||||
function _debloc-filterVirtual { # package
|
||||
pkg=$1
|
||||
if [[ -n $DEBIAN_DB && -f $DEBIAN_DB ]]; then
|
||||
echo $pkg
|
||||
else
|
||||
LANG=C apt-cache policy $1 | grep "Candidate" | grep "(none)" > /dev/null
|
||||
if [ $? == 0 ]; then
|
||||
# TODO This is not really accurate
|
||||
LANG=C apt-cache showpkg $pkg | tail -1 | cut -d ' ' -f 1
|
||||
else
|
||||
echo $pkg
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Tell if a package is installed via debloc
|
||||
function _debloc-locallyInstalled { # package
|
||||
if [ -f $DEBLOC_DB/$1 ]; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Tell if a package is installed system-wide
|
||||
function _debloc-globallyInstalled { # package
|
||||
STATUS=$(mktemp)
|
||||
LANG=C dpkg --list $1 &> $STATUS
|
||||
if [ $? != 0 ]; then
|
||||
rm -f $STATUS > /dev/null
|
||||
return 0
|
||||
fi
|
||||
cat $STATUS | grep '^Status:' | grep ' installed' --quiet
|
||||
if [ $? != 0 ]; then
|
||||
rm -f $STATUS > /dev/null
|
||||
return 0
|
||||
else
|
||||
rm -f $STATUS > /dev/null
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Get informations about a package
|
||||
function _debloc-packageShow { # package
|
||||
pkg=$1
|
||||
if [[ -n $DEBIAN_DB && -f $DEBIAN_DB ]]; then
|
||||
startline=$(grep "^Package: ${pkg}\$" $DEBIAN_DB --line-number | tail -1 | cut -d ':' -f 1)
|
||||
if [ -z "$startline" ]; then
|
||||
return 0
|
||||
fi
|
||||
sed -n "$startline,$(expr $startline + 100)p" $DEBIAN_DB | while read line; do
|
||||
if [ -z "$line" ]; then
|
||||
return 0
|
||||
fi
|
||||
echo $line
|
||||
done
|
||||
return 1
|
||||
else
|
||||
LANG=C apt-cache show $pkg | while read line; do
|
||||
if [ -z "$line" ]; then
|
||||
return 0
|
||||
fi
|
||||
echo "$line"
|
||||
done
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Get the path of a package
|
||||
function _debloc-packagePath { # package
|
||||
_debloc-packageShow $1 | grep "^Filename:" | head -1 | cut -d ':' -f 2 | sed -e 's/^[[:space:]]*//'
|
||||
return 0
|
||||
}
|
||||
|
||||
# Get the md5sum of a package
|
||||
function _debloc-packageMd5sum { # package
|
||||
_debloc-packageShow $1 | grep "^MD5sum:" | cut -d ':' -f 2 | sed -e 's/^[[:space:]]*//'
|
||||
return 0
|
||||
}
|
||||
|
||||
# Update symbolics links in $DEBLOC_ROOT/lib
|
||||
function _debloc-ldconfig {
|
||||
mkdir -p $DEBLOC_LD &> /dev/null
|
||||
rm -f $DEBLOC_LD &> /dev/null
|
||||
find $DEBLOC_ROOT{/usr,}/lib -type f -name "*.so*" | while read lib; do
|
||||
ln --symbolic --force "$lib" "$DEBLOC_LD/$(basename $lib)"
|
||||
done &> /dev/null
|
||||
find $DEBLOC_ROOT{/usr,}/lib -type l -name "*.so*" | while read link; do
|
||||
yes | cp --force --no-dereference --preserve=links "$link" "$DEBLOC_LD" &> /dev/null
|
||||
done &> /dev/null
|
||||
}
|
||||
|
||||
# Fix absolute symbolic links
|
||||
function _debloc-fixRootSymlinks {
|
||||
find $DEBLOC_ROOT -type l | while read src
|
||||
do
|
||||
dst="$(readlink "$src")"
|
||||
if echo "$dst" | grep '^/' | grep -q -v "^$DEBLOC_ROOT"
|
||||
then
|
||||
newDst="$DEBLOC_ROOT$dst"
|
||||
if [ -f "$newDst" ]
|
||||
then
|
||||
echo "$src → $newDst"
|
||||
rm "$src"
|
||||
ln -s "$newDst" "$src"
|
||||
else
|
||||
echo "Ignoring $src pointing to $dst"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function _debloc-fixPkgconfPrefix {
|
||||
sed "s|^prefix=/usr$|prefix=$DEBLOC_ROOT/usr|" $(find $DEBLOC_ROOT -type f -name "*.pc") -i
|
||||
}
|
||||
|
||||
function debloc_fix {
|
||||
echo "Fixing absolute symbolic links..."
|
||||
_debloc-fixRootSymlinks
|
||||
echo "Linking libraries in /ld"
|
||||
_debloc-ldconfig
|
||||
echo "Fixing prefix in pkg-config files"
|
||||
_debloc-fixPkgconfPrefix
|
||||
}
|
||||
|
||||
# Install debian archive
|
||||
function _debloc-installDeb { # path
|
||||
TMP_DIR=$(mktemp -d) &> /dev/null
|
||||
$(cd $TMP_DIR; ar x "$1")
|
||||
TAR_FILE=$(find $TMP_DIR -type f -name "data.tar.*" | head -1)
|
||||
if [ -e "$TAR_FILE" ]; then
|
||||
# Output for DB saving
|
||||
tar tf $TAR_FILE
|
||||
tar xf $TAR_FILE -C $DEBLOC_ROOT
|
||||
|
||||
# _debloc-ldconfig
|
||||
mkdir -p $DEBLOC_LD &> /dev/null
|
||||
tar tf $TAR_FILE | grep '^.\(/usr\)\?/lib/' | grep '\.so' | while read file; do
|
||||
lib=$(readlink -f $DEBLOC_ROOT/$file)
|
||||
if [ -f $lib ]; then
|
||||
ln --symbolic --force "$lib" "$DEBLOC_LD/$(basename $file)"
|
||||
fi
|
||||
if [ -h $lib ]; then
|
||||
yes | cp --force --no-dereference --preserve=links "$(basename $link)" "$DEBLOC_LD/" &> /dev/null
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
rm -rf $TMP_DIR &> /dev/null
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
# Install package
|
||||
function _debloc-install { # package
|
||||
pkg=$1
|
||||
|
||||
DEB_FILE=$(mktemp) &> /dev/null
|
||||
path=$(_debloc-packagePath $pkg)
|
||||
echo -e "${DEBIAN_MIRROR}" | while read mirror; do
|
||||
if [ -z "$mirror" ]; then
|
||||
continue
|
||||
fi
|
||||
url=${mirror}/${path}
|
||||
echo "→ Downloading $url"
|
||||
wget "$url" --quiet -O $DEB_FILE
|
||||
if [ $? == 0 ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ ! -s $DEB_FILE ]; then
|
||||
echo "→ Failed (no deb file)!"
|
||||
rm $DEBLOC_DB/$pkg &> /dev/null
|
||||
return 4
|
||||
fi
|
||||
|
||||
echo "→ Verifying sums"
|
||||
theo=$(_debloc-packageMd5sum $pkg)
|
||||
real=$(md5sum $DEB_FILE | cut -d ' ' -f 1)
|
||||
if [ "$theo" != "$real" ]; then
|
||||
rm -f $DEB_FILE &> /dev/null
|
||||
echo "→ Failed (sum doesn't match)!"
|
||||
rm $DEBLOC_DB/$pkg &> /dev/null
|
||||
return 5
|
||||
fi
|
||||
|
||||
echo "→ Installing"
|
||||
_debloc-installDeb $DEB_FILE > $DEBLOC_DB/$pkg
|
||||
|
||||
echo "→ Done!"
|
||||
rm -f $DEB_FILE &> /dev/null
|
||||
return 0
|
||||
}
|
||||
|
||||
# Get the dependencies of a package
|
||||
function _debloc-packageDeps { # package
|
||||
_debloc-packageShow $1 | grep '^Depends:' | sed 's/Depends: //' | sed 's/, /\n/g' | cut -d ' ' -f 1
|
||||
return 0
|
||||
}
|
||||
|
||||
# Install package with dependencies
|
||||
function _debloc-installDeps { # package
|
||||
pkg=$1
|
||||
echo "Installing $pkg"
|
||||
touch $DEBLOC_DB/$pkg # To prevent cyclic deps
|
||||
_debloc-packageDeps $pkg | while read dep; do
|
||||
dep=$(_debloc-filterVirtual $dep)
|
||||
_debloc-locallyInstalled $dep
|
||||
if [ $? == 1 ]; then
|
||||
echo "- Dependency $dep is already installed with Debloc"
|
||||
continue
|
||||
fi
|
||||
_debloc-globallyInstalled $dep
|
||||
if [ $? == 1 ]; then
|
||||
echo "- Dependency $dep is already installed on the system"
|
||||
continue
|
||||
fi
|
||||
_debloc-installDeps $dep | while read line; do echo "- $line"; done
|
||||
done
|
||||
_debloc-install $pkg
|
||||
return 0
|
||||
}
|
||||
|
||||
# PUBLIC FUNCTIONS
|
||||
|
||||
function proxy_set_help {
|
||||
echo "Usage: $0 env"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo ' eval "$(debloc env)"'
|
||||
return 0
|
||||
}
|
||||
function debloc_env {
|
||||
echo "export PATH=\"$DEBLOC_ROOT/usr/bin:$DEBLOC_ROOT/usr/games/:$DEBLOC_ROOT/usr/lib/git-core:\$PATH\""
|
||||
echo "export LIBRARY_PATH=\"$DEBLOC_LD:\$LIBRARY_PATH\""
|
||||
echo "export C_INCLUDE_PATH=\"$DEBLOC_ROOT/usr/include:\$C_INCLUDE_PATH\""
|
||||
echo "export CPLUS_INCLUDE_PATH=\"$DEBLOC_ROOT/usr/include:$DEBLOC_ROOT/usr/include/python2.7/:$DEBLOC_ROOT/usr/include/x86_64-linux-gnu/python2.7/:\$CPLUS_INCLUDE_PATH\""
|
||||
echo "export LD_LIBRARY_PATH=\"$DEBLOC_LD:\$LD_LIBRARY_PATH\""
|
||||
echo "export PYTHONPATH=\"$DEBLOC_ROOT/usr/lib/python2/dist-packages:$DEBLOC_ROOT/usr/lib/python3/dist-packages:$DEBLOC_ROOT/usr/lib/python2.7/dist-packages:$DEBLOC_ROOT/usr/lib/python3.5/dist-packages:\$PYTHONPATH\""
|
||||
echo "export QT_QPA_PLATFORM_PLUGIN_PATH=\"$DEBLOC_ROOT/usr/lib/x86_64-linux-gnu/qt5/plugins/platforms\""
|
||||
echo "export PKG_CONFIG_PATH=\"$DEBLOC_ROOT/usr/share/pkgconfig/:$DEBLOC_ROOT/usr/lib/x86_64-linux-gnu/pkgconfig/:$DEBLOC_ROOT/usr/lib/pkgconfig/:\$PKG_CONFIG_PATH\""
|
||||
}
|
||||
|
||||
function debloc_info {
|
||||
echo "DEBLOC_PREFIX=$DEBLOC_PREFIX"
|
||||
echo "DEBLOC_ROOT=$DEBLOC_ROOT"
|
||||
echo "DEBLOC_DB=$DEBLOC_DB"
|
||||
echo "DEBLOC_LD=$DEBLOC_LD"
|
||||
echo "DEBIAN_MIRROR='$DEBIAN_MIRROR'"
|
||||
echo "DEBIAN_DB=$DEBIAN_DB"
|
||||
}
|
||||
|
||||
function debloc_install_help {
|
||||
echo "Usage: $0 install PACKAGE"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " PACKAGE Package name"
|
||||
return 0
|
||||
}
|
||||
|
||||
function debloc_install { # package
|
||||
if [ -z $1 ]; then
|
||||
debloc_deb_help
|
||||
fi
|
||||
for pkg in $*
|
||||
do
|
||||
if [ $pkg == '--force' ] || [ $pkg == '-f' ]; then
|
||||
force=0
|
||||
fi
|
||||
done
|
||||
for pkg in $*; do
|
||||
if [ $pkg == '--force' ] || [ $pkg == '-f' ]; then
|
||||
continue
|
||||
fi
|
||||
pkg=$(_debloc-filterVirtual $pkg)
|
||||
_debloc-exists $pkg
|
||||
if [ $? == 0 ]; then
|
||||
echo "Unknown package $pkg"
|
||||
continue
|
||||
fi
|
||||
if [ ! -v force ]; then
|
||||
_debloc-locallyInstalled $pkg
|
||||
if [ $? == 1 ]; then
|
||||
echo "Package $pkg is already installed with Debloc"
|
||||
continue
|
||||
fi
|
||||
_debloc-globallyInstalled $pkg
|
||||
if [ $? == 1 ]; then
|
||||
echo "Package $pkg is already installed on the system"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
_debloc-installDeps $pkg
|
||||
done
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
function debloc_deb_help {
|
||||
echo "Usage: $0 deb PATH"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " PATH Path to the .deb file"
|
||||
return 0
|
||||
}
|
||||
function debloc_deb { # path
|
||||
if [ -z $1 ]; then
|
||||
debloc_deb_help
|
||||
fi
|
||||
for path in $*; do
|
||||
if [ ! -f "$path" ]; then
|
||||
echo "$path is not a file"
|
||||
return 6
|
||||
fi
|
||||
echo "Installing $(basename $path)"
|
||||
_debloc-installDeb "$(readlink -f $path)" > $DEBLOC_DB/$(basename $path)
|
||||
done
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
function debloc_altern_help {
|
||||
echo "Usage: $0 altern PROGRAM ALTERNATIVE"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " PROGRAM Program to set the alternative for"
|
||||
echo " ALTERNATIVE Alternative to set"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo " $0 altern vim nox"
|
||||
echo " $0 altern dmenu xft"
|
||||
return 0
|
||||
}
|
||||
function debloc_altern { # program alternative
|
||||
if [[ -z $1 || -z $2 ]]; then
|
||||
debloc_altern_help
|
||||
exit 1
|
||||
fi
|
||||
if [ -f "$DEBLOC_ROOT/usr/bin/$1.$2" ]; then
|
||||
dest="$DEBLOC_ROOT/usr/bin/$1"
|
||||
alte="$DEBLOC_ROOT/usr/bin/$1.$2"
|
||||
elif [ -f "$DEBLOC_ROOT/bin/$1.$2" ]; then
|
||||
dest="$DEBLOC_ROOT/bin/$1"
|
||||
alte="$DEBLOC_ROOT/bin/$1.$2"
|
||||
else
|
||||
echo "Unknown alternative for $1 : $2"
|
||||
exit 1
|
||||
fi
|
||||
if [ -e "$dest" ]; then
|
||||
rm $dest
|
||||
fi
|
||||
ln -s "$alte" "$dest"
|
||||
}
|
||||
|
||||
function debloc_flush {
|
||||
rm -rf $DEBLOC_ROOT/* &> /dev/null
|
||||
rm -f $DEBLOC_DB/* &> /dev/null
|
||||
}
|
||||
|
||||
# TODO Other word for 'fake filesystem' and/or explain what this is
|
||||
function debloc_help {
|
||||
command="$1"
|
||||
if [ -n "$command" ]; then
|
||||
if type "debloc_${command}_help" &> /dev/null; then
|
||||
shift
|
||||
"debloc_${command}_help" "$@"
|
||||
return $?
|
||||
fi
|
||||
fi
|
||||
echo "Usage: $0 COMMAND"
|
||||
echo
|
||||
echo "Commands:"
|
||||
echo " env Provides the environment variables required to run applications from the fake filesystem"
|
||||
echo " info Gives some information about the fake filesystem"
|
||||
echo " install Install a debian package in the fake filesystem"
|
||||
echo " deb Install from a .deb file in the fake filesystem"
|
||||
echo " altern Update alternative"
|
||||
echo " fix Apply some fixes in the fake filesystem"
|
||||
echo " flush Remove every package installed from the fake filesystem"
|
||||
echo " help Get help with commands"
|
||||
echo
|
||||
echo "Environment variables:"
|
||||
echo " DEBLOC_PREFIX Name of the fake filesystem to use (default: uses dpkg architecture)"
|
||||
echo " DEBLOC_ROOT Path of the fake filesystem (default: ~/.debloc/\$DEBLOC_PREFIX/)"
|
||||
echo " DEBLOC_DB Database of the fake filesystem (default: \$XDG_CONFIG_HOME/debloc/\$DEBLOC_PREFIX)"
|
||||
echo " DEBIAN_MIRROR Multiline list of debian mirror (default: uses /etc/apt/sources.list)"
|
||||
echo " DEBIAN_DB Path to a file with all packages description (default: uses apt-cache showpkg)"
|
||||
echo " help Get help with commands"
|
||||
return 0
|
||||
}
|
||||
|
||||
# MAIN
|
||||
|
||||
command="$1"
|
||||
shift
|
||||
if type "debloc_$command" &> /dev/null; then
|
||||
"debloc_$command" "$@"
|
||||
else
|
||||
debloc_help
|
||||
fi
|
||||
|
25
unprocessed/config/scripts/diapo
Executable file
25
unprocessed/config/scripts/diapo
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Don't forget:
|
||||
# --duration 15m # Specify expected duration of presentation
|
||||
# --half-screen --geometry 2048x768+0+1 # If presenting with beamer notes on the right, and you have two screens with 1024x768 resolution
|
||||
|
||||
|
||||
/home/geoffrey/Documents/Programmation/Impressive/OutOfTree/impressive.py \
|
||||
--transition WipeRight \
|
||||
--bind lmb:=box-zoom --bind lmb=zoom-exit \
|
||||
--bind rmb:=box-add --bind rmb=box-clear \
|
||||
--bind ctrl+p:=overview-enter --bind ctrl+a:=overview-confirm \
|
||||
--bind escape:=time-reset \
|
||||
--bind e:=goto-last \
|
||||
--bind b-=fade-to-black \
|
||||
--bind escape-=quit \
|
||||
--cursor default \
|
||||
--fontsize 26 \
|
||||
--transtime 200 \
|
||||
--mousedelay 1000 \
|
||||
--page-progress \
|
||||
--time-display \
|
||||
--tracking \
|
||||
--zoomdarkness 75 \
|
||||
"$@"
|
2
unprocessed/config/scripts/hc
Executable file
2
unprocessed/config/scripts/hc
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
highlight -O ansi "$@"
|
2
unprocessed/config/scripts/hl
Executable file
2
unprocessed/config/scripts/hl
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
highlight -O ansi "$@" | less -R
|
56
unprocessed/config/scripts/html2pdf
Executable file
56
unprocessed/config/scripts/html2pdf
Executable file
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
// Imports
|
||||
var fs = require('fs');
|
||||
var pdf = require('html-pdf');
|
||||
var yargs = require('yargs');
|
||||
|
||||
|
||||
// Understanding
|
||||
var argv = yargs
|
||||
.usage("Usage: $0 -o out.pdf [options]")
|
||||
.example('$0 -i doc.pdf -o doc.pdf', 'Convert doc.html to PDF using the default values')
|
||||
.help('h')
|
||||
.alias('h', 'help')
|
||||
|
||||
.describe('i', 'Input file')
|
||||
.alias('i', 'input')
|
||||
.default('i', '/dev/stdin')
|
||||
|
||||
.describe('o', 'Output file')
|
||||
.alias('o', 'output')
|
||||
|
||||
.describe('t', 'Title of file')
|
||||
.alias('t', 'title')
|
||||
.default('t', 'Sans titre')
|
||||
|
||||
.describe('b', 'Border')
|
||||
.alias('b', 'border')
|
||||
.default('b', '2cm')
|
||||
|
||||
.demandOption(['o'])
|
||||
.argv;
|
||||
|
||||
|
||||
// Settings
|
||||
options = {
|
||||
"base": "file://" + process.cwd() + '/',
|
||||
"format": "A4",
|
||||
"orientation": "portrait",
|
||||
"border": argv.border,
|
||||
|
||||
"footer": {
|
||||
"height": "10mm",
|
||||
"contents": {
|
||||
default: '<div style="text-align: left; float: left;">' + argv.title + '</div> <div style="text-align:right; float: right;">{{page}}/{{pages}}</div>',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Reading
|
||||
htmlString = fs.readFileSync(argv.i, "utf8");
|
||||
|
||||
// Conversion
|
||||
pdf.create(htmlString, options).toFile(argv.o, function(err, res) {
|
||||
if (err) console.error(err);
|
||||
});
|
11
unprocessed/config/scripts/install-wsl
Executable file
11
unprocessed/config/scripts/install-wsl
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Setups a WSL system the way I like it
|
||||
|
||||
# Remember to use the alwsl script on GitHub to install Arch Linux on WSL
|
||||
# Use github:cbucher/console as a console and github:mintty/wsltty as a shell
|
||||
# (%LOCALAPPDATA%/wsltty/bin/wsl-bridge) to avoid arrow keys bypassing
|
||||
|
||||
(cd /usr/share/i18n/charmaps/; sudo gunzip -k UTF8.gz)
|
||||
echo "fr_FR.UTF-8 UTF-8" | sudo tee -a /etc/locale.gen
|
||||
sudo locale-gen
|
6
unprocessed/config/scripts/logstasync
Executable file
6
unprocessed/config/scripts/logstasync
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
serv="$1"
|
||||
shift
|
||||
|
||||
ssh "$serv" 'sudo tail --follow=name --retry --quiet $(sudo find $(echo /var/log/$([ -d /var/log/httpd/ ] && echo httpd || echo apache2)) -type f -name *access.log)' | logstalgia --sync "$@"
|
527
unprocessed/config/scripts/machines
Executable file
527
unprocessed/config/scripts/machines
Executable file
|
@ -0,0 +1,527 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Handles indexing and SSH keys of machines I
|
||||
# have access on
|
||||
|
||||
MACHINES_HOME=$HOME
|
||||
MACHINES_CONFIG=$HOME/.config/machines
|
||||
MACHINES_API=https://machines.frogeye.fr
|
||||
|
||||
mkdir -p "$MACHINES_HOME" &> /dev/null
|
||||
mkdir -p "$MACHINES_CONFIG" &> /dev/null
|
||||
|
||||
# COMMON
|
||||
|
||||
function prompt { # text
|
||||
while true
|
||||
do
|
||||
read -r -p "$1 [yn] " yn
|
||||
case $yn in
|
||||
[Yy]* ) return 1;;
|
||||
[Nn]* ) return 0;;
|
||||
* ) echo "Please answer y or n.";;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# From https://gist.github.com/cdown/1163649
|
||||
|
||||
urlencode() { # string
|
||||
old_lc_collate=$LC_COLLATE
|
||||
LC_COLLATE=C
|
||||
local length="${#1}"
|
||||
for (( i = 0; i < length; i++ )); do
|
||||
local c="${1:i:1}"
|
||||
case $c in
|
||||
[a-zA-Z0-9.~_-]) printf "%s" "$c" ;;
|
||||
*) printf '%%%02X' "'$c" ;;
|
||||
esac
|
||||
done
|
||||
LC_COLLATE=$old_lc_collate
|
||||
}
|
||||
|
||||
urldecode() { # string
|
||||
local url_encoded="${1//+/ }"
|
||||
printf '%b' "${url_encoded//%/\\x}"
|
||||
}
|
||||
|
||||
# API ACCESS
|
||||
|
||||
function _machines-api {
|
||||
route=$1
|
||||
shift
|
||||
temp=$(mktemp)
|
||||
wget "$MACHINES_API/$route" --content-on-error --quiet --output-document=$temp "$@"
|
||||
result=$?
|
||||
if [ $result != 0 ]; then
|
||||
echo "[ERROR] wget returned $result for route $route" 1>&2;
|
||||
cat $temp 1>&2;
|
||||
rm $temp
|
||||
exit 2
|
||||
fi
|
||||
cat $temp
|
||||
rm $temp
|
||||
}
|
||||
|
||||
function _machines-apiToken {
|
||||
read -r -p 'TOTP token: ' token
|
||||
_machines-api "$@" --header="X-TOTP: $token"
|
||||
}
|
||||
|
||||
function _machines-apiSigned {
|
||||
_machines-ensureAdmin
|
||||
_machines-api "$@" --certificate="$MACHINES_CONFIG/machines.crt" --private-key="$MACHINES_CONFIG/machines.key"
|
||||
}
|
||||
|
||||
|
||||
# APPLICATION KEYS & CERTIFICATE
|
||||
|
||||
function _machines-pubFromCrt {
|
||||
openssl x509 -in "$MACHINES_CONFIG/machines.crt" -pubkey -noout > "$MACHINES_CONFIG/machines.pub"
|
||||
}
|
||||
|
||||
function _machines-verifyCertificate {
|
||||
return
|
||||
if openssl verify "$MACHINES_CONFIG/machines.crt" | grep -v 'error 18' | grep 'error' --quiet; then
|
||||
echo "[ERROR] Invalid certificate" 1>&2;
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function _machines-ensurePub {
|
||||
if [ ! -f "$MACHINES_CONFIG/machines.crt" ]; then
|
||||
CERT_FILE=$(mktemp)
|
||||
echo "[INFO] Downloading certificate..."
|
||||
_machines-api cert > "$CERT_FILE"
|
||||
openssl x509 -fingerprint -in "$CERT_FILE" | grep Fingerprint --color=never
|
||||
prompt "Is this correct ?"
|
||||
if [ $? == 1 ]; then
|
||||
mv "$CERT_FILE" "$MACHINES_CONFIG/machines.crt" &> /dev/null
|
||||
else
|
||||
echo "[ERROR] Certificate rejected." 1>&2;
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
_machines-verifyCertificate
|
||||
if [ ! -f "$MACHINES_CONFIG/machines.pub" ]; then
|
||||
_machines-pubFromCrt
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function _machines-ensureAdmin {
|
||||
if [ ! -f "$MACHINES_CONFIG/machines.key" ]; then
|
||||
echo "[ERROR] You need have to have the private key to do that" 1>&2;
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# SSH ACCESS KEYS
|
||||
|
||||
function _machines-signAkey { # network
|
||||
KEY_FILE=$(mktemp)
|
||||
SIGN_FILE=$(mktemp)
|
||||
_machines-apiSigned "akey/$1?unsigned" > "$KEY_FILE"
|
||||
openssl dgst -sha256 -sign "$MACHINES_CONFIG/machines.key" -out "$SIGN_FILE" "$KEY_FILE"
|
||||
_machines-apiSigned "akey/$1" --method=PUT --body-file="$SIGN_FILE"
|
||||
rm "$KEY_FILE" "$SIGN_FILE" &> /dev/null
|
||||
}
|
||||
|
||||
function _machines-getAkey { # network
|
||||
_machines-ensurePub
|
||||
KEY_FILE=$(mktemp)
|
||||
SIGN_FILE=$(mktemp)
|
||||
_machines-api "akey/$1" > "$KEY_FILE"
|
||||
_machines-api "akey/$1?signature" > "$SIGN_FILE"
|
||||
|
||||
if openssl dgst -sha256 -verify "$MACHINES_CONFIG/machines.pub" -signature "$SIGN_FILE" "$KEY_FILE" &> /dev/null
|
||||
then
|
||||
cat "$KEY_FILE"
|
||||
\rm "$KEY_FILE" "$SIGN_FILE"
|
||||
return 0
|
||||
else
|
||||
\rm "$KEY_FILE" "$SIGN_FILE"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function _machines-updateAkey {
|
||||
MYKEY_FILE=$(mktemp)
|
||||
network=$(grep '^network=' "$MACHINES_CONFIG/this" | cut -d '=' -f 2)
|
||||
if _machines-getAkey "$network" > "$MYKEY_FILE"
|
||||
then
|
||||
\mv -f "$MYKEY_FILE" "$MACHINES_HOME/.ssh/authorized_keys"
|
||||
if [ -f "$MACHINES_HOME/.ssh/authorized_keys.tail" ]
|
||||
then
|
||||
cat "$MACHINES_HOME/.ssh/authorized_keys.tail" >> "$MACHINES_HOME/.ssh/authorized_keys"
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
cat "$MYKEY_FILE"
|
||||
echo "[ERROR] Authorized keys are not properly signed" 1>&2;
|
||||
\rm "$MYKEY_FILE"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function _machines-postFile { # filename
|
||||
cat $1 | while read -r line; do
|
||||
parameter=$(echo "$line" | cut -d '=' -f 1)
|
||||
value="$(echo "$line" | sed 's/^[a-zA-Z0-9]\+\(\[\]\)\?=//')"
|
||||
echo -n "&$parameter=$(urlencode "$value")"
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
function _machines-addElement { # element elementType default
|
||||
FILE=$(mktemp)
|
||||
echo -e "$3" > "$FILE"
|
||||
$EDITOR "$FILE"
|
||||
data=$(_machines-postFile "$FILE")
|
||||
\rm "$FILE"
|
||||
_machines-apiSigned "$2" --post-data "name=$1$data"
|
||||
}
|
||||
|
||||
function _machines-viewElement { # element elementType
|
||||
_machines-apiSigned "$2/$1"
|
||||
}
|
||||
|
||||
function _machines-editElement { # element elementType
|
||||
FILE=$(mktemp)
|
||||
_machines-apiSigned "$2/$1" > "$FILE"
|
||||
$EDITOR "$FILE"
|
||||
data=$(_machines-postFile "$FILE")
|
||||
rm "$FILE" &> /dev/null
|
||||
err=$(_machines-apiSigned "$2/$1" --post-data "$data")
|
||||
}
|
||||
|
||||
function _machines-deleteElement { # element elementType
|
||||
err=$(_machines-apiSigned "$2/$1" --method=DELETE)
|
||||
}
|
||||
|
||||
|
||||
# USER ADMIN FUNCTIONS
|
||||
|
||||
function machines_history {
|
||||
if [ -f "$MACHINES_CONFIG/lastVerifiedLog" ]; then
|
||||
from=$(<"$MACHINES_CONFIG/lastVerifiedLog")
|
||||
else
|
||||
from=0
|
||||
fi
|
||||
d=$(date +%s)
|
||||
_machines-apiSigned log?from=$from | less
|
||||
if prompt "Is this OK?"
|
||||
then
|
||||
exit 1
|
||||
else
|
||||
echo "$d" > "$MACHINES_CONFIG/lastVerifiedLog"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
function machines_sign {
|
||||
machines_history
|
||||
echo "Signing default network authorized_keys..."
|
||||
_machines-signAkey
|
||||
_machines-apiSigned network | while read -r network; do
|
||||
echo "Signing network $network authorized_keys..."
|
||||
_machines-signAkey $network
|
||||
done
|
||||
}
|
||||
|
||||
function machines_machine_list {
|
||||
_machines-apiSigned machine
|
||||
}
|
||||
|
||||
function machines_network_list {
|
||||
_machines-apiSigned network
|
||||
}
|
||||
|
||||
function machines_machine_add_help {
|
||||
echo "Usage: $0 machine|mac|m add MACHINE"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " MACHINE machine to add"
|
||||
return 0
|
||||
}
|
||||
function machines_machine_add { # machine
|
||||
if [ -z "$1" ]; then
|
||||
machines_machine_add_help
|
||||
exit 1
|
||||
fi
|
||||
_machines-addElement "$1" machine "host[]=\nnetwork=\nuserkey=\nhostkey=\nuser="
|
||||
}
|
||||
|
||||
function machines_network_add_help {
|
||||
echo "Usage: $0 network|net|n add NETWORK"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " NETWORK Network to add"
|
||||
return 0
|
||||
}
|
||||
|
||||
function machines_network_add { # network
|
||||
if [ -z "$1" ]; then
|
||||
machines_network_add_help
|
||||
exit 1
|
||||
fi
|
||||
_machines-addElement "$1" network "allowed[]=\nsecure=false"
|
||||
}
|
||||
|
||||
function machines_machine_view_help {
|
||||
echo "Usage: $0 machine|mac|m view MACHINE"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " MACHINE machine to view"
|
||||
return 0
|
||||
}
|
||||
|
||||
function machines_machine_view { # machine
|
||||
if [ -z "$1" ]; then
|
||||
machines_machine_view_help
|
||||
exit 1
|
||||
fi
|
||||
_machines-viewElement "$1" machine
|
||||
}
|
||||
|
||||
function machines_network_view_help {
|
||||
echo "Usage: $0 network|net|n view NETWORK"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " NETWORK Network to view"
|
||||
return 0
|
||||
}
|
||||
function machines_network_view { # network
|
||||
if [ -z "$1" ]; then
|
||||
machines_network_view_help
|
||||
exit 1
|
||||
fi
|
||||
_machines-viewElement "$1" network
|
||||
}
|
||||
|
||||
function machines_machine_edit_help {
|
||||
echo "Usage: $0 machine|mac|m edit MACHINE"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " MACHINE machine to edit"
|
||||
return 0
|
||||
}
|
||||
|
||||
function machines_machine_edit { # machine
|
||||
if [ -z "$1" ]; then
|
||||
machines_machine_edit_help
|
||||
exit 1
|
||||
fi
|
||||
_machines-editElement "$1" machine
|
||||
}
|
||||
|
||||
function machines_network_edit_help {
|
||||
echo "Usage: $0 network|net|n edit NETWORK"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " NETWORK Network to edit"
|
||||
return 0
|
||||
}
|
||||
function machines_network_edit { # network
|
||||
if [ -z "$1" ]; then
|
||||
machines_network_edit_help
|
||||
exit 1
|
||||
fi
|
||||
_machines-editElement "$1" network
|
||||
}
|
||||
|
||||
function machines_machine_delete_help {
|
||||
echo "Usage: $0 machine|mac|m delete machine"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " MACHINE machine to remove"
|
||||
return 0
|
||||
}
|
||||
function machines_machine_delete { # machine
|
||||
if [ -z "$1" ]; then
|
||||
machines_machine_delete_help
|
||||
exit 1
|
||||
fi
|
||||
_machines-deleteElement "$1" machine
|
||||
}
|
||||
|
||||
function machines_network_delete_help {
|
||||
echo "Usage: $0 network|net|n delete NETWORK"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " NETWORK Network to remove"
|
||||
return 0
|
||||
}
|
||||
function machines_network_delete { # network
|
||||
if [ -z "$1" ]; then
|
||||
machines_network_delete_help
|
||||
exit 1
|
||||
fi
|
||||
_machines-deleteElement "$1" network
|
||||
}
|
||||
|
||||
function machines_machine_help {
|
||||
echo "Usage: $0 machine|mac|m COMMAND"
|
||||
echo
|
||||
echo "Commands:"
|
||||
echo " list List all machines"
|
||||
echo " add Interactively add a machine"
|
||||
echo " view Display a machine"
|
||||
echo " edit Interactively edit a specified machine"
|
||||
echo " delete Remove a specified machine"
|
||||
echo " help Get help with commands"
|
||||
return 0
|
||||
}
|
||||
function machines_machine {
|
||||
command="$1"
|
||||
shift
|
||||
if type "machines_machine_$command" &> /dev/null; then
|
||||
"machines_machine_$command" "$@"
|
||||
else
|
||||
machines_machine_help
|
||||
fi
|
||||
}
|
||||
|
||||
function machines_network_help {
|
||||
echo "Usage: $0 network|net|n COMMAND"
|
||||
echo
|
||||
echo "Commands:"
|
||||
echo " list List all networks"
|
||||
echo " add Interactively add a network"
|
||||
echo " view Display a network"
|
||||
echo " edit Interactively edit a specified network"
|
||||
echo " delete Remove a specified network"
|
||||
echo " help Get help with commands"
|
||||
return 0
|
||||
}
|
||||
function machines_network {
|
||||
command="$1"
|
||||
shift
|
||||
if type "machines_network_$command" &> /dev/null; then
|
||||
"machines_network_$command" "$@"
|
||||
else
|
||||
machines_network_help
|
||||
fi
|
||||
}
|
||||
|
||||
machines_mac() { machines_machine "$@"; }
|
||||
machines_m() { machines_machine "$@"; }
|
||||
machines_net() { machines_network "$@"; }
|
||||
machines_n() { machines_network "$@"; }
|
||||
machines_mac_help() { machines_machine_help "$@"; }
|
||||
machines_m_help() { machines_machine_help "$@"; }
|
||||
machines_net_help() { machines_network_help "$@"; }
|
||||
machines_n_help() { machines_network_help "$@"; }
|
||||
|
||||
function machines_update-all {
|
||||
machines_machine_list | while read -r machine; do
|
||||
echo "Updating $machine..."
|
||||
if [ $machine = $(cat "$MACHINES_CONFIG/this.name") ]; then
|
||||
machines_update
|
||||
continue
|
||||
fi
|
||||
ssh -n "$machine" 'cd .dotfiles; git pull; ./config/scripts/machines update'
|
||||
done
|
||||
}
|
||||
|
||||
function machines_regen-keys {
|
||||
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." 1>&2;
|
||||
exit 1
|
||||
else
|
||||
openssl genrsa -out "$MACHINES_CONFIG/machines.key" 4096
|
||||
chmod 600 "$MACHINES_CONFIG/machines.key"
|
||||
openssl req -key "$MACHINES_CONFIG/machines.key" -new -out "$MACHINES_CONFIG/machines.csr"
|
||||
openssl x509 -req -days 1826 -in "$MACHINES_CONFIG/machines.csr" -signkey "$MACHINES_CONFIG/machines.key" -out "$MACHINES_CONFIG/machines.crt"
|
||||
_machines-pubFromCrt
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# USER FUNCTIONS
|
||||
|
||||
function machines_setup {
|
||||
if [ -e "$MACHINES_CONFIG/this.name" ]; then
|
||||
echo "[ERROR] This machine is already set up" 1>&2;
|
||||
exit 1
|
||||
fi
|
||||
|
||||
_machines-ensurePub
|
||||
|
||||
# Variables
|
||||
read -r -p 'Machine name? ' name
|
||||
read -r -p 'Hosts (separated by spaces)? ' hosts
|
||||
|
||||
# User key
|
||||
mkdir -p "$MACHINES_HOME/.ssh" &> /dev/null
|
||||
if [[ ! -f $MACHINES_HOME/.ssh/id_rsa || ! -f $MACHINES_HOME/.ssh/id_rsa.pub ]]; then
|
||||
ssh-keygen -b 4096 -C "$name@machines.frogeye.fr" -f "$MACHINES_HOME/.ssh/id_rsa" -t rsa
|
||||
fi
|
||||
userkey=$(<"$MACHINES_HOME/.ssh/id_rsa.pub")
|
||||
|
||||
# Host key
|
||||
for type in ecdsa ed25519 rsa dsa; do
|
||||
if [ -f "/etc/ssh/ssh_host_${type}_key.pub" ]; then
|
||||
hostkey=$(<"/etc/ssh/ssh_host_${type}_key.pub")
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Subscription
|
||||
data="name=$(urlencode "$name")&userkey=$(urlencode "$userkey")&hostkey=$(urlencode "$hostkey")&user=$(urlencode "$USER")"
|
||||
for host in $hosts; do
|
||||
data="$data&host[]=$(urlencode "$host")"
|
||||
done
|
||||
|
||||
_machines-apiToken machine --post-data "$data"
|
||||
|
||||
echo "$name" > "$MACHINES_CONFIG/this.name"
|
||||
machines_update
|
||||
}
|
||||
|
||||
function machines_update {
|
||||
_machines-api "machine/$(cat "$MACHINES_CONFIG/this.name")" > "$MACHINES_CONFIG/this"
|
||||
_machines-updateAkey
|
||||
}
|
||||
|
||||
function machines_totp {
|
||||
url=$(_machines-apiSigned totp)
|
||||
echo "URL : $url"
|
||||
echo "$url" | qrencode -o - | feh -
|
||||
}
|
||||
|
||||
|
||||
function machines_help {
|
||||
command="$1"
|
||||
if [ -n "$command" ]; then
|
||||
if type "machines_${command}_help" &> /dev/null; then
|
||||
shift
|
||||
"machines_${command}_help" "$@"
|
||||
return $?
|
||||
fi
|
||||
fi
|
||||
echo "Usage: $0 COMMAND"
|
||||
echo
|
||||
echo "User commands:"
|
||||
echo " setup Interactive initial setup for new machine"
|
||||
echo " update Update this machine"
|
||||
echo " help Get help with commands"
|
||||
echo
|
||||
echo "Admin commands:"
|
||||
echo " machine|mac|m Modify machines"
|
||||
echo " network|net|n Modify networks"
|
||||
echo " update-all Update all machines available via SSH"
|
||||
echo " regen-keys Regenerate system keys"
|
||||
echo " sign Sign recent transactions for propagation"
|
||||
echo " totp Get TOTP generating QR code / URL"
|
||||
return 0
|
||||
}
|
||||
|
||||
# MAIN
|
||||
command="$1"
|
||||
shift
|
||||
if type "machines_$command" &> /dev/null; then
|
||||
"machines_$command" "$@"
|
||||
else
|
||||
machines_help "$@"
|
||||
fi
|
128
unprocessed/config/scripts/md2html
Executable file
128
unprocessed/config/scripts/md2html
Executable file
|
@ -0,0 +1,128 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
// Imports
|
||||
var fs = require('fs');
|
||||
var marked = require('marked');
|
||||
var highlight = require('highlight.js');
|
||||
var katex = require('katex');
|
||||
var yargs = require('yargs');
|
||||
var extend = require('util')._extend;
|
||||
|
||||
|
||||
// Constants
|
||||
var template = '<!DOCTYPE html> <html lang="fr"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta charset="UTF-8"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/styles/xcode.min.css" integrity="sha256-OED7Gmqde0cMVVeo1zVd+3fBD4EST32D4h9YT7KY0aY=" crossorigin="anonymous" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.css" integrity="sha384-wITovz90syo1dJWVh32uuETPVEtGigN07tkttEqPv+uR2SE/mbQcG7ATL28aI9H0" crossorigin="anonymous"> <style type="text/css"> image { max-width: 100 % } </style> <title>%TITLE%</title> </head> <body> <main class="page-content" aria-label="Content"> %BODY% </main> </body> </html>'
|
||||
|
||||
|
||||
// Understanding
|
||||
var argv = yargs
|
||||
.usage("Usage: $0 [options]")
|
||||
.example('$0 -i doc.md -o doc.html', 'Convert doc.md to HTML using the default template')
|
||||
.help('h')
|
||||
.alias('h', 'help')
|
||||
|
||||
.describe('i', 'Input file')
|
||||
.alias('i', 'input')
|
||||
.default('i', '/dev/stdin')
|
||||
|
||||
.describe('o', 'Output file')
|
||||
.alias('o', 'output')
|
||||
.default('o', '/dev/stdout')
|
||||
|
||||
.describe('t', 'Template file (%BODY% is replaced by the text)')
|
||||
.alias('t', 'template')
|
||||
|
||||
.argv;
|
||||
|
||||
if (argv.t) {
|
||||
template = fs.readFileSync(argv.t, "utf8");
|
||||
}
|
||||
|
||||
var latex = true;
|
||||
// TODO Arg
|
||||
|
||||
// Settings
|
||||
|
||||
var extraLangages = {
|
||||
avrpseudo: function(hljs) {
|
||||
lang = extend({}, highlight.getLanguage('avrasm'));
|
||||
lang.keywords.keyword += ' Si Alors Sinon FinSi TantQue FinTantQue Pour FinPour allant de à ←';
|
||||
lang.keywords.keyword += ' Lire Sortir sur Appeler Retourner';
|
||||
lang.keywords.keyword += ' DecalerDroite DecalerGauche';
|
||||
lang.keywords.keyword += ' Incrementer Decrementer';
|
||||
lang.keywords.built_in += ' vrai faux';
|
||||
lang.contains.push({
|
||||
className: 'meta',
|
||||
begin: /Configurer.+/,
|
||||
end: /\n/,
|
||||
});
|
||||
return lang;
|
||||
},
|
||||
avrasmplus: function(hljs) {
|
||||
lang = extend({}, highlight.getLanguage('avrasm'));
|
||||
lang.keywords.keyword += ' si saut alors et ou if then goto && || <-';
|
||||
lang.contains.push({
|
||||
className: 'meta',
|
||||
begin: /@\w+/,
|
||||
});
|
||||
return lang;
|
||||
},
|
||||
};
|
||||
|
||||
for (lang in extraLangages) {
|
||||
// This must be done before any call to highlight.highlight :/
|
||||
highlight.registerLanguage(lang, extraLangages[lang]);
|
||||
}
|
||||
|
||||
var renderer = new marked.Renderer();
|
||||
marked.setOptions({
|
||||
highlight: function(code, lang) {
|
||||
if (lang == 'raw') {
|
||||
return code;
|
||||
} else if (highlight.getLanguage(lang)) {
|
||||
return highlight.highlight(lang, code).value;
|
||||
} else {
|
||||
// if (extraLangages[lang]) {
|
||||
// highlight.registerLanguage(lang, extraLangages[lang]);
|
||||
// return highlight.highlight(lang, code).value;
|
||||
// } else {
|
||||
// }
|
||||
console.warn("Unknown language: " + lang);
|
||||
return highlight.highlightAuto(code).value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Processing
|
||||
markdownString = fs.readFileSync(argv.i, "utf8");
|
||||
|
||||
// TeX
|
||||
if (latex) {
|
||||
markdownString = markdownString.replace(/\\\$/g, '$')
|
||||
markdownString = markdownString.replace(/\$\$([\s\S]+)\$\$/gm, function(glob, formula) {
|
||||
return katex.renderToString(formula, {
|
||||
displayMode: true
|
||||
});
|
||||
});
|
||||
markdownString = markdownString.replace(/\$([^$]+)\$/g, function(glob, formula) {
|
||||
return katex.renderToString(formula, {
|
||||
displayMode: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Conversion
|
||||
htmlString = marked(markdownString, {
|
||||
renderer: renderer,
|
||||
breaks: false
|
||||
});
|
||||
// fullHtmlString = htmlString;
|
||||
fullHtmlString = template.replace('%BODY%', () => { return htmlString });
|
||||
|
||||
|
||||
// Saving
|
||||
if (argv.o == '/dev/stdout') {
|
||||
console.log(fullHtmlString);
|
||||
} else {
|
||||
fs.writeFileSync(argv.o, fullHtmlString);
|
||||
}
|
961
unprocessed/config/scripts/mel
Executable file
961
unprocessed/config/scripts/mel
Executable file
|
@ -0,0 +1,961 @@
|
|||
#!/usr/bin/env python3
|
||||
# pylint: disable=E1101
|
||||
|
||||
"""
|
||||
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 Merge file with melConf
|
||||
# TODO Config system revamp
|
||||
|
||||
import argparse
|
||||
import configparser
|
||||
import datetime
|
||||
import email.message
|
||||
import email.parser
|
||||
import html
|
||||
import logging
|
||||
import mailcap
|
||||
import os
|
||||
import pdb
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import traceback
|
||||
import typing
|
||||
|
||||
import colorama
|
||||
import coloredlogs
|
||||
import notmuch
|
||||
import progressbar
|
||||
import xdg.BaseDirectory
|
||||
|
||||
MailLocation = typing.NewType("MailLocation", typing.Tuple[str, str, str])
|
||||
# MessageAction = typing.Callable[[notmuch.Message], None]
|
||||
|
||||
|
||||
class MelEngine:
|
||||
"""
|
||||
Class with all the functions for manipulating the database / mails.
|
||||
"""
|
||||
|
||||
def load_config(self, config_path: str) -> configparser.ConfigParser:
|
||||
"""
|
||||
Load the configuration file into MelEngine
|
||||
"""
|
||||
self.log.info("Loading config file: %s", config_path)
|
||||
if not os.path.isfile(config_path):
|
||||
self.log.fatal("Config file not found!")
|
||||
sys.exit(1)
|
||||
# TODO Create it, maybe?
|
||||
config = configparser.ConfigParser()
|
||||
config.read(config_path)
|
||||
# NOTE An empty/inexistant file while give an empty config
|
||||
return config
|
||||
|
||||
def generate_aliases(self) -> None:
|
||||
"""
|
||||
Populate MelEngine.aliases and MelEngine.accounts
|
||||
"""
|
||||
assert self.config
|
||||
for name in self.config.sections():
|
||||
if not name.islower():
|
||||
continue
|
||||
section = self.config[name]
|
||||
self.aliases.add(section["from"])
|
||||
if "alternatives" in section:
|
||||
for alt in section["alternatives"].split(";"):
|
||||
self.aliases.add(alt)
|
||||
self.accounts[name] = section
|
||||
|
||||
def __init__(self, config_path: str) -> None:
|
||||
self.log = logging.getLogger("MelEngine")
|
||||
|
||||
self.config = self.load_config(config_path)
|
||||
|
||||
self.database = None
|
||||
|
||||
# Caches
|
||||
self.accounts: typing.Dict[str, configparser.SectionProxy] = dict()
|
||||
# All the emails the user is represented as:
|
||||
self.aliases: typing.Set[str] = set()
|
||||
# TODO If the user send emails to himself, maybe that wont cut it.
|
||||
|
||||
self.generate_aliases()
|
||||
|
||||
def notmuch_new(self) -> None:
|
||||
"""
|
||||
Runs `notmuch new`, which basically update the database
|
||||
to match the mail folder.
|
||||
"""
|
||||
assert not self.database
|
||||
self.log.info("Indexing mails")
|
||||
notmuch_config_file = os.path.expanduser(
|
||||
"~/.config/notmuch-config"
|
||||
) # TODO Better
|
||||
cmd = ["notmuch", "--config", notmuch_config_file, "new"]
|
||||
self.log.debug(" ".join(cmd))
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
def list_folders(self) -> typing.List[typing.Tuple[str, ...]]:
|
||||
"""
|
||||
List all the folders of the mail dir.
|
||||
"""
|
||||
assert self.config
|
||||
storage_path = os.path.realpath(
|
||||
os.path.expanduser(self.config["GENERAL"]["storage"])
|
||||
)
|
||||
folders = list()
|
||||
for account in self.accounts:
|
||||
storage_path_account = os.path.join(storage_path, account)
|
||||
for root, dirs, _ in os.walk(storage_path_account):
|
||||
if "cur" not in dirs or "new" not in dirs or "tmp" not in dirs:
|
||||
continue
|
||||
assert root.startswith(storage_path)
|
||||
path = root[len(storage_path) :]
|
||||
path_split = path.split("/")
|
||||
if path_split[0] == "":
|
||||
path_split = path_split[1:]
|
||||
folders.append(tuple(path_split))
|
||||
return folders
|
||||
|
||||
def open_database(self, write: bool = False) -> None:
|
||||
"""
|
||||
Open an access notmuch database in read or read+write mode.
|
||||
Be sure to require only in the mode you want to avoid deadlocks.
|
||||
"""
|
||||
assert self.config
|
||||
mode = (
|
||||
notmuch.Database.MODE.READ_WRITE
|
||||
if write
|
||||
else notmuch.Database.MODE.READ_ONLY
|
||||
)
|
||||
if self.database:
|
||||
# If the requested mode is the one already present,
|
||||
# or we request read when it's already write, do nothing
|
||||
if mode in (self.database.mode, notmuch.Database.MODE.READ_ONLY):
|
||||
return
|
||||
self.log.info("Current database not in mode %s, closing", mode)
|
||||
self.close_database()
|
||||
self.log.info("Opening database in mode %s", mode)
|
||||
db_path = os.path.realpath(
|
||||
os.path.expanduser(self.config["GENERAL"]["storage"])
|
||||
)
|
||||
self.database = notmuch.Database(mode=mode, path=db_path)
|
||||
|
||||
def close_database(self) -> None:
|
||||
"""
|
||||
Close the access notmuch database.
|
||||
"""
|
||||
if self.database:
|
||||
self.log.info("Closing database")
|
||||
self.database.close()
|
||||
self.database = None
|
||||
|
||||
def get_location(self, msg: notmuch.Message) -> MailLocation:
|
||||
"""
|
||||
Return the filesystem location (relative to the mail directory)
|
||||
of the given message.
|
||||
"""
|
||||
path = msg.get_filename()
|
||||
path = os.path.dirname(path)
|
||||
assert self.database
|
||||
base = self.database.get_path()
|
||||
assert path.startswith(base)
|
||||
path = path[len(base) :]
|
||||
path_split = path.split("/")
|
||||
mailbox = path_split[1]
|
||||
assert mailbox in self.accounts
|
||||
state = path_split[-1]
|
||||
folder = tuple(path_split[2:-1])
|
||||
assert state in {"cur", "tmp", "new"}
|
||||
return (mailbox, folder, state)
|
||||
|
||||
@staticmethod
|
||||
def is_uid(uid: typing.Any) -> bool:
|
||||
"""
|
||||
Tells if the provided string is a valid UID.
|
||||
"""
|
||||
return (
|
||||
isinstance(uid, str)
|
||||
and len(uid) == 12
|
||||
and bool(re.match("^[a-zA-Z0-9+/]{12}$", uid))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_email(field: str) -> str:
|
||||
"""
|
||||
Extract the email adress from a To: or From: field
|
||||
(usually the whole field or between < >)
|
||||
"""
|
||||
# TODO Can be made better (extract name and email)
|
||||
# Also what happens with multiple dests?
|
||||
try:
|
||||
sta = field.index("<")
|
||||
sto = field.index(">")
|
||||
return field[sta + 1 : sto]
|
||||
except ValueError:
|
||||
return field
|
||||
|
||||
def retag_msg(self, msg: notmuch.Message) -> None:
|
||||
"""
|
||||
Update automatic tags for message.
|
||||
"""
|
||||
_, folder, _ = self.get_location(msg)
|
||||
|
||||
# Search-friendly folder name
|
||||
slug_folder_list = list()
|
||||
for fold_index, fold in [
|
||||
(fold_index, folder[fold_index]) for fold_index in range(len(folder))
|
||||
]:
|
||||
if fold_index == 0 and len(folder) > 1 and fold == "INBOX":
|
||||
continue
|
||||
slug_folder_list.append(fold.upper())
|
||||
slug_folder = tuple(slug_folder_list)
|
||||
|
||||
tags = set(msg.get_tags())
|
||||
|
||||
def tag_if(tag: str, condition: bool) -> None:
|
||||
"""
|
||||
Ensure the presence/absence of tag depending on the condition.
|
||||
"""
|
||||
nonlocal msg
|
||||
if condition and tag not in tags:
|
||||
msg.add_tag(tag)
|
||||
elif not condition and tag in tags:
|
||||
msg.remove_tag(tag)
|
||||
|
||||
expeditor = MelEngine.extract_email(msg.get_header("from"))
|
||||
|
||||
tag_if("inbox", slug_folder[0] == "INBOX")
|
||||
tag_if("spam", slug_folder[0] in ("JUNK", "SPAM"))
|
||||
tag_if("deleted", slug_folder[0] == "TRASH")
|
||||
tag_if("draft", slug_folder[0] == "DRAFTS")
|
||||
tag_if("sent", expeditor in self.aliases)
|
||||
tag_if("unprocessed", False)
|
||||
|
||||
# UID
|
||||
uid = msg.get_header("X-TUID")
|
||||
if not MelEngine.is_uid(uid):
|
||||
# TODO Happens to sent mails but should it?
|
||||
print(f"{msg.get_filename()} has no UID!")
|
||||
return
|
||||
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 apply_msgs(
|
||||
self,
|
||||
query_str: str,
|
||||
action: typing.Callable,
|
||||
*args: typing.Any,
|
||||
show_progress: bool = False,
|
||||
write: bool = False,
|
||||
close_db: bool = True,
|
||||
**kwargs: typing.Any,
|
||||
) -> int:
|
||||
"""
|
||||
Run a function on the messages selected by the given query.
|
||||
"""
|
||||
self.open_database(write=write)
|
||||
|
||||
self.log.info("Querying %s", query_str)
|
||||
query = notmuch.Query(self.database, query_str)
|
||||
query.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
|
||||
|
||||
elements = query.search_messages()
|
||||
nb_msgs = query.count_messages()
|
||||
|
||||
iterator = (
|
||||
progressbar.progressbar(elements, max_value=nb_msgs)
|
||||
if show_progress and nb_msgs
|
||||
else elements
|
||||
)
|
||||
|
||||
self.log.info("Executing %s", action)
|
||||
for msg in iterator:
|
||||
self.log.debug("On mail %s", msg)
|
||||
if write:
|
||||
msg.freeze()
|
||||
|
||||
action(msg, *args, **kwargs)
|
||||
|
||||
if write:
|
||||
msg.thaw()
|
||||
msg.tags_to_maildir_flags()
|
||||
|
||||
if close_db:
|
||||
self.close_database()
|
||||
|
||||
return nb_msgs
|
||||
|
||||
|
||||
class MelOutput:
|
||||
"""
|
||||
All functions that print mail stuff onto the screen.
|
||||
"""
|
||||
|
||||
WIDTH_FIXED = 31
|
||||
WIDTH_RATIO_DEST_SUBJECT = 0.3
|
||||
|
||||
def compute_line_format(
|
||||
self,
|
||||
) -> typing.Tuple[typing.Optional[int], typing.Optional[int]]:
|
||||
"""
|
||||
Based on the terminal width, assign the width of flexible columns.
|
||||
"""
|
||||
if self.is_tty:
|
||||
columns, _ = shutil.get_terminal_size((80, 20))
|
||||
remain = columns - MelOutput.WIDTH_FIXED - 1
|
||||
dest_width = int(remain * MelOutput.WIDTH_RATIO_DEST_SUBJECT)
|
||||
subject_width = remain - dest_width
|
||||
return (dest_width, subject_width)
|
||||
return (None, None)
|
||||
|
||||
def __init__(self, engine: MelEngine) -> None:
|
||||
colorama.init()
|
||||
self.log = logging.getLogger("MelOutput")
|
||||
|
||||
self.engine = engine
|
||||
|
||||
self.light_background = True
|
||||
self.is_tty = sys.stdout.isatty()
|
||||
self.dest_width, self.subject_width = self.compute_line_format()
|
||||
self.mailbox_colors: typing.Dict[str, str] = dict()
|
||||
|
||||
# TODO Allow custom path
|
||||
self.caps = mailcap.getcaps()
|
||||
|
||||
@staticmethod
|
||||
def format_date(date: datetime.datetime) -> str:
|
||||
"""
|
||||
Format the given date as a 9-characters width string.
|
||||
Show the time if the mail is less than 24h old,
|
||||
else show the date.
|
||||
"""
|
||||
now = datetime.datetime.now()
|
||||
if now - date < datetime.timedelta(days=1):
|
||||
return date.strftime("%H:%M:%S")
|
||||
if now - date < datetime.timedelta(days=28):
|
||||
return date.strftime("%d %H:%M")
|
||||
if now - date < datetime.timedelta(days=365):
|
||||
return date.strftime("%m-%d %H")
|
||||
return date.strftime("%y-%m-%d")
|
||||
|
||||
@staticmethod
|
||||
def clip_text(size: typing.Optional[int], text: str) -> str:
|
||||
"""
|
||||
Fit text into the given character size,
|
||||
fill with spaces if shorter,
|
||||
clip with … if larger.
|
||||
"""
|
||||
if size is None:
|
||||
return text
|
||||
length = len(text)
|
||||
if length == size:
|
||||
return text
|
||||
if length > size:
|
||||
return text[: size - 1] + "…"
|
||||
return text + " " * (size - length)
|
||||
|
||||
@staticmethod
|
||||
def chunks(iterable: str, chunk_size: int) -> typing.Iterable[str]:
|
||||
"""Yield successive chunk_size-sized chunks from iterable."""
|
||||
# From https://stackoverflow.com/a/312464
|
||||
for i in range(0, len(iterable), chunk_size):
|
||||
yield iterable[i : i + chunk_size]
|
||||
|
||||
@staticmethod
|
||||
def sizeof_fmt(num: int, suffix: str = "B") -> str:
|
||||
"""
|
||||
Print the given size in a human-readable format.
|
||||
"""
|
||||
remainder = float(num)
|
||||
# From https://stackoverflow.com/a/1094933
|
||||
for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
|
||||
if abs(remainder) < 1024.0:
|
||||
return "%3.1f %s%s" % (remainder, unit, suffix)
|
||||
remainder /= 1024.0
|
||||
return "%.1f %s%s" % (remainder, "Yi", suffix)
|
||||
|
||||
def get_mailbox_color(self, mailbox: str) -> str:
|
||||
"""
|
||||
Return the color of the given mailbox in a ready to print
|
||||
string with ASCII escape codes.
|
||||
"""
|
||||
if not self.is_tty:
|
||||
return ""
|
||||
if mailbox not in self.mailbox_colors:
|
||||
# RGB colors (not supported everywhere)
|
||||
# color_str = self.config[mailbox]["color"]
|
||||
# color_str = color_str[1:] if color_str[0] == '#' else color_str
|
||||
# R = int(color_str[0:2], 16)
|
||||
# G = int(color_str[2:4], 16)
|
||||
# B = int(color_str[4:6], 16)
|
||||
# self.mailbox_colors[mailbox] = f"\x1b[38;2;{R};{G};{B}m"
|
||||
color_int = int(self.engine.config[mailbox]["color16"])
|
||||
|
||||
self.mailbox_colors[mailbox] = f"\x1b[38;5;{color_int}m"
|
||||
return self.mailbox_colors[mailbox]
|
||||
|
||||
def print_msg(self, msg: notmuch.Message) -> None:
|
||||
"""
|
||||
Print the given message header on one line.
|
||||
"""
|
||||
if not self.dest_width:
|
||||
self.compute_line_format()
|
||||
|
||||
sep = " " if self.is_tty else "\t"
|
||||
line = ""
|
||||
tags = set(msg.get_tags())
|
||||
mailbox, _, _ = self.engine.get_location(msg)
|
||||
if "unread" in tags or "flagged" in tags:
|
||||
line += colorama.Style.BRIGHT
|
||||
# if 'flagged' in tags:
|
||||
# line += colorama.Style.BRIGHT
|
||||
# if 'unread' not in tags:
|
||||
# line += colorama.Style.DIM
|
||||
line += (
|
||||
colorama.Back.LIGHTBLACK_EX
|
||||
if self.light_background
|
||||
else colorama.Back.BLACK
|
||||
)
|
||||
self.light_background = not self.light_background
|
||||
line += self.get_mailbox_color(mailbox)
|
||||
|
||||
# UID
|
||||
uid = None
|
||||
for tag in tags:
|
||||
if tag.startswith("tuid"):
|
||||
uid = tag[4:]
|
||||
assert uid, f"No UID for message: {msg}."
|
||||
assert MelEngine.is_uid(uid), f"{uid} {type(uid)} is not a valid UID."
|
||||
line += uid
|
||||
|
||||
# Date
|
||||
line += sep + colorama.Fore.MAGENTA
|
||||
date = datetime.datetime.fromtimestamp(msg.get_date())
|
||||
line += self.format_date(date)
|
||||
|
||||
# Icons
|
||||
line += sep + colorama.Fore.RED
|
||||
|
||||
def tags2col1(
|
||||
tag1: str, tag2: str, characters: typing.Tuple[str, str, str, str]
|
||||
) -> None:
|
||||
"""
|
||||
Show the presence/absence of two tags with one character.
|
||||
"""
|
||||
nonlocal line
|
||||
both, first, second, none = characters
|
||||
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", ("?", "↑", "↪", " "))
|
||||
|
||||
# Opposed
|
||||
line += sep + colorama.Fore.BLUE
|
||||
if "sent" in tags:
|
||||
dest = msg.get_header("to")
|
||||
else:
|
||||
dest = msg.get_header("from")
|
||||
line += MelOutput.clip_text(self.dest_width, dest)
|
||||
|
||||
# Subject
|
||||
line += sep + colorama.Fore.WHITE
|
||||
subject = msg.get_header("subject")
|
||||
line += MelOutput.clip_text(self.subject_width, subject)
|
||||
|
||||
if self.is_tty:
|
||||
line += colorama.Style.RESET_ALL
|
||||
print(line)
|
||||
|
||||
def notify_msg(self, msg: notmuch.Message) -> None:
|
||||
"""
|
||||
Send a notification for the given message.
|
||||
"""
|
||||
self.log.info("Sending notification for %s", msg)
|
||||
subject = msg.get_header("subject")
|
||||
expd = msg.get_header("from")
|
||||
account, _, _ = self.engine.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, check=False)
|
||||
|
||||
def notify_all(self) -> None:
|
||||
"""
|
||||
Send a notification for unprocessed and unread message.
|
||||
Basically should only send a notification for a given message once
|
||||
since it should be marked as processed right after.
|
||||
"""
|
||||
nb_msgs = self.engine.apply_msgs(
|
||||
"tag:unread and tag:unprocessed", self.notify_msg
|
||||
)
|
||||
if nb_msgs > 0:
|
||||
self.log.info("Playing notification sound (%d new message(s))", nb_msgs)
|
||||
cmd = [
|
||||
"play",
|
||||
"-n",
|
||||
"synth",
|
||||
"sine",
|
||||
"E4",
|
||||
"sine",
|
||||
"A5",
|
||||
"remix",
|
||||
"1-2",
|
||||
"fade",
|
||||
"0.5",
|
||||
"1.2",
|
||||
"0.5",
|
||||
"2",
|
||||
]
|
||||
subprocess.run(cmd, check=False)
|
||||
|
||||
@staticmethod
|
||||
def format_header_value(val: str) -> str:
|
||||
"""
|
||||
Return split header values in a contiguous string.
|
||||
"""
|
||||
return val.replace("\n", "").replace("\t", "").strip()
|
||||
|
||||
PART_MULTI_FORMAT = (
|
||||
colorama.Fore.BLUE + "{count} {indent}+ {typ}" + colorama.Style.RESET_ALL
|
||||
)
|
||||
PART_LEAF_FORMAT = (
|
||||
colorama.Fore.BLUE
|
||||
+ "{count} {indent}→ {desc} ({typ}; {size})"
|
||||
+ colorama.Style.RESET_ALL
|
||||
)
|
||||
|
||||
def show_parts_tree(
|
||||
self, part: email.message.Message, depth: int = 0, count: int = 1
|
||||
) -> int:
|
||||
"""
|
||||
Show a tree of the parts contained in a message.
|
||||
Return the number of parts of the mesage.
|
||||
"""
|
||||
indent = depth * "\t"
|
||||
typ = part.get_content_type()
|
||||
|
||||
if part.is_multipart():
|
||||
print(
|
||||
MelOutput.PART_MULTI_FORMAT.format(count=count, indent=indent, typ=typ)
|
||||
)
|
||||
payl = part.get_payload()
|
||||
assert isinstance(payl, list)
|
||||
size = 1
|
||||
for obj in payl:
|
||||
size += self.show_parts_tree(obj, depth=depth + 1, count=count + size)
|
||||
return size
|
||||
|
||||
payl = part.get_payload(decode=True)
|
||||
assert isinstance(payl, bytes)
|
||||
size = len(payl)
|
||||
desc = part.get("Content-Description", "<no description>")
|
||||
print(
|
||||
MelOutput.PART_LEAF_FORMAT.format(
|
||||
count=count,
|
||||
indent=indent,
|
||||
typ=typ,
|
||||
desc=desc,
|
||||
size=MelOutput.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(self, msg: notmuch.Message) -> None:
|
||||
"""
|
||||
Display the content of a mail.
|
||||
"""
|
||||
# Parse
|
||||
filename = msg.get_filename()
|
||||
parser = email.parser.BytesParser()
|
||||
with open(filename, "rb") as filedesc:
|
||||
mail = parser.parse(filedesc)
|
||||
|
||||
# Defects
|
||||
if mail.defects:
|
||||
self.log.warning("Defects found in the mail:")
|
||||
for defect in mail.defects:
|
||||
self.log.warning(defect)
|
||||
|
||||
# Headers
|
||||
for key in MelOutput.INTERESTING_HEADERS:
|
||||
val = mail.get(key)
|
||||
if val:
|
||||
assert isinstance(val, str)
|
||||
val = self.format_header_value(val)
|
||||
print(MelOutput.HEADER_FORMAT.format(key, val))
|
||||
# TODO Show all headers
|
||||
# TODO BONUS Highlight failed verifications
|
||||
|
||||
self.show_parts_tree(mail)
|
||||
print()
|
||||
|
||||
# Show text/plain
|
||||
# TODO Consider alternative
|
||||
for part in mail.walk():
|
||||
if part.is_multipart():
|
||||
continue
|
||||
payl = part.get_payload(decode=True)
|
||||
assert isinstance(payl, bytes)
|
||||
if part.get_content_type() == "text/plain":
|
||||
print(payl.decode())
|
||||
else:
|
||||
# TODO Use nametemplate from mailcap
|
||||
temp_file = "/tmp/melcap.html" # TODO Real temporary file
|
||||
# TODO FIFO if possible
|
||||
with open(temp_file, "wb") as temp_filedesc:
|
||||
temp_filedesc.write(payl)
|
||||
command, _ = mailcap.findmatch(
|
||||
self.caps, part.get_content_type(), key="view", filename=temp_file
|
||||
)
|
||||
if command:
|
||||
os.system(command)
|
||||
|
||||
def print_dir_list(self) -> None:
|
||||
"""
|
||||
Print a colored directory list.
|
||||
Every line is easilly copiable.
|
||||
"""
|
||||
for arb in self.engine.list_folders():
|
||||
line = colorama.Fore.LIGHTBLACK_EX + "'"
|
||||
line += self.get_mailbox_color(arb[0])
|
||||
line += arb[0].replace("'", "\\'")
|
||||
line += colorama.Fore.LIGHTBLACK_EX
|
||||
for inter in arb[1:-1]:
|
||||
line += "/" + inter.replace("'", "\\'")
|
||||
line += "/" + colorama.Fore.WHITE + arb[-1].replace("'", "\\'")
|
||||
line += colorama.Fore.LIGHTBLACK_EX + "'"
|
||||
line += colorama.Style.RESET_ALL
|
||||
print(line)
|
||||
|
||||
|
||||
class MelCLI:
|
||||
"""
|
||||
Handles the user input and run asked operations.
|
||||
"""
|
||||
|
||||
VERBOSITY_LEVELS = ["NOTSET", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||
|
||||
def apply_msgs_input(
|
||||
self,
|
||||
argmessages: typing.List[str],
|
||||
action: typing.Callable,
|
||||
write: bool = False,
|
||||
) -> None:
|
||||
"""
|
||||
Run a function on the message given by the user.
|
||||
"""
|
||||
# TODO First argument might be unecessary
|
||||
if not argmessages:
|
||||
from_stdin = not sys.stdin.isatty()
|
||||
if argmessages:
|
||||
from_stdin = len(argmessages) == 1 and argmessages == "-"
|
||||
|
||||
messages = list()
|
||||
if from_stdin:
|
||||
for line in sys.stdin:
|
||||
uid = line[:12]
|
||||
if not MelEngine.is_uid(uid):
|
||||
self.log.error("Not an UID: %s", uid)
|
||||
continue
|
||||
messages.append(uid)
|
||||
else:
|
||||
for uids in argmessages:
|
||||
if len(uids) > 12:
|
||||
self.log.warning(
|
||||
"Might have forgotten some spaces "
|
||||
"between the UIDs. Don't worry, I'll "
|
||||
"split them for you"
|
||||
)
|
||||
for uid in MelOutput.chunks(uids, 12):
|
||||
if not MelEngine.is_uid(uid):
|
||||
self.log.error("Not an UID: %s", uid)
|
||||
continue
|
||||
messages.append(uid)
|
||||
|
||||
for message in messages:
|
||||
query_str = f"tag:tuid{message}"
|
||||
nb_msgs = self.engine.apply_msgs(
|
||||
query_str, action, write=write, close_db=False
|
||||
)
|
||||
if nb_msgs < 1:
|
||||
self.log.error("Couldn't execute function for message %s", message)
|
||||
self.engine.close_database()
|
||||
|
||||
def operation_default(self) -> None:
|
||||
"""
|
||||
Default operation: list all message in the inbox
|
||||
"""
|
||||
self.engine.apply_msgs("tag:inbox", self.output.print_msg)
|
||||
|
||||
def operation_inbox(self) -> None:
|
||||
"""
|
||||
Inbox operation: list all message in the inbox,
|
||||
possibly only the unread ones.
|
||||
"""
|
||||
query_str = "tag:unread" if self.args.only_unread else "tag:inbox"
|
||||
self.engine.apply_msgs(query_str, self.output.print_msg)
|
||||
|
||||
def operation_flag(self) -> None:
|
||||
"""
|
||||
Flag operation: Flag user selected messages.
|
||||
"""
|
||||
|
||||
def flag_msg(msg: notmuch.Message) -> None:
|
||||
"""
|
||||
Flag given message.
|
||||
"""
|
||||
msg.add_tag("flagged")
|
||||
|
||||
self.apply_msgs_input(self.args.message, flag_msg, write=True)
|
||||
|
||||
def operation_unflag(self) -> None:
|
||||
"""
|
||||
Unflag operation: Flag user selected messages.
|
||||
"""
|
||||
|
||||
def unflag_msg(msg: notmuch.Message) -> None:
|
||||
"""
|
||||
Unflag given message.
|
||||
"""
|
||||
msg.remove_tag("flagged")
|
||||
|
||||
self.apply_msgs_input(self.args.message, unflag_msg, write=True)
|
||||
|
||||
def operation_read(self) -> None:
|
||||
"""
|
||||
Read operation: show full content of selected message
|
||||
"""
|
||||
self.apply_msgs_input(self.args.message, self.output.read_msg)
|
||||
|
||||
def operation_fetch(self) -> None:
|
||||
"""
|
||||
Fetch operation: Sync remote databases with the local one.
|
||||
"""
|
||||
# Fetch mails
|
||||
self.log.info("Fetching mails")
|
||||
mbsync_config_file = os.path.expanduser("~/.config/mbsyncrc") # TODO Better
|
||||
cmd = ["mbsync", "--config", mbsync_config_file, "--all"]
|
||||
subprocess.run(cmd, check=False)
|
||||
|
||||
# Index new mails
|
||||
self.engine.notmuch_new()
|
||||
|
||||
# Notify
|
||||
self.output.notify_all()
|
||||
|
||||
# Tag new mails
|
||||
self.engine.apply_msgs(
|
||||
"tag:unprocessed", self.engine.retag_msg, show_progress=True, write=True
|
||||
)
|
||||
|
||||
def operation_list(self) -> None:
|
||||
"""
|
||||
List operation: Print all folders.
|
||||
"""
|
||||
self.output.print_dir_list()
|
||||
|
||||
def operation_debug(self) -> None:
|
||||
"""
|
||||
DEBUG
|
||||
"""
|
||||
print("UwU")
|
||||
|
||||
def operation_retag(self) -> None:
|
||||
"""
|
||||
Retag operation: Manually retag all the mails in the database.
|
||||
Mostly debug I suppose.
|
||||
"""
|
||||
self.engine.apply_msgs(
|
||||
"*", self.engine.retag_msg, show_progress=True, write=True
|
||||
)
|
||||
|
||||
def operation_all(self) -> None:
|
||||
"""
|
||||
All operation: list every single message.
|
||||
"""
|
||||
self.engine.apply_msgs("*", self.output.print_msg)
|
||||
|
||||
def add_subparsers(self) -> None:
|
||||
"""
|
||||
Add the operation parser to the main parser.
|
||||
"""
|
||||
# TODO If the only operation to the parser done are adding argument,
|
||||
# we should automate this.
|
||||
subparsers = self.parser.add_subparsers(help="Action to execute")
|
||||
|
||||
# List messages
|
||||
self.parser.set_defaults(operation=self.operation_default)
|
||||
|
||||
# inbox (default)
|
||||
parser_inbox = subparsers.add_parser(
|
||||
"inbox", help="Show unread, unsorted and flagged messages"
|
||||
)
|
||||
parser_inbox.add_argument(
|
||||
"-u", "--only-unread", action="store_true", help="Show unread messages only"
|
||||
)
|
||||
# TODO Make this more relevant
|
||||
parser_inbox.set_defaults(operation=self.operation_inbox)
|
||||
|
||||
# list folder [--recurse]
|
||||
# List actions
|
||||
parser_list = subparsers.add_parser("list", help="List all folders")
|
||||
# parser_list.add_argument('message', nargs='*', help="Messages")
|
||||
parser_list.set_defaults(operation=self.operation_list)
|
||||
|
||||
# flag msg...
|
||||
parser_flag = subparsers.add_parser("flag", help="Mark messages as flagged")
|
||||
parser_flag.add_argument("message", nargs="*", help="Messages")
|
||||
parser_flag.set_defaults(operation=self.operation_flag)
|
||||
|
||||
# unflag msg...
|
||||
parser_unflag = subparsers.add_parser(
|
||||
"unflag", help="Mark messages as not-flagged"
|
||||
)
|
||||
parser_unflag.add_argument("message", nargs="*", help="Messages")
|
||||
parser_unflag.set_defaults(operation=self.operation_unflag)
|
||||
|
||||
# delete msg...
|
||||
# spam msg...
|
||||
# move dest msg...
|
||||
# Read message
|
||||
|
||||
# read msg [--html] [--plain] [--browser]
|
||||
|
||||
parser_read = subparsers.add_parser("read", help="Read message")
|
||||
parser_read.add_argument("message", nargs=1, help="Messages")
|
||||
parser_read.set_defaults(operation=self.operation_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)
|
||||
|
||||
parser_fetch = subparsers.add_parser(
|
||||
"fetch", help="Fetch mail, tag them, and run notifications"
|
||||
)
|
||||
parser_fetch.set_defaults(operation=self.operation_fetch)
|
||||
|
||||
# Debug
|
||||
|
||||
# debug (various)
|
||||
parser_debug = subparsers.add_parser(
|
||||
"debug", help="Who know what this holds..."
|
||||
)
|
||||
parser_debug.set_defaults(verbosity="DEBUG")
|
||||
parser_debug.set_defaults(operation=self.operation_debug)
|
||||
|
||||
# retag (all or unprocessed)
|
||||
parser_retag = subparsers.add_parser(
|
||||
"retag", help="Retag all mails (when you changed configuration)"
|
||||
)
|
||||
parser_retag.set_defaults(operation=self.operation_retag)
|
||||
|
||||
# all
|
||||
parser_all = subparsers.add_parser("all", help="Show ALL messages")
|
||||
parser_all.set_defaults(operation=self.operation_all)
|
||||
|
||||
def create_parser(self) -> argparse.ArgumentParser:
|
||||
"""
|
||||
Create the main parser that will handle the user arguments.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description="Meh mail client")
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--verbosity",
|
||||
choices=MelCLI.VERBOSITY_LEVELS,
|
||||
default="WARNING",
|
||||
help="Verbosity of self.log messages",
|
||||
)
|
||||
# parser.add_argument('-n', '--dry-run', action='store_true',
|
||||
# help="Don't do anything") # DEBUG
|
||||
default_config_file = os.path.join(
|
||||
xdg.BaseDirectory.xdg_config_home, "mel", "accounts.conf"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c", "--config", default=default_config_file, help="Accounts config file"
|
||||
)
|
||||
return parser
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.log = logging.getLogger("MelCLI")
|
||||
|
||||
self.parser = self.create_parser()
|
||||
self.add_subparsers()
|
||||
|
||||
self.args = self.parser.parse_args()
|
||||
coloredlogs.install(
|
||||
level=self.args.verbosity, fmt="%(levelname)s %(name)s %(message)s"
|
||||
)
|
||||
|
||||
self.engine = MelEngine(self.args.config)
|
||||
self.output = MelOutput(self.engine)
|
||||
|
||||
if self.args.operation:
|
||||
self.log.info("Executing operation %s", self.args.operation)
|
||||
self.args.operation()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not os.environ.get("MEL_DEBUG"):
|
||||
CLI = MelCLI()
|
||||
else:
|
||||
try:
|
||||
CLI = MelCLI()
|
||||
except:
|
||||
EXTYPE, VALUE, TB = sys.exc_info()
|
||||
traceback.print_exc()
|
||||
pdb.post_mortem(TB)
|
344
unprocessed/config/scripts/melConf
Executable file
344
unprocessed/config/scripts/melConf
Executable file
|
@ -0,0 +1,344 @@
|
|||
#!/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 Write in .config or .cache /mel
|
||||
# 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"}
|
||||
ACCOUNT_DEFAULTS = {
|
||||
"color": "#FFFFFF",
|
||||
"color16": "0",
|
||||
# "colormutt": "white",
|
||||
"inboxfolder": "INBOX",
|
||||
"archivefolder": "Archive",
|
||||
"draftsfolder": "Drafts",
|
||||
"sentfolder": "Sent",
|
||||
"spamfolder": "Spam",
|
||||
"trashfolder": "Trash",
|
||||
}
|
||||
|
||||
# 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]
|
||||
|
||||
for k, v in config["DEFAULT"].items():
|
||||
if k not in data:
|
||||
data[k] = v
|
||||
|
||||
for k, v in ACCOUNT_DEFAULTS.items():
|
||||
if k not in data:
|
||||
data[k] = v
|
||||
|
||||
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
|
||||
)
|
||||
mbsyncFilepath = os.path.join(os.path.expanduser("~"), ".config/mel/mbsyncrc")
|
||||
with open(mbsyncFilepath, "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)
|
||||
mbsyncFilepath = os.path.join(os.path.expanduser("~"), ".config/msmtp/config")
|
||||
with open(mbsyncFilepath, "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)
|
||||
mbsyncFilepath = os.path.join(os.path.expanduser("~"), ".config/notmuch-config")
|
||||
with open(mbsyncFilepath, "w") as f:
|
||||
f.write(notmuchStr)
|
||||
|
||||
# mutt (temp)
|
||||
|
||||
## mailboxes
|
||||
MAILBOXES_BEGIN = "mailboxes"
|
||||
|
||||
mailboxesStr = MAILBOXES_BEGIN
|
||||
for name, account in accounts.items():
|
||||
lines = "-" * (20 - len(name))
|
||||
mailboxesStr += f' "+{name}{lines}"'
|
||||
for root, dirs, files in os.walk(account["storage"]):
|
||||
if "cur" not in dirs or "new" not in dirs or "tmp" not in dirs:
|
||||
continue
|
||||
assert root.startswith(storageFull)
|
||||
path = root[len(storageFull) + 1 :]
|
||||
mailboxesStr += f' "+{path}"'
|
||||
mailboxesStr += "\n"
|
||||
mailboxesFilepath = os.path.join(os.path.expanduser("~"), ".mutt/mailboxes")
|
||||
with open(mailboxesFilepath, "w") as f:
|
||||
f.write(mailboxesStr)
|
||||
|
||||
## accounts
|
||||
# TODO html mails
|
||||
|
||||
MUTT_ACCOUNT = """set from = "{from}"
|
||||
set sendmail = "/usr/bin/msmtp -a {account}"
|
||||
set realname = "{name}"
|
||||
set spoolfile = "+{account}/{inboxfolder}"
|
||||
set mbox = "+{account}/{archivefolder}"
|
||||
set postponed = "+{account}/{draftsfolder}"
|
||||
set record = "+{account}/{sentfolder}"
|
||||
set trash = "+{account}/{trashfolder}"
|
||||
set signature = "~/.mutt/accounts/{account}.sig"
|
||||
set content_type = "text/plain"
|
||||
set sig_dashes = yes
|
||||
|
||||
color status {colormutt} default
|
||||
|
||||
macro index D \\
|
||||
"<clear-flag>N<save-message>+{account}/{trashfolder}<enter>" \\
|
||||
"move message to the trash"
|
||||
|
||||
macro index S \\
|
||||
"<clear-flag>N<save-message>+{account}/{spamfolder}<enter>" \\
|
||||
"mark message as spam"
|
||||
# vim: syntax=muttrc
|
||||
"""
|
||||
|
||||
for name, account in accounts.items():
|
||||
muttStr = MUTT_ACCOUNT.format(**account)
|
||||
|
||||
# Config
|
||||
muttFilepath = os.path.join(os.path.expanduser("~"), f".mutt/accounts/{name}")
|
||||
with open(muttFilepath, "w") as f:
|
||||
f.write(muttStr)
|
||||
|
||||
# Signature
|
||||
sigStr = account.get("sig", account.get("name", ""))
|
||||
sigFilepath = os.path.join(os.path.expanduser("~"), f".mutt/accounts/{name}.sig")
|
||||
with open(sigFilepath, "w") as f:
|
||||
f.write(sigStr)
|
||||
|
||||
MUTT_SELECTOR = """
|
||||
set folder = "{storage}"
|
||||
source ~/.mutt/mailboxes
|
||||
|
||||
source ~/.mutt/accounts/{main[account]}
|
||||
|
||||
{hooks}
|
||||
|
||||
source ~/.mutt/custom
|
||||
|
||||
# vim: syntax=muttrc
|
||||
"""
|
||||
|
||||
selectStr = ""
|
||||
hooks = ""
|
||||
for name, account in accounts.items():
|
||||
hooks += f"folder-hook {name}/* source ~/.mutt/accounts/{name}\n"
|
||||
selectStr += MUTT_SELECTOR.format(**general, hooks=hooks)
|
||||
selectFilepath = os.path.join(os.path.expanduser("~"), ".mutt/muttrc")
|
||||
with open(selectFilepath, "w") as f:
|
||||
f.write(selectStr)
|
||||
|
||||
## Color
|
||||
for name, account in accounts.items():
|
||||
# Config
|
||||
colorFilepath = os.path.join(
|
||||
os.path.expanduser("~"), f'{general["storage"]}/{name}/color'
|
||||
)
|
||||
with open(colorFilepath, "w") as f:
|
||||
f.write(account["color"])
|
39
unprocessed/config/scripts/musiqueBof
Executable file
39
unprocessed/config/scripts/musiqueBof
Executable file
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
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)
|
83
unprocessed/config/scripts/nv
Executable file
83
unprocessed/config/scripts/nv
Executable file
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Extracted frm nvidia-xrun
|
||||
DRY_RUN=0
|
||||
|
||||
function execute {
|
||||
if [[ ${DRY_RUN} -eq 1 ]]
|
||||
then
|
||||
echo ">>Dry run. Command: $*"
|
||||
else
|
||||
eval $*
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function turn_off_gpu {
|
||||
if [[ "$REMOVE_DEVICE" == '1' ]]; then
|
||||
echo 'Removing Nvidia bus from the kernel'
|
||||
execute "sudo tee /sys/bus/pci/devices/${DEVICE_BUS_ID}/remove <<<1"
|
||||
else
|
||||
echo 'Enabling powersave for the graphic card'
|
||||
execute "sudo tee /sys/bus/pci/devices/${DEVICE_BUS_ID}/power/control <<<auto"
|
||||
fi
|
||||
|
||||
echo 'Enabling powersave for the PCIe controller'
|
||||
execute "sudo tee /sys/bus/pci/devices/${CONTROLLER_BUS_ID}/power/control <<<auto"
|
||||
}
|
||||
|
||||
function turn_on_gpu {
|
||||
echo 'Turning the PCIe controller on to allow card rescan'
|
||||
execute "sudo tee /sys/bus/pci/devices/${CONTROLLER_BUS_ID}/power/control <<<on"
|
||||
|
||||
echo 'Waiting 1 second'
|
||||
execute "sleep 1"
|
||||
|
||||
if [[ ! -d /sys/bus/pci/devices/${DEVICE_BUS_ID} ]]; then
|
||||
echo 'Rescanning PCI devices'
|
||||
execute "sudo tee /sys/bus/pci/rescan <<<1"
|
||||
echo "Waiting ${BUS_RESCAN_WAIT_SEC} second for rescan"
|
||||
execute "sleep ${BUS_RESCAN_WAIT_SEC}"
|
||||
fi
|
||||
|
||||
echo 'Turning the card on'
|
||||
execute "sudo tee /sys/bus/pci/devices/${DEVICE_BUS_ID}/power/control <<<on"
|
||||
}
|
||||
|
||||
function load_modules {
|
||||
for module in "${MODULES_LOAD[@]}"
|
||||
do
|
||||
echo "Loading module ${module}"
|
||||
execute "sudo modprobe ${module}"
|
||||
done
|
||||
}
|
||||
|
||||
function unload_modules {
|
||||
for module in "${MODULES_UNLOAD[@]}"
|
||||
do
|
||||
echo "Unloading module ${module}"
|
||||
execute "sudo modprobe -r ${module}"
|
||||
done
|
||||
}
|
||||
|
||||
if [[ "$1" == "-d" ]]
|
||||
then
|
||||
DRY_RUN=1
|
||||
shift 1
|
||||
fi
|
||||
|
||||
# load config file
|
||||
. /etc/default/nvidia-xrun
|
||||
|
||||
if [ "$1" == "on" ]
|
||||
then
|
||||
turn_on_gpu
|
||||
load_modules
|
||||
elif [ "$1" == "off" ]
|
||||
then
|
||||
unload_modules
|
||||
turn_off_gpu
|
||||
else
|
||||
echo "Usage: $0 [on|off]"
|
||||
fi
|
||||
|
1043
unprocessed/config/scripts/package-lock.json
generated
Normal file
1043
unprocessed/config/scripts/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
22
unprocessed/config/scripts/package.json
Normal file
22
unprocessed/config/scripts/package.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "geoffreyfrogeye-dotfiles-scripts",
|
||||
"version": "1.0.0",
|
||||
"description": "Stores dependencies used for GeoffreyFrogeye's dotfiles scripts.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.frogeye.fr/geoffrey/dotfiles"
|
||||
},
|
||||
"author": "GeoffreyFrogeye",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"highlight.js": "^9.11.0",
|
||||
"html-pdf": "^2.1.0",
|
||||
"katex": "^0.7.1",
|
||||
"marked": "^0.3.6",
|
||||
"yargs": "^8.0.1"
|
||||
}
|
||||
}
|
103
unprocessed/config/scripts/proxy
Executable file
103
unprocessed/config/scripts/proxy
Executable file
|
@ -0,0 +1,103 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Allows easy manipulation of the proxy variables
|
||||
|
||||
function proxy_set_help {
|
||||
echo "Usage: $0 set ADDRESS"
|
||||
echo
|
||||
echo "Arguments:"
|
||||
echo " ADDRESS Address of the proxy"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo ' eval "$(proxy set http://proxy.mycompany.com:3128/)"'
|
||||
return 0
|
||||
}
|
||||
|
||||
function proxy_set {
|
||||
if [ -z $1 ]; then
|
||||
proxy_set_help
|
||||
return 1
|
||||
fi
|
||||
echo "export http_proxy='$1'"
|
||||
echo "export https_proxy='$1'"
|
||||
echo "export ftp_proxy='$1'"
|
||||
echo "export rsync_proxy='$1'"
|
||||
exit 0
|
||||
}
|
||||
|
||||
function proxy_setup_help {
|
||||
echo "Usage: $0 setup"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo " proxy_set # Then eval the output"
|
||||
return 0
|
||||
}
|
||||
function proxy_setup {
|
||||
export no_proxy="localhost,127.0.0.1,localaddress,.localdomain.com"
|
||||
|
||||
if (( $# > 0 )); then
|
||||
valid=$(echo $@ | sed -n 's/\([0-9]\{1,3\}.\)\{4\}:\([0-9]\+\)/&/p')
|
||||
if [[ $valid != $@ ]]; then
|
||||
>&2 echo "Invalid address"
|
||||
return 1
|
||||
fi
|
||||
proxy_set "http://$1/"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -n "User: "; read username
|
||||
if [[ $username != "" ]]; then
|
||||
echo -n "Password: "
|
||||
read -es password
|
||||
local pre="$username:$password@"
|
||||
fi
|
||||
|
||||
echo -n "Server: "; read server
|
||||
echo -n "Port: "; read port
|
||||
proxy_set "http://$pre$server:$port/"
|
||||
return 0
|
||||
}
|
||||
|
||||
function proxy_off_help {
|
||||
echo "Usage: $0 off"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo ' eval $(proxy off)'
|
||||
return 0
|
||||
}
|
||||
function proxy_off {
|
||||
echo 'unset http_proxy'
|
||||
echo 'unset https_proxy'
|
||||
echo 'unset ftp_proxy'
|
||||
echo 'unset rsync_proxy'
|
||||
return 0
|
||||
}
|
||||
|
||||
function proxy_help {
|
||||
command="$1"
|
||||
if [ -n "$command" ]; then
|
||||
if type "proxy_${command}_help" &> /dev/null; then
|
||||
shift
|
||||
"proxy_${command}_help" "$@"
|
||||
return $?
|
||||
fi
|
||||
fi
|
||||
echo "Usage: $0 COMMAND"
|
||||
echo
|
||||
echo "Commands:"
|
||||
echo " setup Interactively setup proxy"
|
||||
echo " set Set proxy from address"
|
||||
echo " off Turn off proxy"
|
||||
echo " help Get help with commands"
|
||||
return 0
|
||||
}
|
||||
|
||||
# MAIN
|
||||
command="$1"
|
||||
shift
|
||||
if type "proxy_$command" &> /dev/null; then
|
||||
"proxy_$command" "$@"
|
||||
else
|
||||
proxy_help
|
||||
fi
|
||||
|
14
unprocessed/config/scripts/remcrlf
Executable file
14
unprocessed/config/scripts/remcrlf
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
#! nix-shell -i bash --pure
|
||||
#! nix-shell -p bash
|
||||
|
||||
# Removes CRLF (^M or \r) from a file
|
||||
|
||||
#sed -e "s/^M//" "$1" -i
|
||||
|
||||
tmpfile=$(mktemp)
|
||||
|
||||
cp "$1" "$tmpfile"
|
||||
tr -d '\r' < "$tmpfile" > "$1"
|
||||
rm "$tmpfile"
|
||||
|
24
unprocessed/config/scripts/tunnel
Executable file
24
unprocessed/config/scripts/tunnel
Executable file
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Dynamically determines if the ssh connection
|
||||
# is to be proxied through `proxytunnel`
|
||||
# To be used with ssh_config ProxyCommand
|
||||
|
||||
host="$1"
|
||||
port="$2"
|
||||
|
||||
if [ -z "$http_proxy" ]; then
|
||||
socat "TCP:$host:$port" -
|
||||
else
|
||||
proxy=$(echo "$http_proxy" | sed 's/^https\?:\/\///' | sed 's/\/$//')
|
||||
port=443 # Most won't want this
|
||||
echo "$proxy" | grep '@'
|
||||
if [ $? == 0 ]; then
|
||||
user=$(echo $proxy | cut -d '@' -f 2)
|
||||
proxy=$(echo $proxy | cut -d '@' -f 1)
|
||||
proxytunnel -p $proxy -P $user -d $host:$port
|
||||
else
|
||||
proxytunnel -p $proxy -d $host:$port
|
||||
fi
|
||||
fi
|
||||
|
193
unprocessed/config/scripts/tvshow
Executable file
193
unprocessed/config/scripts/tvshow
Executable file
|
@ -0,0 +1,193 @@
|
|||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0103,W0621
|
||||
|
||||
# pip install tmdbv3api
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import typing
|
||||
|
||||
import tmdbv3api
|
||||
|
||||
# TODO Override files without warning
|
||||
# TODO Dry run mode (just comment the last line ^^)
|
||||
|
||||
# Typing
|
||||
|
||||
Episode = typing.Any # TODO
|
||||
|
||||
# Constants
|
||||
|
||||
API_KEY_PASS_PATH = "http/themoviedb.org"
|
||||
VIDEO_EXTENSIONS = {"mp4", "mkv", "avi", "webm"}
|
||||
|
||||
# Functions
|
||||
|
||||
|
||||
def get_pass_data(path: str) -> typing.Dict[str, str]:
|
||||
"""
|
||||
Returns the data stored in the Unix password manager
|
||||
given its path.
|
||||
"""
|
||||
run = subprocess.run(["pass", path], stdout=subprocess.PIPE, check=True)
|
||||
lines = run.stdout.decode().split("\n")
|
||||
data = dict()
|
||||
data["pass"] = lines[0]
|
||||
for line in lines[1:]:
|
||||
match = re.match(r"(\w+): ?(.+)", line)
|
||||
if match:
|
||||
data[match[1]] = match[2]
|
||||
return data
|
||||
|
||||
|
||||
def confirm(text: str) -> bool:
|
||||
res = input(text + " [yn] ")
|
||||
while res not in ("y", "n"):
|
||||
res = input("Please answer with y or n: ")
|
||||
return res == "y"
|
||||
|
||||
|
||||
def episode_identifier(episode: typing.Any) -> str:
|
||||
return (
|
||||
f"S{episode['season_number']:02d}E"
|
||||
+ f"{episode['episode_number']:02d} {episode['name']}"
|
||||
)
|
||||
|
||||
|
||||
dryrun = "-n" in sys.argv
|
||||
if dryrun:
|
||||
dryrun = True
|
||||
sys.argv.remove("-n")
|
||||
|
||||
|
||||
# Connecting to TMBDB
|
||||
tmdb = tmdbv3api.TMDb()
|
||||
tmdb.api_key = get_pass_data(API_KEY_PASS_PATH)["api"]
|
||||
tmdb.language = sys.argv[1]
|
||||
|
||||
# Searching the TV show name (by current directory name)
|
||||
tv = tmdbv3api.TV()
|
||||
season = tmdbv3api.Season()
|
||||
if len(sys.argv) >= 3:
|
||||
show_name = sys.argv[2]
|
||||
else:
|
||||
show_name = os.path.split(os.path.realpath(os.path.curdir))[1]
|
||||
if "(" in show_name:
|
||||
show_name = show_name.split("(")[0].strip()
|
||||
|
||||
search = tv.search(show_name)
|
||||
|
||||
# Asking the user to select the one
|
||||
show = None
|
||||
|
||||
for res in search:
|
||||
print(f"#{res.id} {res.name} ({res.first_air_date[:4]}): {res.overview}")
|
||||
if confirm("Is this the show for this folder?"):
|
||||
show = tv.details(res.id)
|
||||
break
|
||||
|
||||
if not show:
|
||||
print("Could not find a matching " + f"show on TheMovieDatabase for {show_name}.")
|
||||
sys.exit(1)
|
||||
|
||||
# Retrieving all the episode of the show
|
||||
episodes: typing.List[Episode] = list()
|
||||
|
||||
print(f"List of episodes for {show.name}:")
|
||||
for season_number in range(0, show.number_of_seasons + 1):
|
||||
season_details = season.details(show.id, season_number)
|
||||
|
||||
try:
|
||||
season_details.episodes
|
||||
except AttributeError:
|
||||
continue
|
||||
|
||||
for episode in season_details.episodes:
|
||||
episodes.append(episode)
|
||||
print(f"- {episode_identifier(episode)}")
|
||||
|
||||
# Finding movie files in the folder
|
||||
print("List of video files in this folder")
|
||||
videos: typing.List[typing.Tuple[str, str]] = list()
|
||||
for root, dirs, files in os.walk(os.path.curdir):
|
||||
for filename in files:
|
||||
basename, ext = os.path.splitext(filename)
|
||||
real_ext = ext[1:].lower()
|
||||
if real_ext not in VIDEO_EXTENSIONS:
|
||||
continue
|
||||
videos.append((root, filename))
|
||||
print(f"- {filename}")
|
||||
|
||||
|
||||
def get_episode(season_number: int, episode_number: int) -> typing.Optional[Episode]:
|
||||
# TODO Make more efficient using indexing
|
||||
for episode in episodes:
|
||||
if (
|
||||
episode["season_number"] == season_number
|
||||
and episode["episode_number"] == episode_number
|
||||
):
|
||||
return episode
|
||||
return None
|
||||
|
||||
|
||||
# Matching movie files to episode
|
||||
associations: typing.List[typing.Tuple[typing.Tuple[str, str], Episode]] = list()
|
||||
for video in videos:
|
||||
root, filename = video
|
||||
match = re.search(r"S(\d+)E(\d+)", filename)
|
||||
print(f"Treating file: {root}/{filename}")
|
||||
episode = None
|
||||
season_number = 0
|
||||
episode_number = 0
|
||||
while not episode:
|
||||
if match:
|
||||
season_number = int(match[1])
|
||||
episode_number = int(match[2])
|
||||
else:
|
||||
try:
|
||||
season_number = int(input("Season number ?"))
|
||||
episode_number = int(input("Episode number ?"))
|
||||
except ValueError:
|
||||
continue
|
||||
if season_number < 0 and episode_number < 0:
|
||||
break
|
||||
match = None
|
||||
episode = get_episode(season_number, episode_number)
|
||||
if not episode:
|
||||
print(
|
||||
f" could not find episode S{season_number:02d}E{episode_number:02d} in TMBD"
|
||||
)
|
||||
|
||||
# Skip
|
||||
if not episode:
|
||||
if season_number < -1 and episode_number < -1:
|
||||
# Skip all
|
||||
break
|
||||
# Skip one
|
||||
continue
|
||||
|
||||
associations.append((video, episode))
|
||||
print(f" associated to: {episode_identifier(episode)}")
|
||||
|
||||
|
||||
# Rename video files
|
||||
for association in associations:
|
||||
video, episode = association
|
||||
root, filename = video
|
||||
basename, ext = os.path.splitext(filename)
|
||||
new_name = f"{show.name} ({show.first_air_date[:4]}) {episode_identifier(episode)}"
|
||||
# Rename all file with the same base name as the original file so we
|
||||
# can rename nfo files and subtitles (only one though)
|
||||
for a_filename in os.listdir(root):
|
||||
a_basename, a_ext = os.path.splitext(a_filename)
|
||||
if a_basename == basename:
|
||||
old_path = os.path.join(root, a_filename)
|
||||
new_path = os.path.join(root, new_name + a_ext)
|
||||
if old_path == new_path:
|
||||
continue
|
||||
|
||||
print(old_path, "->", new_path)
|
||||
if not dryrun:
|
||||
os.rename(old_path, new_path)
|
3
unprocessed/config/scripts/updatedate
Executable file
3
unprocessed/config/scripts/updatedate
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
echo ssh "$1" sudo date --set="'$(date -R)'"
|
1
unprocessed/config/systemd/user/.gitignore
vendored
Normal file
1
unprocessed/config/systemd/user/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.wants/*
|
10
unprocessed/config/systemd/user/ipfs.service
Normal file
10
unprocessed/config/systemd/user/ipfs.service
Normal file
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=IPFS daemon
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/ipfs daemon
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
6
unprocessed/config/systemd/user/melfetch.service
Normal file
6
unprocessed/config/systemd/user/melfetch.service
Normal file
|
@ -0,0 +1,6 @@
|
|||
[Unit]
|
||||
Description=Meh mail client new mail fetcher
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/home/geoffrey/.config/scripts/mel fetch
|
10
unprocessed/config/systemd/user/melfetch.timer
Normal file
10
unprocessed/config/systemd/user/melfetch.timer
Normal file
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=Meh mail client fetcher timer
|
||||
|
||||
[Timer]
|
||||
OnBootSec=2m
|
||||
OnUnitActiveSec=5m
|
||||
Unit=melfetch.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
10
unprocessed/config/systemd/user/urxvtd.service
Normal file
10
unprocessed/config/systemd/user/urxvtd.service
Normal file
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=Urxvt Terminal Daemon
|
||||
Requires=urxvtd.socket
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/urxvtd -o -q
|
||||
Environment=RXVT_SOCKET=%t/urxvtd-%H
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
9
unprocessed/config/systemd/user/urxvtd.socket
Normal file
9
unprocessed/config/systemd/user/urxvtd.socket
Normal file
|
@ -0,0 +1,9 @@
|
|||
[Unit]
|
||||
Description=urxvt daemon (socket activation)
|
||||
Documentation=man:urxvtd(1) man:urxvt(1)
|
||||
|
||||
[Socket]
|
||||
ListenStream=%t/urxvtd-%H
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
13
unprocessed/config/systemd/user/x0vncserver.service
Normal file
13
unprocessed/config/systemd/user/x0vncserver.service
Normal file
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=Remote desktop service (VNC)
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
# wait for Xorg started by ${USER}
|
||||
ExecStartPre=/bin/sh -c 'while ! pgrep -U "$USER" Xorg; do sleep 2; done'
|
||||
ExecStart=/usr/bin/x0vncserver -rfbauth /home/${USER}/.vnc/passwd
|
||||
# or login with your username & password
|
||||
#ExecStart=/usr/bin/x0vncserver -PAMService=login -PlainUsers=${USER} -SecurityTypes=TLSPlain
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
4
unprocessed/config/todoman/todoman.conf
Normal file
4
unprocessed/config/todoman/todoman.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
[main]
|
||||
path = ~/.cache/vdirsyncer/calendars/*
|
||||
default_list = Personnel
|
||||
humanize = True
|
1
unprocessed/config/tridactyl/themes/.gitignore
vendored
Normal file
1
unprocessed/config/tridactyl/themes/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
theme.css
|
105
unprocessed/config/tridactyl/tridactylrc
Normal file
105
unprocessed/config/tridactyl/tridactylrc
Normal file
|
@ -0,0 +1,105 @@
|
|||
" Trydactyl (vim-like keybindings for Firefox) configuration file
|
||||
" Make sure to have the native messenger installed (:native)
|
||||
|
||||
" Fair part took from https://gist.github.com/BurntSushi/393546a65db38d57cedcfd72c6d89bf3
|
||||
|
||||
" Reset parameters to tridactyl's default
|
||||
" so there's nothing being kept when :source ing
|
||||
sanitise tridactyllocal tridactylsync
|
||||
|
||||
colors dark
|
||||
" For when https://github.com/bezmi/base16-tridactyl/issues/2 will be closed
|
||||
" colors theme
|
||||
|
||||
" I use H and L for moving accross windows,
|
||||
" so I'd rather use those for tabs too
|
||||
bind H tabprev
|
||||
bind L tabnext
|
||||
bind J back
|
||||
bind K forward
|
||||
|
||||
" I prefer the qutebrowser-style keybindings for opening stuff in a new tab
|
||||
" Also it is consistent with f/F p/P s/S... in tridactyl itself
|
||||
bind o fillcmdline open
|
||||
bind O fillcmdline tabopen
|
||||
" Let's reuse t/T to use that useful feature of editing the current URL before
|
||||
" opening
|
||||
" bind t current_url open
|
||||
" bint T current_url tabopen
|
||||
bind t composite url2args | fillcmdline open
|
||||
bind T composite url2args | fillcmdline tabopen
|
||||
" We will let the w/W the same, as in my case tab=window
|
||||
|
||||
" Add to ...
|
||||
unbind a
|
||||
unbind A
|
||||
|
||||
" Reorder bookmarks/quickmarks
|
||||
bind M current_url bmark
|
||||
|
||||
" Activate the rudimentary search feature
|
||||
" Not activated by default because `incsearch` is not implemented,
|
||||
" so since I don't know what it is I don't care about it
|
||||
bind / fillcmdline find
|
||||
bind ? fillcmdline find -?
|
||||
bind n findnext 1
|
||||
bind N findnext -1
|
||||
" Remove search highlighting
|
||||
bind ,<Space> nohlsearch
|
||||
|
||||
" Ctrl-F should use the browser's native 'find' functionality.
|
||||
unbind <C-f>
|
||||
|
||||
" Subscribe to RSS
|
||||
bind af rssexec
|
||||
set rsscmd tabopen add_rss %u
|
||||
set searchurls.add_rss https://rss.frogeye.fr/i/?c=feed&a=add&url_rss=%s
|
||||
|
||||
bind as composite get_current_url | tabopen add_links
|
||||
set searchurls.add_links https://links.frogeye.fr/?post=%s
|
||||
|
||||
" New tab page (this link won't work for you :P)
|
||||
set newtab https://geoffrey.frogeye.fr/home.php
|
||||
|
||||
" Search engines
|
||||
set searchengine qwant
|
||||
|
||||
set searchurls.arch https://wiki.archlinux.org/?search=%s
|
||||
set searchurls.archp https://www.archlinux.org/packages/?q=%s
|
||||
set searchurls.aur https://aur.archlinux.org/packages/?K=%s
|
||||
set searchurls.aw http://www.amp-what.com/unicode/search/%s
|
||||
set searchurls.bulbapedia https://bulbapedia.bulbagarden.net/w/index.php?title=Special:Search&search=%s&go=Go
|
||||
set searchurls.fdroid https://search.f-droid.org/?q=%s
|
||||
set searchurls.gfr https://www.google.fr/search?hl=fr&q=%s
|
||||
set searchurls.g https://www.google.fr/search?q=%s
|
||||
set searchurls.gihpy https://giphy.com/search/%s
|
||||
set searchurls.gi http://images.google.com/search?q=%s
|
||||
set searchurls.github https://github.com/search?q=%s
|
||||
set searchurls.npm https://www.npmjs.com/search?q=%s
|
||||
set searchurls.pypi https://pypi.org/search/?q=%s
|
||||
set searchurls.python https://docs.python.org/3/search.html?q=%s
|
||||
set searchurls.qwant https://www.qwant.com/?t=web&q=%s
|
||||
set searchurls.invidious https://invidious.drycat.fr/search?q=%s
|
||||
set searchurls.id https://invidious.drycat.fr/search?q=%s
|
||||
set searchurls.wa https://www.wolframalpha.com/input/?i=%s
|
||||
set searchurls.yt https://www.youtube.com/results?search_query=%s
|
||||
|
||||
" Firefox GUI
|
||||
" This can still be shown with F6!
|
||||
" guiset_quiet gui none
|
||||
|
||||
" Never autofocus
|
||||
set allowautofocus false
|
||||
|
||||
" Hide the mode indicator in the lower right corner
|
||||
set modeindicator false
|
||||
|
||||
" Hint chars
|
||||
" As I take more time finding the key I need to type (even if it's on the home
|
||||
" row) than moving my fingers to get it, I prefer to reduce the number of keys
|
||||
" to type rather than the movement of my fingers, hence the big amount of
|
||||
" hint chars
|
||||
set hintchars asdfhjklgqweryuioptzxcbnmv1234678905
|
||||
|
||||
" This will have to do until someone writes us a nice syntax file :)
|
||||
" vim: set filetype=vim:
|
0
unprocessed/config/vdirsyncer/.dfrecur
Normal file
0
unprocessed/config/vdirsyncer/.dfrecur
Normal file
70
unprocessed/config/vdirsyncer/config
Normal file
70
unprocessed/config/vdirsyncer/config
Normal file
|
@ -0,0 +1,70 @@
|
|||
# An example configuration for vdirsyncer.
|
||||
#
|
||||
# Move it to ~/.cache/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 = "~/.cache/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 = "~/.cache/vdirsyncer/contacts/"
|
||||
fileext = ".vcf"
|
||||
|
||||
[storage geoffrey_contacts_remote]
|
||||
type = "carddav"
|
||||
url = "https://cloud.frogeye.fr/remote.php/dav"
|
||||
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 = "~/.cache/vdirsyncer/calendars/"
|
||||
fileext = ".ics"
|
||||
|
||||
[storage geoffrey_calendar_remote]
|
||||
type = "caldav"
|
||||
url = "https://cloud.frogeye.fr/remote.php/dav"
|
||||
username = "geoffrey"
|
||||
password.fetch = ["command", "sh", "-c", "cat ~/.config/vdirsyncer/pass"]
|
103
unprocessed/config/xinitrc
Executable file
103
unprocessed/config/xinitrc
Executable file
|
@ -0,0 +1,103 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# ~/.xinitrc
|
||||
#
|
||||
# Executed by startx
|
||||
#
|
||||
|
||||
# Execute system modules, just in case
|
||||
if [ -d /etc/X11/xinit/xinitrc.d ]; then
|
||||
for f in /etc/X11/xinit/xinitrc.d/*; do
|
||||
[ -x "$f" ] && . "$f"
|
||||
done
|
||||
unset f
|
||||
fi
|
||||
|
||||
# Load Xresources
|
||||
[ -f ~/.config/Xresources/main ] && xrdb -I"$HOME" ~/.config/Xresources/main
|
||||
|
||||
# Disable the bell
|
||||
xset b off
|
||||
|
||||
# Folders to search for desktop environments (DE) in
|
||||
sessions_dirs="/usr/share/xsessions"
|
||||
|
||||
# If we have locally installed DE try them before system ones
|
||||
sessions_dir_local="$HOME/.local/share/xsessions"
|
||||
if [ -d "$sessions_dir_local" ]
|
||||
then
|
||||
sessions_dirs="$sessions_dir_local $sessions_dirs"
|
||||
fi
|
||||
|
||||
# If we have junest installed DE try them before all others
|
||||
sessions_dir_junest="$HOME/.junest/usr/share/xsessions"
|
||||
if [ -d "$sessions_dir_junest" ]
|
||||
then
|
||||
sessions_dirs="$sessions_dir_junest $sessions_dirs"
|
||||
fi
|
||||
|
||||
startSession() {
|
||||
session_dir="$1"
|
||||
session_name="$2"
|
||||
|
||||
session_file="${session_dir}/${session_name}.desktop"
|
||||
executable="$(grep ^Exec= "$session_file" | cut -d'=' -f2)"
|
||||
# TODO Does this work with parameters?
|
||||
# gnome-classic might need some
|
||||
|
||||
# If this is a Junest DE, we need to wrap it
|
||||
if [ "$sessions_dir" = "$sessions_dir_junest" ]
|
||||
then
|
||||
# Some DMs enforce that to you,
|
||||
# which shows warning on Junest
|
||||
unset LD_PRELOAD
|
||||
|
||||
# The intended way:
|
||||
# exec ~/.local/bin/junest "$executable" $parameters
|
||||
# Too restricted to the outside (e.g. Yubikey isn't accessible)
|
||||
|
||||
# The custom way
|
||||
exec ~/.local/bin/junest --backend-args "--dev-bind /run /run" "$executable" $parameters
|
||||
|
||||
# The fallback wrappers way
|
||||
# export PATH="$PATH:~/.junest/usr/bin_wrappers"
|
||||
# exec "$executable" $parameters
|
||||
# Should work but doesn't, I forgot why
|
||||
|
||||
# The "I do what I want" way
|
||||
#exec bwrap --bind $HOME/.junest / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev-bind /dev /dev --dev-bind /run /run "$executable" $parameters
|
||||
# Even Alacritty doesn't work here
|
||||
|
||||
fi
|
||||
|
||||
exec "$executable" $parameters
|
||||
}
|
||||
|
||||
trySession() { # session_name
|
||||
session_name="$1"
|
||||
for sessions_dir in $sessions_dirs
|
||||
do
|
||||
session_file="$sessions_dir/${session_name}.desktop"
|
||||
if [ -f "$session_file" ]
|
||||
then
|
||||
startSession "$sessions_dir" "$session_name"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
if [ -n "$1" ]
|
||||
then
|
||||
trySession "$1"
|
||||
else
|
||||
trySession i3
|
||||
trySession xfce4
|
||||
trySession mate
|
||||
trySession plasma
|
||||
trySession gnome
|
||||
trySession kde
|
||||
fi
|
||||
|
||||
# If we found nothing by then, RIP
|
||||
echo "Couldn't find a suitable DM."
|
||||
exit 1
|
||||
|
1
unprocessed/termux/.gitignore
vendored
Normal file
1
unprocessed/termux/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
colors.properties
|
2
unprocessed/termux/bin/.gitignore
vendored
Normal file
2
unprocessed/termux/bin/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
2
unprocessed/termux/boot/autosvc
Executable file
2
unprocessed/termux/boot/autosvc
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
autosvc
|
4
unprocessed/termux/boot/symlink
Executable file
4
unprocessed/termux/boot/symlink
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
echo "/system/bin/mount -o remount,rw /" | tsu
|
||||
echo "ln -s /data/data/com.termux/files/usr /usr" | tsu
|
||||
echo "/system/bin/mount -o remount,ro /" | tsu
|
BIN
unprocessed/termux/font.ttf
Normal file
BIN
unprocessed/termux/font.ttf
Normal file
Binary file not shown.
39
unprocessed/termux/scripts/autosvc
Executable file
39
unprocessed/termux/scripts/autosvc
Executable file
|
@ -0,0 +1,39 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
#
|
||||
# Start services based on phone state
|
||||
#
|
||||
|
||||
function act() {
|
||||
# Services that should be always on
|
||||
|
||||
service sshd start
|
||||
service autosvc start
|
||||
|
||||
# Services that should be on depending on battery
|
||||
|
||||
bat="$(termux-battery-status | jq -r '.status')"
|
||||
|
||||
if [[ "$bat" == "FULL" || "$bat" == "CHARGING" ]]
|
||||
then
|
||||
service syncthing start
|
||||
else
|
||||
service syncthing stop
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$1" == "-d" ]
|
||||
then
|
||||
# Daemon mode
|
||||
while true
|
||||
do
|
||||
echo 29
|
||||
act &>> $HOME/.local/log/autosvc.log
|
||||
echo 31
|
||||
sleep 60
|
||||
done
|
||||
else
|
||||
# One shot mode
|
||||
# TODO Soft-code the log destination & the program arguments
|
||||
act
|
||||
fi
|
||||
|
22
unprocessed/termux/scripts/service
Executable file
22
unprocessed/termux/scripts/service
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
#
|
||||
# Run & stop Termux services
|
||||
#
|
||||
|
||||
if [ $# -lt 1 ]
|
||||
then
|
||||
echo "Expected a service name as first argument."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
service="$1"
|
||||
file="$HOME/.termux/services/$1"
|
||||
|
||||
if [ -f "$file" ]
|
||||
then
|
||||
shift
|
||||
$file "$@"
|
||||
else
|
||||
echo "Service not found: $1"
|
||||
fi
|
||||
|
11
unprocessed/termux/scripts/sudo
Executable file
11
unprocessed/termux/scripts/sudo
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
#
|
||||
# Substitution for sudo
|
||||
#
|
||||
|
||||
if [ "$(whoami)" != 'root' ]
|
||||
then
|
||||
echo "$@" | tsu
|
||||
else
|
||||
"$@"
|
||||
fi
|
6
unprocessed/termux/scripts/tsu.old
Executable file
6
unprocessed/termux/scripts/tsu.old
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)"
|
3
unprocessed/termux/scripts/yt
Executable file
3
unprocessed/termux/scripts/yt
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/data/data/com.termux/files/usr/bin/env bash
|
||||
cd ~/storage/shared/Movies/NewPipe/
|
||||
youtube-dl --all-subs "${@: -1}"
|
59
unprocessed/termux/services/autosvc
Executable file
59
unprocessed/termux/services/autosvc
Executable file
|
@ -0,0 +1,59 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
#
|
||||
# Charge services based on phone state
|
||||
#
|
||||
|
||||
PIDFILE="$HOME/.local/run/autosvc.pid"
|
||||
LOGFILE="$HOME/.local/log/autosvc.log"
|
||||
|
||||
start() {
|
||||
printf "Starting autosvc: "
|
||||
start-stop-daemon -p "$PIDFILE" -x /data/data/com.termux/files/usr/bin/bash -S -b -m -- "$HOME/.termux/scripts/autosvc" -d -l "$LOGFILE"
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
stop() {
|
||||
printf "Stopping autosvc: "
|
||||
start-stop-daemon -p "$PIDFILE" -x /data/data/com.termux/files/usr/bin/bash -K
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
status() {
|
||||
printf "autosvc: "
|
||||
PID="$(cat "$PIDFILE" 2> /dev/null)"
|
||||
if [[ -n "$PID" && -d "/proc/$PID" ]]
|
||||
then
|
||||
echo "running"
|
||||
else
|
||||
echo "stopped"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
tail "$@" "$LOGFILE"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
restart|reload)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
log)
|
||||
shift
|
||||
log "$@"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status|log}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $?
|
59
unprocessed/termux/services/crond
Executable file
59
unprocessed/termux/services/crond
Executable file
|
@ -0,0 +1,59 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
#
|
||||
# Start crond
|
||||
#
|
||||
|
||||
PIDFILE="$HOME/.local/run/crond.pid"
|
||||
LOGFILE="$HOME/.local/log/crond.log"
|
||||
|
||||
start() {
|
||||
printf "Starting crond: "
|
||||
start-stop-daemon -p "$PIDFILE" -x crond -S -b -m -- -f -L "$LOGFILE"
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
stop() {
|
||||
printf "Stopping crond: "
|
||||
start-stop-daemon -p "$PIDFILE" -x crond -K
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
status() {
|
||||
printf "crond: "
|
||||
PID="$(cat "$PIDFILE" 2> /dev/null)"
|
||||
if [[ -n "$PID" && -d "/proc/$PID" ]]
|
||||
then
|
||||
echo "running"
|
||||
else
|
||||
echo "stopped"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
tail "$@" "$LOGFILE"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
restart|reload)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
log)
|
||||
shift
|
||||
log "$@"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status|log}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $?
|
59
unprocessed/termux/services/sshd
Executable file
59
unprocessed/termux/services/sshd
Executable file
|
@ -0,0 +1,59 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
#
|
||||
# Start SSH server daemon
|
||||
#
|
||||
|
||||
PIDFILE="/data/data/com.termux/files/usr/var/run/sshd.pid"
|
||||
LOGFILE="$HOME/.local/log/sshd.log"
|
||||
|
||||
start() {
|
||||
printf "Starting SSHD: "
|
||||
start-stop-daemon -p "$PIDFILE" -x sshd -S -- -E "$LOGFILE"
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
stop() {
|
||||
printf "Stopping SSHD: "
|
||||
start-stop-daemon -p "$PIDFILE" -x sshd -K
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
status() {
|
||||
printf "SSHD: "
|
||||
PID="$(cat "$PIDFILE" 2> /dev/null)"
|
||||
if [[ -n "$PID" && -d "/proc/$PID" ]]
|
||||
then
|
||||
echo "running"
|
||||
else
|
||||
echo "stopped"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
tail "$@" "$LOGFILE"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
restart|reload)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
log)
|
||||
shift
|
||||
log "$@"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status|log}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $?
|
59
unprocessed/termux/services/syncthing
Executable file
59
unprocessed/termux/services/syncthing
Executable file
|
@ -0,0 +1,59 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
#
|
||||
# Start Syncthing synchronization service
|
||||
#
|
||||
|
||||
PIDFILE="$HOME/.local/run/syncthing.pid"
|
||||
LOGFILE="$HOME/.local/log/syncthing.log"
|
||||
|
||||
start() {
|
||||
printf "Starting Syncthing: "
|
||||
sudo start-stop-daemon -p "$PIDFILE" -x syncthing -S -b -N 5 -m -- -logfile="$LOGFILE" -home ~/.config/syncthing
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
stop() {
|
||||
printf "Stopping Syncthing: "
|
||||
sudo start-stop-daemon -p "$PIDFILE" -x syncthing -K
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
status() {
|
||||
printf "Syncthing: "
|
||||
PID="$(sudo cat "$PIDFILE" 2> /dev/null)"
|
||||
if [[ -n "$PID" && -d "/proc/$PID" ]]
|
||||
then
|
||||
echo "running"
|
||||
else
|
||||
echo "stopped"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
sudo tail "$@" "$LOGFILE"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
restart|reload)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
log)
|
||||
shift
|
||||
log "$@"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status|log}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $?
|
59
unprocessed/termux/services/syncthing.user
Executable file
59
unprocessed/termux/services/syncthing.user
Executable file
|
@ -0,0 +1,59 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
#
|
||||
# Start Syncthing synchronization service
|
||||
#
|
||||
|
||||
PIDFILE="$HOME/.local/run/syncthing.pid"
|
||||
LOGFILE="$HOME/.local/log/syncthing.log"
|
||||
|
||||
start() {
|
||||
printf "Starting Syncthing: "
|
||||
start-stop-daemon -p "$PIDFILE" -x syncthing -S -b -N 5 -m -- -logfile="$LOGFILE" -home ~/.config/syncthing
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
stop() {
|
||||
printf "Stopping Syncthing: "
|
||||
start-stop-daemon -p "$PIDFILE" -x syncthing -K
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
status() {
|
||||
printf "Syncthing: "
|
||||
PID="$(cat "$PIDFILE" 2> /dev/null)"
|
||||
if [[ -n "$PID" && -d "/proc/$PID" ]]
|
||||
then
|
||||
echo "running"
|
||||
else
|
||||
echo "stopped"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
tail "$@" "$LOGFILE"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
restart|reload)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
log)
|
||||
shift
|
||||
log "$@"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status|log}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $?
|
1
unprocessed/termux/shell
Symbolic link
1
unprocessed/termux/shell
Symbolic link
|
@ -0,0 +1 @@
|
|||
/data/data/com.termux/files/usr/bin/zsh
|
15
unprocessed/xsession
Executable file
15
unprocessed/xsession
Executable file
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# ~/.xsession
|
||||
#
|
||||
# Sourced by display managers
|
||||
#
|
||||
|
||||
[ -f ~/.xprofile ] && . ~/.xprofile
|
||||
if [ -f ~/.config/override_dm_choice ]
|
||||
then
|
||||
. ~/.config/xinitrc
|
||||
else
|
||||
. ~/.config/xinitrc $@
|
||||
fi
|
Loading…
Add table
Add a link
Reference in a new issue