first commit

This commit is contained in:
2025-04-17 18:00:15 -07:00
commit d4d48ef96d
35 changed files with 6842 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
[env]
TERM = "xterm-256color"
[font]
size = 16
[font.normal]
family = "Monospace"
style = "Regular"
[font.offset]
x = 0
y = 0
[window]
opacity = 0.97
[general]
import = ["/home/opal/.config/alacritty/theme.toml"]

View File

@@ -0,0 +1,28 @@
# Colors (Nord)
# Default colors
[colors.primary]
background = '#2E3440'
foreground = '#D8DEE9'
# Normal colors
[colors.normal]
black = '#3B4252'
red = '#BF616A'
green = '#A3BE8C'
yellow = '#EBCB8B'
blue = '#81A1C1'
magenta = '#B48EAD'
cyan = '#88C0D0'
white = '#E5E9F0'
# Bright colors
[colors.bright]
black = '#4C566A'
red = '#BF616A'
green = '#A3BE8C'
yellow = '#EBCB8B'
blue = '#81A1C1'
magenta = '#B48EAD'
cyan = '#8FBCBB'
white = '#ECEFF4'

49
.config/dunst/dunstrc Normal file
View File

@@ -0,0 +1,49 @@
[global]
monitor = 0
follow = keyboard
indicate_hidden = yes
shrink = no
separator_height = 0
padding = 16
horizontal_padding = 24
frame_width = 2
sort = no
idle_threshold = 120
font = Noto Sans 8
line_height = 4
markup = full
format = "<b>%s</b>\n%b"
alignment = left
show_age_threshold = 60
word_wrap = yes
ignore_newline = no
stack_duplicates = false
hide_duplicate_count = yes
show_indicators = no
icon_position = off
sticky_history = yes
history_length = 20
browser = /usr/bin/icecat -new-tab
always_run_script = true
title = Dunst
class = Dunst
close = ctrl+space
close_all = ctrl+shift+space
history = ctrl+grave
context = ctrl+shift+period
[urgency_low]
background = "#2f343f"
foreground = "#d8dee8"
timeout = 2
[urgency_normal]
background = "#2f343f"
foreground = "#d8dee8"
timeout = 4
[urgency_critical]
background = "#2f343f"
foreground = "#d8dee8"
frame_color = "#bf616a"
timeout = 0

3
.config/foot/foot.ini Normal file
View File

@@ -0,0 +1,3 @@
[main]
font=monospace:size=18
term=xterm-256color

View File

@@ -0,0 +1,2 @@
[Settings]
gtk-icon-theme-name = Papirus

7
.config/lf/lfrc Normal file
View File

@@ -0,0 +1,7 @@
# Basic vars
set ifs "\n"
set scrolloff 10
set icons
set period 1
set hiddenfiles ".*:*.aux:*.log:*.bbl:*.bcf:*.blg:*.run.xml"
set autoquit true

46
.config/newsboat/config Normal file
View File

@@ -0,0 +1,46 @@
#show-read-feeds no
auto-reload yes
bind-key j down
bind-key k up
bind-key j next articlelist
bind-key k prev articlelist
bind-key J next-feed articlelist
bind-key K prev-feed articlelist
bind-key G end
bind-key g home
bind-key d pagedown
bind-key u pageup
bind-key l open
bind-key h quit
bind-key a toggle-article-read
bind-key n next-unread
bind-key N prev-unread
bind-key D pb-download
bind-key U show-urls
bind-key x pb-delete
color listnormal cyan default
color listfocus black yellow standout bold
color listnormal_unread blue default
color listfocus_unread yellow default bold
color info red black bold
color article white default bold
highlight all "---.*---" yellow
highlight feedlist ".*(0/0))" black
highlight article "(^Feed:.*|^Title:.*|^Author:.*)" cyan default bold
highlight article "(^Link:.*|^Date:.*)" default default
highlight article "https?://[^ ]+" green default
highlight article "^(Title):.*$" blue default
highlight article "\\[[0-9][0-9]*\\]" magenta default bold
highlight article "\\[image\\ [0-9]+\\]" green default bold
highlight article "\\[embedded flash: [0-9][0-9]*\\]" green default bold
highlight article ":.*\\(link\\)$" cyan default
highlight article ":.*\\(image\\)$" blue default
highlight article ":.*\\(embedded flash\\)$" magenta default
#urls-source "ttrss"
#ttrss-url "https://rss.opal.sh/tt-rss/"
#ttrss-login "ryan"
#ttrss-passwordeval "gopass show -o self-hosted/rss.opal.sh"

18
.config/newsboat/urls Normal file
View File

@@ -0,0 +1,18 @@
---Reddit---
https://www.reddit.com/r/stupidpol/.rss
---News---
https://thegrayzone.com/rss
https://multipolarista.com/rss
https://www.telesurenglish.net/feed/
https://theintercept.com/feed/
---Tech---
https://landchad.net/rss.xml
https://videos.lukesmith.xyz/feeds/videos.xml?videoChannelId=2 "~Luke Smith (Videos)"
https://pluralistic.net/feed/
https://blog.privacyguides.org/feed_rss_created.xml
---Podcasts---
https://feeds.simplecast.com/dCXMIpJz "Last Podcast On the Left"
http://feeds.soundcloud.com/users/soundcloud:users:572119410/sounds.rss podcasts "Fall of Civilziation"
https://feeds.feedburner.com/dancarlin/history?format=xml podcasts "Hardcore History"
https://www.darkdescentrecords.com/shop/shop/rss

8
.config/nvim/init.lua Normal file
View File

@@ -0,0 +1,8 @@
-- ~/.config/nvim/init.lua
vim.o.number = true
vim.o.relativenumber = true
vim.o.clipboard = "unnamedplus"
vim.cmd [[highlight Normal guibg=NONE ctermbg=NONE]]
vim.cmd [[highlight NormalNC guibg=NONE ctermbg=NONE]]
vim.cmd [[highlight EndOfBuffer guibg=NONE ctermbg=NONE]]

View File

