dotfiles

<-- duh.
git clone https://hhvn.uk/dotfiles
git clone git://hhvn.uk/dotfiles
Log | Files | Refs | Submodules | LICENSE

commit 68e3a68d70162f56363d57d430d0b4d10a10e84c
parent 9ca4c54b86cacc24893f9ddbf930ce54b9363115
Author: hhvn <dev@hhvn.uk>
Date:   Thu,  9 May 2024 19:35:18 +0100

Stuff

Diffstat:
D.config/bspwm/bspd | 21---------------------
M.config/bspwm/bspwmrc | 4+++-
M.config/bspwm/conf | 57++++++++++++++++++++++++++++++++-------------------------
M.config/bspwm/keys | 44++++++++++++++++++++++++++++++++++++++++++--
M.config/hirc/config | 9+++++++--
M.config/ls | 9++++++---
M.config/mpv/mpv.conf | 23++++++++++++++---------
A.config/mpv/scripts/sponsorblock.lua | 566+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/mpv/scripts/sponsorblock_shared/main.lua | 4++++
A.config/mpv/scripts/sponsorblock_shared/sponsorblock.py | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/mpv/scripts/sponsorblock_shared/sponsorblock.txt | 2++
A.config/mpv/watch_later/04DA18843AC93F825AE495D1DFCA4CBF | 1+
A.config/mpv/watch_later/1DAD0641B5D9BC10A47E66A8B9D6A9E9 | 1+
A.config/mpv/watch_later/20963CD7DBA0991EFF3F99883ACA8F4B | 2++
A.config/mpv/watch_later/46DB9A533C9815F63F3232F2B01601A4 | 3+++
A.config/neomutt/alias | 1+
D.config/neomutt/colours | 72------------------------------------------------------------------------
M.config/neomutt/neomuttrc | 38+++++++-------------------------------
A.config/neomutt/signatures | 2++
A.config/neomutt/users/backtrack@airmail.cc | 7+++++++
A.config/neomutt/users/hayden@haydenvh.com | 8++++++++
A.config/neomutt/users/hhvn@dataswamp.org | 6++++++
A.config/neomutt/users/irc@hlirc.net | 9+++++++++
M.config/nvim/init.vim | 3---
M.config/nvim/modules/filetype.vim | 1-
M.config/qutebrowser/config.py | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
M.config/redshift/redshift.conf | 7+++++--
M.config/sxhkd/sxhkdrc | 58++++++++++++----------------------------------------------
D.config/transmission/settings.json | 99-------------------------------------------------------------------------------
M.rcrc | 199+++++++++++++++++--------------------------------------------------------------
D.ssh/config | 58----------------------------------------------------------
M.xinitrc | 18++++++++++++++----
MLICENSE | 2+-
Mcmd/colotable | 2+-
Tcmd/dpass | 0
Acmd/pass | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
36 files changed, 1126 insertions(+), 555 deletions(-)

