Rebuild dotfiles as one branch with per-host layers
Replaces the previous repo, which had split into two histories that never met (mainframe on a dead GitLab remote, the laptops on Gitea) with 146 dirty files across three machines and the NAS never enrolled at all. Branch-per-machine is gone. One main, with host differences expressed as small files under hosts/<hostname>/ rather than as branches, so there is nothing to merge. The reconciled zsh layer reduces 15-33 line forks to 1-7 effective lines per host; distro differences (oh-my-zsh prefix, syntax-highlighting path, fd vs fdfind) are probed in common/ instead. Fresh history: the old one carried six plaintext credentials, 45 MB of mail caches, browser caches and vendored binaries. 5,096 tracked files and 144 MB become 462 files and 2.6 MB. The .gitignore is now an allowlist, which is what keeps that true. Root cause of the rot: ~/.local/bin was a symlink to scripts/ with GOPATH inside it, so every go install wrote into version control (2.2 GB on the work laptop). PATH now points at the repo instead of the reverse. Also: Hyprland replaces sway and is sourced in two halves so $browser is defined before use; singleton automations carry ConditionHost= alongside host-layer-only placement; ddns moves from cron to a guarded timer; package manifests and pkg-snapshot/pkg-restore replace the X11-era install_scripts/; networkmanager-dmenu added to system76 (the binding always existed, the package never did).
This commit is contained in:
commit
e6644d0616
462 files changed
+23524
No files matched your search
@@ -0,0 +1,36 @@
|
||||
# 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:
|
||||
auto_save.session:
|
||||
global: true
|
||||
content.desktop_capture:
|
||||
global: true
|
||||
content.javascript.clipboard:
|
||||
https://ai.rcjohnstone.com: access-paste
|
||||
https://chatgpt.com: access-paste
|
||||
https://claude.ai: access-paste
|
||||
https://huggingface.co: access-paste
|
||||
https://www.google.com: access-paste
|
||||
content.media.audio_capture:
|
||||
global: true
|
||||
https://voice.google.com: true
|
||||
content.media.audio_video_capture:
|
||||
global: true
|
||||
https://gov.teams.microsoft.us: true
|
||||
content.media.video_capture:
|
||||
global: true
|
||||
content.notifications.enabled:
|
||||
https://mail.proton.me: false
|
||||
https://runway.rcjohnstone.com: true
|
||||
https://voice.google.com: false
|
||||
https://www.chess.com: false
|
||||
https://www.italki.com: true
|
||||
content.register_protocol_handler:
|
||||
https://mail.proton.me#mailto=%25s: false
|
||||
tabs.show:
|
||||
global: always
|
||||
@@ -0,0 +1,28 @@
|
||||
https://www.codecademy.com/paths/web-development/tracks/getting-started-with-javascript/modules/learn-javascript-introduction/lessons/introduction-to-javascript/exercises/libraries Learn JavaScript: Introduction | Codecademy
|
||||
https://docs.google.com/spreadsheets/d/1izX7ZJX_ATHFUEuRw-tFlyV1dWhMwJb9PkEGh6p-wrU/edit#gid=0 Air Composition Bounds - Google Sheets
|
||||
https://hangouts.google.com/ Google Hangouts
|
||||
https://docs.google.com/spreadsheets/d/1ep7lTi1iSDn6wBlDLUWstPsxuKIIxYUGRiIC4fg7mnY/edit#gid=0 Untitled spreadsheet - Google Sheets
|
||||
https://gitlab.palskichat.com/usspacetraining/simulator/merge_requests/3 Sim announce creation/destruction (!3) · Merge Requests · US Space Training / simulator · GitLab
|
||||
https://sts.digitalglobe.com/adfs/ls/?login_hint=connor.johnstone%40sslmda.com&client-request-id=a7cda4d2-77e1-4095-8e2a-ab7e63e54b09&username=connor.johnstone%40sslmda.com&wa=wsignin1.0&wtrealm=urn%3Afederation%3Amicrosoftonline.us&wreply=https%3A%2F%2Flogin.microsoftonline.us%2Flogin.srf&wctx=estsredirect%3D5%26estsrequest%3DrQIIAYWUP8jcdBjHe-9b39pWahUHQZAODlLI9Zf_yTs1ufy5y5vk7nK5yyUIIf8u_3-5N8ld7m5wFgcpQhdHES11Eafi6FgQiqPgoCCIk3Rx9aq4OOjyDA_fhw_P8P3cuEb18T7og7unaB89f4fACdKjfRZhPQpHCBYFiEdgFIKTOIVjAA1JgNev37j9_WffffFT9_D-R3e_fD_45eL6497bSduum_N797qu61erVRpE_aAq7xUeDFMYP-n1nvV6v_Z6H5-8FVQQVnU_qxLYtBWM7jdNUYbei_jjk4bCaYyiMBrHCAIcsSTWdwQl10x7PxaCVs-KTB8AYJd6ploiqR-4VhOCvWbOu7GQ7xxLA1oWo7qpF_ZBazUzKbXZMW-NCNXMUU3gWl3gDo452jtCToxNqfzh5NUxt2kT7MWo6vQQPT-5vqrq0l1XTfvJ6VfX6uloxNnWbGtvTZsTZBVBQ3ZOG_NdJ04tssuVce6zJMMOq7hUN2DZVmU7h1RqCJ4u4jMFQp_U8CJvJGeoGRIPAkMKsWCnD3dTnh92c4kXB-EOhENKomMGdJMJR7urXVxGdppwcQQYM5TpBZrKpO0VcydvBLyUHa0Bo1HQkGIp23gsc7DWuJnNbOkhyUSQJlFklhxWG59GKBun6ppmcjVr7AM1Ce1MUsR4rSuX5Ho-8_cpS3SyuuFd244niSCGhEJAaXPg6ot2G-ykiTQeTDhWFWTDafhDPBLmU--gOzQV6iAwL1CluUQ6AayspUdJNqEY405VLte1GpnrLKZlaBQjkW2tVlzUpKtYuh0uWc9yPVrUt1NHtZvBIp8mMpLMxgkPfWm8Rdbs3iHbQcbjhIoKldN6W3xSiYlP7IydhMAhMk_BZm8SF5vmEDATuYoLJwASdZlx7GI9kCVBk_jMEohApxUsmq0XgeZT3tKsi2aaI4DGNbVwlnR82YFO3KiDPTaOJmw62vr-htj5scDtSbExnG5hSLRItonrpFGI7EHJzjTDwHyl5fztPDV3isdP564cBNDqYLmscGB4q4UItw7QAFRXF6OtQE3XqhRNqI2WY8NVADw1CyHvL6bHntWUHdW2GmLmZNHOmmMLpJGBTyPSKxn1chzNHC7BDx6dlIuS5i4sd8eXhYM2ydyXU29hpRBVunXU8YWSuzgJxySsvfJQ8jkdtCwCZ0xjr6pqrFGr6VKrAy30mR2vLzWXKms2r1KeG5kLyUz4RJJivGqyw47RXURAGjFjLZNkGn9sb-ty3y5VwB22O0dxqEadYpQb-UmD0m7o4tKlsfIh4obWoYguQM3Oajmj4_jSnNgy9IeT5ayxIob3Mk2smMLws3BZpuOtpHv5qG70EMllPpK4ajvYBEcBHQxe9lQ1YHV6UI2FagMVXZxSsCpTopEWvOSNBis-UjepY-GUyxjsjEG_Pj072qSs4NPTW9U6gml4Z11Xq7SIfj79L_88u9r77eorL5_dPn3zyp0r774Bbj2_-j9m-_Slow_fe_Lw86X9x8Wjm4_u_vjhh1cenPUenJ19e_Z6mQZ11VSrI6dIYdTfNE_PXhsJri6aM5M7isgQMBf8fnbywbUr31y__w-qqOIU9v99_IL691v3dK9NK-gVg6LahFIURvVfix9uvIEBDCCAQgB6B6XOSfIcZ5wPbvb-BA2# Sign In
|
||||
https://todoist.com/app/?r=1567192910424#project%2F955568460%2Ffull Personal: Todoist
|
||||
https://mxrgcc-my.sharepoint.us/:x:/r/personal/nick_staehler_digitalglobe_com/_layouts/15/guestaccess.aspx?e=ibkRBn&share=ERV-6_TTNV1Hi9YKbLzArMYB-plW6Oez81y3Z9kaFg8raw Book.xlsx
|
||||
https://app.youneedabudget.com/44b49b05-e87e-4e1c-9bb2-8f239df455b7/budget/202007 Budget | 2018 | YNAB
|
||||
https://todoist.com/app/?r=1567192910424#upcoming Upcoming: Todoist
|
||||
https://todoist.com/app/#start Upcoming: Todoist
|
||||
https://docs.google.com/document/d/1Xpq1i5eRtg77f6eGAeNhYr1UK_fUCx-IXUn-qO_vcpg/edit Spring 21 Thesis Starting Point - Google Docs
|
||||
https://voice.google.com/u/0/messages?itemId=t.%2B15024424023 Voice - Ben Schardein
|
||||
https://rconnorjohnstone.com/ Richard Connor Johnstone
|
||||
https://confluence.nyxatlas.com/pages/resumedraft.action?draftId=21004570&draftShareId=1a28a278-63b5-41fa-bd45-04c3ad3aa1c1& Edit - D-Region Absorption Model - SET4D Mission - SET4D
|
||||
https://confluence.nyxatlas.com/pages/resumedraft.action?draftId=21954601&draftShareId=91c77ddc-8628-484c-bd56-129354a53c69& Plotting Page - SET4D Mission - SET4D
|
||||
https://tasks.rconnorjohnstone.com/login Login | Vikunja
|
||||
https://cronometer.com/#custom-foods Cronometer
|
||||
https://arcfield.sharepoint.us/:x:/r/teams/RROCI-2/_layouts/15/Doc.aspx?sourcedoc=%7B6F6B1842-D840-43ED-B36A-8984742B48B3%7D&file=Measurement%20Mode%20Orientation%20Tracking.xlsx&fromShare=true&action=default&mobileredirect=true Measurement Mode Orientation Tracking.xlsx
|
||||
https://rdweb.wvd.azure.us/arm/webclient/index.html Remote Desktop Web Client
|
||||
https://onestop.registration.ky.gov/ers/TaxRegistration/AdditionalInformation AdditionalInformation - KY OneStop Tax Registration
|
||||
https://web.whatsapp.com/ WhatsApp
|
||||
https://www.youtube.com/watch?v=TOs5cR-10xA (207) An Italian Tries CATHY MITCHELL's Pasta Recipes (it didn't go well) - YouTube
|
||||
https://arcfield.sharepoint.us/:p:/r/teams/Ouija1/_layouts/15/Doc.aspx?sourcedoc=%7B7637D81B-64ED-4C72-A77F-D9AED88D0236%7D&file=OUIJA%20Re-entry%20Analysis%20August%202025%20with%20Copper%20Pucks.pptx&action=edit&mobileredirect=true OUIJA Re-entry Analysis August 2025 with Copper Pucks.pptx
|
||||
https://voice.google.com/u/0/messages?itemId=t.%2B15025541141 Voice - Messages
|
||||
https://claude.ai/chat/bd163dd2-45ab-4376-9c8e-3560230dd2a3 Makefile shell command best practices - Claude
|
||||
https://arcfield-my.sharepoint.us/:p:/r/personal/matthew_cooper_arcfield_com/_layouts/15/Doc.aspx?sourcedoc=%7BB5C78A7E-B47D-4DA6-92A2-C2F5F7E62088%7D&file=2026_HORUS-OSIRIS_IRaD_KickoffSlides.pptx&fromShare=true&action=edit&mobileredirect=true 2026_HORUS-OSIRIS_IRaD_KickoffSlides.pptx
|
||||
https://claude.ai/chat/28944c2b-f3a4-47d9-9854-aab012449b34 C++ for loop iteration range - Claude
|
||||
@@ -0,0 +1,25 @@
|
||||
# Qutebrowser color scheme from wallust
|
||||
|
||||
# You can use this template by adding the following to wallust.toml:
|
||||
# qutebrowser = { src = "qutebrowser.py", dst = "~/.config/qutebrowser/colors.py" }
|
||||
# and then on config.py:
|
||||
# from colors import *
|
||||
|
||||
foreground = "#E8EFFC"
|
||||
background = "#171917"
|
||||
color0 = "#414441"
|
||||
color1 = "#718B81"
|
||||
color2 = "#86B4C4"
|
||||
color3 = "#DCA0D2"
|
||||
color4 = "#9CBBDA"
|
||||
color5 = "#E3B0CE"
|
||||
color6 = "#BED0F7"
|
||||
color7 = "#D6DFF2"
|
||||
color8 = "#969CAA"
|
||||
color9 = "#718B81"
|
||||
color10 = "#86B4C4"
|
||||
color11 = "#DCA0D2"
|
||||
color12 = "#9CBBDA"
|
||||
color13 = "#E3B0CE"
|
||||
color14 = "#BED0F7"
|
||||
color15 = "#D6DFF2"
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,31 @@
|
||||
// ==UserScript==
|
||||
// @name Userstyle (dreamingspanish.css)
|
||||
// @include *dreaming.com*
|
||||
// ==/UserScript==
|
||||
GM_addStyle(`.ds-page {
|
||||
max-width: 95%;
|
||||
}
|
||||
|
||||
.ds-form-calendar {
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.ds-form-calendar__row {
|
||||
height: 3.5rem;
|
||||
}
|
||||
|
||||
.ds-form-calendar__column {
|
||||
height: 100%;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.ds-form-calendar__column-wrapper {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.ds-form-calendar__column-time {
|
||||
font-size: 0.65rem;
|
||||
line-height: 1.4rem;
|
||||
}
|
||||
`)
|
||||
@@ -0,0 +1,12 @@
|
||||
// ==UserScript==
|
||||
// @name Userstyle (italki.css)
|
||||
// @include *italki.com*
|
||||
// ==/UserScript==
|
||||
GM_addStyle(`.MessageList-main {
|
||||
padding-bottom: 250px !important;
|
||||
}
|
||||
|
||||
#app .min-h-10 {
|
||||
min-height: 200px !important;
|
||||
}
|
||||
`)
|
||||
@@ -0,0 +1,41 @@
|
||||
// ==UserScript==
|
||||
// @name Userstyle (qute.help.css)
|
||||
// @include qute://help*
|
||||
// @include *someotherdomain.xyz*
|
||||
// ==/UserScript==
|
||||
GM_addStyle(`html {
|
||||
background-color: #041E39;
|
||||
}
|
||||
|
||||
html > body, html ul > li > * {
|
||||
color: #EBEBD3;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
html a {
|
||||
color: #F78764;
|
||||
}
|
||||
|
||||
html a:visited {
|
||||
color: #2D8CF0;
|
||||
}
|
||||
|
||||
.monospaced, code, pre {
|
||||
color: #F4D35E;
|
||||
}
|
||||
|
||||
div.admonitionblock {
|
||||
color: #FAB49E;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
html em, html dt {
|
||||
color: #FAB49E;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
html div.listingblock > div.content, div.listingblock .highlight {
|
||||
background-color: #611B05;
|
||||
}
|
||||
|
||||
`)
|
||||
@@ -0,0 +1,8 @@
|
||||
// ==UserScript==
|
||||
// @name Userstyle (readthedocs.css)
|
||||
// @include *readthedocs.io*
|
||||
// ==/UserScript==
|
||||
GM_addStyle(`.wy-nav-content {
|
||||
max-width: 1200px;
|
||||
}
|
||||
`)
|
||||
@@ -0,0 +1,8 @@
|
||||
// ==UserScript==
|
||||
// @name Userstyle (twitch.css)
|
||||
// @include *twitch.tv*
|
||||
// ==/UserScript==
|
||||
GM_addStyle(`body {
|
||||
width: 80% !important;
|
||||
}
|
||||
`)
|
||||
@@ -0,0 +1,8 @@
|
||||
[FileDialog]
|
||||
history=file:///home/connorjohnstone/scout/projects/gnsuite_temp, file:///home/connorjohnstone/docs/dnd/one_shots/tress/guide/build, file:///home/connorjohnstone/downloads, file:///home/connorjohnstone, file:///home/connorjohnstone/scout/projects/sim_prototype
|
||||
lastVisited=file:///home/connorjohnstone
|
||||
qtVersion=6.11.1
|
||||
shortcuts=file:, file:///home/connorjohnstone, file:///home/connorjohnstone/scout, file:///tmp, file:///mnt
|
||||
sidebarWidth=110
|
||||
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\x2Q\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\x1V\0\0\0\x1\0\0\0\0\0\0\0\x62\0\0\0\x1\0\0\0\0\0\0\0\x38\0\0\0\x1\0\0\0\0\0\0\0\x61\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1)
|
||||
viewMode=Detail
|
||||
@@ -0,0 +1,134 @@
|
||||
ynab https://app.youneedabudget.com/44b49b05-e87e-4e1c-9bb2-8f239df455b7/budget
|
||||
schwab https://www.schwab.com/
|
||||
538 https://fivethirtyeight.com/
|
||||
chase https://www.chase.com/
|
||||
discover https://www.discover.com/
|
||||
reddit https://www.reddit.com/
|
||||
mtn https://www.mountainproject.com/
|
||||
khc https://kyhousing.estatusconnect.com/index.html#/home/login
|
||||
netflix https://www.netflix.com/browse
|
||||
digitalocean https://cloud.digitalocean.com/projects/a159e12a-d207-4870-a787-9b8e1f0bcfe8/resources?i=c279e6
|
||||
plotlyjs https://plot.ly/javascript/reference/#scatter
|
||||
yt https://www.youtube.com/
|
||||
photos https://photo.rcjohnstone.com/photos
|
||||
maps https://www.google.com/maps
|
||||
rent https://realiantcincinnati.appfolio.com/connect
|
||||
nyt https://www.nytimes.com/
|
||||
reuters https://www.reuters.com/
|
||||
ap https://apnews.com/
|
||||
files https://files.rcjohnstone.com/
|
||||
baikal https://baikal.rcjohnstone.com/
|
||||
spotify https://open.spotify.com/collection/tracks
|
||||
cal_inspirations https://uicookies.com/css-calendar/
|
||||
pomodoro https://pomofocus.io/
|
||||
weather https://www.accuweather.com/en/us/cincinnati/45202/weather-forecast/350126
|
||||
bw https://bw.rcjohnstone.com/#/vault
|
||||
cronometer https://cronometer.com/
|
||||
boa https://www.bankofamerica.com/
|
||||
ascii https://textkool.com/en/ascii-art-generator?hl=default&vl=default&font=ANSI%20Regular&text=Connor%20Johnstone
|
||||
host https://check-host.net/
|
||||
git_work https://gitserver.idm.orionspace.com/users/sign_in
|
||||
tsheets https://tsheets.intuit.com/page/login_oii
|
||||
tasks https://tasks.rconnorjohnstone.com/login
|
||||
unifi https://localhost:8443/manage/default/dashboard
|
||||
mail https://mail.proton.me/u/0/inbox
|
||||
home https://home.rcjohnstone.com/
|
||||
radarr https://radarr.rcjohnstone.com/
|
||||
lidarr https://lidarr.rcjohnstone.com/
|
||||
sonarr https://sonarr.rcjohnstone.com/
|
||||
readarr https://readarr.rcjohnstone.com/
|
||||
prowlarr https://prowlarr.rcjohnstone.com/
|
||||
deluge https://deluge.rcjohnstone.com/
|
||||
jellyfin https://jellyfin.rcjohnstone.com/web/#/home.html
|
||||
gov_outlook https://outlook.office365.us/mail/inbox
|
||||
outlook https://outlook.office365.us/mail/
|
||||
office https://www.office.com/?auth=2
|
||||
pw https://cloud.parallel.works/u
|
||||
navidrome https://music.rcjohnstone.com/app/#/album/recentlyAdded?sort=recently_added&order=DESC&filter=%7B%7D
|
||||
aws https://d-9a6717b3d2.awsapps.com/start/#/?tab=accounts
|
||||
jira https://arcfield.atlassian.net/jira/your-work
|
||||
powerpoint https://www.office365.us/launch/powerpoint?home=1&auth=2
|
||||
idp https://us-east-2.signin.aws.amazon.com/oauth?client_id=arn%3Aaws%3Asignin%3A%3A%3Aconsole%2Fcanvas&code_challenge=hI-YTRoJe-q_Opf7U6MJ3j8VMH1kKcu0lvHNb2s6KlI&code_challenge_method=SHA-256&response_type=code&redirect_uri=https%3A%2F%2Fconsole.aws.amazon.com%2Fconsole%2Fhome%3FhashArgs%3D%2523%26isauthcode%3Dtrue%26state%3DhashArgsFromTB_us-east-2_8a19eb167a21c928&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEKX%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMiJIMEYCIQDqnVwz2X34AZVABzKtfHEPE%2F59u9rQQEkJ0o6gDV%2BO8QIhAOSZJo6tpkb60bJizA%2BO5Zi1kqzgQ1%2B7IJGHxZtX5Gy2KpMCCN7%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQARoMOTE0NTM5MTg3MDEzIgxl8i0DimVmLyH8BGQq5wEuNonk7zorfA97NzhaMzmw%2FqWpkQDhId%2Bc7t2zDHa%2FLJd3UFX6WFJc0yZ7vV1ALw5HdYbAyKHp7F9DLY7GGsnSoZPyaEFgufyXGrK%2B0TKy%2FNKnzoQhkAPeV39sXSLLzPGy409dKwo%2FwwdOv6q7XTK%2FpgdBlnmq3EtVRfGjGTDbLtBKwOPD2DU%2FE%2Fc0%2FPv8GJVVZuL3iPblbiprdnAKh5MKtZiXuYLQpEanD0ep9qjLZfkDhlz6kkzRGOlZuzcADAvduDNNu4bAv060coXws9HqBZmTvP9Y0oR1iDPKZU15Y9XrP6mP4KAwxJm1qgY6jgF7YtgvKj9LsOY%2B8mKzAUtm%2BiRAmCVNAE%2FRmqaiUqTLdMwPf1NuLuzoDMl92r9C1FjinI4B2YzLiFT1QhldZy1PaqiwZ3A6heGl6Ukjc%2BykLWGkKX7udDPE6t%2FwF%2BRB%2Bll84WsdrDzDgfnWWXt2avODw3aZIbyHd1LYG2LTXBYfKW0S05QQ8GFOh5pb8QBk&X-Amz-Date=20231109T213036Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA5J3WIRNCUZKZXBV6%2F20231109%2Fus-east-2%2Fsignin%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=2fb29f68a471103ac445233ac6c66bdaac91cd5a4cf8e38b7a7b47872517b250
|
||||
rroci_grafana http://10.10.201.55:3000/login
|
||||
confluence https://scout-space.atlassian.net/wiki/spaces/SCOUTSPACE/pages/250642433/Weekly+TACFI+Owl?contentRecommendation=on&popular=true
|
||||
colorschemes http://gogh-co.github.io/Gogh/
|
||||
gitlab https://gitlab.rcjohnstone.com/users/sign_in
|
||||
chatgpt https://chat.openai.com/
|
||||
git_idp https://gitlab.orionspacestation.com/users/sign_in
|
||||
apps https://myapplications.azure.us/
|
||||
vdi https://rdweb.wvd.azure.us/arm/webclient/index.html
|
||||
grafana https://3.30.135.27:3000/
|
||||
teams https://gov.teams.microsoft.us/v2
|
||||
voice https://voice.google.com/u/0/messages
|
||||
cal https://cal.rcjohnstone.com/
|
||||
aero https://filespace.aero.org/human.aspx?r=4292318470
|
||||
whatsapp https://web.whatsapp.com/
|
||||
sedaro_onedrive https://sedarocorp-my.sharepoint.us/personal/robbie_robertson_sedaro_com/_layouts/15/onedrive.aspx?id=%2Fpersonal%2Frobbie_robertson_sedaro_com%2FDocuments%2F00%20Sedaro%20Drive%2F06%20Contracts%2F15%20RROCI%2FDeliverables%2FOrion_Sedaro_Fileshare&ga=1
|
||||
sedaro_sharepoint https://sedarocorp-my.sharepoint.us/personal/robbie_robertson_sedaro_com/_layouts/15/onedrive.aspx?id=%2Fpersonal%2Frobbie_robertson_sedaro_com%2FDocuments%2F00%20Sedaro%20Drive%2F06%20Contracts%2F15%20RROCI%2FDeliverables%2FOrion_Sedaro_Fileshare&ga=1
|
||||
jellyseerr https://jellyseerr.rcjohnstone.com/
|
||||
e https://192.168.1.101:8006/#v1:0:=qemu%2F101:4:::::8::
|
||||
element https://element.rcjohnstone.com/
|
||||
aws access portal https://start.us-gov-east-1.us-gov-home.awsapps.com/directory/d-c267218df8#/?tab=accounts
|
||||
aws portal https://start.us-gov-east-1.us-gov-home.awsapps.com/directory/d-c267218df8#/?tab=accounts
|
||||
satrs https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main
|
||||
vorago https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/embassy/src/time_driver.rs
|
||||
jelly https://jellyfin.rcjohnstone.com/web/#/home.html
|
||||
transmission https://transmission.rcjohnstone.com/transmission/web/
|
||||
boxes.py https://boxes.hackerspace-bamberg.de/
|
||||
router https://10.0.0.1/
|
||||
laser templates https://www.templatemaker.nl/en/
|
||||
laser_puzzles https://draradech.github.io/jigsaw/jigsaw.html
|
||||
fte https://arcfield.sharepoint.us/:x:/r/sites/ProgramMissionManagementOfficePM2O/_layouts/15/doc2.aspx?sourcedoc=%7B344DE6A2-BC95-4BFE-8D73-81C0803EB62C%7D&file=Orion%20FTE%20Tracker%20Base%20-%20ACTIVE%20FILE.xlsm&action=default&mobileredirect=true
|
||||
ai https://ai.rcjohnstone.com/
|
||||
dsa_cal https://www.dsalouisville.org/events/events-calendar
|
||||
sftp https://sftp.rcjohnstone.com/web/client/login
|
||||
wled http://192.168.1.182/#Colors
|
||||
kraken/requirements https://arcfield.sharepoint.us/:x:/r/teams/Ouija1/_layouts/15/Doc.aspx?sourcedoc=%7B369FB775-26A9-4C95-9FC7-8EF0BA0B015B%7D&file=402SPEC100%20-%20Kraken%20Requirements%20Verification%20Matrix%2009092024.xlsx&action=default&mobileredirect=true
|
||||
kraken/trr https://arcfield.sharepoint.us/:p:/r/teams/Ouija1/_layouts/15/Doc.aspx?sourcedoc=%7B0DED2C57-DC24-4C97-8B1A-ABF8B9210319%7D&file=CUI-OUIJA-Kraken-TA1-Full%20System%20Test%20Readiness%20Review.pptx&action=edit&mobileredirect=true&previoussessionid=822b8401-6b37-130b-a7cb-bcc1eb9e7398
|
||||
kraken/flexcore_icd https://arcfield.sharepoint.us/teams/Ouija1/Shared%20Documents/Forms/AllItems.aspx?id=%2Fteams%2FOuija1%2FShared%20Documents%2FTA1%20%28Kraken%29%20Phase%201%2FSystems%20Engineering%2FICDs%2FEXTERNAL%2FADCS%2FFlexcore%2F30ICD4249revB%20-%20FleXcore%20Gen3.1%20Interface%20Control%20Document%20%28ICD%29%20%284%29.pdf&parent=%2Fteams%2FOuija1%2FShared%20Documents%2FTA1%20%28Kraken%29%20Phase%201%2FSystems%20Engineering%2FICDs%2FEXTERNAL%2FADCS%2FFlexcore
|
||||
kraken/rsso qute://pdfjs/web/viewer.html?filename=tmpluv5gspz_PPD_1011_RC_FINAL.pdf&file=&source=https://ntrs.nasa.gov/api/citations/20230001348/downloads/PPD_1011_RC_FINAL.pdf
|
||||
lisird_f107 https://lasp.colorado.edu/lisird/data/display?lz=N4IgDgNg9gLgziAXCYAdc17sQbTSAEwEMYi4BTLJPdY0imASQO3QGMI4B9AJyIICWULgDMIAVwAeogIwAGAOzoANOj4A7AObkAakR5xsNEOqIBbcqxD8AVuLgxyBWYq5sVtAXEhEAngDlzSyR0AGEoHh5yNkcCAAIAQQI7Byc4gCV%2BITiAMQlJdABfAF0S1RAoMBghdUMkYEKy9AA3KxkAOgAmdrkikGUQTWgAIyIIAHkqmoRkfCGoUYgAWXJ1cUnqqFrsBsKQQqA
|
||||
books1 https://annas-archive.org/
|
||||
books2 http://libgen.rs/
|
||||
books3 https://www.reddit.com/r/Piracy/comments/2oftbu/guide_the_idiot_proof_guide_to_downloading_ebooks/
|
||||
kvm https://pikvm/login/
|
||||
aws_gov https://start.us-gov-east-1.us-gov-home.awsapps.com/directory/d-c267218df8#/?tab=accounts
|
||||
gitea https://git.rcjohnstone.com/
|
||||
wenzel_water https://louisvilleky.watersmart.com/index.php/home/index
|
||||
wenzel_lge https://my.lge-ku.com/cs/doStart.sap
|
||||
wenzel_internet https://www.att.com/acctmgmt/overview?authNState=Y&haloSuccess=true<=QHVBdylFK25HdGFncnh8dmd5a0x8ZCZRNDgmPiVPPGpuJiJnPyhbSzY0ODduPiZGVCRxeVoiJkA%3D
|
||||
box https://console.hetzner.com/projects/11834759/storage-boxes/474410/overview
|
||||
git_arcfield https://gitlab.arcfield.com/users/sign_in
|
||||
lazylibrarian https://lazylibrarian.rcjohnstone.com/authors
|
||||
ll https://lazylibrarian.rcjohnstone.com/authors
|
||||
drawers https://www.printables.com/model/1149008-improved-modular-gridfinity-drawers/files
|
||||
gridfinity https://gridfinity.tools/
|
||||
itatorrents https://itatorrents.xyz/
|
||||
insta https://www.instagram.com/
|
||||
ha http://10.0.0.2:8123/auth/authorize?response_type=code&redirect_uri=http%3A%2F%2F10.0.0.2%3A8123%2F%3Fauth_callback%3D1&client_id=http%3A%2F%2F10.0.0.2%3A8123%2F&state=eyJoYXNzVXJsIjoiaHR0cDovLzEwLjAuMC4yOjgxMjMiLCJjbGllbnRJZCI6Imh0dHA6Ly8xMC4wLjAuMjo4MTIzLyJ9
|
||||
conferences https://spaceindustrydatabase.com/events
|
||||
camera https://camera.rcjohnstone.com/
|
||||
authentik https://bus-auth.ntc.dsausa.org/if/user/#/library
|
||||
lichess_time https://ra314.github.io/lichess-time-tracker/
|
||||
maproulette https://maproulette.org/browse/challenges/53913
|
||||
spanish_notes https://www.tldraw.com/f/M4_Lwl178dtCuMz6mbbnC?d=v-147.199.2156.1157.page
|
||||
whisparr https://whisparr.rcjohnstone.com/
|
||||
scout/github https://github.com/SCOUTdotspace
|
||||
gusto https://app.gusto.com/
|
||||
scout/sharepoint https://scoutspacegcchigh.sharepoint.us/_layouts/15/sharepoint.aspx
|
||||
scout/thrivepass https://app.thrivepass.com/dashboard
|
||||
shanty https://shanty.rcjohnstone.com/
|
||||
greenhouse https://app8.greenhouse.io/dashboard
|
||||
scout/owl/icd_sheet https://scoutspacegcchigh.sharepoint.us/:x:/s/ScoutPrograms/IQBD2Qz4VNIaSqArGE1jyCCzAcyeSs-A0CBFq35ZsRabZTk?e=PIphpz&isSPOFile=1&ovuser=f50f4fcc-38ea-4525-a42e-e89136a91fed%2Cconnor.johnstone%40scout.space&clickparams=eyJBcHBOYW1lIjoiVGVhbXMtRGVza3RvcCIsIkFwcFZlcnNpb24iOiIxNDE1LzI2MDIyNzA0MjE1IiwiSGFzRmVkZXJhdGVkVXNlciI6ZmFsc2V9
|
||||
scout/tailscale https://login.tailscale.com/admin/machines
|
||||
wordle https://www.nytimes.com/games/wordle/index.html
|
||||
contexto https://contexto.me/en/
|
||||
sim http://localhost:5173/
|
||||
conjugaciones https://spanish.rcjohnstone.com/
|
||||
time https://time.rcjohnstone.com/#/dashboard/4/Spanish
|
||||
kimi https://platform.kimi.ai/console/general
|
||||
openai https://platform.openai.com/home
|
||||
anthropic https://platform.claude.com/dashboard
|
||||
moey_rent https://moeyproperties.managebuilding.com/Resident/portal/
|
||||
jessica https://meet.google.com/pez-pnzg-nxo
|
||||
dashboard https://docs.google.com/spreadsheets/d/1vwAxNKKzGNAPbqasXk52l8O0v4WfCXaxZmDd4ZzQYl8/edit?gid=1259809999#gid=1259809999
|
||||
@@ -0,0 +1,119 @@
|
||||
# import json
|
||||
# import os
|
||||
#
|
||||
# qutewal_dynamic_loading = False
|
||||
#
|
||||
# home = os.getenv('HOME')
|
||||
# colors_relative = '.cache/wal/colors.json'
|
||||
# daemon_relative = '.config/qutebrowser/qutewald.py'
|
||||
# colors_absolute = os.path.join(home, colors_relative)
|
||||
# daemon_absolute = os.path.join(home, daemon_relative)
|
||||
#
|
||||
# if os.path.isfile(colors_absolute):
|
||||
# with open(colors_absolute) as colorfile:
|
||||
# colors = json.load(colorfile)
|
||||
# cursor = colors['special']['cursor']
|
||||
# background = colors['special']['background']
|
||||
# foreground = colors['special']['foreground']
|
||||
# black = colors['colors']['color0']
|
||||
# white = colors['colors']['color7']
|
||||
# gray = colors['colors']['color8']
|
||||
# red = colors['colors']['color1']
|
||||
# green = colors['colors']['color2']
|
||||
# yellow = colors['colors']['color3']
|
||||
# blue = colors['colors']['color4']
|
||||
# magenta = colors['colors']['color5']
|
||||
# cyan = colors['colors']['color6']
|
||||
#
|
||||
# c.colors.completion.category.bg = background
|
||||
# c.colors.completion.category.border.bottom = background
|
||||
# c.colors.completion.category.border.top = background
|
||||
# c.colors.completion.category.fg = foreground
|
||||
# c.colors.completion.even.bg = background
|
||||
# c.colors.completion.odd.bg = background
|
||||
# c.colors.completion.fg = foreground
|
||||
# c.colors.completion.item.selected.bg = gray
|
||||
# c.colors.completion.item.selected.border.bottom = background
|
||||
# c.colors.completion.item.selected.border.top = background
|
||||
# c.colors.completion.item.selected.fg = foreground
|
||||
# c.colors.completion.match.fg = yellow
|
||||
# c.colors.completion.scrollbar.bg = background
|
||||
# c.colors.completion.scrollbar.fg = gray
|
||||
# c.colors.downloads.bar.bg = background
|
||||
# c.colors.downloads.error.bg = red
|
||||
# c.colors.downloads.error.fg = foreground
|
||||
# c.colors.downloads.stop.bg = cyan
|
||||
# c.colors.downloads.system.bg = 'none'
|
||||
# c.colors.hints.bg = yellow
|
||||
# c.colors.hints.fg = background
|
||||
# c.colors.hints.match.fg = blue
|
||||
# c.colors.keyhint.bg = background
|
||||
# c.colors.keyhint.fg = foreground
|
||||
# c.colors.keyhint.suffix.fg = yellow
|
||||
# c.colors.messages.error.bg = red
|
||||
# c.colors.messages.error.border = red
|
||||
# c.colors.messages.error.fg = foreground
|
||||
# c.colors.messages.info.bg = blue
|
||||
# c.colors.messages.info.border = blue
|
||||
# c.colors.messages.info.fg = foreground
|
||||
# c.colors.messages.warning.bg = red
|
||||
# c.colors.messages.warning.border = red
|
||||
# c.colors.messages.warning.fg = foreground
|
||||
# c.colors.prompts.bg = background
|
||||
# c.colors.prompts.border = '1px solid ' + background
|
||||
# c.colors.prompts.fg = foreground
|
||||
# c.colors.prompts.selected.bg = magenta
|
||||
# c.colors.statusbar.caret.bg = cyan
|
||||
# c.colors.statusbar.caret.fg = cursor
|
||||
# c.colors.statusbar.caret.selection.bg = cyan
|
||||
# c.colors.statusbar.caret.selection.fg = foreground
|
||||
# c.colors.statusbar.command.bg = background
|
||||
# c.colors.statusbar.command.fg = foreground
|
||||
# c.colors.statusbar.command.private.bg = background
|
||||
# c.colors.statusbar.command.private.fg = foreground
|
||||
# c.colors.statusbar.insert.bg = green
|
||||
# c.colors.statusbar.insert.fg = background
|
||||
# c.colors.statusbar.normal.bg = background
|
||||
# c.colors.statusbar.normal.fg = foreground
|
||||
# c.colors.statusbar.passthrough.bg = blue
|
||||
# c.colors.statusbar.passthrough.fg = foreground
|
||||
# c.colors.statusbar.private.bg = background
|
||||
# c.colors.statusbar.private.fg = foreground
|
||||
# c.colors.statusbar.progress.bg = foreground
|
||||
# c.colors.statusbar.url.error.fg = red
|
||||
# c.colors.statusbar.url.fg = foreground
|
||||
# c.colors.statusbar.url.hover.fg = blue
|
||||
# c.colors.statusbar.url.success.http.fg = foreground
|
||||
# c.colors.statusbar.url.success.https.fg = gray
|
||||
# c.colors.statusbar.url.warn.fg = red
|
||||
# c.colors.tabs.bar.bg = background
|
||||
# c.colors.tabs.even.bg = background
|
||||
# c.colors.tabs.even.fg = foreground
|
||||
# c.colors.tabs.indicator.error = red
|
||||
# # c.colors.tabs.indicator.start = magenta
|
||||
# # c.colors.tabs.indicator.stop = red
|
||||
# c.colors.tabs.indicator.system = 'none'
|
||||
# c.colors.tabs.odd.bg = background
|
||||
# c.colors.tabs.odd.fg = foreground
|
||||
# c.colors.tabs.selected.even.bg = blue
|
||||
# c.colors.tabs.selected.even.fg = foreground
|
||||
# c.colors.tabs.selected.odd.bg = blue
|
||||
# c.colors.tabs.selected.odd.fg = foreground
|
||||
# c.colors.webpage.bg = foreground
|
||||
# c.colors.tabs.pinned.even.bg = background
|
||||
# c.colors.tabs.pinned.even.fg = foreground
|
||||
# c.colors.tabs.pinned.odd.bg = background
|
||||
# c.colors.tabs.pinned.odd.fg = foreground
|
||||
# c.colors.tabs.pinned.selected.even.bg = blue
|
||||
# c.colors.tabs.pinned.selected.even.fg = foreground
|
||||
# c.colors.tabs.pinned.selected.odd.bg = blue
|
||||
# c.colors.tabs.pinned.selected.odd.fg = foreground
|
||||
# if qutewal_dynamic_loading or bool(os.getenv('QUTEWAL_DYNAMIC_LOADING')):
|
||||
# import signal
|
||||
# import subprocess
|
||||
# import prctl
|
||||
#
|
||||
# # start iqutefy to refresh colors on the fly
|
||||
# qutewald = subprocess.Popen(
|
||||
# [daemon_absolute, colors_absolute],
|
||||
# preexec_fn=lambda: prctl.set_pdeathsig(signal.SIGTERM))
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
# #!/usr/bin/env python3
|
||||
#
|
||||
# import os
|
||||
# import signal
|
||||
# import sys
|
||||
# from pathlib import Path
|
||||
#
|
||||
# import daemon
|
||||
# import psutil
|
||||
# from daemon.pidfile import PIDLockFile
|
||||
# from inotify_simple import INotify, flags
|
||||
#
|
||||
#
|
||||
# def cleanup():
|
||||
# os.remove(pidfile)
|
||||
# sys.exit()
|
||||
#
|
||||
#
|
||||
# pidfile = '/tmp/iqutefy.pid'
|
||||
#
|
||||
# # check if pidfile refers to dead process
|
||||
# # if so, remove it
|
||||
# if os.path.isfile(pidfile):
|
||||
# with open(pidfile) as pf:
|
||||
# pid = int(pf.readline())
|
||||
# if not psutil.pid_exists(pid):
|
||||
# os.remove(pidfile)
|
||||
#
|
||||
# with daemon.DaemonContext(
|
||||
# detach_process=False,
|
||||
# pidfile=PIDLockFile(pidfile),
|
||||
# signal_map={signal.SIGTERM: cleanup}):
|
||||
# inotify = INotify()
|
||||
# watch_flags = flags.CREATE | flags.MODIFY
|
||||
# wd = inotify.add_watch(sys.argv[1], watch_flags)
|
||||
# process = psutil.Process()
|
||||
#
|
||||
# # inotify iterator runs out immediately
|
||||
# while True:
|
||||
# for event in inotify.read():
|
||||
# os.system('qutebrowser :config-source')
|
||||
#
|
||||
# # kill after qutebrowser exits
|
||||
# # not reached on SIGKILL
|
||||
# cleanup()
|
||||
@@ -0,0 +1,7 @@
|
||||
styles = {
|
||||
'qute.help.css': ['qute://help*', '*someotherdomain.xyz*'],
|
||||
'twitch.css': ['*twitch.tv*'],
|
||||
'dreamingspanish.css': ['*dreaming.com*'],
|
||||
'readthedocs.css': ['*readthedocs.io*'],
|
||||
'italki.css': ['*italki.com*']
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
.max-w-3xl {
|
||||
max-width: 65vw;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
.ds-page {
|
||||
max-width: 95%;
|
||||
}
|
||||
|
||||
.ds-form-calendar {
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.ds-form-calendar__row {
|
||||
height: 3.5rem;
|
||||
}
|
||||
|
||||
.ds-form-calendar__column {
|
||||
height: 100%;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.ds-form-calendar__column-wrapper {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.ds-form-calendar__column-time {
|
||||
font-size: 0.65rem;
|
||||
line-height: 1.4rem;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
.MessageList-main {
|
||||
padding-bottom: 250px !important;
|
||||
}
|
||||
|
||||
#app .min-h-10 {
|
||||
min-height: 200px !important;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
html {
|
||||
background-color: #041E39;
|
||||
}
|
||||
|
||||
html > body, html ul > li > * {
|
||||
color: #EBEBD3;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
html a {
|
||||
color: #F78764;
|
||||
}
|
||||
|
||||
html a:visited {
|
||||
color: #2D8CF0;
|
||||
}
|
||||
|
||||
.monospaced, code, pre {
|
||||
color: #F4D35E;
|
||||
}
|
||||
|
||||
div.admonitionblock {
|
||||
color: #FAB49E;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
html em, html dt {
|
||||
color: #FAB49E;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
html div.listingblock > div.content, div.listingblock .highlight {
|
||||
background-color: #611B05;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// ==UserScript==
|
||||
// @name Userstyle (qute.help.css)
|
||||
// @include qute://help*
|
||||
// ==/UserScript==
|
||||
GM_addStyle(`html {
|
||||
background-color: #041E39;
|
||||
}
|
||||
|
||||
html > body, html ul > li > * {
|
||||
color: #EBEBD3;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
html a {
|
||||
color: #F78764;
|
||||
}
|
||||
|
||||
html a:visited {
|
||||
color: #2D8CF0;
|
||||
}
|
||||
|
||||
.monospaced, code, pre {
|
||||
color: #F4D35E;
|
||||
}
|
||||
|
||||
div.admonitionblock {
|
||||
color: #FAB49E;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
html em, html dt {
|
||||
color: #FAB49E;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
html div.listingblock > div.content, div.listingblock .highlight {
|
||||
background-color: #611B05;
|
||||
}
|
||||
`)
|
||||
@@ -0,0 +1,3 @@
|
||||
.wy-nav-content {
|
||||
max-width: 1200px;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
body {
|
||||
width: 80% !important;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import importlib.machinery as im
|
||||
import importlib.util as iu
|
||||
|
||||
class RebuildGreaseStyles(object):
|
||||
def __init__(self):
|
||||
self.config_dir = self.get_config_dir()
|
||||
self.stylemap = self.import_stylemap(self.config_dir)
|
||||
|
||||
def get_config_dir(self):
|
||||
config_dir = os.getenv('QUTE_CONFIG_DIR')
|
||||
if config_dir: return config_dir
|
||||
|
||||
dir = os.getenv('XDG_CONFIG_HOME')
|
||||
if dir: return dir + '/qutebrowser'
|
||||
|
||||
dir = os.getenv('HOME', '~')
|
||||
return dir + '/.config/qutebrowser'
|
||||
|
||||
def import_stylemap(self, config_dir):
|
||||
loader = im.SourceFileLoader('stylemap', f"{config_dir}/stylemap.py")
|
||||
spec = iu.spec_from_loader( 'stylemap', loader )
|
||||
if spec:
|
||||
stylemap = iu.module_from_spec( spec )
|
||||
loader.exec_module( stylemap )
|
||||
return stylemap.styles
|
||||
|
||||
def create_grease_scripts_from_css_files(self):
|
||||
if not self.stylemap: return
|
||||
|
||||
for css_filename, patterns in self.stylemap.items():
|
||||
self.create_grease_script_from_css_file(css_filename, patterns)
|
||||
|
||||
def create_grease_script_from_css_file(self, css_filename, patterns):
|
||||
with open(f'{self.config_dir}/styles/{css_filename}') as css_file:
|
||||
css = css_file.read()
|
||||
|
||||
grease = self.css_to_grease(css_filename, css, patterns)
|
||||
|
||||
grease_script_path = f'{self.config_dir}/greasemonkey/{css_filename}.js'
|
||||
with open(grease_script_path, 'w') as grease_file:
|
||||
grease_file.write(grease)
|
||||
|
||||
def css_to_grease(self, css_filename, css, patterns):
|
||||
includes = '\n'.join([f'// @include {p}' for p in patterns])
|
||||
|
||||
return (
|
||||
'// ==UserScript==\n'
|
||||
+ f'// @name Userstyle ({css_filename})\n'
|
||||
+ includes + '\n'
|
||||
+ '// ==/UserScript==\n'
|
||||
+ f'GM_addStyle(`{css}`)'
|
||||
)
|
||||
|
||||
def reload():
|
||||
fifo = os.getenv('QUTE_FIFO')
|
||||
|
||||
if not fifo: return
|
||||
|
||||
with open(fifo, 'w') as feefifofam:
|
||||
feefifofam.write('greasemonkey-reload -q\n')
|
||||
feefifofam.write('reload\n')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
RebuildGreaseStyles().create_grease_scripts_from_css_files()
|
||||
reload()
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Log the full length of the current page's video to Traggo as one finished span."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from datetime import datetime, timedelta
|
||||
from html import unescape
|
||||
|
||||
API = "https://time.rcjohnstone.com/graphql"
|
||||
TOKEN_PATH = os.path.expanduser("~/.config/traggo/token")
|
||||
TAGS = [
|
||||
{"key": "language", "value": "spanish"},
|
||||
{"key": "mode", "value": "listening"},
|
||||
]
|
||||
YTDLP_TIMEOUT = 45
|
||||
HTTP_TIMEOUT = 20
|
||||
UA = ("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/124.0.0.0 Safari/537.36")
|
||||
|
||||
FIFO = os.environ.get("QUTE_FIFO")
|
||||
|
||||
|
||||
class ProbeError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def report(kind, text):
|
||||
text = " ".join(text.split())
|
||||
line = "message-{} {}\n".format(kind, shlex.quote(text))
|
||||
if FIFO:
|
||||
with open(FIFO, "a") as fh:
|
||||
fh.write(line)
|
||||
else:
|
||||
sys.stderr.write(line)
|
||||
|
||||
|
||||
def die(text):
|
||||
report("error", "traggo: " + text)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def human(secs):
|
||||
hours, rem = divmod(secs, 3600)
|
||||
mins, s = divmod(rem, 60)
|
||||
if hours:
|
||||
return "{}h{:02d}m".format(hours, mins)
|
||||
if mins:
|
||||
return "{}m".format(mins)
|
||||
return "{}s".format(s)
|
||||
|
||||
|
||||
def ytdlp_argv():
|
||||
local = shutil.which("yt-dlp")
|
||||
if local:
|
||||
return [local]
|
||||
# qutebrowser runs inside distrobox, so reach the host's copy if the container lacks one.
|
||||
host = shutil.which("distrobox-host-exec")
|
||||
if host:
|
||||
return [host, "yt-dlp"]
|
||||
raise ProbeError("yt-dlp not found")
|
||||
|
||||
|
||||
def probe_ytdlp(url):
|
||||
argv = ytdlp_argv() + [
|
||||
"--skip-download", "--no-warnings",
|
||||
# We only ever want metadata, so a stale extractor failing on formats must not abort.
|
||||
"--ignore-no-formats-error",
|
||||
"--print", "%(duration)s|%(title)s", url,
|
||||
]
|
||||
try:
|
||||
proc = subprocess.run(argv, capture_output=True, text=True,
|
||||
timeout=YTDLP_TIMEOUT)
|
||||
except subprocess.TimeoutExpired:
|
||||
raise ProbeError("yt-dlp timed out after {}s".format(YTDLP_TIMEOUT))
|
||||
except OSError as exc:
|
||||
raise ProbeError("yt-dlp failed to start: {}".format(exc))
|
||||
|
||||
line = next((ln for ln in reversed(proc.stdout.splitlines()) if "|" in ln), "")
|
||||
if not line:
|
||||
detail = " ".join(proc.stderr.split())[:160] or "no output"
|
||||
raise ProbeError("yt-dlp: " + detail)
|
||||
|
||||
raw, _, title = line.partition("|")
|
||||
raw = raw.strip()
|
||||
if not raw.isdigit() or int(raw) <= 0:
|
||||
raise ProbeError("yt-dlp gave no duration (got {!r})".format(raw))
|
||||
return int(raw), title.strip()
|
||||
|
||||
|
||||
def probe_html(url):
|
||||
req = urllib.request.Request(url, headers={
|
||||
"User-Agent": UA, "Accept-Language": "en-US,en;q=0.9"})
|
||||
try:
|
||||
page = urllib.request.urlopen(req, timeout=HTTP_TIMEOUT).read().decode(
|
||||
"utf-8", "replace")
|
||||
except Exception as exc:
|
||||
raise ProbeError("page fetch failed: {}".format(exc))
|
||||
|
||||
match = re.search(r'"lengthSeconds":"(\d+)"', page)
|
||||
if not match:
|
||||
raise ProbeError("no lengthSeconds in page")
|
||||
secs = int(match.group(1))
|
||||
if secs <= 0:
|
||||
raise ProbeError("page reported zero length")
|
||||
title = re.search(r'<meta name="title" content="([^"]*)"', page)
|
||||
return secs, unescape(title.group(1)) if title else ""
|
||||
|
||||
|
||||
def qute_title():
|
||||
return re.sub(r"\s+-\s+YouTube$", "", os.environ.get("QUTE_TITLE", "")).strip()
|
||||
|
||||
|
||||
def create_span(token, start, end, note):
|
||||
query = ("mutation($s:Time!,$e:Time!,$t:[InputTimeSpanTag!],$n:String!){"
|
||||
"createTimeSpan(start:$s,end:$e,tags:$t,note:$n){id}}")
|
||||
body = json.dumps({"query": query, "variables": {
|
||||
"s": start, "e": end, "t": TAGS, "n": note}}).encode()
|
||||
req = urllib.request.Request(API, data=body, headers={
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "traggo " + token})
|
||||
try:
|
||||
raw = urllib.request.urlopen(req, timeout=HTTP_TIMEOUT).read().decode()
|
||||
except urllib.error.HTTPError as exc:
|
||||
die("server returned HTTP {}: {}".format(
|
||||
exc.code, exc.read().decode("utf-8", "replace")[:160]))
|
||||
except Exception as exc:
|
||||
die("cannot reach server: {}".format(exc))
|
||||
|
||||
data = json.loads(raw)
|
||||
if data.get("errors"):
|
||||
die("api: {}".format(data["errors"][0].get("message", "unknown error")))
|
||||
return data["data"]["createTimeSpan"]["id"]
|
||||
|
||||
|
||||
def main():
|
||||
url = os.environ.get("QUTE_URL", "").strip()
|
||||
if not url:
|
||||
die("no QUTE_URL in environment")
|
||||
|
||||
try:
|
||||
token = open(TOKEN_PATH).read().strip()
|
||||
except OSError as exc:
|
||||
die("cannot read token: {}".format(exc))
|
||||
if not token:
|
||||
die("token file {} is empty".format(TOKEN_PATH))
|
||||
|
||||
try:
|
||||
secs, title = probe_ytdlp(url)
|
||||
except ProbeError as primary:
|
||||
try:
|
||||
secs, title = probe_html(url)
|
||||
except ProbeError as fallback:
|
||||
die("no duration. {} / fallback: {}".format(primary, fallback))
|
||||
|
||||
note = title or qute_title() or url
|
||||
end = datetime.now().astimezone().replace(microsecond=0)
|
||||
start = end - timedelta(seconds=secs)
|
||||
span = create_span(token, start.isoformat(), end.isoformat(), note)
|
||||
report("info", "traggo: logged {} [{}] - {}".format(human(secs), span, note))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user