@@ -0,0 +1,167 @@
# If a config.py file exists, this file is ignored unless it's explicitly loaded
# via config.load_autoconfig(). For more information, see:
# https://github.com/qutebrowser/qutebrowser/blob/main/doc/help/configuring.asciidoc#loading-autoconfigyml
# DO NOT edit this file by hand, qutebrowser will overwrite it.
# Instead, create a config.py - see :help for details.
config_version: 2
settings:
content.blocking.method:
global: both
content.javascript.enabled:
'*://*.01.emailinboundprocessing.eu/*': true
'*://*.127.0.0.1/*': true
'*://*.4chanlit.fandom.com/*': true
'*://*.account.proton.me/*': true
'*://*.account.protonvpn.com/*': true
'*://*.ancientdead.com/*': true
'*://*.app.netdata.cloud/*': true
'*://*.app.simplelogin.io/*': true
'*://*.askubuntu.com/*': true
'*://*.babeground.com/*': true
'*://*.babeground.net/*': true
'*://*.babegrounds.live/*': true
'*://*.bandcamp.com/*': true
'*://*.chmodcommand.com/*': true
'*://*.codeberg.org/*': true
'*://*.confluence.atg-corp.com/*': false
'*://*.crontab.guru/*': true
'*://*.customer.xfinity.com/*': true
'*://*.demo.uptime.kuma.pet/*': true
'*://*.docs.google.com/*': true
'*://*.drop.download/*': true
'*://*.duckduckgo.com/*': true
'*://*.features.jellyfin.org/*': true
'*://*.flathub.org/*': true
'*://*.fleet.linuxserver.io/*': true
'*://*.fmovies.to/*': true
'*://*.framatube.org/*': true
'*://*.get.adobe.com/*': true
'*://*.github.com/*': true
'*://*.gitlab.com/*': true
'*://*.goauthentik.io/*': true
'*://*.greyzone.com/*': true
'*://*.heretic.camp/*': true
'*://*.html.duckduckgo.com/*': true
'*://*.hub.docker.com/*': true
'*://*.id.atlassian.com/*': true
'*://*.idcs-3359adb31e35415e8c1729c5c8098c6d.identity.oraclecloud.com/*': true
'*://*.imgflip.com/*': true
'*://*.inv.odyssey346.dev/*': true
'*://*.jf.opal.sh/*': true
'*://*.jira.atg-corp.com/*': true
'*://*.layoffs.fyi/*': true
'*://*.learningnetwork.cisco.com/*': true
'*://*.listen.20buckspin.com/*': true
'*://*.localhost/*': true
'*://*.login.seattle.gov/*': true
'*://*.login.xfinity.com/*': true
'*://*.looking-glass.io/*': true
'*://*.lotrproject.com/*': true
'*://*.mail.proton.me/*': true
'*://*.main.realsecure.flyingcroc.net/*': true
'*://*.metalodyssey.8merch.com/*': true
'*://*.my.uscis.gov/*': true
'*://*.my.vultr.com/*': true
'*://*.myaccount.standingstonegames.com/*': true
'*://*.myutilities.seattle.gov/*': true
'*://*.nagios.realsecure.flyingcroc.net/*': true
'*://*.netbox.realsecure.flyingcroc.net/*': true
'*://*.online.adp.com/*': true
'*://*.onlinebanking.becu.org/*': true
'*://*.onyxboox.com/*': true
'*://*.openscrobbler.com/*': true
'*://*.payments.xfinity.com/*': true
'*://*.portainer.opal.sh/*': true
'*://*.protesilaos.com/*': true
'*://*.proton.me/*': true
'*://*.rateyourmusic.com/*': true
'*://*.register.be.xfinity.com/*': false
'*://*.reverb.com/*': true
'*://*.sack.realsecure.flyingcroc.net/*': true
'*://*.search.brave.com/*': true
'*://*.seattle.bibliocommons.com/*': true
'*://*.seattle.craigslist.org/*': true
'*://*.shop.bulletproof.com/*': true
'*://*.spl.overdrive.com/*': true
'*://*.stackoverflow.com/*': true
'*://*.stash.atg-corp.com/*': true
'*://*.superuser.com/*': true
'*://*.support-acquia.force.com/*': true
'*://*.thecirclemusic.gr/*': true
'*://*.thegrayzone.com/*': true
'*://*.translate.google.com/*': true
'*://*.twitter.com/*': true
'*://*.unix.stackexchange.com/*': true
'*://*.uploadev.org/*': true
'*://*.utilities-self-service.ebill.seattle.gov/*': true
'*://*.veganmenshoes.com/*': true
'*://*.vid.puffyan.us/*': true
'*://*.wooddove.fciis.net/*': true
'*://*.www.20buckspin.com/*': true
'*://*.www.airplane.dev/*': true
'*://*.www.amazon.com/*': true
'*://*.www.astound.com/*': true
'*://*.www.budgetbytes.com/*': true
'*://*.www.calculator.net/*': true
'*://*.www.carhartt.com/*': true
'*://*.www.dancarlin.com/*': true
'*://*.www.drmartens.com/*': true
'*://*.www.duluthtrading.com/*': true
'*://*.www.easyime.com/*': true
'*://*.www.ebay.com/*': true
'*://*.www.filson.com/*': true
'*://*.www.foodnetwork.com/*': true
'*://*.www.geoguessr.com/*': true
'*://*.www.goodreads.com/*': true
'*://*.www.google.com/*': true
'*://*.www.harddrivesdirect.com/*': true
'*://*.www.knoll.com/*': true
'*://*.www.kobo.com/*': true
'*://*.www.last.fm/*': true
'*://*.www.lastpodcastontheleft.com/*': true
'*://*.www.lotro.com/*': true
'*://*.www.metal-archives.com/*': true
'*://*.www.mmorpg.com/*': true
'*://*.www.moddb.com/*': true
'*://*.www.netaddictionrecovery.com/*': true
'*://*.www.nightshiftmerch.com/*': true
'*://*.www.openstreetmap.org/*': true
'*://*.www.patagonia.com/*': true
'*://*.www.paypal.com/*': true
'*://*.www.raspberrypi.com/*': true
'*://*.www.reddit.com/*': true
'*://*.www.seattle.gov/*': true
'*://*.www.startpage.com/*': true
'*://*.www.thisisclassicalguitar.com/*': true
'*://*.www.vegetarian-shoes.co.uk/*': true
'*://*.www.vultr.com/*': true
'*://*.www.wills-vegan-store.com/*': true
'*://*.www.xfinity.com/*': true
'*://*.www.youtube.com/*': true
'*://*.www.zillow.com/*': true
'*://chatgpt.com/*': true
'*://digital.fidelity.com/*': true
'*://gethomepage.dev/*': true
'*://git.opal.sh/*': true
'*://jf.opal.sh/*': true
'*://jsonformatter.curiousconcept.com/*': true
'*://lemmygrad.ml/*': true
'*://login.becu.org/*': true
'*://myaccounts.capitalone.com/*': true
'*://rateyourmusic.com/*': true
'*://revelationofdoom.com/*': true
'*://safereddit.com/*': true
'*://verified.capitalone.com/*': true
'*://wiki.alpinelinux.org/*': true
'*://www.duplicati.com/*': true
'*://www.fidelity.com/*': true
'*://www.newegg.com/*': true
'*://www.vitamix.com/*': true
'*://www.youtube.com/*': true
'*://yewtu.be/*': true
content.notifications.enabled:
https://jf.opal.sh: false
https://www.facebook.com: false
content.register_protocol_handler:
https://mail.proton.me#mailto=%25s: false