diff --git a/.config/bspwm/bspd b/.config/bspwm/bspd @@ -1,21 +0,0 @@ -#!/usr/bin/env python - -import sys -import os - - -while True: - line = sys.stdin.readline() - if line == '': - sys.exit() - if line[0] != 'W': - tokens = line.rstrip('\n').split(' ') - path = os.getenv("PATH").split(':') - - for pdir in path: - script = "%s/bspwm/handler/%s" % (pdir, tokens[0]) - if os.access(script, os.X_OK): - tokens[0] = script - if (os.fork() == 0): - os.execv(script, tokens) - break diff --git a/.config/bspwm/bspwmrc b/.config/bspwm/bspwmrc @@ -6,5 +6,7 @@ bspwm/configure-monitors bspc dekstop Desktop -r c_global_settings +c_normal_win +c_rules -bspc subscribe all | $home/.config/bspwm/bspd +#bspc subscribe all | $home/.config/bspwm/bspd diff --git a/.config/bspwm/conf b/.config/bspwm/conf @@ -2,39 +2,46 @@ fn set { bspc config $* } +c_bg = '#050a10' +c_sel = '#1b364b' +c_urg = '#90222b' + fn c_global_settings { + set remove_unplugged_monitors true + set remove_disabled_monitors true + set split_ratio 0.5 - set borderless_monacle true - set gapless_monacle true -} + set borderless_monocle true + set gapless_monocle true -# Monitors & desktops {{{ -c_monpriority = (HDMI2 HDMI1 eDP1) + set border_width 2 + set normal_border_color $c_bg + set active_border_color $c_bg + set focused_border_color $c_sel -c_desktops = ( - 'HDMI2 1 2 3 4' - 'HDMI1 5 6 7 8' - 'eDP1 9 10' -) -#}}} + set ignore_ewmh_focus true + set honor_size_hints false + set pointer_follows_focus true + set pointer_modifier super + set pointer_action1 resize_corner + set pointer_action2 move + set pointer_action3 move + set click_to_focus none +} -# Colours and aesthetics {{{ -c_bg = '#050a10' -c_sel = '#1b364b' -c_urg = '#90222b' +fn rule { bspc rule -a $* } -fn c_norm_border { - set $* normal_border_color $c_bg - set $* active_border_color $c_bg - set $* focused_border_color $c_sel +fn c_rules { + rule scrcpy state=floating sticky=on } -fn c_urgent_border { - set $* normal_border_color $c_urgent - set $* active_border_color $c_urgent - set $* focused_border_color $c_sel -} +# Monitors & desktops +c_monpriority = (HDMI1 HDMI2 eDP1) -# }}} +c_desktops = ( + 'HDMI1 1 2 3 4' + 'HDMI2 5 6 7 8' + 'eDP1 9 10' +) diff --git a/.config/bspwm/keys b/.config/bspwm/keys @@ -1,6 +1,46 @@ # Copyright (c) 2023 hhvn <dev@hhvn.uk> # ISC license +# vim: filetype=sxhkd : # # See also: git://hhvn.uk/sxhkd-rc -# -# vim: filetype=sxhkd : + +super + r + pkill -USR1 -x sxhkd; bspc wm -r + +super + q + bspc node -c + +# Tiled / monocle +super + f + bspc desktop -l next + +# Like dwm +super + shift + Return + bspc node -s biggest.local + +# Window management +super + [ ,shift + ][h, j, k, l] + bspc node -[f,s] [west, south, north, east] + +super + [ ,shift + ][comma, period] + bspc node -[f,s] [prev, next].local + + +super + alt + [h, j, k, l] + bspc node -p [west, south, north, east] + +super + alt + Return + bspc node -p cancel + +# super + f +# bspc node -t ~fullscreen + +super + shift + f + bspc node -t ~floating + +# Desktop management +super + [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] + bspc desktop [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -f + +super + shift + [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] + bspc node -d [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] diff --git a/.config/hirc/config b/.config/hirc/config @@ -36,13 +36,14 @@ Formats /format topic %{b}topic%{b}%{=}${2}\nset by %{nick:${nick}}${nick}%{o} now /format rpl.notopic %{b}topic%{b}%{=}no topic set /format rpl.topic %{b}topic%{b}%{=}${3} -/format rpl.whoreply %{b}%{nick:${6}}${6}!${3}@${4}%{b}%{o} (%{split:2, ,${8}}): ${7} %{split:1, ,${8} +/format rpl.whoreply %{b}%{nick:${6}}${6}!${3}@${4}%{b}%{o} (%{split:2, ,${8}}): ${7} %{split:1, ,${8}} Ignore ends of some commands for aesthetics /ignore -format rpl.endofwhois .* /ignore -format rpl.endofinfo .* /ignore -format rpl.endofmotd .* /ignore -format rpl.listend .* +/ignore -format ui.ignores.end .* Window decorations /format ui.separator.vertical %{c:91}│ @@ -51,7 +52,6 @@ Window decorations /format ui.separator.horizontal %{c:91}─ irssi muscle memory -/alias /lastlog /grep /alias /wc /close Niceties @@ -98,6 +98,11 @@ Buffer selection Scrolling /bind ^k /scroll 20 /bind ^j /scroll -20 +/bind ^Y /scroll 5 +/bind ^E /scroll -5 + +Macros +/bind ^[b /source ~/.config/hirc/macros/clutter Autoconnexion /source ~/.config/hirc/networks diff --git a/.config/ls b/.config/ls @@ -1,9 +1,11 @@ di=38;5;5 : fi=0 : ln=38;5;3 : ex=38;5;9;01 -*.sh=38;5;9 : *.zsh=38;5;9 : *.rc=38;5;9 -*.html=38;5;15 : *.css=38;5;15 : *.md=38;5;15 -*.conf=38;5;10 : *.vim=38;5;10 : *.yml=38;5;10 : *.hirc=38;5;10 +*.sh=38;5;9 : *.zsh=38;5;9 : *.rc=38;5;9 +*.html=38;5;15;02 : *.css=38;5;15 : *.md=38;5;15 : *.adoc=38;5;15 +*.conf=38;5;10 : *.vim=38;5;10 : *.yml=38;5;10 : *.hirc=38;5;10 + +*.go=38;5;12 *.c=38;5;12 : *.h=38;5;12 : *.y=38;5;12 *.c.orig=38;5;12;01 : *.c.rej=38;5;12;01 *.h.orig=38;5;12;01 : *.h.rej=38;5;12;01 @@ -24,6 +26,7 @@ di=38;5;5 : fi=0 : ln=38;5;3 : ex=38;5;9;01 *Makefile=38;5;8 : *mkfile=38;5;8 *make.sh=38;5;8 : *.mk=38;5;8 +*go.mod=38;5;8 : *go.sum=38;5;8 *configure=38;5;8 : *autogen.sh=38;5;8 : *configure.sh=38;5;8 : *configure.rc=38;5;8 *.am=38;5;8 : *.in=38;5;8 diff --git a/.config/mpv/mpv.conf b/.config/mpv/mpv.conf @@ -1,9 +1,16 @@ -ytdl-format="(bestvideo[height<=640]+bestaudio)[ext=webm]/bestvideo[height<=640]+bestaudio/best[height<=640]/bestvideo+bestaudio/best" +# 1080p +# ytdl-format="(bestvideo[height<=1080]+bestaudio)[ext=webm]/bestvideo[height<=1080]+bestaudio/best[height<=1080]/bestvideo+bestaudio/best" + +# 1440p +ytdl-format="(bestvideo[height<=1080]+bestaudio)[ext=webm]/bestvideo[height<=1080]+bestaudio/best[height<=1080]/bestvideo+bestaudio/best" + +# default to no subtitles no-sub-ass no-sub no-audio-display volume-max=175 +video-sync=display-resample profile=low-latency scale=bilinear cscale=bilinear @@ -17,19 +24,17 @@ deband=no hwdec=auto vd-lavc-fast -# vd-lavc-skiploopfilter=<skipvalue> -# vd-lavc-skipframe=<skipvalue> -# vd-lavc-framedrop=<skipvalue> vd-lavc-threads=4 -# uosc -osc=no -osd-bar=no -border=no - alang=en,eng,sv,swe,se slang=en,eng,sv,swe,se ao=sndio +# make speed up audio sound better af=scaletempo2 + +# uosc +osc=no +osd-bar=no +border=no diff --git a/.config/mpv/scripts/sponsorblock.lua b/.config/mpv/scripts/sponsorblock.lua @@ -0,0 +1,566 @@ +-- GPLv3 + +-- sponsorblock.lua +-- +-- This script skips sponsored segments of YouTube videos +-- using data from https://github.com/ajayyy/SponsorBlock + +local ON_WINDOWS = package.config:sub(1,1) ~= "/" + +local options = { + server_address = "https://sponsor.ajay.app", + + python_path = ON_WINDOWS and "python" or "python3", + + -- Categories to fetch + categories = "sponsor,intro,outro,interaction,selfpromo", + + -- Categories to skip automatically + skip_categories = "sponsor", + + -- If true, sponsored segments will only be skipped once + skip_once = true, + + -- Note that sponsored segments may ocasionally be inaccurate if this is turned off + -- see https://blog.ajay.app/voting-and-pseudo-randomness-or-sponsorblock-or-youtube-sponsorship-segment-blocker + local_database = false, + + -- Update database on first run, does nothing if local_database is false + auto_update = false, + + -- How long to wait between local database updates + -- Format: "X[d,h,m]", leave blank to update on every mpv run + auto_update_interval = "6h", + + -- User ID used to submit sponsored segments, leave blank for random + user_id = "", + + -- Name to display on the stats page https://sponsor.ajay.app/stats/ leave blank to keep current name + display_name = "", + + -- Tell the server when a skip happens + report_views = true, + + -- Auto upvote skipped sponsors + auto_upvote = false, + + -- Use sponsor times from server if they're more up to date than our local database + server_fallback = true, + + -- Create chapters at sponsor boundaries for OSC display and manual skipping + make_chapters = true, + + -- Minimum duration for sponsors (in seconds), segments under that threshold will be ignored + min_duration = 1, + + -- Fade audio for smoother transitions + audio_fade = false, + + -- Audio fade step, applied once every 100ms until cap is reached + audio_fade_step = 10, + + -- Audio fade cap + audio_fade_cap = 0, + + -- Fast forward through sponsors instead of skipping + fast_forward = false, + + -- Playback speed modifier when fast forwarding, applied once every second until cap is reached + fast_forward_increase = .2, + + -- Playback speed cap + fast_forward_cap = 2, + + -- Length of the sha256 prefix (3-32) when querying server, 0 to disable + sha256_length = 4, + + -- Pattern for video id in local files, ignored if blank + -- Recommended value for base youtube-dl is "-([%w-_]+)%.[mw][kpe][v4b]m?$" + local_pattern = "", + + -- Legacy option, use skip_categories instead + skip = true +} + +mp.options = require "mp.options" +mp.options.read_options(options, "sponsorblock") + +local legacy = mp.command_native_async == nil +if legacy then + options.local_database = false +end + +local utils = require "mp.utils" +scripts_dir = mp.find_config_file("scripts") + +local sponsorblock = utils.join_path(scripts_dir, "sponsorblock_shared/sponsorblock.py") +local uid_path = utils.join_path(scripts_dir, "sponsorblock_shared/sponsorblock.txt") +local database_file = options.local_database and utils.join_path(scripts_dir, "sponsorblock_shared/sponsorblock.db") or "" +local youtube_id = nil +local ranges = {} +local init = false +local segment = {a = 0, b = 0, progress = 0, first = true} +local retrying = false +local last_skip = {uuid = "", dir = nil} +local speed_timer = nil +local fade_timer = nil +local fade_dir = nil +local volume_before = mp.get_property_number("volume") +local categories = {} +local all_categories = {"sponsor", "intro", "outro", "interaction", "selfpromo", "preview", "music_offtopic"} +local chapter_cache = {} + +for category in string.gmatch(options.skip_categories, "([^,]+)") do + categories[category] = true +end + +function file_exists(name) + local f = io.open(name,"r") + if f ~= nil then io.close(f) return true else return false end +end + +function t_count(t) + local count = 0 + for _ in pairs(t) do count = count + 1 end + return count +end + +function time_sort(a, b) + if a.time == b.time then + return string.match(a.title, "segment end") + end + return a.time < b.time +end + +function parse_update_interval() + local s = options.auto_update_interval + if s == "" then return 0 end -- Interval Disabled + + local num, mod = s:match "^(%d+)([hdm])$" + + if num == nil or mod == nil then + mp.osd_message("[sponsorblock] auto_update_interval " .. s .. " is invalid", 5) + return nil + end + + local time_table = { + m = 60, + h = 60 * 60, + d = 60 * 60 * 24, + } + + return num * time_table[mod] +end + +function clean_chapters() + local chapters = mp.get_property_native("chapter-list") + local new_chapters = {} + for _, chapter in pairs(chapters) do + if chapter.title ~= "Preview segment start" and chapter.title ~= "Preview segment end" then + table.insert(new_chapters, chapter) + end + end + mp.set_property_native("chapter-list", new_chapters) +end + +function create_chapter(chapter_title, chapter_time) + local chapters = mp.get_property_native("chapter-list") + local duration = mp.get_property_native("duration") + table.insert(chapters, {title=chapter_title, time=(duration == nil or duration > chapter_time) and chapter_time or duration - .001}) + table.sort(chapters, time_sort) + mp.set_property_native("chapter-list", chapters) +end + +function process(uuid, t, new_ranges) + start_time = tonumber(string.match(t, "[^,]+")) + end_time = tonumber(string.sub(string.match(t, ",[^,]+"), 2)) + for o_uuid, o_t in pairs(ranges) do + if (start_time >= o_t.start_time and start_time <= o_t.end_time) or (o_t.start_time >= start_time and o_t.start_time <= end_time) then + new_ranges[o_uuid] = o_t + return + end + end + category = string.match(t, "[^,]+$") + if categories[category] and end_time - start_time >= options.min_duration then + new_ranges[uuid] = { + start_time = start_time, + end_time = end_time, + category = category, + skipped = false + } + end + if options.make_chapters and not chapter_cache[uuid] then + chapter_cache[uuid] = true + local category_title = (category:gsub("^%l", string.upper):gsub("_", " ")) + create_chapter(category_title .. " segment start (" .. string.sub(uuid, 1, 6) .. ")", start_time) + create_chapter(category_title .. " segment end (" .. string.sub(uuid, 1, 6) .. ")", end_time) + end +end + +function getranges(_, exists, db, more) + if type(exists) == "table" and exists["status"] == "1" then + if options.server_fallback then + mp.add_timeout(0, function() getranges(true, true, "") end) + else + return mp.osd_message("[sponsorblock] database update failed, gave up") + end + end + if db ~= "" and db ~= database_file then db = database_file end + if exists ~= true and not file_exists(db) then + if not retrying then + mp.osd_message("[sponsorblock] database update failed, retrying...") + retrying = true + end + return update() + end + if retrying then + mp.osd_message("[sponsorblock] database update succeeded") + retrying = false + end + local sponsors + local args = { + options.python_path, + sponsorblock, + "ranges", + db, + options.server_address, + youtube_id, + options.categories, + tostring(options.sha256_length) + } + if not legacy then + sponsors = mp.command_native({name = "subprocess", capture_stdout = true, playback_only = false, args = args}) + else + sponsors = utils.subprocess({args = args}) + end + mp.msg.debug("Got: " .. string.gsub(sponsors.stdout, "[\n\r]", "")) + if not string.match(sponsors.stdout, "^%s*(.*%S)") then return end + if string.match(sponsors.stdout, "error") then return getranges(true, true) end + local new_ranges = {} + local r_count = 0 + if more then r_count = -1 end + for t in string.gmatch(sponsors.stdout, "[^:%s]+") do + uuid = string.match(t, "([^,]+),[^,]+$") + if ranges[uuid] then + new_ranges[uuid] = ranges[uuid] + else + process(uuid, t, new_ranges) + end + r_count = r_count + 1 + end + local c_count = t_count(ranges) + if c_count == 0 or r_count >= c_count then + ranges = new_ranges + end +end + +function fast_forward() + if options.fast_forward and options.fast_forward == true then + speed_timer = nil + mp.set_property("speed", 1) + end + local last_speed = mp.get_property_number("speed") + local new_speed = math.min(last_speed + options.fast_forward_increase, options.fast_forward_cap) + if new_speed <= last_speed then return end + mp.set_property("speed", new_speed) +end + +function fade_audio(step) + local last_volume = mp.get_property_number("volume") + local new_volume = math.max(options.audio_fade_cap, math.min(last_volume + step, volume_before)) + if new_volume == last_volume then + if step >= 0 then fade_dir = nil end + if fade_timer ~= nil then fade_timer:kill() end + fade_timer = nil + return + end + mp.set_property("volume", new_volume) +end + +function skip_ads(name, pos) + if pos == nil then return end + local sponsor_ahead = false + for uuid, t in pairs(ranges) do + if (options.fast_forward == uuid or not options.skip_once or not t.skipped) and t.start_time <= pos and t.end_time > pos then + if options.fast_forward == uuid then return end + if options.fast_forward == false then + mp.osd_message("[sponsorblock] " .. t.category .. " skipped") + mp.set_property("time-pos", t.end_time) + else + mp.osd_message("[sponsorblock] skipping " .. t.category) + end + t.skipped = true + last_skip = {uuid = uuid, dir = nil} + if options.report_views or options.auto_upvote then + local args = { + options.python_path, + sponsorblock, + "stats", + database_file, + options.server_address, + youtube_id, + uuid, + options.report_views and "1" or "", + uid_path, + options.user_id, + options.auto_upvote and "1" or "" + } + if not legacy then + mp.command_native_async({name = "subprocess", playback_only = false, args = args}, function () end) + else + utils.subprocess_detached({args = args}) + end + end + if options.fast_forward ~= false then + options.fast_forward = uuid + if speed_timer ~= nil then speed_timer:kill() end + speed_timer = mp.add_periodic_timer(1, fast_forward) + end + return + elseif (not options.skip_once or not t.skipped) and t.start_time <= pos + 1 and t.end_time > pos + 1 then + sponsor_ahead = true + end + end + if options.audio_fade then + if sponsor_ahead then + if fade_dir ~= false then + if fade_dir == nil then volume_before = mp.get_property_number("volume") end + if fade_timer ~= nil then fade_timer:kill() end + fade_dir = false + fade_timer = mp.add_periodic_timer(.1, function() fade_audio(-options.audio_fade_step) end) + end + elseif fade_dir == false then + fade_dir = true + if fade_timer ~= nil then fade_timer:kill() end + fade_timer = mp.add_periodic_timer(.1, function() fade_audio(options.audio_fade_step) end) + end + end + if options.fast_forward and options.fast_forward ~= true then + options.fast_forward = true + speed_timer:kill() + speed_timer = nil + mp.set_property("speed", 1) + end +end + +function vote(dir) + if last_skip.uuid == "" then return mp.osd_message("[sponsorblock] no sponsors skipped, can't submit vote") end + local updown = dir == "1" and "up" or "down" + if last_skip.dir == dir then return mp.osd_message("[sponsorblock] " .. updown .. "vote already submitted") end + last_skip.dir = dir + local args = { + options.python_path, + sponsorblock, + "stats", + database_file, + options.server_address, + youtube_id, + last_skip.uuid, + "", + uid_path, + options.user_id, + dir + } + if not legacy then + mp.command_native_async({name = "subprocess", playback_only = false, args = args}, function () end) + else + utils.subprocess({args = args}) + end + mp.osd_message("[sponsorblock] " .. updown .. "vote submitted") +end + +function update() + mp.command_native_async({name = "subprocess", playback_only = false, args = { + options.python_path, + sponsorblock, + "update", + database_file, + options.server_address + }}, getranges) +end + +function file_loaded() + local initialized = init + ranges = {} + segment = {a = 0, b = 0, progress = 0, first = true} + last_skip = {uuid = "", dir = nil} + chapter_cache = {} + local video_path = mp.get_property("path", "") + mp.msg.debug("Path: " .. video_path) + local video_referer = string.match(mp.get_property("http-header-fields", ""), "Referer:([^,]+)") or "" + mp.msg.debug("Referer: " .. video_referer) + + local urls = { + "https?://youtu%.be/([%w-_]+).*", + "https?://w?w?w?%.?youtube%.com/v/([%w-_]+).*", + "/watch.*[?&]v=([%w-_]+).*", + "/embed/([%w-_]+).*" + } + youtube_id = nil + for i,url in ipairs(urls) do + youtube_id = youtube_id or string.match(video_path, url) or string.match(video_referer, url) + end + youtube_id = youtube_id or string.match(video_path, options.local_pattern) + + if not youtube_id or string.len(youtube_id) < 11 or (local_pattern and string.len(youtube_id) ~= 11) then return end + youtube_id = string.sub(youtube_id, 1, 11) + mp.msg.debug("Found YouTube ID: " .. youtube_id) + init = true + if not options.local_database then + getranges(true, true) + else + local exists = file_exists(database_file) + if exists and options.server_fallback then + getranges(true, true) + mp.add_timeout(0, function() getranges(true, true, "", true) end) + elseif exists then + getranges(true, true) + elseif options.server_fallback then + mp.add_timeout(0, function() getranges(true, true, "") end) + end + end + if initialized then return end + if options.skip then + mp.observe_property("time-pos", "native", skip_ads) + end + if options.display_name ~= "" then + local args = { + options.python_path, + sponsorblock, + "username", + database_file, + options.server_address, + youtube_id, + "", + "", + uid_path, + options.user_id, + options.display_name + } + if not legacy then + mp.command_native_async({name = "subprocess", playback_only = false, args = args}, function () end) + else + utils.subprocess_detached({args = args}) + end + end + if not options.local_database or (not options.auto_update and file_exists(database_file)) then return end + + if file_exists(database_file) then + local db_info = utils.file_info(database_file) + local cur_time = os.time(os.date("*t")) + local upd_interval = parse_update_interval() + if upd_interval == nil or os.difftime(cur_time, db_info.mtime) < upd_interval then return end + end + + update() +end + +function set_segment() + if not youtube_id then return end + local pos = mp.get_property_number("time-pos") + if pos == nil then return end + if segment.progress > 1 then + segment.progress = segment.progress - 2 + end + if segment.progress == 1 then + segment.progress = 0 + segment.b = pos + mp.osd_message("[sponsorblock] segment boundary B set, press again for boundary A", 3) + else + segment.progress = 1 + segment.a = pos + mp.osd_message("[sponsorblock] segment boundary A set, press again for boundary B", 3) + end + if options.make_chapters and not segment.first then + local start_time = math.min(segment.a, segment.b) + local end_time = math.max(segment.a, segment.b) + if end_time - start_time ~= 0 and end_time ~= 0 then + clean_chapters() + create_chapter("Preview segment start", start_time) + create_chapter("Preview segment end", end_time) + end + end + segment.first = false +end + +function select_category(selected) + for category in string.gmatch(options.categories, "([^,]+)") do + mp.remove_key_binding("select_category_"..category) + mp.remove_key_binding("kp_select_category_"..category) + end + submit_segment(selected) +end + +function submit_segment(category) + if not youtube_id then return end + local start_time = math.min(segment.a, segment.b) + local end_time = math.max(segment.a, segment.b) + if end_time - start_time == 0 or end_time == 0 then + mp.osd_message("[sponsorblock] empty segment, not submitting") + elseif segment.progress <= 1 then + segment.progress = segment.progress + 2 + local category_list = "" + for category_id, category in pairs(all_categories) do + local category_title = (category:gsub("^%l", string.upper):gsub("_", " ")) + category_list = category_list .. category_id .. ": " .. category_title .. "\n" + mp.add_forced_key_binding(tostring(category_id), "select_category_"..category, function() select_category(category) end) + mp.add_forced_key_binding("KP"..tostring(category_id), "kp_select_category_"..category, function() select_category(category) end) + end + mp.osd_message(string.format("[sponsorblock] press a number to select category for segment: %.2d:%.2d:%.2d to %.2d:%.2d:%.2d\n\n" .. category_list .. "\nyou can press Shift+G again for default (Sponsor) or hide this message with g", math.floor(start_time/(60*60)), math.floor(start_time/60%60), math.floor(start_time%60), math.floor(end_time/(60*60)), math.floor(end_time/60%60), math.floor(end_time%60)), 30) + else + mp.osd_message("[sponsorblock] submitting segment...", 30) + local submit + local args = { + options.python_path, + sponsorblock, + "submit", + database_file, + options.server_address, + youtube_id, + tostring(start_time), + tostring(end_time), + uid_path, + options.user_id, + category or "sponsor" + } + if not legacy then + submit = mp.command_native({name = "subprocess", capture_stdout = true, playback_only = false, args = args}) + else + submit = utils.subprocess({args = args}) + end + if string.match(submit.stdout, "success") then + segment = {a = 0, b = 0, progress = 0, first = true} + mp.osd_message("[sponsorblock] segment submitted") + if options.make_chapters then + clean_chapters() + create_chapter("Submitted segment start", start_time) + create_chapter("Submitted segment end", end_time) + end + elseif string.match(submit.stdout, "error") then + mp.osd_message("[sponsorblock] segment submission failed, server may be down. try again", 5) + elseif string.match(submit.stdout, "502") then + mp.osd_message("[sponsorblock] segment submission failed, server is down. try again", 5) + elseif string.match(submit.stdout, "400") then + mp.osd_message("[sponsorblock] segment submission failed, impossible inputs", 5) + segment = {a = 0, b = 0, progress = 0, first = true} + elseif string.match(submit.stdout, "429") then + mp.osd_message("[sponsorblock] segment submission failed, rate limited. try again", 5) + elseif string.match(submit.stdout, "409") then + mp.osd_message("[sponsorblock] segment already submitted", 3) + segment = {a = 0, b = 0, progress = 0, first = true} + else + mp.osd_message("[sponsorblock] segment submission failed", 5) + end + end +end + +mp.register_event("file-loaded", file_loaded) +mp.add_key_binding("g", "set_segment", set_segment) +mp.add_key_binding("G", "submit_segment", submit_segment) +mp.add_key_binding("$", "upvote_segment", function() return vote("1") end) +mp.add_key_binding("%", "downvote_segment", function() return vote("0") end) +-- Bindings below are for backwards compatibility and could be removed at any time +mp.add_key_binding(nil, "sponsorblock_set_segment", set_segment) +mp.add_key_binding(nil, "sponsorblock_submit_segment", submit_segment) +mp.add_key_binding(nil, "sponsorblock_upvote", function() return vote("1") end) +mp.add_key_binding(nil, "sponsorblock_downvote", function() return vote("0") end) diff --git a/.config/mpv/scripts/sponsorblock_shared/main.lua b/.config/mpv/scripts/sponsorblock_shared/main.lua @@ -0,0 +1,3 @@ +-- This is a dummy main.lua +-- required for mpv 0.33 +-- do not delete +\ No newline at end of file diff --git a/.config/mpv/scripts/sponsorblock_shared/sponsorblock.py b/.config/mpv/scripts/sponsorblock_shared/sponsorblock.py @@ -0,0 +1,124 @@ +# GPLv3 + +import urllib.request +import urllib.parse +import hashlib +import sqlite3 +import random +import string +import json +import sys +import os + +if sys.argv[1] in ["submit", "stats", "username"]: + if not sys.argv[8]: + if os.path.isfile(sys.argv[7]): + with open(sys.argv[7]) as f: + uid = f.read() + else: + uid = "".join(random.choices(string.ascii_letters + string.digits, k=36)) + with open(sys.argv[7], "w") as f: + f.write(uid) + else: + uid = sys.argv[8] + +opener = urllib.request.build_opener() +opener.addheaders = [("User-Agent", "mpv_sponsorblock/1.0 (https://github.com/po5/mpv_sponsorblock)")] +urllib.request.install_opener(opener) + +if sys.argv[1] == "ranges" and (not sys.argv[2] or not os.path.isfile(sys.argv[2])): + sha = None + if 3 <= int(sys.argv[6]) <= 32: + sha = hashlib.sha256(sys.argv[4].encode()).hexdigest()[:int(sys.argv[6])] + times = [] + try: + response = urllib.request.urlopen(sys.argv[3] + "/api/skipSegments" + ("/" + sha + "?" if sha else "?videoID=" + sys.argv[4] + "&") + urllib.parse.urlencode([("categories", json.dumps(sys.argv[5].split(",")))])) + segments = json.load(response) + for segment in segments: + if sha and sys.argv[4] != segment["videoID"]: + continue + if sha: + for s in segment["segments"]: + times.append(str(s["segment"][0]) + "," + str(s["segment"][1]) + "," + s["UUID"] + "," + s["category"]) + else: + times.append(str(segment["segment"][0]) + "," + str(segment["segment"][1]) + "," + segment["UUID"] + "," + segment["category"]) + print(":".join(times)) + except (TimeoutError, urllib.error.URLError) as e: + print("error") + except urllib.error.HTTPError as e: + if e.code == 404: + print("") + else: + print("error") +elif sys.argv[1] == "ranges": + conn = sqlite3.connect(sys.argv[2]) + conn.row_factory = sqlite3.Row + c = conn.cursor() + times = [] + for category in sys.argv[5].split(","): + c.execute("SELECT startTime, endTime, votes, UUID, category FROM sponsorTimes WHERE videoID = ? AND shadowHidden = 0 AND votes > -1 AND category = ?", (sys.argv[4], category)) + sponsors = c.fetchall() + best = list(sponsors) + dealtwith = [] + similar = [] + for sponsor_a in sponsors: + for sponsor_b in sponsors: + if sponsor_a is not sponsor_b and sponsor_a["startTime"] >= sponsor_b["startTime"] and sponsor_a["startTime"] <= sponsor_b["endTime"]: + similar.append([sponsor_a, sponsor_b]) + if sponsor_a in best: + best.remove(sponsor_a) + if sponsor_b in best: + best.remove(sponsor_b) + for sponsors_a in similar: + if sponsors_a in dealtwith: + continue + group = set(sponsors_a) + for sponsors_b in similar: + if sponsors_b[0] in group or sponsors_b[1] in group: + group.add(sponsors_b[0]) + group.add(sponsors_b[1]) + dealtwith.append(sponsors_b) + best.append(max(group, key=lambda x:x["votes"])) + for time in best: + times.append(str(time["startTime"]) + "," + str(time["endTime"]) + "," + time["UUID"] + "," + time["category"]) + print(":".join(times)) +elif sys.argv[1] == "update": + try: + urllib.request.urlretrieve(sys.argv[3] + "/database.db", sys.argv[2] + ".tmp") + os.replace(sys.argv[2] + ".tmp", sys.argv[2]) + except PermissionError: + print("database update failed, file currently in use", file=sys.stderr) + sys.exit(1) + except ConnectionResetError: + print("database update failed, connection reset", file=sys.stderr) + sys.exit(1) + except TimeoutError: + print("database update failed, timed out", file=sys.stderr) + sys.exit(1) + except urllib.error.URLError: + print("database update failed", file=sys.stderr) + sys.exit(1) +elif sys.argv[1] == "submit": + try: + req = urllib.request.Request(sys.argv[3] + "/api/skipSegments", data=json.dumps({"videoID": sys.argv[4], "segments": [{"segment": [float(sys.argv[5]), float(sys.argv[6])], "category": sys.argv[9]}], "userID": uid}).encode(), headers={"Content-Type": "application/json"}) + response = urllib.request.urlopen(req) + print("success") + except urllib.error.HTTPError as e: + print(e.code) + except: + print("error") +elif sys.argv[1] == "stats": + try: + if sys.argv[6]: + urllib.request.urlopen(sys.argv[3] + "/api/viewedVideoSponsorTime?UUID=" + sys.argv[5]) + if sys.argv[9]: + urllib.request.urlopen(sys.argv[3] + "/api/voteOnSponsorTime?UUID=" + sys.argv[5] + "&userID=" + uid + "&type=" + sys.argv[9]) + except: + pass +elif sys.argv[1] == "username": + try: + data = urllib.parse.urlencode({"userID": uid, "userName": sys.argv[9]}).encode() + req = urllib.request.Request(sys.argv[3] + "/api/setUsername", data=data) + urllib.request.urlopen(req) + except: + pass diff --git a/.config/mpv/scripts/sponsorblock_shared/sponsorblock.txt b/.config/mpv/scripts/sponsorblock_shared/sponsorblock.txt @@ -0,0 +1 @@ +tKxWZu9YIdFw0N076PS1f66ZjxP9TpM8Rcnk +\ No newline at end of file diff --git a/.config/mpv/watch_later/04DA18843AC93F825AE495D1DFCA4CBF b/.config/mpv/watch_later/04DA18843AC93F825AE495D1DFCA4CBF @@ -0,0 +1 @@ +start=707.842333 diff --git a/.config/mpv/watch_later/1DAD0641B5D9BC10A47E66A8B9D6A9E9 b/.config/mpv/watch_later/1DAD0641B5D9BC10A47E66A8B9D6A9E9 @@ -0,0 +1 @@ +# redirect entry diff --git a/.config/mpv/watch_later/20963CD7DBA0991EFF3F99883ACA8F4B b/.config/mpv/watch_later/20963CD7DBA0991EFF3F99883ACA8F4B @@ -0,0 +1,2 @@ +start=178.006556 +fullscreen=yes diff --git a/.config/mpv/watch_later/46DB9A533C9815F63F3232F2B01601A4 b/.config/mpv/watch_later/46DB9A533C9815F63F3232F2B01601A4 @@ -0,0 +1,3 @@ +start=949.833000 +pause=no +fullscreen=yes diff --git a/.config/neomutt/alias b/.config/neomutt/alias @@ -0,0 +1 @@ +alias alex Alex Hamilton <alexhamilton1978@hotmail.com> diff --git a/.config/neomutt/colours b/.config/neomutt/colours @@ -1,72 +0,0 @@ -# vim: filetype=neomuttrc - -set index_format="%4C %Z %{%b %d} %-15.15r %-20.20L (%?l?%4l&%4c?) %-3.3M %s" - -# Default index colors: -color index yellow default '.*' -color index_author magenta default '.*' -color index_number magenta default -color index_subject cyan default '.*' - -# For new mail: -color index_flags color14 default "~N" -color index_flags color14 default "~O" - -# For threads -#color index_subject default default "~v" -color index_flags color14 default "~(~N)" # matches threads which contain unread entries -color index_flags color14 default "~(~O)" # ditto - -# Header colors: -color header blue default ".*" -color header brightmagenta default "^(From)" -color header brightcyan default "^(Subject)" -color header brightwhite default "^(CC|BCC)" - -mono bold bold -mono underline underline -mono indicator reverse -mono error bold -color normal default default -color indicator brightblack white -color normal brightyellow default -color error red default -color tilde black default -color message cyan default -color markers red white -color attachment white default -color search brightmagenta default -color status brightyellow black -color hdrdefault brightgreen default -color quoted color3 default -color quoted1 color4 default -color quoted2 color5 default -color quoted3 color6 default -color quoted4 color7 default -color quoted5 color7 default -color quoted6 color7 default -color quoted7 color7 default -color signature brightgreen default -color bold black default -color underline black default -color normal default default - -color body brightred default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+" # Email addresses -color body brightblue default "(https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+" # URL -color body green default "\`[^\`]*\`" # Green text between ` and ` -color body brightblue default "^# \.*" # Headings as bold blue -color body brightcyan default "^## \.*" # Subheadings as bold cyan -color body brightgreen default "^### \.*" # Subsubheadings as bold green -color body yellow default "^(\t| )*(-|\\*) \.*" # List items as yellow -color body color10 default "(BAD signature)" -color body color14 default "(Good signature)" -color body brightyellow default "^gpg: " -color body red default "([a-z][a-z0-9+-]*://(((([a-z0-9_.!~*'();:&=+$,-]|%[0-9a-f][0-9a-f])*@)?((([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)(:[0-9]+)?)|([a-z0-9_.!~*'()$,;:@&=+-]|%[0-9a-f][0-9a-f])+)(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?(#([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?|(www|ftp)\\.(([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?(:[0-9]+)?(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?(#([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?)[^].,:;!)? \t\r\n<>\"]" - -# Set status bar color -set status_format="" -set compose_format="" -set pager_format="" -set markers=no -color status color5 default -color progress color2 color23 diff --git a/.config/neomutt/neomuttrc b/.config/neomutt/neomuttrc @@ -1,40 +1,16 @@ -set ssl_starttls = yes -set ssl_force_tls = yes set mailcap_path = "~/.config/neomutt/mailcap" -set smtp_authenticators = "plain" - -set abort_key = "<Esc>" -set abort_nosubject = no -set abort_unmodified = no set alias_file = "~/.config/neomutt/alias" -source folders -source colours +set folder = "~/mail/" +set header_cache = "~/mail/cache/" +set message_cachedir = "~/mail/cache/" + +source ~/mail/neomuttrc source sidebar source alias source gpg -bind index D purge-message -bind index,pager M compose-to-sender -bind index \Ct collapse-thread -bind index \Ca collapse-all - -bind compose F edit-from - -set sort=threads -set collapse_all -set help=no - set signature=~/.config/neomutt/signatures -macro index S <save-message>=spam<enter><enter> -macro index A <save-message>=spam-domain<enter><enter> -macro index R \ - <collapse-all>"T ~O | ~N\n;N" \ - "mark all new as read" -macro index E <save-message>=sent<enter><enter> - -my_hdr X-Mailer: neomutt -hdr_order Subject From To Date - -set new_mail_command = "sh -c 'herbe \"%b mailboxes have new mail\" &'" +macro index z "<enter-command>unset wait_key\n<pipe-entry>bmf -S\n<enter-command>set wait_key\n<save-message>=spam" +macro index x "<enter-command>unset wait_key\n<pipe-entry>bmf -N\n<enter-command>set wait_key\n<save-message>=" diff --git a/.config/neomutt/signatures b/.config/neomutt/signatures @@ -0,0 +1,2 @@ +Regards, +Hayden diff --git a/.config/neomutt/users/backtrack@airmail.cc b/.config/neomutt/users/backtrack@airmail.cc @@ -0,0 +1,7 @@ +# vim: set syntax=neomuttrc : +set imap_pass = `dpass cock.li` +set smtp_pass = `dpass cock.li` +set spoolfile = "+inbox-airmail" +set smtp_url = "smtp://backtrack@airmail.cc@mail.cock.li:587" +set from = "backtrack@airmail.cc" +set realname = "hhvn" diff --git a/.config/neomutt/users/hayden@haydenvh.com b/.config/neomutt/users/hayden@haydenvh.com @@ -0,0 +1,8 @@ +# vim: set syntax=neomuttrc : +set spoolfile = "+haydenvhcom" +set smtp_url = "smtp://haydenvh.com:15556" +set from = "hayden@haydenvh.com" +set realname = "Hayden Hamilton" +set smtp_authenticators = plain + +my_hdr Organization: haydenvh.com diff --git a/.config/neomutt/users/hhvn@dataswamp.org b/.config/neomutt/users/hhvn@dataswamp.org @@ -0,0 +1,6 @@ +# vim: set syntax=neomuttrc : +set smtp_pass = `dpass smtp-hayden@haydenvh.com` +set spoolfile = "+dataswamporg" +set smtp_url = "smtp://void@haydenvh.com:587" +set from = "hhvn@dataswamp.org" +set realname = "hhvn" diff --git a/.config/neomutt/users/irc@hlirc.net b/.config/neomutt/users/irc@hlirc.net @@ -0,0 +1,9 @@ +# vim: set syntax=neomuttrc : +set smtp_pass = `dpass smtp-hayden@haydenvh.com` +set spoolfile = "+inbox-hlircnet" +set smtp_url = "smtp://hayden@haydenvh.com:587" +set from = "hhvn@hlirc.net" +set realname = "hhvn" +#set pgp_sign_as=0xCDCBDA3B70AC90AB + +my_hdr Organization: HLIRCnet diff --git a/.config/nvim/init.vim b/.config/nvim/init.vim @@ -156,9 +156,6 @@ ino <Down> <Nop> ino <Left> <Nop> ino <Right> <Nop> -"Use o/O -no A<CR> <Nop> - "Registers set clipboard=unnamed diff --git a/.config/nvim/modules/filetype.vim b/.config/nvim/modules/filetype.vim @@ -49,7 +49,6 @@ endfunction augroup filetypes autocmd FileType,WinEnter,BufEnter netrw call Configurenetrw() - autocmd FileType html :normal gg=G autocmd FileType html :setlocal nowrap autocmd FileType c :noremap <buffer> <localleader>e $a;<esc> autocmd FileType c :inoremap <buffer> <localleader><localleader>e <esc>$a;<esc> diff --git a/.config/qutebrowser/config.py b/.config/qutebrowser/config.py @@ -1,4 +1,4 @@ -from PyQt5.QtCore import QUrl +from PyQt6.QtCore import QUrl from qutebrowser.api import interceptor from qutebrowser.browser import commands import subprocess @@ -21,17 +21,59 @@ c.changelog_after_upgrade = 'never' # Don't annoy me. c.new_instance_open_target = 'tab-bg-silent' +white = '#cccccc' +normfg = '#cccccc' +normbg = '#050a10' +selbg = '#1b364b' + # Selected tabs c.colors.tabs.selected.even.bg = '#1b364b' c.colors.tabs.selected.odd.bg = '#1b364b' -c.colors.tabs.selected.even.fg = 'white' -c.colors.tabs.selected.odd.fg = 'white' - -# Unselected tabs +c.colors.tabs.selected.even.fg = white +c.colors.tabs.selected.odd.fg = white c.colors.tabs.even.bg = '#050a10' c.colors.tabs.odd.bg = '#050a10' -c.colors.tabs.even.fg = 'white' -c.colors.tabs.odd.fg = 'white' +c.colors.tabs.even.fg = white +c.colors.tabs.odd.fg = white + +# Unselected tabs +c.colors.webpage.darkmode.enabled = False +c.colors.webpage.darkmode.enabled = False + +# Statusbar +c.colors.statusbar.url.hover.fg = 'aqua' +c.colors.statusbar.progress.bg = selbg +c.colors.statusbar.command.private.fg = '#005f87' +c.colors.statusbar.command.private.bg = selbg +c.colors.statusbar.passthrough.fg = '#bb5540' +c.colors.statusbar.passthrough.bg = normbg +c.colors.statusbar.normal.fg = normfg +c.colors.statusbar.normal.bg = 'black' +c.colors.statusbar.command.fg = '#005f87' +c.colors.statusbar.command.bg = 'black' + +# Completion +# c.colors.completion.category.border.bottom = 'black' +# c.colors.completion.category.border.top = 'black' +# c.colors.completion.category.fg = 'white' +# c.colors.completion.even.bg = '#333333' +# c.colors.completion.fg = [white, white, 'white'] +# c.colors.completion.odd.bg = '#444444' +# c.colors.completion.odd.bg = '#444444' +# c.colors.completion.category.fg = cyan +# c.colors.completion.category.bg = normbg +# c.colors.completion.category.border.bottom = normbg +# c.colors.completion.category.border.top = normbg +# c.colors.completion.item.selected.bg = '#e8c000' +# c.colors.completion.item.selected.border.bottom = '#bbbb00' +# c.colors.completion.item.selected.border.top = '#bbbb00' +# c.colors.completion.item.selected.fg = 'black' +# c.colors.completion.item.selected.match.fg = '#ff4444' +# c.colors.completion.match.fg = '#ff4444' +# c.completion.scrollbar.width = 0 +# c.completion.scrollbar.padding = 0 +# c.colors.completion.scrollbar.bg = normbg +# c.colors.completion.scrollbar.fg = normbg # Tabbed muscle memory config.bind('<Alt-q>', 'tab-close') @@ -54,17 +96,23 @@ c.editor.command = ['rc', '-c', 'cd `$nl{dirname \'{file}\'}; st -e vim `$nl{bas config.bind('R', 'config-source') config.bind('e', 'config-edit') +# Shady +c.aliases = {'tor': 'set content.proxy socks://localhost:9050 ;; set content.javascript.enabled false ;; open -t check.torproject.org', + 'i2p': 'set content.proxy http://localhost:4444 ;; set content.javascript.enabled false ;; open -t localhost:7070', + 'unproxy': 'set content.proxy none ;; set content.javascript.enabled true', + 'jon': 'set content.javascript.enabled true', + 'joff': 'set content.javascript.enabled false'} + # I need to plumb -config.bind('d', 'hint all spawn plumb {hint-url}') -config.bind('D', 'hint all spawn rc -c \'net/download -d {hint-url}\'') -config.bind('v', 'hint all spawn rc -c \'nohup mpv --pause {hint-url} >/dev/null >[2]/dev/null &\'') +config.bind('d', 'hint all download') +c.downloads.location.directory = "~/downloads/" # Warp the mouse as seen by qtwebengine config.bind('a', 'hint all hover') # Alphabet soup config.bind('A', 'spawn --userscript randomagent') -c.content.headers.user_agent = '.' +c.content.headers.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36' # Stylesheets c.content.user_stylesheets = stylesheets.list @@ -102,15 +150,11 @@ def domainredir(info: interceptor.Request): # them? Why can't you give me a switch statement? I would love for # string-capable switch statements to exist in more languages. if (host == 'twitter.com' or host == 'www.twitter.com' or host == 'mobile.twitter.com'): - target.setHost('nitter.net'); - elif (host == 'reddit.com' or host == 'www.reddit.com' or host == 'old.reddit.com'): - target.setHost('teddit.net'); - elif (host == 'instagram.com' or host == 'www.instagram.com'): - target.setHost('bibliogram.art'); + target.setHost('nitter.io.lol'); + elif (host == 'reddit.com' or host == 'www.reddit.com' or host == 'teddit.net'): + target.setHost('old.reddit.com'); elif (host == 'en.m.wikipedia.org'): target.setHost('en.wikipedia.org'); - elif (host == 'npr.org' or host == 'www.npr.org'): - target.setHost('text.npr.org'); else: return @@ -137,3 +181,16 @@ config.bind('ym', 'yank inline [{title}]({url}) -s') config.bind('yp', 'yank pretty-url -s') config.bind('yt', 'yank title -s') config.bind('yy', 'yank -s') +config.bind('yh', 'hint all yank-primary') + +# Keeps getting in the way +config.unbind('q') + +# Bookmarks +config.bind('m', 'bookmark-add') +config.bind('b', 'set-cmd-text -s :bookmark-load') +config.bind('B', 'set-cmd-text -s :bookmark-load -t') +config.bind('M', 'set-cmd-text -s :bookmark-del') + +# Notifications +c.content.notifications.presenter = 'herbe' diff --git a/.config/redshift/redshift.conf b/.config/redshift/redshift.conf @@ -2,9 +2,12 @@ [redshift] temp-day=4700 -temp-night=3500 +temp-night=1700 -; Pozzy london time - I don't wanna be v& +dawn-time=6:30-8:00 +dusk-time=20:00-21:30 + +; London. Yeah whatever. location-provider=manual [manual] lat=51.509865 diff --git a/.config/sxhkd/sxhkdrc b/.config/sxhkd/sxhkdrc @@ -13,19 +13,13 @@ super + shift + t pkill -SIGUSR2 herbe super + ctrl + t - pkill -SIGKILL herbe; herbe + pkill -SIGKILL herbe; herbe; herbe Fixed! super + alt + t herbe 'test' -super + a - addrbook - -super + shift + a - mailselect - super + b - pgrep qutebrowser && herbe 'qutebrowser already running' || qutebrowser + qutebrowser super + n st -t neomutt -c neomutt -e sh -c 'neomutt; $SHELL' @@ -34,7 +28,7 @@ super + c slock_mod super + shift + c - slock + slock_mod & doas zzz super + d dmenu_run @@ -43,7 +37,7 @@ super + u plumb `''{xclip -o} super + s - dpass + st -c dpass -g 100x45 -b -e dpass super + shift + s maim -s | hlpaste 'png' @@ -52,45 +46,23 @@ super + ctrl + s maim | hlpaste 'png' @super + w - wallp $home/general/images/wallpapers/ - -super + ctrl + w - wallblur + wallp $home/wallpapers/ -super + shift + g - chradio - -super + shift + o - addtorrent xclip - -# Socket mpv control -# super + alt + [y,u] -# rmpv general/[videos,music]/list -# -# super + ctrl + [i,p] -# hmpv [back,forward] /tmp/mpv-socket -# -# super + alt + [i,p] -# hmpv [prev,next] /tmp/mpv-socket -# -# super + [ctrl,alt] + o -# hmpv [toggle,quit] /tmp/mpv-socket -# -# super + shift + n -# st -c mpvrcp -g 150x30 -b -e mpvrcp /tmp/mpv-socket +super + p + if (pgrep -x scrcpy >/dev/null) { xid = `{xdotool search --class scrcpy}; xid = $xid(1); bspc node $xid -g hidden; if (~ `{bspc query -n $xid -T | jq .hidden} false) { bspc node $xid -f } } else { scrcpy --no-audio } # cmus control super + ctrl + [i,p] - cmus-remote --seek [-5,+5] + cmus-remote --server 127.0.0.1 --passwd helloworld --seek [-5,+5] super + alt + [i,p] - cmus-remote [--prev,--next] + cmus-remote --server 127.0.0.1 --passwd helloworld [--prev,--next] super + [ctrl,alt] + o - cmus-remote [--pause,--stop] + cmus-remote --server 127.0.0.1 --passwd helloworld [--pause,--stop] -super + m - st -c cmus -g 150x30 -b -e rc -c 'tmux new-session -As cmus cmus' +super + shift + m + st -c cmus -g 150x30 -b -e rc -c 'tmux new-session -As cmus cmus --listen 0.0.0.0' super + [minus,equal] hvol 3%[-,+] @@ -104,12 +76,6 @@ super + shift [minus,equal] shift + [XF86AudioLowerVolume, XF86AudioRaiseVolume] hvol 6%[-,+] -super + shift + h - st -e htop - -Menu - xdotool click 2 - #thinkpad codes # XF86Sleep diff --git a/.config/transmission/settings.json b/.config/transmission/settings.json @@ -1,99 +0,0 @@ -{ - "alt-speed-down": 50, - "alt-speed-enabled": true, - "alt-speed-time-begin": 540, - "alt-speed-time-day": 127, - "alt-speed-time-enabled": false, - "alt-speed-time-end": 1020, - "alt-speed-up": 0, - "bind-address-ipv4": "0.0.0.0", - "bind-address-ipv6": "::", - "blocklist-enabled": true, - "blocklist-updates-enabled": true, - "blocklist-url": "https://github.com/sahsu/transmission-blocklist/releases/latest/download/blocklist.gz", - "cache-size-mb": 4, - "compact-view": false, - "details-window-height": 542, - "details-window-width": 700, - "dht-enabled": false, - "download-dir": "/home/hayden/general/music", - "download-queue-enabled": true, - "download-queue-size": 5, - "encryption": 1, - "idle-seeding-limit": 30, - "idle-seeding-limit-enabled": false, - "incomplete-dir": "/home/hayden/.incomplete", - "incomplete-dir-enabled": true, - "inhibit-desktop-hibernation": false, - "lpd-enabled": true, - "main-window-height": 1031, - "main-window-is-maximized": 0, - "main-window-width": 850, - "main-window-x": 1930, - "main-window-y": 35, - "message-level": 2, - "open-dialog-dir": "/home/hayden", - "peer-congestion-algorithm": "", - "peer-id-ttl-hours": 6, - "peer-limit-global": 200, - "peer-limit-per-torrent": 50, - "peer-port": 51413, - "peer-port-random-high": 65535, - "peer-port-random-low": 49152, - "peer-port-random-on-start": false, - "peer-socket-tos": "default", - "pex-enabled": true, - "port-forwarding-enabled": false, - "preallocation": 1, - "prefetch-enabled": true, - "queue-stalled-enabled": true, - "queue-stalled-minutes": 30, - "ratio-limit": 30, - "ratio-limit-enabled": true, - "recent-download-dir-1": "/home/hayden/general/music", - "rename-partial-files": true, - "rpc-authentication-required": false, - "rpc-bind-address": "0.0.0.0", - "rpc-enabled": true, - "rpc-host-whitelist": "", - "rpc-host-whitelist-enabled": true, - "rpc-password": "{72dc83c52677798ae1153353e83400d2301771ff2ownXslf", - "rpc-port": 9091, - "rpc-url": "/transmission/", - "rpc-username": "", - "rpc-whitelist": "127.0.0.1,::1", - "rpc-whitelist-enabled": true, - "scrape-paused-torrents-enabled": true, - "script-torrent-done-enabled": false, - "script-torrent-done-filename": "/home/hayden", - "seed-queue-enabled": false, - "seed-queue-size": 10, - "show-backup-trackers": false, - "show-extra-peer-details": false, - "show-filterbar": false, - "show-notification-area-icon": false, - "show-options-window": true, - "show-statusbar": true, - "show-toolbar": false, - "show-tracker-scrapes": true, - "sort-mode": "sort-by-time-left", - "sort-reversed": true, - "speed-limit-down": 750, - "speed-limit-down-enabled": true, - "speed-limit-up": 1000000, - "speed-limit-up-enabled": true, - "start-added-torrents": true, - "statusbar-stats": "total-transfer", - "torrent-added-notification-enabled": true, - "torrent-complete-notification-enabled": true, - "torrent-complete-sound-command": "torrentdone", - "torrent-complete-sound-enabled": true, - "trash-can-enabled": true, - "trash-original-torrent-files": false, - "umask": 18, - "upload-slots-per-torrent": 14, - "user-has-given-informed-consent": true, - "utp-enabled": true, - "watch-dir": "/home/hayden/Desktop", - "watch-dir-enabled": false -} diff --git a/.rcrc b/.rcrc @@ -1,31 +1,3 @@ -# Fuck GNU -if (~ `$nl{grep --version >[2=1]} *GNU*) - __prompt_gnu_binary = 'a' - -fn __prompt_tput { - # Use \001 and \002 to tell readline - # wether a character is visible or not - printf '\001%s\002' `''{tput $*} -} - -fn __prompt_exit_colour { - if (~ $1 0) { - __prompt_tput setaf 15 - } else if (~ $1 sig*) { - __prompt_tput setaf 8 - } else { - __prompt_tput setaf 10 - } -} - -fn __prompt_cleanup { - for (f in $__prompt_tmp) { - rm -f $f - } - __prompt_tmp = () - tput sgr0 -} - fn sigexit { __prompt_cleanup for (f in $manconfs) { @@ -33,117 +5,8 @@ fn sigexit { } } -# Backend prompt function -fn __prompt { - __prompt_exitcodes = $status - __prompt_gitoutput = 0 - __prompt_tmp = (/tmp/$pid.prompt.tmp $__prompt_tmp) - - # exit codes - # rc produces a list if there is a pipeline - if (~ $__prompt_exitcodes(2) ()) { - # only one - __prompt_exit_colour $__prompt_exitcodes(1) - printf '%s ' $__prompt_exitcodes(1) | sed 's/^sig//' - } else { - __prompt_tput setaf 3 - printf '[' - __prompt_print_bar = 0 - for (__prompt_exitcode in $__prompt_exitcodes) { - if (~ $__prompt_print_bar 1) { - __prompt_tput setaf 3 - printf '|' - } else { - __prompt_print_bar = 1 - } - __prompt_exit_colour $__prompt_exitcode - printf '%s' $__prompt_exitcode | sed 's/^sig//' - } - __prompt_tput setaf 3 - printf '] ' - } - - # username - __prompt_tput setaf 5 - printf '%s ' `{whoami} - - if (!~ $hide_git 1) { - # branch - __prompt_tput setaf 3 - __prompt_branch = `{git branch >[2]/dev/null | - grep '^*' | - awk '{print $2 "|"}'} - if (!~ $__prompt_branch ()) { - printf '%s' $__prompt_branch - __prompt_gitoutput = 1 - } - - # unstaged changes - git diff >[2]/dev/null > $__prompt_tmp(1) - __prompt_diffstatus = $bqstatus - if (head -n 1 < $__prompt_tmp(1) | grep '^.' >/dev/null) { - __prompt_tput setaf 8 - printf '%s+' `{cat $__prompt_tmp(1) | - grep '-E'^$__prompt_gnu_binary '^(\+\+\+|---)' | - sed -E 's~^[^a]*a/|^[^b]*b/~~' | - grep -v /dev/null | - uniq | - wc -l | - tr -d '\n'} - __prompt_gitoutput = 1 - } else if (~ $bqstatus 0) { - __prompt_tput setaf 15 - printf '=' - __prompt_gitoutput = 1 - } - - # unpushed commits - git log '--pretty=format:commit %h%d' >[2]/dev/null > $__prompt_tmp(1) - if (!~ `$nl{head -n 1 < $__prompt_tmp(1)} */*) { - __prompt_tput setaf 14 - < $__prompt_tmp(1) awk ' - BEGIN {c = 0; exitcode = 1} - /^commit/ { - if ($0 ~ /\//) { - printf("%d^", c) - exitcode = 0 - exit(0) - } else c += 1 - } - END { exit(exitcode) }' && __prompt_gitoutput = 1 - } - } - - if (~ $__prompt_gitoutput 1) { - printf ' ' - } - - # dir - __prompt_tput setaf 7 - printf '%s' `{pwd | sed 's~' ^ $home ^ '~\~~'} - - # end - printf '$ ' - __prompt_cleanup -} - -# Frontend prompt function fn prompt { - __prompt_content = `''{__prompt} - __prompt_indent = `$nl{printf '%s' $__prompt_content | - awk '{gsub(/\001[^\002]*\002/, ""); print}' | - sed 's/[^ ]/ /g;s/$/ /g'} - prompt = ($__prompt_content $__prompt_indent) - - # missing newline - # https://www.vidarholen.net/contents/blog/?p=878 - __prompt_tput setaf 14 - printf '%%' - tr '\0' ' ' < /dev/zero | head -c `{tput cols} | sed 's/.//' - printf '\r' - - # set X11 title - printf '\033]0;rc (%s)\007' `{pwd | sed 's~' ^ $home ^ '~\~~'} + prompt = (`''{builtin prompt $status} '>') } # Aliases @@ -165,15 +28,15 @@ fn v { nvim $* } fn xi { doas xbps-install $*} fn xr { doas xbps-remove $*} fn xq { doas xbps-query $*} -fn ytdl { youtube-dl --add-metadata -ic $* } -fn ytdla { youtube-dl --add-metadata -xic $* } +fn ytdl { yt-dlp --add-metadata -ic $* } +fn ytdla { yt-dlp --add-metadata -xic $* } fn tmux { builtin tmux -f $home/.config/tmux/config $* } fn sloccount { mkdir -p $home/.local/sloccount builtin sloccount --datadir $home/.local/sloccount $* } fn camerasync { - rsync -azP /mnt/DCIM/* $home/general/images/byme + rsync -azP /mnt/DCIM/* $home/photos } fn wtf { if (flag i) { @@ -186,20 +49,6 @@ fn w3m { # Symlink $home/.config/w3m -> $home/.config/.w3m home = $home/.config { builtin w3m $* } } -fn _man { - conf = '/tmp/'^$pid^'.man.conf' program = $1 { - sed -E 's~HOME~'^$home^'~g' < $home/.config/man.conf > $conf - manconfs = ($manconfs $conf) - shift 1 - builtin $program -C $conf $* - for (f in $manconfs) { - rm -f $f >[2]/dev/null - } - } -} -fn man { _man man $* } -fn apropos { _man apropos $* } -fn makewhatis { _man makewhatis $* } fn gpg { builtin gpg --armor $* } fn convert { if (flag i) { @@ -222,10 +71,35 @@ fn dict { } } +# Evaluate command with rc +fn doas { + opts = () exec = () args = () { + while (~ $1 -*) { + if (~ $1 *[Cu]) { + opts = ($opts $1 $2) + shift 2 + } else { + opts = ($opts $1) + shift + } + } + + args=`''{whatis '*' | sed -E 's~^\*=\(?~~;s~\)$~~' | head -c -1} + + builtin doas $opts rc -c $args + } +} + +fn feeds { + SFEED_URL_FILE=$home/.local/sfeed-read + sfeed_curses $home/.local/sfeed/* +} + # Enable coredumps of practically infinite size. limit coredumpsize 99999999 # .profile +CC = clang INPUTRC = $home/.config/readline/inputrc EDITOR = nvim PAGER = less @@ -244,6 +118,8 @@ IPFS_PATH = $home/.local/ipfs CURLHOME = $home/.config/curl/" LS_COLORS = `''{<$home/.config/ls tr -d ' ' | tr '\n' ':' | tr -s ':'} +ANDROID_HOME=$home/.android-sdk + history = $XDG_CACHE_HOME/history # Originally I had $HOME/.scripts placed before the regular $PATH to override # things, however this can mess with traditional unix shells that don't @@ -251,4 +127,15 @@ history = $XDG_CACHE_HOME/history # still run the regular /bin/rm, but sh will go 'ah, let's try execute this # directory and see what happens' - of course nothing happens and it gives up # on trying to locate rm. -path = ($path $HOME/.scripts/ /usr/lib/plan9/bin) +if (!~ $rcrcdone true) { + path = ($path $home/cmd/ $home/mail/.cmd $home/go/bin /usr/lib/plan9/bin) +} + +. /etc/locale.conf + +if (~ `{tty} /dev/tty1) { + doas net/autoconf + startx +} + +rcrcdone = true diff --git a/.ssh/config b/.ssh/config @@ -1,58 +0,0 @@ -# Host * -# ControlMaster auto -# ControlPath ~/.ssh/session.%h%p%r.sock -# ControlPersist yes -# VisualHostKey yes -# CheckHostIP yes -# Compression yes - -Host neutron neutron.hhvn.uk phony phony.haydenvh.com phony.hhvn.uk dumbterm dumbterm.haydenvh.com dumbterm.hhvn.uk port port.haydenvh.com port.hhvn.uk - # these are (most of the time) on my LAN - haydenvh.com - # is too, but port forwarded, so proxy to that - #ProxyJump void@haydenvh.com - ForwardX11 yes - -Host neutron neutron.haydenvh.com neutron.hhvn.uk - Hostname 192.168.1.57 - User hayden - -Host port port.haydenvh.com port.hhvn.uk - Hostname 192.168.1.97 - User hayden - -Host dumbterm dumbterm.haydenvh.com dumbterm.hhvn.uk - Hostname 192.168.1.13 - User hayden - -Host phony phony.haydenvh.com phony.hhvn.uk - Hostname 192.168.1.8 - User "user" - -Host dataswamp ds dataswamp.org - Hostname dataswamp.org - User hhvn - -Host local l haydenvh.com hhvn.uk 192.168.1.20 - Hostname hhvn.uk - User void - -Host irc1 irc.haydenvh.com irc.hhvn.uk - Hostname irc.hhvn.uk - User hayden - -Host matrix matrix.haydenvh.com matrix.hhvn.uk - Hostname matrix.hhvn.uk - User hayden - -Host irc2 irc.area51.haydenvh.com irc.area51.hhvn.uk - Hostname irc.area51.hhvn.uk - User hayden - Port 15552 - -Host mx1 mx1.haydenvh.com - Hostname mx1.hhvn.uk - User hayden - -Host tetris - Hostname netris.rocketnine.space - User hhvn diff --git a/.xinitrc b/.xinitrc @@ -1,7 +1,8 @@ #!/bin/rc host = `{hostname} -wm = `{printf 'dwm\nbspwm\n' | dmenu -i} +# wm = `{printf 'dwm\nbspwm\n' | dmenu -i} +wm = bspwm $host^/displays @@ -11,19 +12,29 @@ $host^/keyboard & xmodmap -e 'keysym Control_R = Multi_key' & st & +# while (inotifywait -e close /sys/class/drm/card0*) { +# $host^/displays +# bspwm/configure-monitors +# } & + switch ($wm) { case dwm dwmbar/dwmbar & sxhkd & - while (dwm > .dwm-log) { + while (dwm > /tmp/dwm-log) { true } pkill dwmbar case bspwm sxhkd $home/.config/bspwm/keys & - bspwm > .bspwm-log + # give hbspbar a moment because it needs to connect to bspwm + @{ + sleep 1 + hbspbar & + } + bspwm > /tmp/bspwm-log case * if (command -v $wm >/dev/null) { $wm @@ -32,4 +43,3 @@ case * } } - diff --git a/LICENSE b/LICENSE @@ -1,7 +1,7 @@ Any file not explicitly containing a license included in this repository implicitly falls under the following copyright and licensing terms. -Copyright (C) 2020-2022 hhvn <dev@hhvn.uk> +Copyright (C) 2020-2024 hhvn <dev@hhvn.uk> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. diff --git a/cmd/colotable b/cmd/colotable @@ -1,7 +1,7 @@ #!/bin/sh o=0 -for i in $(seq 0 256) +for i in $(seq 0 ${1:-256}) do [ $o -gt 5 ] && printf "\n" && o=0 o=$(($o+1)) diff --git a/cmd/dpass b/cmd/dpass diff --git a/cmd/pass b/cmd/pass @@ -0,0 +1,128 @@ +#!/bin/rc +# Copyright (c) 2022 hhvn <dev@hhvn.uk> + +if (~ $#PASS 0) { + PASS = $home/.local/pass +} + +if (~ $DISPLAY ()) { + x11 = false +} else { + x11 = true +} + +fn send { + if (~ $x11 true) { + xclip + } else { + cat + printf '\n' + } +} + +fn getpass { + if (! ~ $1 ()) { + if (~ $x11 true) { + p = (-p $1) + shift + } else { + p = $1 + shift + } + } else { + p = () + } + + if (~ $x11 true) { + dmenu $p -P < /dev/null + } else { + printf '%s: ' $p >/dev/stderr + + stty -echo + head -n 1 < /dev/tty + stty echo + } +} + +fn choose { + if (! ~ $1 '-'*) { + if (~ $x11 true) { + p = (-p $1) + shift + } else { + p = (--prompt=$1) + shift + } + } else { + p = () + } + + if (~ $x11 true) { + dmenu -i $p $* + } else { + fzf $p + } +} + +dec = `''{getpass 'Master password' | gpg -qd --passphrase-fd 0 $PASS} + +if (!~ $#* 0) { + opt = $1 + fromarg = 1 +} else { + opt = `$nl{printf '%s' $dec | awk -F: 'BEGIN {printf("GENERATE\nAPPEND\nEDIT\n")}; {print $1}' | choose -l 20} +} + +switch ($opt) { +case GENERATE + newpass = `''{tr -dc 'a-zA-Z0-9~!@$%^&*_+=-' < /dev/urandom | head -c 35} + newname = `$nl{choose 'Name' </dev/null} + if (~ $newname '') { + herbe 'dpass exiting... no pass given' + exit 1 + } + dec = `''{printf '%s%s: %s\n' $dec $newname $newpass} + encfile = /tmp/$pid.plain + touch $encfile + chmod 0700 $encfile + printf '%s' $dec > $encfile + gpg --armor -e --default-recipient-self < $encfile > $PASS + shred -u $encfile + printf '%s' $newpass | send + @{ sleep 25; send </dev/null } & +case APPEND + newname = `$nl{choose 'Name' </dev/null} + newpass = `$nl{getpass 'Password'} + if (~ $newname '') { + herbe 'dpass exiting... no pass given' + exit 1 + } + dec = `''{printf '%s%s: %s\n' $dec $newname $newpass} + encfile = /tmp/$pid.plain + touch $encfile + chmod 0700 $encfile + printf '%s' $dec > $encfile + gpg --armor -e --default-recipient-self < $encfile > $PASS + shred -u $encfile + printf '%s' $newpass | send + @{ sleep 25; send </dev/null } & +case EDIT + encfile = /tmp/$pid.plain + touch $encfile + chmod 0700 $encfile + printf '%s' $dec > $encfile + if (~ $EDITOR ()) { EDITOR=vim } + $EDITOR $encfile + gpg --armor -e --default-recipient-self < $encfile > $PASS + shred -u $encfile + printf '%s' $newpass | send + @{ sleep 25; send </dev/null } & +case * + out = `$nl{printf '%s' $dec | awk -F: -v 'opt=' ^ $opt '$1 == opt { print $2 }' | sed 's/^.//'} + if (~ $fromarg 1) { + echo $out + } else { + printf '%s' $out | send + @{ sleep 25; send </dev/null } & + } +}