dotfiles with stow
This commit is contained in:
1
config/.scripts/add-project
Executable file
1
config/.scripts/add-project
Executable file
@@ -0,0 +1 @@
|
||||
echo "$(pwd) $1" >> ~/.scripts/store/projects
|
||||
21
config/.scripts/bar.sh
Executable file
21
config/.scripts/bar.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
DATE=$(date +'%Y-%m-%d %I:%M:%S %p')
|
||||
# BAT=$(cat /sys/class/power_supply/BAT1/capacity)
|
||||
VOL=$(pactl get-sink-volume @DEFAULT_SINK@ | tr "," "\n" | grep \% | sed s/Volume\:// | sed 's/\%.*$//' | sed 's/^.*\///' | head -n1 | sed s/\ *//)
|
||||
VOL="${VOL}%"
|
||||
MUTED=$(pactl get-sink-mute @DEFAULT_SINK@ | cut -d\ -f2)
|
||||
# BRIGHT=$(brightnessctl | tr "\n" " " | cut -d\ -f9 | tr -d "()%")
|
||||
MEM=$(free -h | sed 's/[ ]\+/:/g' | cut -d\: -f4 | tr "\n" ":" | cut -d\: -f2)
|
||||
USER=$(id -u -n)
|
||||
HOST=$(cat /proc/sys/kernel/hostname)
|
||||
# LAYOUT=$(swaymsg -t get_inputs | jq -r '.[] | select( .type == "keyboard") .xkb_active_layout_name' | tr "\n" ":" | cut -d\: -f1 | cut -d\ -f2| tr -d "()")
|
||||
LAYOUT=$(setxkbmap -print -verbose 10 | grep layout | cut -d ":" -f 2 | tr -d " ")
|
||||
NETWORK_NAME=$(iwctl station wlan0 show | grep network | sed s/"Connected network"// | tr -d " ")
|
||||
IP=$(iwctl station wlan0 show | grep IPv4 | sed s/"IPv4 address"// | tr -d " ")
|
||||
|
||||
if [ $MUTED == 'yes' ]
|
||||
then
|
||||
VOL='muted'
|
||||
fi
|
||||
|
||||
echo ${MEM} \| ${USER}\@${HOST} \| KB\: ${LAYOUT} \| ${NETWORK_NAME}\@${IP} \| V: ${VOL} \| ${BRIGHT}% Bl \| ${BAT}\% B \| ${DATE}
|
||||
1
config/.scripts/build.sh
Executable file
1
config/.scripts/build.sh
Executable file
@@ -0,0 +1 @@
|
||||
/usr/lib/jvm/java-11-openjdk/bin/javac -cp ./ $*
|
||||
1
config/.scripts/buildtest.sh
Executable file
1
config/.scripts/buildtest.sh
Executable file
@@ -0,0 +1 @@
|
||||
/usr/lib/jvm/java-11-openjdk/bin/javac -cp .:/usr/share/java/junit.jar:/usr/share/java/hamcrest/core.jar $*
|
||||
18206
config/.scripts/cloc
Executable file
18206
config/.scripts/cloc
Executable file
File diff suppressed because it is too large
Load Diff
5
config/.scripts/cloc-git
Executable file
5
config/.scripts/cloc-git
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
git clone --depth 1 "$1" temp-linecount-repo &&
|
||||
printf "('temp-linecount-repo' will be deleted automatically)\n\n\n" &&
|
||||
cloc temp-linecount-repo &&
|
||||
rm -rf temp-linecount-repo
|
||||
18
config/.scripts/dmenu_emoji
Executable file
18
config/.scripts/dmenu_emoji
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
# The famous "get a menu of emojis to copy" script.
|
||||
|
||||
# Get user selection via dmenu from emoji file.
|
||||
chosen=$(cut -d ';' -f1 ~/.scripts/store/* | dmenu -i -l 30 | sed "s/ .*//")
|
||||
|
||||
# Exit if none chosen.
|
||||
[ -z "$chosen" ] && exit
|
||||
|
||||
# If you run this command with an argument, it will automatically insert the
|
||||
# character. Otherwise, show a message that the emoji has been copied.
|
||||
if [ -n "$1" ]; then
|
||||
xdotool type "$chosen"
|
||||
else
|
||||
printf "%s" "$chosen" | xclip -selection clipboard
|
||||
notify-send "'$chosen' copied to clipboard." &
|
||||
fi
|
||||
12
config/.scripts/enter-dev.sh
Executable file
12
config/.scripts/enter-dev.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
dir="$(cat ~/.scripts/store/projects | fzf | cut -d\ -f1)"
|
||||
if [ -z "$dir" ]; then
|
||||
return
|
||||
fi
|
||||
if [ -n "$(command -v tmux)" ] && [ -z "$TMUX" ]; then
|
||||
tmux new-session -d -c $dir
|
||||
# tmux send-keys -t 0 C-z kak Enter
|
||||
tmux attach
|
||||
else
|
||||
cd $dir
|
||||
kak
|
||||
fi
|
||||
94
config/.scripts/fzf-ctags
Executable file
94
config/.scripts/fzf-ctags
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
IFS=
|
||||
|
||||
# Allow ** glob and Bash extended globbing
|
||||
shopt -s globstar extglob nullglob
|
||||
|
||||
# Set up the template variable.
|
||||
helper_bin=fzf-ctags-helper
|
||||
lib_src=fzf-ctags-lib
|
||||
helper="%FZF_DIR%/bin/$helper_bin"
|
||||
lib="%FZF_DIR%/bin/$lib_src"
|
||||
|
||||
# Setup the colorization preview helper.
|
||||
if [[ $helper = %*%* ]]; then
|
||||
# Find the helper if run directly, without installing.
|
||||
help_dir=${0%/*}
|
||||
[[ $0 != /* ]] && help_dir=$PWD/$help_dir
|
||||
lib="$help_dir/$lib_src"
|
||||
helper=$help_dir/$helper_bin
|
||||
# Found? Try cat if not.
|
||||
[[ ! -f $helper ]] && helper=cat
|
||||
[[ ! -f $lib ]] && {
|
||||
#printf "Library fzf-ctags-lib not found, exiting.\n"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# Load shared functions library.
|
||||
source "$lib"
|
||||
export FZF_CTAGS_LIB="$lib"
|
||||
|
||||
# Which mode? Symbol, or surrounding text?
|
||||
if [[ $1 == symbol-only ]]; then
|
||||
q=2
|
||||
elif [[ -z $1 || $1 = text ]]; then
|
||||
q=1
|
||||
fi
|
||||
|
||||
typeset tags tags_path ptags="/tmp/.TAGS.z-$$"
|
||||
get_tags && tags="$REPLY"
|
||||
|
||||
# Is there any TAGS file to read?
|
||||
if [[ -z $tags || ! -f $tags ]]; then
|
||||
#printf "No \e[38;5;208mTAGS\e[0m file found, exiting…\e[0m\n"
|
||||
#printf "(\`univeral ctags\` is recommended tool to generate one;\n"
|
||||
#printf "homepage: https://github.com/universal-ctags/ctags).\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tags_path="${tags%/TAGS}"
|
||||
# Sort out the symbol to open at.
|
||||
type &>/dev/null sed && sed=sed
|
||||
type &>/dev/null ged && sed=gsed
|
||||
|
||||
command $sed -r -n $'/^\x0c$/ { n; s/,[^,]*$//;s/^/\x02/; h; d;}; G; y/\\n/,/; p' "$tags" > "$ptags"
|
||||
|
||||
line="$(fzf --preview="printf '%s' {} |$helper" --delimiter '\177' --with-nth $q < <( $sed -r -e 's/^\s+//' \
|
||||
-e 's/[\x01\x02]/\x7f/g' $ptags ))"
|
||||
ret=$?
|
||||
|
||||
command rm -f $ptags
|
||||
|
||||
# Check if anything has been picked.
|
||||
if (( ret != 0 )) || [[ -z $line ]]; then
|
||||
printf "\e[38;5;208mNo symbol has been picked out, nothing to do…\e[0m\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Split the input.
|
||||
q=$(cut -d$'\x7f' -f2 <<< $line)
|
||||
nr=$(cut -d$'\x7f' -f3 <<< $line)
|
||||
nr=${nr%%,*}
|
||||
e=$(cut -d$'\x7f' -f4 <<< $line)
|
||||
|
||||
# Use the user's configured editor falling back to vim.
|
||||
ed="${VISUAL:-${EDITOR:-vim}}"
|
||||
type $ed &>/dev/null || ed=emacs
|
||||
type $ed &>/dev/null || ed=nano
|
||||
if ! type $ed &>/dev/null; then
|
||||
#printf "\e[38;5;208mNo supported editor found, exiting…\e[0m\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
#printf "\nPicked: \e[1;38;5;39m$q\e[0m, opening: \
|
||||
#\e[1;38;5;70m$ed\e[0m with the file: \e[1;38;5;140m$e\e[0m:\e[38;5;208m$nr\e[0m\n"
|
||||
|
||||
# Run editor on the selected file and line.
|
||||
# The one-time loop is to emphasize the final step.
|
||||
while
|
||||
( cd "$tags_path"; command "$ed" +"$nr" "$e"; )
|
||||
false
|
||||
do true; done
|
||||
36
config/.scripts/fzf-ctags-helper
Executable file
36
config/.scripts/fzf-ctags-helper
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Set **/… globs.
|
||||
shopt -s globstar nullglob extglob
|
||||
|
||||
# Load the library of shared functions.
|
||||
source "$FZF_CTAGS_LIB"
|
||||
|
||||
# Prevent word split
|
||||
IFS=
|
||||
|
||||
# Read the line of input.
|
||||
builtin read -d '' -r q
|
||||
|
||||
# Split the input.
|
||||
p=$(cut -d$'\x7f' -f3 <<< $q)
|
||||
p=${p%%,*}
|
||||
e=$(cut -d$'\x7f' -f4 <<< $q)
|
||||
(( p --, p=p-LINES/2+4, p=p<0?0:p ))
|
||||
|
||||
# Preamble,
|
||||
printf "Showing \e[1;38;5;208m««\e[1;38;5;70m$e\e[0m:\e[1;38;5;33m$p\e[1;38;5;208m»»\e[0m\\n"
|
||||
eval "printf '—%.0s' {1..$COLUMNS}"
|
||||
printf "\n"
|
||||
|
||||
get_tags && pth=${REPLY%/TAGS} || pth=
|
||||
(
|
||||
[[ -n $pth ]] && builtin cd $pth
|
||||
if [[ -e $e ]]; then
|
||||
colorize "$p" "$e"
|
||||
else
|
||||
printf "File $e not found\n"
|
||||
fi
|
||||
)
|
||||
|
||||
#less +${p%,*} **/"$e"
|
||||
51
config/.scripts/fzf-ctags-lib
Executable file
51
config/.scripts/fzf-ctags-lib
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
get_tags() {
|
||||
local d pth
|
||||
|
||||
#PWD=`pwd`
|
||||
pth=`pwd`
|
||||
while true; do
|
||||
[[ -e $pth/TAGS || -z ${pth%/} ]] && break
|
||||
pth=${pth%/*}
|
||||
d+=/..
|
||||
done
|
||||
[[ -n ${pth#/} ]] && REPLY="$pth"/TAGS
|
||||
|
||||
# Explicit!ly testable.
|
||||
return $?
|
||||
}
|
||||
|
||||
colorize() {
|
||||
local line="$1" file="$2" lines="$(tput lines 2>/dev/null)"
|
||||
local sed tool opts end
|
||||
|
||||
# Lines to show.
|
||||
[[ -z $lines ]] && lines="$LINES"
|
||||
[[ -z $lines ]] && lines=10
|
||||
((end=line+lines))
|
||||
|
||||
# Find sed binary to use.
|
||||
if type sed &>/dev/null; then
|
||||
sed=sed
|
||||
elif type gsed &>/dev/null; then
|
||||
sed-gsed
|
||||
else
|
||||
sed=cat
|
||||
fi
|
||||
|
||||
# Find the tool to use. Prefer pygments for its speed.
|
||||
if type pygmentize &>/dev/null; then
|
||||
tool="$sed -e 1,${line}d $file | pygmentize -g | head -n $lines"
|
||||
opts= file=
|
||||
elif type pygmentize3 &>/dev/null; then
|
||||
tool="$sed -e 1,${line}d $file | pygmentize3 -g | head -n $lines"
|
||||
opts= file=
|
||||
elif type source-highlight &>/dev/null; then
|
||||
tool=source-highlight
|
||||
opts="--line-range=$line-$end -f esc -o STDOUT -i"
|
||||
else
|
||||
tool="head -n $end $file | tail -n $lines"
|
||||
opts= file=
|
||||
fi
|
||||
eval "$tool $opts $file"
|
||||
}
|
||||
3
config/.scripts/gb.sh
Executable file
3
config/.scripts/gb.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
GAMES=$(find /home/mikec/Documents/Games/ROMS/GB -iname "*.zip" | bemenu -i --fn "Cascadia Code 12")
|
||||
[ -z "$GAMES" ] || mgba "$GAMES"
|
||||
3
config/.scripts/gba.sh
Executable file
3
config/.scripts/gba.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
GAMES=$(find /home/mikec/Documents/Games/ROMS/GBA -iname "*.zip" | bemenu -i --fn "Cascadia Code 12")
|
||||
[ -z "$GAMES" ] || mgba "$GAMES"
|
||||
3
config/.scripts/gbc.sh
Executable file
3
config/.scripts/gbc.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
GAMES=$(find /home/mikec/Documents/Games/ROMS/GBC -iname "*.zip" | bemenu -i --fn "Cascadia Code 12")
|
||||
[ -z "$GAMES" ] || mgba "$GAMES"
|
||||
3
config/.scripts/genesis.sh
Executable file
3
config/.scripts/genesis.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
GAMES=$(find /home/mikec/Documents/Games/ROMS/Genesis -iname "*.zip" | bemenu -i --fn "Cascadia Code 12")
|
||||
[ -z "$GAMES" ] || blastem "$GAMES"
|
||||
BIN
config/.scripts/get_local_path
Executable file
BIN
config/.scripts/get_local_path
Executable file
Binary file not shown.
17
config/.scripts/get_local_path.c
Normal file
17
config/.scripts/get_local_path.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
return -1;
|
||||
}
|
||||
bool rel = true;
|
||||
if (argv[1][1] == '/') {
|
||||
rel = false;
|
||||
}
|
||||
char* last = strrchr(argv[1], '/');
|
||||
*last = '\0';
|
||||
puts(argv[1]);
|
||||
return 0;
|
||||
}
|
||||
421
config/.scripts/mutt_oauth2.py
Executable file
421
config/.scripts/mutt_oauth2.py
Executable file
@@ -0,0 +1,421 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Mutt OAuth2 token management script, version 2020-08-07
|
||||
# Written against python 3.7.3, not tried with earlier python versions.
|
||||
#
|
||||
# Copyright (C) 2020 Alexander Perlis
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
'''Mutt OAuth2 token management'''
|
||||
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
import imaplib
|
||||
import poplib
|
||||
import smtplib
|
||||
import base64
|
||||
import secrets
|
||||
import hashlib
|
||||
import time
|
||||
from datetime import timedelta, datetime
|
||||
from pathlib import Path
|
||||
import socket
|
||||
import http.server
|
||||
import subprocess
|
||||
import readline
|
||||
|
||||
# The token file must be encrypted because it contains multi-use bearer tokens
|
||||
# whose usage does not require additional verification. Specify whichever
|
||||
# encryption and decryption pipes you prefer. They should read from standard
|
||||
# input and write to standard output. The example values here invoke GPG,
|
||||
# although won't work until an appropriate identity appears in the first line.
|
||||
ENCRYPTION_PIPE = ['gpg', '--encrypt', '--recipient', 'mikecchalupiak@outlook.com']
|
||||
DECRYPTION_PIPE = ['gpg', '--decrypt']
|
||||
|
||||
registrations = {
|
||||
'google': {
|
||||
'authorize_endpoint': 'https://accounts.google.com/o/oauth2/auth',
|
||||
'devicecode_endpoint': 'https://oauth2.googleapis.com/device/code',
|
||||
'token_endpoint': 'https://accounts.google.com/o/oauth2/token',
|
||||
'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob',
|
||||
'imap_endpoint': 'imap.gmail.com',
|
||||
'pop_endpoint': 'pop.gmail.com',
|
||||
'smtp_endpoint': 'smtp.gmail.com',
|
||||
'sasl_method': 'OAUTHBEARER',
|
||||
'scope': 'https://mail.google.com/',
|
||||
'client_id': '',
|
||||
'client_secret': '',
|
||||
},
|
||||
'microsoft': {
|
||||
'authorize_endpoint': 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
|
||||
'devicecode_endpoint': 'https://login.microsoftonline.com/common/oauth2/v2.0/devicecode',
|
||||
'token_endpoint': 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
|
||||
'redirect_uri': 'https://login.microsoftonline.com/common/oauth2/nativeclient',
|
||||
'tenant': 'common',
|
||||
'imap_endpoint': 'outlook.office365.com',
|
||||
'pop_endpoint': 'outlook.office365.com',
|
||||
'smtp_endpoint': 'smtp.office365.com',
|
||||
'sasl_method': 'XOAUTH2',
|
||||
'scope': ('offline_access https://outlook.office.com/IMAP.AccessAsUser.All '
|
||||
'https://outlook.office.com/POP.AccessAsUser.All '
|
||||
'https://outlook.office.com/SMTP.Send'),
|
||||
'client_id': '9e5f94bc-e8a4-4e73-b8be-63364c29d753',
|
||||
'client_secret': '',
|
||||
},
|
||||
}
|
||||
|
||||
ap = argparse.ArgumentParser(epilog='''
|
||||
This script obtains and prints a valid OAuth2 access token. State is maintained in an
|
||||
encrypted TOKENFILE. Run with "--verbose --authorize" to get started or whenever all
|
||||
tokens have expired, optionally with "--authflow" to override the default authorization
|
||||
flow. To truly start over from scratch, first delete TOKENFILE. Use "--verbose --test"
|
||||
to test the IMAP/POP/SMTP endpoints.
|
||||
''')
|
||||
ap.add_argument('-v', '--verbose', action='store_true', help='increase verbosity')
|
||||
ap.add_argument('-d', '--debug', action='store_true', help='enable debug output')
|
||||
ap.add_argument('tokenfile', help='persistent token storage')
|
||||
ap.add_argument('-a', '--authorize', action='store_true', help='manually authorize new tokens')
|
||||
ap.add_argument('--authflow', help='authcode | localhostauthcode | devicecode')
|
||||
ap.add_argument('-t', '--test', action='store_true', help='test IMAP/POP/SMTP endpoints')
|
||||
args = ap.parse_args()
|
||||
|
||||
token = {}
|
||||
path = Path(args.tokenfile)
|
||||
if path.exists():
|
||||
if 0o777 & path.stat().st_mode != 0o600:
|
||||
sys.exit('Token file has unsafe mode. Suggest deleting and starting over.')
|
||||
try:
|
||||
sub = subprocess.run(DECRYPTION_PIPE, check=True, input=path.read_bytes(),
|
||||
capture_output=True)
|
||||
token = json.loads(sub.stdout)
|
||||
except subprocess.CalledProcessError:
|
||||
sys.exit('Difficulty decrypting token file. Is your decryption agent primed for '
|
||||
'non-interactive usage, or an appropriate environment variable such as '
|
||||
'GPG_TTY set to allow interactive agent usage from inside a pipe?')
|
||||
|
||||
|
||||
def writetokenfile():
|
||||
'''Writes global token dictionary into token file.'''
|
||||
if not path.exists():
|
||||
path.touch(mode=0o600)
|
||||
if 0o777 & path.stat().st_mode != 0o600:
|
||||
sys.exit('Token file has unsafe mode. Suggest deleting and starting over.')
|
||||
sub2 = subprocess.run(ENCRYPTION_PIPE, check=True, input=json.dumps(token).encode(),
|
||||
capture_output=True)
|
||||
path.write_bytes(sub2.stdout)
|
||||
|
||||
|
||||
if args.debug:
|
||||
print('Obtained from token file:', json.dumps(token))
|
||||
if not token:
|
||||
if not args.authorize:
|
||||
sys.exit('You must run script with "--authorize" at least once.')
|
||||
print('Available app and endpoint registrations:', *registrations)
|
||||
token['registration'] = input('OAuth2 registration: ')
|
||||
token['authflow'] = input('Preferred OAuth2 flow ("authcode" or "localhostauthcode" '
|
||||
'or "devicecode"): ')
|
||||
token['email'] = input('Account e-mail address: ')
|
||||
token['access_token'] = ''
|
||||
token['access_token_expiration'] = ''
|
||||
token['refresh_token'] = ''
|
||||
writetokenfile()
|
||||
|
||||
if token['registration'] not in registrations:
|
||||
sys.exit(f'ERROR: Unknown registration "{token["registration"]}". Delete token file '
|
||||
f'and start over.')
|
||||
registration = registrations[token['registration']]
|
||||
|
||||
authflow = token['authflow']
|
||||
if args.authflow:
|
||||
authflow = args.authflow
|
||||
|
||||
baseparams = {'client_id': registration['client_id']}
|
||||
# Microsoft uses 'tenant' but Google does not
|
||||
if 'tenant' in registration:
|
||||
baseparams['tenant'] = registration['tenant']
|
||||
|
||||
|
||||
def access_token_valid():
|
||||
'''Returns True when stored access token exists and is still valid at this time.'''
|
||||
token_exp = token['access_token_expiration']
|
||||
return token_exp and datetime.now() < datetime.fromisoformat(token_exp)
|
||||
|
||||
|
||||
def update_tokens(r):
|
||||
'''Takes a response dictionary, extracts tokens out of it, and updates token file.'''
|
||||
token['access_token'] = r['access_token']
|
||||
token['access_token_expiration'] = (datetime.now() +
|
||||
timedelta(seconds=int(r['expires_in']))).isoformat()
|
||||
if 'refresh_token' in r:
|
||||
token['refresh_token'] = r['refresh_token']
|
||||
writetokenfile()
|
||||
if args.verbose:
|
||||
print(f'NOTICE: Obtained new access token, expires {token["access_token_expiration"]}.')
|
||||
|
||||
|
||||
if args.authorize:
|
||||
p = baseparams.copy()
|
||||
p['scope'] = registration['scope']
|
||||
|
||||
if authflow in ('authcode', 'localhostauthcode'):
|
||||
verifier = secrets.token_urlsafe(90)
|
||||
challenge = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode()).digest())[:-1]
|
||||
redirect_uri = registration['redirect_uri']
|
||||
listen_port = 0
|
||||
if authflow == 'localhostauthcode':
|
||||
# Find an available port to listen on
|
||||
s = socket.socket()
|
||||
s.bind(('127.0.0.1', 0))
|
||||
listen_port = s.getsockname()[1]
|
||||
s.close()
|
||||
redirect_uri = 'http://localhost:'+str(listen_port)+'/'
|
||||
# Probably should edit the port number into the actual redirect URL.
|
||||
|
||||
p.update({'login_hint': token['email'],
|
||||
'response_type': 'code',
|
||||
'redirect_uri': redirect_uri,
|
||||
'code_challenge': challenge,
|
||||
'code_challenge_method': 'S256'})
|
||||
print(registration["authorize_endpoint"] + '?' +
|
||||
urllib.parse.urlencode(p, quote_via=urllib.parse.quote))
|
||||
|
||||
authcode = ''
|
||||
if authflow == 'authcode':
|
||||
authcode = input('Visit displayed URL to retrieve authorization code. Enter '
|
||||
'code from server (might be in browser address bar): ')
|
||||
else:
|
||||
print('Visit displayed URL to authorize this application. Waiting...',
|
||||
end='', flush=True)
|
||||
|
||||
class MyHandler(http.server.BaseHTTPRequestHandler):
|
||||
'''Handles the browser query resulting from redirect to redirect_uri.'''
|
||||
|
||||
# pylint: disable=C0103
|
||||
def do_HEAD(self):
|
||||
'''Response to a HEAD requests.'''
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'text/html')
|
||||
self.end_headers()
|
||||
|
||||
def do_GET(self):
|
||||
'''For GET request, extract code parameter from URL.'''
|
||||
# pylint: disable=W0603
|
||||
global authcode
|
||||
querystring = urllib.parse.urlparse(self.path).query
|
||||
querydict = urllib.parse.parse_qs(querystring)
|
||||
if 'code' in querydict:
|
||||
authcode = querydict['code'][0]
|
||||
self.do_HEAD()
|
||||
self.wfile.write(b'<html><head><title>Authorizaton result</title></head>')
|
||||
self.wfile.write(b'<body><p>Authorization redirect completed. You may '
|
||||
b'close this window.</p></body></html>')
|
||||
with http.server.HTTPServer(('127.0.0.1', listen_port), MyHandler) as httpd:
|
||||
try:
|
||||
httpd.handle_request()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
if not authcode:
|
||||
sys.exit('Did not obtain an authcode.')
|
||||
|
||||
for k in 'response_type', 'login_hint', 'code_challenge', 'code_challenge_method':
|
||||
del p[k]
|
||||
p.update({'grant_type': 'authorization_code',
|
||||
'code': authcode,
|
||||
'client_secret': registration['client_secret'],
|
||||
'code_verifier': verifier})
|
||||
print('Exchanging the authorization code for an access token')
|
||||
try:
|
||||
response = urllib.request.urlopen(registration['token_endpoint'],
|
||||
urllib.parse.urlencode(p).encode())
|
||||
except urllib.error.HTTPError as err:
|
||||
print(err.code, err.reason)
|
||||
response = err
|
||||
response = response.read()
|
||||
if args.debug:
|
||||
print(response)
|
||||
response = json.loads(response)
|
||||
if 'error' in response:
|
||||
print(response['error'])
|
||||
if 'error_description' in response:
|
||||
print(response['error_description'])
|
||||
sys.exit(1)
|
||||
|
||||
elif authflow == 'devicecode':
|
||||
try:
|
||||
response = urllib.request.urlopen(registration['devicecode_endpoint'],
|
||||
urllib.parse.urlencode(p).encode())
|
||||
except urllib.error.HTTPError as err:
|
||||
print(err.code, err.reason)
|
||||
response = err
|
||||
response = response.read()
|
||||
if args.debug:
|
||||
print(response)
|
||||
response = json.loads(response)
|
||||
if 'error' in response:
|
||||
print(response['error'])
|
||||
if 'error_description' in response:
|
||||
print(response['error_description'])
|
||||
sys.exit(1)
|
||||
print(response['message'])
|
||||
del p['scope']
|
||||
p.update({'grant_type': 'urn:ietf:params:oauth:grant-type:device_code',
|
||||
'client_secret': registration['client_secret'],
|
||||
'device_code': response['device_code']})
|
||||
interval = int(response['interval'])
|
||||
print('Polling...', end='', flush=True)
|
||||
while True:
|
||||
time.sleep(interval)
|
||||
print('.', end='', flush=True)
|
||||
try:
|
||||
response = urllib.request.urlopen(registration['token_endpoint'],
|
||||
urllib.parse.urlencode(p).encode())
|
||||
except urllib.error.HTTPError as err:
|
||||
# Not actually always an error, might just mean "keep trying..."
|
||||
response = err
|
||||
response = response.read()
|
||||
if args.debug:
|
||||
print(response)
|
||||
response = json.loads(response)
|
||||
if 'error' not in response:
|
||||
break
|
||||
if response['error'] == 'authorization_declined':
|
||||
print(' user declined authorization.')
|
||||
sys.exit(1)
|
||||
if response['error'] == 'expired_token':
|
||||
print(' too much time has elapsed.')
|
||||
sys.exit(1)
|
||||
if response['error'] != 'authorization_pending':
|
||||
print(response['error'])
|
||||
if 'error_description' in response:
|
||||
print(response['error_description'])
|
||||
sys.exit(1)
|
||||
print()
|
||||
|
||||
else:
|
||||
sys.exit(f'ERROR: Unknown OAuth2 flow "{token["authflow"]}. Delete token file and '
|
||||
f'start over.')
|
||||
|
||||
update_tokens(response)
|
||||
|
||||
|
||||
if not access_token_valid():
|
||||
if args.verbose:
|
||||
print('NOTICE: Invalid or expired access token; using refresh token '
|
||||
'to obtain new access token.')
|
||||
if not token['refresh_token']:
|
||||
sys.exit('ERROR: No refresh token. Run script with "--authorize".')
|
||||
p = baseparams.copy()
|
||||
p.update({'client_secret': registration['client_secret'],
|
||||
'refresh_token': token['refresh_token'],
|
||||
'grant_type': 'refresh_token'})
|
||||
try:
|
||||
response = urllib.request.urlopen(registration['token_endpoint'],
|
||||
urllib.parse.urlencode(p).encode())
|
||||
except urllib.error.HTTPError as err:
|
||||
print(err.code, err.reason)
|
||||
response = err
|
||||
response = response.read()
|
||||
if args.debug:
|
||||
print(response)
|
||||
response = json.loads(response)
|
||||
if 'error' in response:
|
||||
print(response['error'])
|
||||
if 'error_description' in response:
|
||||
print(response['error_description'])
|
||||
print('Perhaps refresh token invalid. Try running once with "--authorize"')
|
||||
sys.exit(1)
|
||||
update_tokens(response)
|
||||
|
||||
|
||||
if not access_token_valid():
|
||||
sys.exit('ERROR: No valid access token. This should not be able to happen.')
|
||||
|
||||
|
||||
if args.verbose:
|
||||
print('Access Token: ', end='')
|
||||
print(token['access_token'])
|
||||
|
||||
|
||||
def build_sasl_string(user, host, port, bearer_token):
|
||||
'''Build appropriate SASL string, which depends on cloud server's supported SASL method.'''
|
||||
if registration['sasl_method'] == 'OAUTHBEARER':
|
||||
return f'n,a={user},\1host={host}\1port={port}\1auth=Bearer {bearer_token}\1\1'
|
||||
if registration['sasl_method'] == 'XOAUTH2':
|
||||
return f'user={user}\1auth=Bearer {bearer_token}\1\1'
|
||||
sys.exit(f'Unknown SASL method {registration["sasl_method"]}.')
|
||||
|
||||
|
||||
if args.test:
|
||||
errors = False
|
||||
|
||||
imap_conn = imaplib.IMAP4_SSL(registration['imap_endpoint'])
|
||||
sasl_string = build_sasl_string(token['email'], registration['imap_endpoint'], 993,
|
||||
token['access_token'])
|
||||
if args.debug:
|
||||
imap_conn.debug = 4
|
||||
try:
|
||||
imap_conn.authenticate(registration['sasl_method'], lambda _: sasl_string.encode())
|
||||
# Microsoft has a bug wherein a mismatch between username and token can still report a
|
||||
# successful login... (Try a consumer login with the token from a work/school account.)
|
||||
# Fortunately subsequent commands fail with an error. Thus we follow AUTH with another
|
||||
# IMAP command before reporting success.
|
||||
imap_conn.list()
|
||||
if args.verbose:
|
||||
print('IMAP authentication succeeded')
|
||||
except imaplib.IMAP4.error as e:
|
||||
print('IMAP authentication FAILED (does your account allow IMAP?):', e)
|
||||
errors = True
|
||||
|
||||
pop_conn = poplib.POP3_SSL(registration['pop_endpoint'])
|
||||
sasl_string = build_sasl_string(token['email'], registration['pop_endpoint'], 995,
|
||||
token['access_token'])
|
||||
if args.debug:
|
||||
pop_conn.set_debuglevel(2)
|
||||
try:
|
||||
# poplib doesn't have an auth command taking an authenticator object
|
||||
# Microsoft requires a two-line SASL for POP
|
||||
# pylint: disable=W0212
|
||||
pop_conn._shortcmd('AUTH ' + registration['sasl_method'])
|
||||
pop_conn._shortcmd(base64.standard_b64encode(sasl_string.encode()).decode())
|
||||
if args.verbose:
|
||||
print('POP authentication succeeded')
|
||||
except poplib.error_proto as e:
|
||||
print('POP authentication FAILED (does your account allow POP?):', e.args[0].decode())
|
||||
errors = True
|
||||
|
||||
# SMTP_SSL would be simpler but Microsoft does not answer on port 465.
|
||||
smtp_conn = smtplib.SMTP(registration['smtp_endpoint'], 587)
|
||||
sasl_string = build_sasl_string(token['email'], registration['smtp_endpoint'], 587,
|
||||
token['access_token'])
|
||||
smtp_conn.ehlo('test')
|
||||
smtp_conn.starttls()
|
||||
smtp_conn.ehlo('test')
|
||||
if args.debug:
|
||||
smtp_conn.set_debuglevel(2)
|
||||
try:
|
||||
smtp_conn.auth(registration['sasl_method'], lambda _=None: sasl_string)
|
||||
if args.verbose:
|
||||
print('SMTP authentication succeeded')
|
||||
except smtplib.SMTPAuthenticationError as e:
|
||||
print('SMTP authentication FAILED:', e)
|
||||
errors = True
|
||||
|
||||
if errors:
|
||||
sys.exit(1)
|
||||
3
config/.scripts/n64.sh
Executable file
3
config/.scripts/n64.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
GAMES=$(find /home/mikec/Documents/Games/ROMS/N64 -iname "*.zip" | bemenu -i --fn "Cascadia Code 12")
|
||||
[ -z "$GAMES" ] || mupen64plus "$GAMES"
|
||||
3
config/.scripts/nes.sh
Executable file
3
config/.scripts/nes.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
GAMES=$(find /home/mikec/Documents/Games/ROMS/NES/USA -iname "*.nes" | bemenu -i --fn "Cascadia Code 12")
|
||||
[ -z "$GAMES" ] || fceux "$GAMES"
|
||||
6
config/.scripts/open-note.sh
Executable file
6
config/.scripts/open-note.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
FILE=$(rg --no-heading -n . | fzf)
|
||||
FILEPATH=$(echo $FILE | sed 's/:.*//')
|
||||
NUMBER=$(echo $FILE | cut -d':' -f2)
|
||||
kak +$NUMBER $FILEPATH
|
||||
6
config/.scripts/pws.sh
Executable file
6
config/.scripts/pws.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
(rg -uu --color=always --line-number --no-heading . > $1) & tail -n +1 -f $1 | \
|
||||
fzf-tmux --cycle -p 80%,90% < /dev/null \
|
||||
--disabled --ansi \
|
||||
--bind "change:reload:rg -uu --smart-case {q} $1 || :" \
|
||||
--bind "enter:become(echo {1} {2})" \
|
||||
--delimiter : ; pkill -P $$
|
||||
5
config/.scripts/remove-project
Executable file
5
config/.scripts/remove-project
Executable file
@@ -0,0 +1,5 @@
|
||||
proj="$(cat -n ~/.scripts/store/projects | fzf | cut -f 1 | tr -d ' ')"
|
||||
if [ -z "$proj" ]; then
|
||||
exit
|
||||
fi
|
||||
sed -i "$proj"d ~/.scripts/store/projects
|
||||
8
config/.scripts/rfs.sh
Executable file
8
config/.scripts/rfs.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
rg -uu --color=always --line-number --no-heading --smart-case "${*:3}" "$1" | tr -d '\r' |
|
||||
fzf-tmux --cycle -p 80%,90% --ansi \
|
||||
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
||||
--delimiter : \
|
||||
--preview "bat --theme='base16-256' --color=always $1 --highlight-line {1}" \
|
||||
--bind "enter:become(echo \"$2\" '{1}')" \
|
||||
--preview-window 'right,55%,+{1}+3/3,~3' \
|
||||
|
||||
8
config/.scripts/rfv.sh
Executable file
8
config/.scripts/rfv.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
rg --uu --color=always --line-number --no-heading --smart-case -H "${*:-}" | tr -d '\r' |
|
||||
fzf-tmux --cycle -p 80%,90% --ansi \
|
||||
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
||||
--delimiter : \
|
||||
--preview 'bat --theme="base16-256" --color=always {1} --highlight-line {2}' \
|
||||
--bind 'enter:become(echo "{1}" "{2}")' \
|
||||
--preview-window 'right,55%,+{2}+3/3,~3' \
|
||||
#--preview-window 'right,55%' \
|
||||
8
config/.scripts/rfve.sh
Executable file
8
config/.scripts/rfve.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
rg --color=always --line-number --no-heading --smart-case "${*:-}" | tr -d '\r' |
|
||||
fzf-tmux --cycle -p 80%,90% --ansi +x -e\
|
||||
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
||||
--delimiter : \
|
||||
--preview 'bat --theme="base16-256" --color=always {1} --highlight-line {2}' \
|
||||
--bind 'enter:become(echo "{1}" "{2}")' \
|
||||
--preview-window 'right,55%,+{2}+3/3,~3' \
|
||||
#--preview-window 'right,55%' \
|
||||
8
config/.scripts/rgfs.sh
Executable file
8
config/.scripts/rgfs.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
(RELOAD='reload:rg -uu --color=always --line-number --no-heading --smart-case {q} || :'
|
||||
fzf-tmux --cycle -p 80%,90% < /dev/null \
|
||||
--disabled --ansi \
|
||||
--bind "start:$RELOAD" --bind "change:$RELOAD" \
|
||||
--bind "enter:become(echo '{1}' '{2}')" \
|
||||
--delimiter : \
|
||||
--preview-window 'right,55%,+{2}+3/3,~3' \
|
||||
--preview "bat --theme='base16-256' --color=always {1} --highlight-line {2}")
|
||||
8
config/.scripts/rgrs.sh
Executable file
8
config/.scripts/rgrs.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
(RELOAD="reload:rg -uu --color=always --pcre2 --line-number --no-heading --smart-case {q} $1|| :"
|
||||
fzf-tmux --cycle -p 80%,90% < /dev/null \
|
||||
--disabled --ansi \
|
||||
--bind "start:$RELOAD" --bind "change:$RELOAD" \
|
||||
--bind "enter:become(echo \"$2\" '{1}')" \
|
||||
--delimiter : \
|
||||
--preview-window 'right,55%,+{1}+3/3,~3' \
|
||||
--preview "bat --theme='base16-256' --color=always $1 --highlight-line {1}")
|
||||
1
config/.scripts/run.sh
Executable file
1
config/.scripts/run.sh
Executable file
@@ -0,0 +1 @@
|
||||
/usr/lib/jvm/java-11-openjdk/bin/java -cp ./ $*
|
||||
1
config/.scripts/ryujinx.sh
Executable file
1
config/.scripts/ryujinx.sh
Executable file
@@ -0,0 +1 @@
|
||||
/opt/ryujinx/Ryujinx.sh
|
||||
3
config/.scripts/shutdown.sh
Executable file
3
config/.scripts/shutdown.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#! /bin/sh
|
||||
killall startup.sh
|
||||
killall xss-lock
|
||||
3
config/.scripts/snes.sh
Executable file
3
config/.scripts/snes.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
GAMES=$(find /home/mikec/Documents/Games/ROMS/SNES/USA -iname "*.zip" | bemenu -i --fn "Cascadia Code 12")
|
||||
[ -z "$GAMES" ] || snes9x-gtk "$GAMES"
|
||||
6
config/.scripts/startup.sh
Executable file
6
config/.scripts/startup.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#! /bin/sh
|
||||
while true; do
|
||||
xsetroot -name "$(/home/mikec/.scripts/bar.sh)"
|
||||
sleep 1
|
||||
done &
|
||||
xss-lock -- slock &
|
||||
1630
config/.scripts/store/emoji.txt
Normal file
1630
config/.scripts/store/emoji.txt
Normal file
File diff suppressed because it is too large
Load Diff
1456
config/.scripts/store/font-awesome.txt
Normal file
1456
config/.scripts/store/font-awesome.txt
Normal file
File diff suppressed because it is too large
Load Diff
3
config/.scripts/store/projects
Executable file
3
config/.scripts/store/projects
Executable file
@@ -0,0 +1,3 @@
|
||||
/home/mikec
|
||||
/home/mikec/Documents/Projects/crafting_interpreters
|
||||
/home/mikec/Documents/Projects/crafting_interpreters/jlox
|
||||
470
config/.scripts/styli.sh
Executable file
470
config/.scripts/styli.sh
Executable file
@@ -0,0 +1,470 @@
|
||||
#!/usr/bin/env bash
|
||||
link="https://source.unsplash.com/random/"
|
||||
|
||||
if [ -z ${XDG_CONFIG_HOME+x} ]; then
|
||||
XDG_CONFIG_HOME="${HOME}/.config"
|
||||
fi
|
||||
if [ -z ${XDG_HOME+x} ]; then
|
||||
XDG_HOME="${HOME}"
|
||||
fi
|
||||
confdir="${XDG_CONFIG_HOME}/styli.sh"
|
||||
if [ ! -d "${confdir}" ]; then
|
||||
mkdir -p "${confdir}"
|
||||
fi
|
||||
cachedir="${XDG_HOME}/Pictures/wallpapers"
|
||||
if [ ! -d "${cachedir}" ]; then
|
||||
mkdir -p "${cachedir}"
|
||||
fi
|
||||
|
||||
wallpaper="${cachedir}/wallpaper.jpg"
|
||||
wallpath=""
|
||||
die() {
|
||||
printf "ERR: %s\n" "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# https://github.com/egeesin/alacritty-color-export
|
||||
alacritty_change() {
|
||||
DEFAULT_MACOS_CONFIG="$HOME"/.config/alacritty/alacritty.yml
|
||||
|
||||
# Wal generates a shell script that defines color0..color15
|
||||
SRC="$HOME"/.cache/wal/colors.sh
|
||||
|
||||
[ -e "$SRC" ] || die "Wal colors not found, exiting script. Have you executed Wal before?"
|
||||
printf "Colors found, source ready.\n"
|
||||
|
||||
READLINK=$( command -v greadlink || command -v readlink )
|
||||
|
||||
# Get config file
|
||||
if [ -n "$1" ]; then
|
||||
[ -e "$1" ] || die "Selected config doesn't exist, exiting script."
|
||||
printf "Config found, destination ready.\n"
|
||||
CFG=$1
|
||||
[ -L "$1" ] && {
|
||||
printf "Following symlink to config...\n"
|
||||
CFG=$($READLINK -f "$1")
|
||||
}
|
||||
else
|
||||
# Default config path in Mac systems
|
||||
[ -e "$DEFAULT_MACOS_CONFIG" ] || die "Alacritty config not found, exiting script."
|
||||
|
||||
CFG="$DEFAULT_MACOS_CONFIG"
|
||||
[ -L "$DEFAULT_MACOS_CONFIG" ] && {
|
||||
printf "Following symlink to config...\n"
|
||||
CFG=$($READLINK -f "$DEFAULT_MACOS_CONFIG")
|
||||
}
|
||||
fi
|
||||
|
||||
# Get hex colors from Wal cache
|
||||
# No need for shellcheck to check this, it comes from pywal
|
||||
# shellcheck disable=SC1090
|
||||
. "$SRC"
|
||||
|
||||
# Create temp file for sed results
|
||||
tempfile=$(mktemp)
|
||||
trap 'rm $tempfile' INT TERM EXIT
|
||||
|
||||
# Delete existing color declarations generated by this script
|
||||
# If begin comment exists
|
||||
if grep -q '^# BEGIN ACE' "$CFG"; then
|
||||
# And if end comment exists
|
||||
if grep -q '^# END ACE' "$CFG"; then
|
||||
# Delete contents of the block
|
||||
printf "Existing generated colors found, replacing new colors...\n"
|
||||
sed '/^# BEGIN ACE/,/^# END ACE/ {
|
||||
/^# BEGIN ACE/! { /^# END ACE/!d; }
|
||||
}' "$CFG" > "$tempfile" \
|
||||
&& cat "$tempfile" > "$CFG"
|
||||
# If no end comment, don't do anything
|
||||
else
|
||||
die "No '# END ACE' comment found, please ensure it is present."
|
||||
fi
|
||||
# If no begin comment found
|
||||
else
|
||||
# Don't do anything and notify user if there's an end comment in the file
|
||||
! grep -q '^# END ACE' "$CFG" || die "Found '# END ACE' comment, but no '# BEGIN ACE' comment found. Please ensure it is present."
|
||||
printf "There's no existing 'generated' colors, adding comments...\n";
|
||||
printf '# BEGIN ACE\n# END ACE' >> "$CFG";
|
||||
fi
|
||||
|
||||
# Write new color definitions
|
||||
# We know $colorX is unset, we set it by sourcing above
|
||||
# shellcheck disable=SC2154
|
||||
{ sed "/^# BEGIN ACE/ r /dev/stdin" "$CFG" > "$tempfile" <<EOP
|
||||
colors:
|
||||
primary:
|
||||
background: '$color0'
|
||||
foreground: '$color7'
|
||||
cursor:
|
||||
text: '$color0'
|
||||
cursor: '$color7'
|
||||
normal:
|
||||
black: '$color0'
|
||||
red: '$color1'
|
||||
green: '$color2'
|
||||
yellow: '$color3'
|
||||
blue: '$color4'
|
||||
magenta: '$color5'
|
||||
cyan: '$color6'
|
||||
white: '$color7'
|
||||
bright:
|
||||
black: '$color8'
|
||||
red: '$color9'
|
||||
green: '$color10'
|
||||
yellow: '$color11'
|
||||
blue: '$color12'
|
||||
magenta: '$color13'
|
||||
cyan: '$color14'
|
||||
white: '$color15'
|
||||
EOP
|
||||
} && cat "$tempfile" > "$CFG" \
|
||||
&& rm "$tempfile"
|
||||
trap - INT TERM EXIT
|
||||
printf "'%s' exported to '%s'\n" "$SRC" "$CFG"
|
||||
}
|
||||
|
||||
reddit(){
|
||||
useragent="thevinter"
|
||||
timeout=60
|
||||
|
||||
sort=$2
|
||||
top_time=$3
|
||||
if [ -z $sort ]; then
|
||||
sort="hot"
|
||||
fi
|
||||
|
||||
if [ -z $top_time ]; then
|
||||
top_time=""
|
||||
fi
|
||||
|
||||
if [ ! -z $1 ]; then
|
||||
sub=$1
|
||||
else
|
||||
if [ ! -f "${confdir}/subreddits" ]; then
|
||||
echo "Please install the subreddits file in ${confdir}"
|
||||
exit 2
|
||||
fi
|
||||
readarray subreddits < "${confdir}/subreddits"
|
||||
a=${#subreddits[@]}
|
||||
b=$(($RANDOM % $a))
|
||||
sub=${subreddits[$b]}
|
||||
sub="$(echo -e "${sub}" | tr -d '[:space:]')"
|
||||
fi
|
||||
|
||||
url="https://www.reddit.com/r/$sub/$sort/.json?raw_json=1&t=$top_time"
|
||||
content=`wget -T $timeout -U "$useragent" -q -O - $url`
|
||||
urls=$(echo -n "$content"| jq -r '.data.children[]|select(.data.post_hint|test("image")?) | .data.preview.images[0].source.url')
|
||||
names=$(echo -n "$content"| jq -r '.data.children[]|select(.data.post_hint|test("image")?) | .data.title')
|
||||
ids=$(echo -n "$content"| jq -r '.data.children[]|select(.data.post_hint|test("image")?) | .data.id')
|
||||
arrURLS=($urls)
|
||||
arrNAMES=($names)
|
||||
arrIDS=($ids)
|
||||
wait # prevent spawning too many processes
|
||||
size=${#arrURLS[@]}
|
||||
if [ $size -eq 0 ]; then
|
||||
echo The current subreddit is not valid.
|
||||
exit 1
|
||||
fi
|
||||
idx=$(($RANDOM % $size))
|
||||
target_url=${arrURLS[$idx]}
|
||||
target_name=${arrNAMES[$idx]}
|
||||
target_id=${arrIDS[$idx]}
|
||||
ext=`echo -n "${target_url##*.}"|cut -d '?' -f 1`
|
||||
newname=`echo $target_name | sed "s/^\///;s/\// /g"`_"$subreddit"_$target_id.$ext
|
||||
wget -T $timeout -U "$useragent" --no-check-certificate -q -P down -O ${wallpaper} $target_url &>/dev/null
|
||||
}
|
||||
|
||||
unsplash() {
|
||||
local search="${search// /_}"
|
||||
if [ ! -z $height ] || [ ! -z $width ]; then
|
||||
link="${link}${width}x${height}";
|
||||
else
|
||||
link="${link}1920x1080";
|
||||
fi
|
||||
|
||||
if [ ! -z $search ]; then
|
||||
link="${link}/?${search}"
|
||||
fi
|
||||
|
||||
wget -q -O ${wallpaper} $link
|
||||
}
|
||||
|
||||
deviantart(){
|
||||
client_id=16531
|
||||
client_secret=68c00f3d0ceab95b0fac638b33a3368e
|
||||
payload="grant_type=client_credentials&client_id=${client_id}&client_secret=${client_secret}"
|
||||
access_token=`curl --silent -d $payload https://www.deviantart.com/oauth2/token | jq -r '.access_token'`
|
||||
if [ ! -z $1 ]; then
|
||||
artist=$1
|
||||
url="https://www.deviantart.com/api/v1/oauth2/gallery/?username=${artist}&mode=popular&limit=24"
|
||||
elif [ ! -z $search ]; then
|
||||
[[ "$search" =~ ^(tag:)(.*)$ ]] && tag=${BASH_REMATCH[2]}
|
||||
if [ ! -z $tag ]; then
|
||||
url="https://www.deviantart.com/api/v1/oauth2/browse/tags?tag=$tag&offset=${RANDOM:0:2}&limit=24"
|
||||
else
|
||||
url="https://www.deviantart.com/api/v1/oauth2/browse/popular?q=$search&limit=24&timerange=1month"
|
||||
fi
|
||||
else
|
||||
#url="https://www.deviantart.com/api/v1/oauth2/browse/hot?limit=24&offset=${offset}"
|
||||
topics=( "adoptables" "artisan-crafts" "anthro" "comics" "drawings-and-paintings" "fan-art" "poetry" "stock-images" "sculpture" "science-fiction" "traditional-art" "street-photography" "street-art" "pixel-art" "wallpaper" "digital-art" "photo-manipulation" "science-fiction" "fractal" "game-art" "fantasy" "3d" "drawings-and-paintings" "game-art" )
|
||||
rand=$[$RANDOM % ${#topics[@]}]
|
||||
url="https://www.deviantart.com/api/v1/oauth2/browse/topic?limit=24&topic=${topics[$rand]}"
|
||||
fi
|
||||
content=`curl --silent -H "Authorization: Bearer ${access_token}" -H "Accept: application/json" -H "Content-Type: application/json" $url`
|
||||
urls=$(echo -n $content | jq -r '.results[].content.src')
|
||||
arrURLS=($urls)
|
||||
size=${#arrURLS[@]}
|
||||
idx=$(($RANDOM % $size))
|
||||
target_url=${arrURLS[$idx]}
|
||||
wget --no-check-certificate -q -P down -O ${wallpaper} $target_url &>/dev/null
|
||||
}
|
||||
|
||||
usage(){
|
||||
echo "Usage: styli.sh [-s | --search <string>]
|
||||
[-h | --height <height>]
|
||||
[-w | --width <width>]
|
||||
[-b | --fehbg <feh bg opt>]
|
||||
[-c | --fehopt <feh opt>]
|
||||
[-a | --artist <deviant artist>]
|
||||
[-r | --subreddit <subreddit>]
|
||||
[-l | --link <source>]
|
||||
[-p | --termcolor]
|
||||
[-d | --directory]
|
||||
[-k | --kde]
|
||||
[-x | --xfce]
|
||||
[-g | --gnome]
|
||||
[-m | --monitors <monitor count (nitrogen)>]
|
||||
[-n | --nitrogen]
|
||||
"
|
||||
exit 2
|
||||
}
|
||||
|
||||
type_check() {
|
||||
mime_types=("image/bmp" "image/jpeg" "image/gif" "image/png" "image/heic")
|
||||
isType=false
|
||||
|
||||
for requiredType in "${mime_types[@]}"
|
||||
do
|
||||
if [ $dir ]; then
|
||||
imageType=$(file --mime-type "$HOME/Pictures/wallpaper_dump/${wallpaper}" | sed 's/.*image/image/')
|
||||
echo $imageType
|
||||
if [ "$requiredType" = "$imageType" ]; then
|
||||
isType=true
|
||||
break
|
||||
fi
|
||||
else
|
||||
imageType=$(file --mime-type ${wallpaper} | awk '{print $2}')
|
||||
if [ "$requiredType" = "$imageType" ]; then
|
||||
isType=true
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $isType = false ]; then
|
||||
echo "MIME-Type missmatch. Downloaded file is not an image!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
select_random_wallpaper () {
|
||||
wallpaper=$(ls $HOME/Pictures/wallpaper_dump | shuf -n 1)
|
||||
}
|
||||
|
||||
pywal_cmd() {
|
||||
|
||||
if [ $pywal -eq 1 ]; then
|
||||
wal -c
|
||||
wal -i ${wallpaper} -n -q
|
||||
if [ $TERM = alacritty ]; then
|
||||
alacritty_change
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
sway_cmd() {
|
||||
mode="fill"
|
||||
if [ ! -z $dir ]; then
|
||||
cp "$HOME/Pictures/wallpaper_dump/${wallpaper}" "$HOME/Pictures/wallpapers/wallpaper"
|
||||
swaymsg output "*" bg "$HOME/Pictures/wallpaper_dump/${wallpaper}" "${mode}"
|
||||
else
|
||||
swaymsg output "*" bg "${wallpaper}" "${mode}"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
nitrogen_cmd() {
|
||||
for ((monitor=0; monitor < $monitors; monitor++))
|
||||
do
|
||||
local nitrogen=(nitrogen --save --head=${monitor})
|
||||
|
||||
if [ ! -z $bgtype ]; then
|
||||
if [ $bgtype == 'bg-center' ]; then
|
||||
nitrogen+=(--set-centered)
|
||||
fi
|
||||
if [ $bgtype == 'bg-fill' ]; then
|
||||
nitrogen+=(--set-zoom-fill)
|
||||
fi
|
||||
if [ $bgtype == 'bg-max' ]; then
|
||||
nitrogen+=(--set-zoom)
|
||||
fi
|
||||
if [ $bgtype == 'bg-scale' ]; then
|
||||
nitrogen+=(--set-scaled)
|
||||
fi
|
||||
if [ $bgtype == 'bg-tile' ]; then
|
||||
nitrogen+=(--set-tiled)
|
||||
fi
|
||||
else
|
||||
nitrogen+=(--set-scaled)
|
||||
fi
|
||||
|
||||
if [ ! -z $custom ]; then
|
||||
nitrogen+=($custom)
|
||||
fi
|
||||
|
||||
nitrogen+=(${wallpaper})
|
||||
|
||||
"${nitrogen[@]}"
|
||||
done
|
||||
}
|
||||
|
||||
kde_cmd() {
|
||||
if [ ! -z $dir ]; then
|
||||
qdbus org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript "var allDesktops = desktops();print (allDesktops);for (i=0;i<allDesktops.length;i++) {d = allDesktops[i];d.wallpaperPlugin = \"org.kde.image\";d.currentConfigGroup = Array(\"Wallpaper\", \"org.kde.image\", \"General\");d.writeConfig(\"Image\", \"file:$HOME/Pictures/wallpaper_dump/${wallpaper}\")}"
|
||||
qdbus org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript "var allDesktops = desktops();print (allDesktops);for (i=0;i<allDesktops.length;i++) {d = allDesktops[i];d.wallpaperPlugin = \"org.kde.image\";d.currentConfigGroup = Array(\"Wallpaper\", \"org.kde.image\", \"General\");d.writeConfig(\"Image\", \"file:$HOME/Pictures/wallpaper_dump/${wallpaper}\")}"
|
||||
else
|
||||
cp ${wallpaper} "${cachedir}/tmp.jpg"
|
||||
qdbus org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript "var allDesktops = desktops();print (allDesktops);for (i=0;i<allDesktops.length;i++) {d = allDesktops[i];d.wallpaperPlugin = \"org.kde.image\";d.currentConfigGroup = Array(\"Wallpaper\", \"org.kde.image\", \"General\");d.writeConfig(\"Image\", \"file:${cachedir}/tmp.jpg\")}"
|
||||
qdbus org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript "var allDesktops = desktops();print (allDesktops);for (i=0;i<allDesktops.length;i++) {d = allDesktops[i];d.wallpaperPlugin = \"org.kde.image\";d.currentConfigGroup = Array(\"Wallpaper\", \"org.kde.image\", \"General\");d.writeConfig(\"Image\", \"file:${wallpaper}\")}"
|
||||
rm "${cachedir}/tmp.jpg"
|
||||
fi
|
||||
}
|
||||
|
||||
xfce_cmd() {
|
||||
connectedOutputs=$(xrandr | grep " connected" | sed -e "s/\([A-Z0-9]\+\) connected.*/\1/")
|
||||
activeOutput=$(xrandr | grep -e " connected [^(]" | sed -e "s/\([A-Z0-9]\+\) connected.*/\1/")
|
||||
connected=$(echo $connectedOutputs | wc -w)
|
||||
|
||||
xfconf-query -c xfce4-desktop -p /backdrop/screen0/monitor0/image-path -n -t string -s ~/Pictures/1.jpeg
|
||||
xfconf-query -c xfce4-desktop -p /backdrop/screen0/monitorLVDS1/workspace0/last-image -n -t string -s ~/Pictures/1.jpeg
|
||||
|
||||
for i in $(xfconf-query -c xfce4-desktop -p /backdrop -l|egrep -e "screen.*/monitor.*image-path$" -e "screen.*/monitor.*/last-image$"); do
|
||||
xfconf-query -c xfce4-desktop -p $i -n -t string -s ${wallpaper}
|
||||
xfconf-query -c xfce4-desktop -p $i -s ${wallpaper}
|
||||
done
|
||||
}
|
||||
|
||||
gnome_cmd() {
|
||||
if [ ! -z $dir ]; then
|
||||
gsettings set org.gnome.desktop.background picture-uri "file://$HOME/Pictures/wallpaper_dump/${wallpaper}"
|
||||
gsettings set org.gnome.desktop.background picture-uri-dark "file://$HOME/Pictures/wallpaper_dump/${wallpaper}"
|
||||
else
|
||||
gsettings set org.gnome.desktop.background picture-uri "file://${wallpaper}"
|
||||
gsettings set org.gnome.desktop.background picture-uri-dark "file://${wallpaper}"
|
||||
fi
|
||||
}
|
||||
|
||||
feh_cmd() {
|
||||
local feh=(feh)
|
||||
if [ ! -z $bgtype ]; then
|
||||
if [ $bgtype == 'bg-center' ]; then
|
||||
feh+=(--bg-center)
|
||||
fi
|
||||
if [ $bgtype == 'bg-fill' ]; then
|
||||
feh+=(--bg-fill)
|
||||
fi
|
||||
if [ $bgtype == 'bg-max' ]; then
|
||||
feh+=(--bg-max)
|
||||
fi
|
||||
if [ $bgtype == 'bg-scale' ]; then
|
||||
feh+=(--bg-scale)
|
||||
fi
|
||||
if [ $bgtype == 'bg-tile' ]; then
|
||||
feh+=(--bg-tile)
|
||||
fi
|
||||
else
|
||||
feh+=(--bg-scale)
|
||||
fi
|
||||
|
||||
if [ ! -z $custom ]; then
|
||||
feh+=($custom)
|
||||
fi
|
||||
|
||||
if [ ! -z $dir ]; then
|
||||
cp "$HOME/Pictures/wallpaper_dump/${wallpaper}" "$HOME/Pictures/wallpapers/wallpaper"
|
||||
feh+=("$HOME/Pictures/wallpaper_dump/${wallpaper}")
|
||||
else
|
||||
feh+=(${wallpaper})
|
||||
fi
|
||||
|
||||
"${feh[@]}"
|
||||
}
|
||||
|
||||
pywal=0
|
||||
kde=false
|
||||
xfce=false
|
||||
gnome=false
|
||||
nitrogen=false
|
||||
sway=false
|
||||
monitors=1
|
||||
|
||||
PARSED_ARGUMENTS=$(getopt -a -n $0 -o h:w:s:l:b:r:a:c:d:m:pknxgy --long search:,height:,width:,fehbg:,fehopt:,artist:,subreddit:,directory:,monitors:,termcolor:,kde,nitrogen,xfce,gnome,sway -- "$@")
|
||||
|
||||
VALID_ARGUMENTS=$?
|
||||
if [ "$VALID_ARGUMENTS" != "0" ]; then
|
||||
usage
|
||||
exit
|
||||
fi
|
||||
while :
|
||||
do
|
||||
case "${1}" in
|
||||
-b | --fehbg) bgtype=${2} ; shift 2 ;;
|
||||
-s | --search) search=${2} ; shift 2 ;;
|
||||
-h | --height) height=${2} ; shift 2 ;;
|
||||
-w | --width) width=${2} ; shift 2 ;;
|
||||
-l | --link) link=${2} ; shift 2 ;;
|
||||
-r | --subreddit) sub=${2} ; shift 2 ;;
|
||||
-a | --artist) artist=${2} ; shift 2 ;;
|
||||
-c | --fehopt) custom=${2} ; shift 2 ;;
|
||||
-m | --monitors) monitors=${2} ; shift 2 ;;
|
||||
-n | --nitrogen) nitrogen=true ; shift ;;
|
||||
-d | --directory) dir=${2} ; shift 2 ;;
|
||||
-p | --termcolor) pywal=1 ; shift ;;
|
||||
-k | --kde) kde=true ; shift ;;
|
||||
-x | --xfce) xfce=true ; shift ;;
|
||||
-g | --gnome) gnome=true ; shift ;;
|
||||
-y | --sway) sway=true ; shift ;;
|
||||
-- | '') shift; break ;;
|
||||
*) echo "Unexpected option: $1 - this should not happen." ; usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ! -z $dir ]; then
|
||||
select_random_wallpaper
|
||||
elif [ $link = "reddit" ] || [ ! -z $sub ]; then
|
||||
reddit "$sub"
|
||||
elif [ $link = "deviantart" ] || [ ! -z $artist ]; then
|
||||
deviantart "$artist"
|
||||
else
|
||||
unsplash
|
||||
fi
|
||||
echo $dir
|
||||
type_check
|
||||
|
||||
if [ $kde = true ]; then
|
||||
kde_cmd
|
||||
elif [ $xfce = true ]; then
|
||||
xfce_cmd
|
||||
elif [ $gnome = true ]; then
|
||||
gnome_cmd
|
||||
elif [ $nitrogen = true ]; then
|
||||
nitrogen_cmd
|
||||
elif [ $sway = true ]; then
|
||||
sway_cmd
|
||||
else
|
||||
feh_cmd
|
||||
fi
|
||||
|
||||
|
||||
pywal_cmd
|
||||
1
config/.scripts/test.sh
Executable file
1
config/.scripts/test.sh
Executable file
@@ -0,0 +1 @@
|
||||
/usr/lib/jvm/java-11-openjdk/bin/java -cp .:/usr/share/java/junit.jar:/usr/share/java/hamcrest/core.jar org.junit.runner.JUnitCore $*
|
||||
2
config/.scripts/zigcc
Executable file
2
config/.scripts/zigcc
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
zig cc $@
|
||||
Reference in New Issue
Block a user