View File

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env python3
from PyQt6.QtCore import QUrl
from qutebrowser.api import interceptor
def rewrite(request: interceptor.Request):
url = request.request_url
host = url.host()
# Avoid redirect loops
if "reddit.com" in host and "safereddit.com" not in host:
new_url = QUrl("https://safereddit.com")
new_url.setPath(url.path())
new_url.setQuery(url.query())
request.redirect(new_url)
#interceptor.register(rewrite)
# Load existing settings made via :set
config.load_autoconfig()
c.qt.highdpi = True
c.fonts.default_size = "15pt"
c.fonts.tabs.selected = "13pt default_family"
c.fonts.tabs.unselected = "13pt default_family"
c.zoom.default = "130%"
c.content.javascript.enabled = False
c.downloads.location.directory = "~/dls"
c.editor.command = ["alacritty", "-e", "nvim", "{}"]
c.editor.encoding = "utf-8"
c.auto_save.session = True
c.colors.webpage.preferred_color_scheme = "dark"
# privacy
c.content.cookies.accept = "no-3rdparty"
c.content.webrtc_ip_handling_policy = "default-public-interface-only"
c.content.site_specific_quirks.enabled = False
c.content.headers.user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.79 Safari/537.36"
config.bind("j", "scroll-px 0 100")
config.bind("k", "scroll-px 0 -100")
config.bind("K", "tab-next")
config.bind("J", "tab-prev")
c.url.searchengines = {
"DEFAULT": "https://duckduckgo.com/?q={}",
}
c.url.start_pages = ["https://start.duckduckgo.com"]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
[FileDialog]
history=file:///home/opal/pictures
lastVisited=file:///home/opal/pictures
qtVersion=5.15.6
shortcuts=file:, file:///home/opal
sidebarWidth=87
treeViewHeader="@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1\xd1\0\0\0\x4\x1\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x4\0\0\0\xf5\0\0\0\x1\0\0\0\0\0\0\0\x39\0\0\0\x1\0\0\0\0\0\0\0=\0\0\0\x1\0\0\0\0\0\0\0\x66\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\xff\xff\xff\xff)"
viewMode=Detail

View File

@@ -0,0 +1 @@
66h&!@Vj4n$cAfwN https://verified.capitalone.com/auth/signin

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,343 @@
#!/usr/bin/env python3
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2021 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Claude (longneck) <longneck@scratchbook.ch>
# This file is part of qutebrowser.
#
# qutebrowser 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 3 of the License, or
# (at your option) any later version.
#
# qutebrowser 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 qutebrowser. If not, see <https://www.gnu.org/licenses/>.
"""Tool to import data from other browsers.
Currently importing bookmarks from Netscape HTML Bookmark files, Chrome
profiles, and Mozilla profiles is supported.
"""
import argparse
import textwrap
import sqlite3
import os
import urllib.parse
import json
import string
def main():
args = get_args()
bookmark_types = []
output_format = None
input_format = args.input_format
if args.search_output:
bookmark_types = ["search"]
if args.oldconfig:
output_format = "oldsearch"
else:
output_format = "search"
else:
if args.bookmark_output:
output_format = "bookmark"
elif args.quickmark_output:
output_format = "quickmark"
if args.import_bookmarks:
bookmark_types.append("bookmark")
if args.import_keywords:
bookmark_types.append("keyword")
if not bookmark_types:
bookmark_types = ["bookmark", "keyword"]
if not output_format:
output_format = "quickmark"
import_function = {
"html": import_html_bookmarks,
"mozilla": import_moz_places,
"chrome": import_chrome,
}
import_function[input_format](args.bookmarks, bookmark_types, output_format)
def get_args():
"""Get the argparse parser."""
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=textwrap.dedent(
"""
To import bookmarks, you'll need the path to your profile or an
exported HTML file from your browser's bookmark manager. Redirect
the output from this script to the appropriate file in your
qutebrowser config directory (listed in the output of :version),
usually done with the '>' operator; for example,
./importer.py -i mozilla your_profile_path > ~/.config/qutebrowser/quickmarks
Common browsers with native input format support:
chrome: Chrome, Chromium, Edge
mozilla: Firefox, SeaMonkey, Pale Moon
"""
),
)
parser.add_argument(
"-i",
"--input-format",
help="Which input format? Defaults to html",
choices=["html", "mozilla", "chrome"],
default="html",
required=False,
)
parser.add_argument(
"-b",
"--bookmark-output",
help="Output in bookmark format.",
action="store_true",
default=False,
required=False,
)
parser.add_argument(
"-q",
"--quickmark-output",
help="Output in quickmark format (default).",
action="store_true",
default=False,
required=False,
)
parser.add_argument(
"-s",
"--search-output",
help="Output config.py search engine format (negates -B and -K)",
action="store_true",
default=False,
required=False,
)
parser.add_argument(
"--oldconfig",
help="Output search engine format for old qutebrowser.conf format",
default=False,
action="store_true",
required=False,
)
parser.add_argument(
"-B",
"--import-bookmarks",
help="Import plain bookmarks (can be combiend with -K)",
action="store_true",
default=False,
required=False,
)
parser.add_argument(
"-K",
"--import-keywords",
help="Import keywords (can be combined with -B)",
action="store_true",
default=False,
required=False,
)
parser.add_argument(
"bookmarks",
help="Bookmarks file (html format) or " "profile folder (Mozilla format)",
)
args = parser.parse_args()
return args
def search_escape(url):
"""Escape URLs such that preexisting { and } are handled properly.
Will obviously trash a properly-formatted qutebrowser URL.
"""
return url.replace("{", "{{").replace("}", "}}")
def opensearch_convert(url):
"""Convert a basic OpenSearch URL into something qutebrowser can use.
Exceptions:
KeyError:
An unknown and required parameter is present in the URL. This
usually means there's browser/addon specific functionality needed
to build the URL (I'm looking at you and your browser, Google) that
obviously won't be present here.
"""
subst = {
"searchTerms": "%s", # for proper escaping later
"language": "*",
"inputEncoding": "UTF-8",
"outputEncoding": "UTF-8",
}
# remove optional parameters (even those we don't support)
for param in string.Formatter().parse(url):
if param[1]:
if param[1].endswith("?"):
url = url.replace("{" + param[1] + "}", "")
elif param[2] and param[2].endswith("?"):
url = url.replace("{" + param[1] + ":" + param[2] + "}", "")
return search_escape(url.format(**subst)).replace("%s", "{}")
def import_html_bookmarks(bookmarks_file, bookmark_types, output_format):
"""Import bookmarks from a NETSCAPE-Bookmark-file v1.
Generated by Chromium, Firefox, IE and possibly more browsers. Not all
export all possible bookmark types:
- Firefox mostly works with everything
- Chrome doesn't support keywords at all; searches are a separate
database
"""
import bs4
with open(bookmarks_file, encoding="utf-8") as f:
soup = bs4.BeautifulSoup(f, "html.parser")
bookmark_query = {
"search": lambda tag: (
(tag.name == "a") and ("shortcuturl" in tag.attrs) and ("%s" in tag["href"])
),
"keyword": lambda tag: (
(tag.name == "a")
and ("shortcuturl" in tag.attrs)
and ("%s" not in tag["href"])
),
"bookmark": lambda tag: (
(tag.name == "a") and ("shortcuturl" not in tag.attrs) and (tag.string)
),
}
output_template = {
"search": {
"search": "c.url.searchengines['{tag[shortcuturl]}'] = "
"'{tag[href]}' #{tag.string}"
},
"oldsearch": {
"search": "{tag[shortcuturl]} = {tag[href]} #{tag.string}",
},
"bookmark": {
"bookmark": "{tag[href]} {tag.string}",
"keyword": "{tag[href]} {tag.string}",
},
"quickmark": {
"bookmark": "{tag.string} {tag[href]}",
"keyword": "{tag[shortcuturl]} {tag[href]}",
},
}
bookmarks = []
for typ in bookmark_types:
tags = soup.findAll(bookmark_query[typ])
for tag in tags:
if typ == "search":
tag["href"] = search_escape(tag["href"]).replace("%s", "{}")
if tag["href"] not in bookmarks:
bookmarks.append(output_template[output_format][typ].format(tag=tag))
for bookmark in bookmarks:
print(bookmark)
def import_moz_places(profile, bookmark_types, output_format):
"""Import bookmarks from a Mozilla profile's places.sqlite database."""
place_query = {
"bookmark": (
"SELECT DISTINCT moz_bookmarks.title,moz_places.url "
"FROM moz_bookmarks,moz_places "
"WHERE moz_places.id=moz_bookmarks.fk "
"AND moz_places.id NOT IN (SELECT place_id FROM moz_keywords) "
"AND moz_places.url NOT LIKE 'place:%';"
), # Bookmarks with no keywords assigned
"keyword": (
"SELECT moz_keywords.keyword,moz_places.url "
"FROM moz_keywords,moz_places,moz_bookmarks "
"WHERE moz_places.id=moz_bookmarks.fk "
"AND moz_places.id=moz_keywords.place_id "
"AND moz_places.url NOT LIKE '%!%s%' ESCAPE '!';"
), # Bookmarks with keywords assigned but no %s substitution
"search": (
"SELECT moz_keywords.keyword, "
" moz_bookmarks.title, "
" search_conv(moz_places.url) AS url "
"FROM moz_keywords,moz_places,moz_bookmarks "
"WHERE moz_places.id=moz_bookmarks.fk "
"AND moz_places.id=moz_keywords.place_id "
"AND moz_places.url LIKE '%!%s%' ESCAPE '!';"
), # bookmarks with keyword and %s substitution
}
out_template = {
"bookmark": {"bookmark": "{url} {title}", "keyword": "{url} {keyword}"},
"quickmark": {"bookmark": "{title} {url}", "keyword": "{keyword} {url}"},
"oldsearch": {"search": "{keyword} {url} #{title}"},
"search": {"search": "c.url.searchengines['{keyword}'] = '{url}' #{title}"},
}
def search_conv(url):
return search_escape(url).replace("%s", "{}")
places = sqlite3.connect(os.path.join(profile, "places.sqlite"))
places.create_function("search_conv", 1, search_conv)
places.row_factory = sqlite3.Row
c = places.cursor()
for typ in bookmark_types:
c.execute(place_query[typ])
for row in c:
print(out_template[output_format][typ].format(**row))
def import_chrome(profile, bookmark_types, output_format):
"""Import bookmarks and search keywords from Chrome-type profiles.
On Chrome, keywords and search engines are the same thing and handled in
their own database table; bookmarks cannot have associated keywords. This
is why the dictionary lookups here are much simpler.
"""
out_template = {
"bookmark": "{url} {name}",
"quickmark": "{name} {url}",
"search": "c.url.searchengines['{keyword}'] = '{url}'",
"oldsearch": "{keyword} {url}",
}
if "search" in bookmark_types:
webdata = sqlite3.connect(os.path.join(profile, "Web Data"))
c = webdata.cursor()
c.execute("SELECT keyword,url FROM keywords;")
for keyword, url in c:
try:
url = opensearch_convert(url)
print(out_template[output_format].format(keyword=keyword, url=url))
except KeyError:
print(
"# Unsupported parameter in url for {}; skipping....".format(
keyword
)
)
else:
with open(os.path.join(profile, "Bookmarks"), encoding="utf-8") as f:
bookmarks = json.load(f)
def bm_tree_walk(bm, template):
"""Recursive function to walk through bookmarks."""
if not isinstance(bm, dict):
return
assert "type" in bm, bm
if bm["type"] == "url":
if urllib.parse.urlparse(bm["url"]).scheme != "chrome":
print(template.format(**bm))
elif bm["type"] == "folder":
for child in bm["children"]:
bm_tree_walk(child, template)
for root in bookmarks["roots"].values():
bm_tree_walk(root, out_template[output_format])
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,356 @@
#!/usr/bin/env python3
# Copyright 2017 Chris Braun (cryzed) <cryzed@googlemail.com>
# Adapted for Bitwarden by Jonathan Haylett (JonnyHaystack) <jonathan@haylett.dev>
#
# This file is part of qutebrowser.
#
# qutebrowser 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 3 of the License, or
# (at your option) any later version.
#
# qutebrowser 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 qutebrowser. If not, see <https://www.gnu.org/licenses/>.
"""
Insert login information using Bitwarden CLI and a dmenu-compatible application
(e.g. dmenu, rofi -dmenu, ...).
"""
USAGE = """The domain of the site has to be in the name of the Bitwarden entry, for example: "github.com/cryzed" or
"websites/github.com". The login information is inserted by emulating key events using qutebrowser's fake-key command in this manner:
[USERNAME]<Tab>[PASSWORD], which is compatible with almost all login forms.
If enabled, with the `--totp` flag, it will also move the TOTP code to the
clipboard, much like the Firefox add-on.
You must log into Bitwarden CLI using `bw login` prior to use of this script.
The session key will be stored using keyctl for the number of seconds passed to
the --auto-lock option.
To use in qutebrowser, run: `spawn --userscript qute-bitwarden`
"""
EPILOG = """Dependencies: tldextract (Python 3 module), pyperclip (optional
Python module, used for TOTP codes), Bitwarden CLI (1.7.4 is known to work
but older versions may well also work)
WARNING: The login details are viewable as plaintext in qutebrowser's debug log
(qute://log) and might be shared if you decide to submit a crash report!"""
import argparse
import enum
import functools
import os
import shlex
import subprocess
import sys
import json
import tldextract
argument_parser = argparse.ArgumentParser(
description=__doc__,
usage=USAGE,
epilog=EPILOG,
)
argument_parser.add_argument("url", nargs="?", default=os.getenv("QUTE_URL"))
argument_parser.add_argument(
"--dmenu-invocation",
"-d",
default="bemenu -x -b --prompt=Pass",
help="Invocation used to execute a dmenu-provider",
)
argument_parser.add_argument(
"--password-prompt-invocation",
"-p",
default='bemenu -x -b -p "Master Password"',
help="Invocation used to prompt the user for their Bitwarden password",
)
argument_parser.add_argument(
"--no-insert-mode",
"-n",
dest="insert_mode",
action="store_false",
help="Don't automatically enter insert mode",
)
argument_parser.add_argument(
"--totp", "-t", action="store_true", help="Copy TOTP key to clipboard"
)
argument_parser.add_argument(
"--io-encoding",
"-i",
default="UTF-8",
help="Encoding used to communicate with subprocesses",
)
argument_parser.add_argument(
"--merge-candidates",
"-m",
action="store_true",
help="Merge pass candidates for fully-qualified and registered domain name",
)
argument_parser.add_argument(
"--auto-lock",
type=int,
default=900,
help="Automatically lock the vault after this many seconds",
)
group = argument_parser.add_mutually_exclusive_group()
group.add_argument(
"--username-only", "-e", action="store_true", help="Only insert username"
)
group.add_argument(
"--password-only", "-w", action="store_true", help="Only insert password"
)
group.add_argument(
"--totp-only", "-T", action="store_true", help="Only insert totp code"
)
stderr = functools.partial(print, file=sys.stderr)
class ExitCodes(enum.IntEnum):
SUCCESS = 0
FAILURE = 1
# 1 is automatically used if Python throws an exception
NO_PASS_CANDIDATES = 2
COULD_NOT_MATCH_USERNAME = 3
COULD_NOT_MATCH_PASSWORD = 4
def qute_command(command):
with open(os.environ["QUTE_FIFO"], "w") as fifo:
fifo.write(command + "\n")
fifo.flush()
def ask_password(password_prompt_invocation):
process = subprocess.run(
shlex.split(password_prompt_invocation),
text=True,
stdout=subprocess.PIPE,
)
if process.returncode > 0:
raise Exception("Could not unlock vault")
master_pass = process.stdout.strip()
return subprocess.check_output(
["bw", "unlock", "--raw", master_pass],
text=True,
).strip()
def get_session_key(auto_lock, password_prompt_invocation):
if auto_lock == 0:
subprocess.call(["keyctl", "purge", "user", "bw_session"])
return ask_password(password_prompt_invocation)
else:
process = subprocess.run(
["keyctl", "request", "user", "bw_session"],
text=True,
stdout=subprocess.PIPE,
)
key_id = process.stdout.strip()
if process.returncode > 0:
session = ask_password(password_prompt_invocation)
if not session:
raise Exception("Could not unlock vault")
key_id = subprocess.check_output(
["keyctl", "add", "user", "bw_session", session, "@u"],
text=True,
).strip()
if auto_lock > 0:
subprocess.call(["keyctl", "timeout", str(key_id), str(auto_lock)])
return subprocess.check_output(
["keyctl", "pipe", str(key_id)],
text=True,
).strip()
def pass_(domain, encoding, auto_lock, password_prompt_invocation):
session_key = get_session_key(auto_lock, password_prompt_invocation)
process = subprocess.run(
["bw", "list", "items", "--session", session_key, "--url", domain],
capture_output=True,
)
err = process.stderr.decode(encoding).strip()
if err:
msg = "Bitwarden CLI returned for {:s} - {:s}".format(domain, err)
stderr(msg)
if process.returncode:
return "[]"
out = process.stdout.decode(encoding).strip()
return out
def get_totp_code(
selection_id, domain_name, encoding, auto_lock, password_prompt_invocation
):
session_key = get_session_key(auto_lock, password_prompt_invocation)
process = subprocess.run(
["bw", "get", "totp", "--session", session_key, selection_id],
capture_output=True,
)
err = process.stderr.decode(encoding).strip()
if err:
# domain_name instead of selection_id to make it more user-friendly
msg = "Bitwarden CLI returned for {:s} - {:s}".format(domain_name, err)
stderr(msg)
if process.returncode:
return "[]"
out = process.stdout.decode(encoding).strip()
return out
def dmenu(items, invocation, encoding):
command = shlex.split(invocation)
process = subprocess.run(
command, input="\n".join(items).encode(encoding), stdout=subprocess.PIPE
)
return process.stdout.decode(encoding).strip()
def fake_key_raw(text):
for character in text:
# Escape all characters by default, space requires special handling
sequence = '" "' if character == " " else r"\{}".format(character)
qute_command("fake-key {}".format(sequence))
def main(arguments):
if not arguments.url:
argument_parser.print_help()
return ExitCodes.FAILURE
extract_result = tldextract.extract(arguments.url)
# Try to find candidates using targets in the following order: fully-qualified domain name (includes subdomains),
# the registered domain name and finally: the IPv4 address if that's what
# the URL represents
candidates = []
for target in filter(
None,
[
extract_result.fqdn,
extract_result.registered_domain,
extract_result.subdomain + "." + extract_result.domain,
extract_result.domain,
extract_result.ipv4,
],
):
target_candidates = json.loads(
pass_(
target,
arguments.io_encoding,
arguments.auto_lock,
arguments.password_prompt_invocation,
)
)
if not target_candidates:
continue
candidates = candidates + target_candidates
if not arguments.merge_candidates:
break
else:
if not candidates:
stderr("No pass candidates for URL {!r} found!".format(arguments.url))
return ExitCodes.NO_PASS_CANDIDATES
if len(candidates) == 1:
selection = candidates.pop()
else:
choices = []
for c in candidates:
if c["login"]["username"] is None:
c["login"]["username"] = ""
choices.append("{:s} | {:s}".format(c["name"], c["login"]["username"]))
# choices = [
# "{:s} | {:s}".format(c["name"], c["login"]["username"]) for c in candidates
# ]
choice = dmenu(choices, arguments.dmenu_invocation, arguments.io_encoding)
choice_tokens = choice.split("|")
choice_name = choice_tokens[0].strip()
choice_username = choice_tokens[1].strip()
selection = next(
(
c
for (i, c) in enumerate(candidates)
if c["name"] == choice_name
and c["login"]["username"] == choice_username
),
None,
)
# Nothing was selected, simply return
if not selection:
return ExitCodes.SUCCESS
username = selection["login"]["username"]
password = selection["login"]["password"]
totp = selection["login"]["totp"]
if arguments.username_only:
fake_key_raw(username)
elif arguments.password_only:
fake_key_raw(password)
elif arguments.totp_only:
# No point in moving it to the clipboard in this case
fake_key_raw(
get_totp_code(
selection["id"],
selection["name"],
arguments.io_encoding,
arguments.auto_lock,
arguments.password_prompt_invocation,
)
)
else:
# Enter username and password using fake-key and <Tab> (which seems to work almost universally), then switch
# back into insert-mode, so the form can be directly submitted by
# hitting enter afterwards
fake_key_raw(username)
qute_command("fake-key <Tab>")
fake_key_raw(password)
if arguments.insert_mode:
qute_command("mode-enter insert")
# If it finds a TOTP code, it copies it to the clipboard,
# which is the same behavior as the Firefox add-on.
if not arguments.totp_only and totp and arguments.totp:
# The import is done here, to make pyperclip an optional dependency
import pyperclip
pyperclip.copy(
get_totp_code(
selection["id"],
selection["name"],
arguments.io_encoding,
arguments.auto_lock,
arguments.password_prompt_invocation,
)
)
return ExitCodes.SUCCESS
if __name__ == "__main__":
arguments = argument_parser.parse_args()
sys.exit(main(arguments))

313
.config/sway/config Normal file
View File

@@ -0,0 +1,313 @@
output * bg /home/opal/.config/wallpapers/wall.jpg fill #0D0703
#######################
# VARIABLES
#######################
# Directional Keys
set $left h
set $down j
set $up k
set $right l
# Mod Key
set $mod Mod4
# Terminal
set $term alacritty
# Application Launcher
set $menu bemenu-run -p Run: -l 10 -c -M 500 --fn 'Monospace 17' --tf '#ff4e00' --ff '#dbc077' --hf '#ff4e00'
#######################
# GENERAL KEYBINDS
#######################
# Start a terminal
bindsym $mod+Return exec $term
# Start wofi
bindsym $mod+d exec $menu
# Kill focused window
bindsym $mod+Shift+q kill
# Lock SwayWM
bindsym Control+Shift+l exec swaylock
# Change normal to inverse to use left mouse button for resizing and right
# mouse button for dragging.
floating_modifier $mod normal
# Reload the configuration file
bindsym $mod+Shift+c reload
# Log out menu
bindsym $mod+Shift+x exec wlogout
# Moving around:
# Move your focus around
bindsym $mod+$left focus left
bindsym $mod+$down focus down
bindsym $mod+$up focus up
bindsym $mod+$right focus right
# Or use $mod+[up|down|left|right]
bindsym $mod+Left focus left
bindsym $mod+Down focus down
bindsym $mod+Up focus up
bindsym $mod+Right focus right
# Move the focused window with the same, but add Shift
bindsym $mod+Shift+$left move left
bindsym $mod+Shift+$down move down
bindsym $mod+Shift+$up move up
bindsym $mod+Shift+$right move right
# Ditto, with arrow keys
bindsym $mod+Shift+Left move left
bindsym $mod+Shift+Down move down
bindsym $mod+Shift+Up move up
bindsym $mod+Shift+Right move right
# Layout stuff:
#
# You can "split" the current object of your focus with
# $mod+b or $mod+v, for horizontal and vertical splits
# respectively.
bindsym $mod+b splith
bindsym $mod+v splitv
# Switch the current container between different layout styles
#bindsym $mod+s layout stacking
#bindsym $mod+w layout tabbed
#bindsym $mod+e layout toggle split
# Make the current focus fullscreen
bindsym $mod+f fullscreen
# Toggle the current focus between tiling and floating mode
bindsym $mod+Shift+space floating toggle
# Swap focus between the tiling area and the floating area
bindsym $mod+space focus mode_toggle
# Move focus to the parent container
bindsym $mod+a focus parent
# Scratchpad:
#
# Sway has a "scratchpad", which is a bag of holding for windows.
# You can send windows there and get them back later.
# Move the currently focused window to the scratchpad
bindsym $mod+Shift+minus move scratchpad
# Show the next scratchpad window or hide the focused scratchpad window.
# If there are multiple scratchpad windows, this command cycles through them.
bindsym $mod+minus scratchpad show
# Volume up
bindsym XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +5%
# Volume down
bindsym XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -5%
# Mute toggle
bindsym XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ toggle
# Resizing containers:
mode "resize" {
# left will shrink the containers width
# right will grow the containers width
# up will shrink the containers height
# down will grow the containers height
bindsym $left resize shrink width 10px
bindsym $down resize grow height 10px
bindsym $up resize shrink height 10px
bindsym $right resize grow width 10px
# Ditto, with arrow keys
bindsym Left resize shrink width 10px
bindsym Down resize grow height 10px
bindsym Up resize shrink height 10px
bindsym Right resize grow width 10px
# Return to default mode
bindsym Return mode "default"
bindsym Escape mode "default"
}
bindsym $mod+r mode "resize"
# Screenshot (Grimshot)
# Captures the currently active window
bindsym $mod+g exec grimshot save active
# Allows manually selecting a rectangular region
bindsym $mod+Shift+g exec grimshot save area
# Captures currently active output
bindsym $mod+Mod1+g exec grimshot save output
# Allows manually selecting a single window
bindsym $mod+Ctrl+g exec grimshot save window
# Bookmarks
# Enter selected bookmark into target text field
bindsym $mod+i exec wtype $(grep -v '^#' ~/.local/share/bookmarks/bookmarks | bemenu -p Bookmark: -l 50 -c -M 500 --fn 'Monospace 14' --tf '#ff4e00' --ff '#dbc077' --hf '#ff4e00' | cut -d ' ' -f1) wtype -k Return
# Insert bookmark into bookmark file (~/.local/share/bookmarks/bookmarks)
bindsym $mod+Shift+i exec ~/.local/bin/bookmark_insert
# Emojis
bindsym $mod+Shift+e exec wtype $(awk '{print $1, $0}' ~/.local/share/chars/emojis* | bemenu -p Emoji: -l 25 -c -M 500 --fn 'Noto Color Emoji,Monospace 14' --tf '#ff4e00' --ff '#dbc077' --hf '#ff4e00' | awk '{print $1}')
# Gopass
bindsym $mod+y exec ~/.local/bin/pass_copy
bindsym $mod+u exec ~/.local/bin/pass_user_copy
bindsym $mod+p exec ~/.local/bin/pass_autofill
#######################
# EXECS
#######################
# Notifications
exec_always pgrep -x dunst > /dev/null || dunst
# Wlsunset (Night Light)
exec_always pgrep -x wlsunset > /dev/null || wlsunset -l 47.6 -L -122.3 -t 3500 -T 6000
# udiskie - auto usb mounting
exec /usr/bin/udiskie &
# Network Manager tray applet
#exec /usr/bin/nm-applet
# Bluetooth manager tray applet
exec /usr/bin/blueman-applet
# Pipewire
exec /usr/libexec/pipewire-launcher
# Idle configuration
#exec swayidle -w \
# timeout 3200 'swaymsg "output * dpms off"' \
# resume 'swaymsg "output * dpms on"' \
# before-sleep 'swaylock -f'
# timeout 15 'if pgrep -x swaylock; then swaymsg "output * dpms off"; fi' \
#######################
# DECORATIONS
#######################
# Gaps
smart_gaps off
gaps inner 5
gaps outer 5
# Window Borders
default_border pixel 3
default_floating_border none
client.focused "#D27A31" "#5F9EA0" "#000000" "#D27A31"
#######################
# INPUTS
#######################
input type:keyboard {
# Capslock key should work as escape key
# See /usr/share/X11/xkb/rules/xorg.lst for options
xkb_layout "us(altgr-intl)"
xkb_options caps:escape
repeat_delay 250
repeat_rate 45
}
# Disable trackpad by default
#input "1739:52824:SYNA8008:00_06CB:CE58_Touchpad" {
# events disable
#}
# Set trackpoint sensitivity on Laptop
input "2:10:TPPS/2_Elan_TrackPoint" {
pointer_accel 1.0
accel_profile "flat"
}
# Set trackpoint sensitivity on Tex Shinobi USB
input "1241:1031:USB-HID_Keyboard_Mouse" {
pointer_accel 0.3
accel_profile "flat"
}
# Hide mouse cursor after inactivity
seat * hide_cursor 10000
seat seat0 xcursor_theme breeze_cursors 24
# Enable/disable trackpad
bindsym $mod+t exec swaymsg input "1739:52824:SYNA8008:00_06CB:CE58_Touchpad" events disabled
bindsym $mod+Shift+t exec swaymsg input "1739:52824:SYNA8008:00_06CB:CE58_Touchpad" events enabled
#######################
# OUTPUTS
#######################
# Lid stuff
set $laptop eDP-1
bindswitch --reload --locked lid:on output $laptop disable
bindswitch --reload --locked lid:off output $laptop enable
#######################
# WORKSPACES
#######################
# Assign workspaces to numbers
set $ws1 "1"
set $ws2 "2"
set $ws3 "3"
set $ws4 "4"
set $ws5 "5"
set $ws6 "6"
set $ws7 "7"
# Switch to workspace
bindsym $mod+1 workspace $ws1
bindsym $mod+2 workspace $ws2
bindsym $mod+3 workspace $ws3
bindsym $mod+4 workspace $ws4
bindsym $mod+5 workspace $ws5
bindsym $mod+6 workspace $ws6
bindsym $mod+0 workspace $ws7
# Move focused container to workspace
bindsym $mod+Shift+1 move container to workspace $ws1
bindsym $mod+Shift+2 move container to workspace $ws2
bindsym $mod+Shift+3 move container to workspace $ws3
bindsym $mod+Shift+4 move container to workspace $ws4
bindsym $mod+Shift+5 move container to workspace $ws5
bindsym $mod+Shift+6 move container to workspace $ws6
bindsym $mod+Shift+0 move container to workspace $ws7
#######################
# BAR
#######################
bar {
position top
font "Monospace 17"
height 40
strip_workspace_numbers yes
status_command ~/.config/sway/scripts/bar.sh
colors {
statusline #c0c0c0
background #1a1a1aAA
inactive_workspace #2a2a2aAA #2a2a2aAA #555555AA
focused_workspace #2a2a2aAA #555555AA #ddddddAA
}
}

37
.config/sway/scripts/bar.sh Executable file
View File

@@ -0,0 +1,37 @@
#!/bin/sh
get_date() {
date '+%H:%M %a %d/%m/%y'
}
get_battery() {
BATTERY_PATH="/sys/class/power_supply/BAT0"
if [ -f "$BATTERY_PATH/capacity" ]; then
BAT_PERCENT=$(cat "$BATTERY_PATH/capacity")
BAT_STATUS=$(cat "$BATTERY_PATH/status")
printf "%s%%" "$BAT_PERCENT"
if [ "$BAT_STATUS" = "Charging" ] || [ "$BAT_STATUS" = "Unknown" ]; then
printf "^"
fi
else
printf "NoBat"
fi
}
get_volume() {
SINK=$(pactl info | awk -F': ' '/Default Sink/ {print $2}')
VOLUME=$(pactl get-sink-volume "$SINK" | awk '{print $5}' | head -n 1)
MUTE_STATUS=$(pactl get-sink-mute "$SINK" | awk '{print $2}')
printf "%s" "$VOLUME"
[ "$MUTE_STATUS" = "yes" ] && printf " (m)"
}
while true; do
printf "V: %s | %s | B: %s\n" "$(get_volume)" "$(get_date)" "$(get_battery)"
sleep 1
done

View File

@@ -0,0 +1,6 @@
#!/usr/bin/bash
if grep -q open /proc/acpi/button/lid/LID/state; then
swaymsg output eDP-1 enable
else
swaymsg output eDP-1 disable
fi

32
.config/swaylock/config Normal file
View File

@@ -0,0 +1,32 @@
# Image
image=~/.config/wallpapers/wall.jpg
scaling=fill
# Indicator
ignore-empty-password
indicator-caps-lock
indicator-radius=100
indicator-thickness=20
line-color=1f1d2e
ring-color=191724
inside-color=1f1d2e
key-hl-color=eb6f92
separator-color=00000000
text-color=e0def4
text-caps-lock-color=""
line-ver-color=eb6f92
ring-ver-color=eb6f92
inside-ver-color=1f1d2e
text-ver-color=e0def4
ring-wrong-color=31748f
text-wrong-color=31748f
inside-wrong-color=1f1d2e
inside-clear-color=1f1d2e
text-clear-color=e0def4
ring-clear-color=9ccfd8
line-clear-color=1f1d2e
line-wrong-color=1f1d2e
bs-hl-color=31748f
# Behavior
show-failed-attempts

BIN
.config/wallpapers/wall.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

32
.local/bin/bookmark_insert Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/sh
bookmarks_file="$HOME/.local/share/bookmarks/bookmarks"
if [ ! -f "$bookmarks_file" ]; then
notify-send "Error" "Bookmark file doesn't exist. Please pull the repo."
echo "Bookmark file doesn't exist. Please pull the repo." >&2
exit 1
fi
# Try clipboard first, fall back to primary
clipboard_text=$(wl-paste --no-newline 2>/dev/null)
[ -z "$clipboard_text" ] && clipboard_text=$(wl-paste -p --no-newline 2>/dev/null)
# Trim leading/trailing whitespace
clipboard_text=$(echo "$clipboard_text" | xargs)
# Remove trailing slashes
clipboard_text=$(echo "$clipboard_text" | sed 's#/$##')
# Check if clipboard is not empty
if [ -n "$clipboard_text" ]; then
if grep -Fxq "$clipboard_text" "$bookmarks_file"; then
notify-send "Bookmark already exists!" "$clipboard_text"
else
echo "$clipboard_text" >> "$bookmarks_file"
notify-send "Bookmark saved" "$clipboard_text"
sh "$HOME/.local/bin/bookmark_update"
fi
else
notify-send "No text to save" "Clipboard and primary selection are empty."
fi

29
.local/bin/bookmark_update Executable file
View File

@@ -0,0 +1,29 @@
#!/bin/sh
# Try to source keychain's environment file
if [ -f "$HOME/.keychain/$(hostname)-sh" ]; then
. "$HOME/.keychain/$(hostname)-sh"
fi
# Define the paths and repository
bookmarks_file="$HOME/.local/share/bookmarks/bookmarks"
repo_path="$HOME/.local/share/bookmarks"
# Pull the latest changes
cd "$repo_path" || exit
git pull origin master
# Check if the bookmarks file has changed
if [ -n "$(git status --porcelain "$bookmarks_file")" ]; then
# Add and commit the bookmarks file
git add "$bookmarks_file"
git commit -m "Update bookmarks file"
# Push the changes and log output
GIT_SSH_COMMAND="ssh -i ~/.ssh/ry_ecdsa" git push origin master 2>&1 | tee -a /tmp/bookmark_git_push.log
notify-send "Bookmarks updated" "Push your changes."
else
notify-send "No changes" "No changes to the bookmarks file."
fi

22
.local/bin/pass_autofill Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/sh
entry=$(gopass list --flat | bemenu -p Autofill: -l 25 -c -M 500 --fn 'Monospace 14' --tf '#ff4e00' --ff '#dbc077' --hf '#ff4e00')
if [ -n "$entry" ]; then
username=$(gopass show "$entry" | grep '^username:' | cut -d' ' -f2-)
password=$(gopass show -o "$entry")
if [ -z "$password" ]; then
notify-send "Gopass Error" "No password for $entry"
exit 1
fi
notify-send "Autofill in 1s: Focus username field in form"
sleep 1
# Type username, press Tab, then password, then Enter
wtype "$username"
wtype -k Tab
wtype "$password"
wtype -k Return
fi

8
.local/bin/pass_copy Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
entry=$(gopass list --flat | bemenu -p Password: -l 25 -c -M 500 --fn 'Monospace 14' --tf '#ff4e00' --ff '#dbc077' --hf '#ff4e00')
if [ -n "$entry" ]; then
gopass show -c "$entry" 2>/dev/null || notify-send "Gopass Error" "Failed to copy: $entry"
fi

8
.local/bin/pass_user_copy Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
entry=$(gopass list --flat | bemenu -p Username: -l 25 -c -M 500 --fn 'Monospace 14' --tf '#ff4e00' --ff '#dbc077' --hf '#ff4e00')
if [ -n "$entry" ]; then
gopass show -c "$entry" username 2>/dev/null || notify-send "Gopass Error" "Failed to copy username from: $entry"
fi

47
.local/bin/todo Executable file
View File

@@ -0,0 +1,47 @@
#!/bin/sh
TODO_FILE="$HOME/docs/todo.txt"
ARCHIVE_FILE="$HOME/docs/todo-archive.txt"
TODAY="$(date +%Y-%m-%d)"
case "$1" in
add)
shift
echo "($TODAY) $*" >> "$TODO_FILE"
echo "Added: ($TODAY) $*"
;;
lsa)
nl -w2 -s'. ' "$TODO_FILE"
;;
ls)
grep -v '^x ' "$TODO_FILE" | nl -w2 -s'. '
;;
done)
if [ -z "$2" ]; then
echo "Usage: $0 done <task-number>"
exit 1
fi
TASK=$(sed -n "${2}p" "$TODO_FILE")
[ -z "$TASK" ] && { echo "Invalid task number."; exit 1; }
sed -i "${2}s/^/x ($TODAY) /" "$TODO_FILE"
echo "Marked done: $TASK"
;;
archive)
grep '^x ' "$TODO_FILE" >> "$ARCHIVE_FILE"
sed -i '/^x /d' "$TODO_FILE"
echo "Archived completed tasks to $ARCHIVE_FILE"
;;
tags)
if [ -z "$2" ]; then
echo "Usage: $0 tags <+tag|@context>"
exit 1
fi
grep "$2" "$TODO_FILE" | grep -v '^x ' | nl -w2 -s'. '
;;
help|*)
echo "Usage: $0 {add <task> | list | done <number> | archive}"
;;
esac

50
.local/bin/vault Executable file
View File

@@ -0,0 +1,50 @@
#!/bin/sh
CONTAINER=${2:-"$HOME/vault.hc"}
BASENAME=$(basename "$CONTAINER")
MAPPER_NAME="${BASENAME%.*}"
MOUNT_POINT="/mnt/$MAPPER_NAME"
case "$1" in
open)
if [ ! -f "$CONTAINER" ]; then
echo "Container not found: $CONTAINER"
exit 1
fi
if [ -e "/dev/mapper/$MAPPER_NAME" ]; then
echo "Already opened at /dev/mapper/$MAPPER_NAME"
exit 1
fi
mkdir -p "$MOUNT_POINT" || exit 1
if sudo cryptsetup open --type tcrypt "$CONTAINER" "$MAPPER_NAME"; then
sudo mount "/dev/mapper/$MAPPER_NAME" "$MOUNT_POINT" &&
echo "Mounted at $MOUNT_POINT"
else
echo "Failed to open container."
exit 1
fi
;;
close)
if mountpoint -q "$MOUNT_POINT"; then
sudo umount "$MOUNT_POINT"
fi
if [ -e "/dev/mapper/$MAPPER_NAME" ]; then
sudo cryptsetup close "$MAPPER_NAME"
echo "Closed and unmounted $MOUNT_POINT."
else
echo "Container is not open."
fi
;;
*)
echo "Usage: $0 {open|close} [path/to/container.hc]"
exit 1
;;
esac

1630
.local/share/chars/emojis Normal file

File diff suppressed because it is too large Load Diff

19
.yash_env Normal file
View File

@@ -0,0 +1,19 @@
#!/bin/sh
# Environment exports
export XDG_CONFIG_HOME="$HOME/.config"
export XDG_CACHE_HOME="$HOME/.cache"
export XDG_DATA_HOME="$HOME/.local/share"
export VISUAL=nvim
export EDITOR=nvim
export BROWSER=/usr/bin/librewolf
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
export XDG_DATA_DIRS="/usr/share"
export XDG_CURRENT_DESKTOP="sway"
export XDG_SESSION_DESKTOP="sway"
export XDG_SESSION_TYPE="wayland"
export GTK_ICON_THEME="Papirus"
export QT_QPA_PLATFORMTHEME=gtk3

9
.yash_profile Normal file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
if [ -f "$HOME/.yash_env" ]; then
. "$HOME/.yash_env"
fi
if [ -z "$WAYLAND_DISPLAY" ] && [ "$(tty)" = "/dev/tty1" ]; then
exec dbus-run-session sway
fi

69
.yashrc Normal file
View File

@@ -0,0 +1,69 @@
# Load global initialization script, if exists.
if [ -f /etc/yashrc ]; then
. /etc/yashrc
fi
#######################################################
# Alias
#######################################################
alias v='nvim'
alias vim='nvim'
alias vi='nvim'
alias add='doas apk add'
alias del='doas apk del'
alias search='apk search'
alias info='doas apk info'
alias update='doas apk update'
alias upgrade='doas apk upgrade'
alias ll='ls -lF --color=auto'
alias la='ls -A --color=auto'
alias gs='git status'
alias clr='clear'
#######################################################
# Exports & Shell Vars
#######################################################
export HISTFILE="$HOME/.yash_history"
export HISTSIZE=99999
export PATH="$HOME/bin:/sbin:/usr/sbin:/bin:/usr/bin:$PATH"
#######################################################
# Prompt
#######################################################
PS1='$(pwd) $ '
#######################################################
# SSH
#######################################################
keys() {
eval "$(keychain --eval --quiet ry_ecdsa)"
eval "$(keychain --eval --quiet id_rsa)"
}
keys
#######################################################
# WORK
#######################################################
# Wireguard
alias wgup='doas wg-quick up /etc/wireguard/wg0.conf'
alias wgdown='doas wg-quick down /etc/wireguard/wg0.conf'
#######################################################
# Misc
#######################################################
# Uncomment if you want to clear the screen with Ctrl-L.
bindkey --emacs '\^L' clear-and-redraw-all
bindkey --vi-insert '\^L' clear-and-redraw-all
bindkey --vi-command '\^L' clear-and-redraw-all

0
README.md Normal file
View File