seems working

This commit is contained in:
Audrey 2025-10-17 15:43:11 -07:00
parent c1c092bea7
commit c4f7edac42
10 changed files with 288 additions and 39 deletions

View File

@ -27,6 +27,8 @@ in
};
# sway stuff
programs.ydotool.enable = true;
users.users.audrey.extraGroups = [ "ydotool" ];
programs.regreet.enable = true;
services.greetd.settings = {
default_session.command = "${pkgs.dbus}/bin/dbus-run-session ${lib.getExe config.programs.sway.package} -c /etc/sway/greeter-config";
@ -74,8 +76,8 @@ in
xwayland.enable = true;
extraPackages = with pkgs; [
swaylock
swayr
pavucontrol
pasystray
libnotify
wdisplays
playerctl
@ -88,7 +90,6 @@ in
adwaita-icon-theme
glib
kdePackages.kwallet
swaynotificationcenter
];
extraSessionCommands = ''
export ELECTRON_OZONE_PLATFORM_HINT=wayland
@ -165,6 +166,16 @@ in
partOf = [ "graphical-environment.target" ];
wantedBy = [ "graphical-environment.target" ];
};
systemd.user.services.pasystray = lib.mkIf config.programs.sway.enable {
description = "Pulseaudio system tray icon";
serviceConfig = {
Type = "simple";
ExecStart = "${lib.getExe pkgs.pasystray} --notify source --notify sink -m 100";
};
path = [ "/run/current-system/sw" ];
partOf = [ "graphical-environment.target" ];
wantedBy = [ "graphical-environment.target" ];
};
systemd.user.services.kdeconnect-indicator = lib.mkIf config.programs.sway.enable {
description = "KDE connect indicator";
serviceConfig = {
@ -175,6 +186,16 @@ in
partOf = [ "graphical-environment.target" ];
wantedBy = [ "graphical-environment.target" ];
};
systemd.user.services.swayr = lib.mkIf config.programs.sway.enable {
description = "Sway MRU window switcher";
serviceConfig = {
Type = "simple";
ExecStart = "${lib.getBin pkgs.swayr}/bin/swayrd";
};
path = [ "/run/current-system/sw" ];
partOf = [ "graphical-environment.target" ];
wantedBy = [ "graphical-environment.target" ];
};
virtualisation.docker = {
enable = true;
@ -200,6 +221,7 @@ in
];
};
};
environment.sessionVariables.TERMINAL = "foot";
environment.systemPackages = with pkgs; [
dino

View File

@ -13,7 +13,7 @@ in {
description = "kakoune packages to include in the global editor";
};
};
imports = [ ./overlays/packages.nix ./configuration-cross.nix ];
imports = [ ./overlays/packages.nix ./overlays/lix.nix ./configuration-cross.nix ];
config = {
nixpkgs.config.allowUnfree = true;
@ -23,7 +23,6 @@ in {
nix.settings.cores = 0;
nix.settings.secret-key-files = [ "/var/lib/nix/binary-cache-key" ];
nix.settings.trusted-public-keys = builtins.filter (f: f != "") <| lib.strings.splitString "\n" <| builtins.readFile ./keys/nix;
nix.package = pkgs.lixPackageSets.stable.lix;
# Select internationalisation properties.
i18n.defaultLocale = "en_US.UTF-8";
@ -45,9 +44,9 @@ in {
environment.systemPackages = with pkgs; [
man-pages
man-pages-posix
bat
gnumake
wget
moar
ripgrep
fd
curl
@ -55,11 +54,14 @@ in {
file
nettools
psmisc
units
units-desktop
patchelf
gdb
kubectl
p7zip
unzip
zip
foremost
binwalk
jq
@ -117,7 +119,7 @@ in {
pag = "ps aux | grep -v grep | grep -i";
hd = "hexdump -C";
hdc = "hexdump -ve '\"\\\x\" 1/1 \"%02x\"'";
man = "MAN_POSIXLY_CORRECT=1 man";
man = "batman";
nose = "pytest -v --capture=no --pdbcls=IPython.terminal.debugger:TerminalPdb";
mkvirtualenv = "mkvirtualenv -r /etc/venv-default.txt";
};
@ -140,8 +142,22 @@ in {
url."ssh://git@".insteadOf = "git://";
};
};
bat = {
enable = true;
extraPackages = with pkgs.bat-extras; [
batdiff
batman
prettybat
];
settings = {
italic-text = "always";
wrap = "never";
style = "plain";
};
};
};
environment.variables.PAGER = "moar";
environment.etc.zinputrc.text = lib.mkForce (builtins.readFile ./dotfiles/zsh-input.sh);
environment.etc."gdb/gdbinit".source = ./dotfiles/gdb-init.gdb;

View File

@ -97,7 +97,7 @@ function precmd-osc-title() {
print -Pn "\e]2;%n@%M | %~\a"
}
function preexec-osc-title() {
print -Pn "\e]2;%n@%M | $1\a"
print -Pn "\e]2;%n@%M | ${~1:gs/%/%%}\a"
}
autoload -Uz add-zsh-hook
@ -128,6 +128,8 @@ export PYTHONBREAKPOINT="ipdb.set_trace"
export COLORTERM=1
export SHELL=$(which zsh)
export npm_config_prefix=~/.local
export HISTSIZE=100000
export SAVEHIST=100000
# site vars, functions, and aliases
if [ -e ~/.site_aliases.sh ]; then

View File

@ -2,11 +2,11 @@
"nodes": {
"bingosync": {
"locked": {
"lastModified": 1751571764,
"narHash": "sha256-KEII5eCIBsBJy3eowAmmtRbdmV2aREOjU8AHypPz5y8=",
"lastModified": 1760739933,
"narHash": "sha256-yhgeHqfn0ZlXYkhZMqccTzWDvzre+DpcYzpk/7a7xec=",
"owner": "rhelmot",
"repo": "bingosync",
"rev": "08ab441fee60360435c263430610fc10406b0602",
"rev": "59f0555be4e7679750bc15396dc1b3e559325951",
"type": "github"
},
"original": {
@ -23,11 +23,11 @@
]
},
"locked": {
"lastModified": 1745193236,
"narHash": "sha256-1hG3it3DDdn+VXmKUgF/KCbO3VMteEZ8xuh20jXqFus=",
"lastModified": 1759863336,
"narHash": "sha256-H8NRd03xQVKVunTYsd95pMzZS5nfYTDUw6R78dJESrs=",
"ref": "refs/heads/main",
"rev": "5cb010a404c5a6c9fe2257aee2afe4aa3b288974",
"revCount": 8,
"rev": "bc6337d8f649f5afdc281b64fad2891bb2067a51",
"revCount": 11,
"type": "git",
"url": "https://git.lain.faith/rhelmot/blog.rhelmot.io"
},
@ -45,11 +45,11 @@
"utils": "utils"
},
"locked": {
"lastModified": 1745191548,
"narHash": "sha256-z8BhZIXNNNfGop+k/6+psSKp9BLz5eiuE16fDICdnyE=",
"lastModified": 1759863318,
"narHash": "sha256-6yXyEllmvAFgSg4KzFqJ3bx6K1+ZBsqOOdX08F29k08=",
"owner": "rhelmot",
"repo": "coricamu",
"rev": "225536eafef6d8de6bdad3bc756587ad3ebaecb7",
"rev": "f109bad2add146f3001805a8600b198473b3c9c2",
"type": "github"
},
"original": {

15
overlays/lix.nix Normal file
View File

@ -0,0 +1,15 @@
{
pkgs,
...
}:
{
nixpkgs.overlays = [ (final: prev: {
inherit (prev.lixPackageSets.latest)
nixpkgs-review
nix-eval-jobs
nix-fast-build
colmena;
}) ];
nix.package = pkgs.lixPackageSets.latest.lix;
}

View File

@ -12,6 +12,7 @@ let overlay = final: prev: {
});
idapro9 = pkgs.callPackage ../pkgs/idapro9.nix {};
condition-unmetered-network = pkgs.callPackage ../pkgs/condition-unmetered-network {};
units-desktop = pkgs.callPackage ../pkgs/units-desktop.nix {};
};
in {

18
pkgs/units-desktop.nix Normal file
View File

@ -0,0 +1,18 @@
{
lib,
writeTextFile,
units,
}:
writeTextFile {
name = "units-desktop";
destination = "/share/applications/units.desktop";
text = ''
[Desktop Entry]
Encoding=UTF-8
Version=${units.version}
Type=Application
Terminal=true
Exec=${lib.getExe units}
Name=Units
'';
}

View File

@ -48,6 +48,7 @@
#} );
environment.systemPackages = [
pkgs.racket
pkgs.idapro9
pkgs.qemu_kvm
(pkgs.runCommand "OVMF-fd" {} ''
@ -183,4 +184,19 @@
# enable = true;
# nginxHost = "noscope";
#};
boot.binfmt.emulatedSystems = [
"aarch64-linux"
"mips-linux"
"mipsel-linux"
"armv7l-linux"
];
boot.binfmt.preferStaticEmulators = true;
programs.steam.enable = true;
programs.steam.gamescopeSession.enable = true;
programs.gamescope.enable = true;
programs.gamescope.capSysNice = true;
services.pulseaudio.support32Bit = true;
hardware.graphics.enable32Bit = true;
}

View File

@ -93,10 +93,6 @@
};
};
services.keycloak = {
enable = true;
};
services.postgresql = {
enable = true;
ensureDatabases = [
@ -246,30 +242,20 @@
};
};
systemd.services.spamkick = let
src = pkgs.fetchFromGitHub {
owner = "maddie480";
repo = "SpamKick";
rev = "9dd5b5e3cc78e2520b13a0875ae7ef264a5a52c5";
hash = "sha256-ZjxnqIiXBaxrZwrCfDPVTpGmRxtrL5kc5ZcDUaQtbZo=";
};
env = pkgs.python3.withPackages (ps: with ps; [ discordpy ]);
in {
path = [ env ];
users.users.reminder-bot = {
isSystemUser = true;
group = "nogroup";
};
systemd.services.reminder-bot = {
path = [ (pkgs.python3.withPackages (p: with p; [ discordpy aiocron aiosqlite cronsim ])) ];
script = ''
export TOKEN="$(cat /var/lib/spamkick/token.txt)"
exec python ${src}/main.py
exec python ${./reminder_bot.py}
'';
serviceConfig = {
Type = "simple";
Restart = "always";
User = "reminder-bot";
};
wantedBy = [ "multi-user.target" ];
environment = {
LOG_CHANNEL_ID = "532689319350108160";
CHANNEL_COUNT = "4";
DELAY_SECONDS = "5";
DEBUG = "0";
};
};
}

View File

@ -0,0 +1,173 @@
from cronsim import CronSimError
import discord
from discord.ext import commands
import aiosqlite
import aiocron
from datetime import datetime, timedelta, timezone
import logging
log = logging.getLogger("reminder_bot")
DATABASE = '/var/lib/reminder-bot/db'
with open('/var/lib/reminder-bot/token') as fp:
TOKEN = fp.read().strip()
BOTSPAM_CHANNEL_ID = 1428820508178124820
intents = discord.Intents.default()
intents.message_content = True
client = commands.Bot('/', intents=intents)
tree = client.tree
# ------------------------------------------------------------
# DATABASE SETUP
# ------------------------------------------------------------
async def init_db():
async with aiosqlite.connect(DATABASE) as db:
await db.execute("""
CREATE TABLE IF NOT EXISTS reminders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message TEXT NOT NULL,
cron TEXT NOT NULL
)
""")
await db.commit()
# ------------------------------------------------------------
# DISMISS BUTTON
# ------------------------------------------------------------
class DismissButton(discord.ui.View):
def __init__(self, reminder_id: int):
super().__init__(timeout=None)
self.reminder_id = reminder_id
@discord.ui.button(label="Dismiss", style=discord.ButtonStyle.red)
async def dismiss(self, interaction: discord.Interaction, button: discord.ui.Button):
user = interaction.user.display_name
timestamp = datetime.now(tz=timezone(timedelta(hours=-7))).strftime("%a %b %-m %-I:%M %p")
assert interaction.message is not None
button.disabled = True
await interaction.response.edit_message(content=interaction.message.content + f"\nCompleted by {user} at {timestamp}", view=self)
# ------------------------------------------------------------
# GLOBAL JOB REGISTRY
# ------------------------------------------------------------
scheduled_jobs = {}
async def send_reminder(message: str, reminder_id: int):
channel = client.get_channel(BOTSPAM_CHANNEL_ID)
assert isinstance(channel, discord.TextChannel)
await channel.send(
f"⏰ **Reminder:** {message}",
view=DismissButton(reminder_id),
allowed_mentions=discord.AllowedMentions(everyone=True, users=True, roles=True)
)
async def schedule_reminder(reminder_id: int, message: str, cron_expr: str):
assert reminder_id not in scheduled_jobs
job = aiocron.crontab(cron_expr, func=send_reminder, args=(message, reminder_id))
scheduled_jobs[reminder_id] = job
# ------------------------------------------------------------
# COMMANDS
# ------------------------------------------------------------
@tree.command(name="reminder-add")
async def add_reminder(ctx: discord.Interaction, cron_expr: str, *, message: str):
"""
Add a new reminder using a cron expression.
"""
try:
aiocron.CronSim(cron_expr, datetime.now())
except CronSimError as e:
await ctx.response.send_message(f"Your cron expression did not parse: {e}", ephemeral=True)
else:
async with aiosqlite.connect(DATABASE) as db:
cursor = await db.execute(
"INSERT INTO reminders (message, cron) VALUES (?, ?)",
(message, cron_expr)
)
await db.commit()
reminder_id = cursor.lastrowid
assert reminder_id is not None
await schedule_reminder(reminder_id, message, cron_expr)
await ctx.response.send_message(f"✅ Reminder {reminder_id} added: '{message}' `{cron_expr}`")
@tree.command(name="reminder-list")
async def list_reminders(ctx: discord.Interaction):
"""List all active reminders."""
async with aiosqlite.connect(DATABASE) as db:
async with db.execute("SELECT id, message, cron FROM reminders") as cursor:
rows = await cursor.fetchall()
if not rows:
await ctx.response.send_message("No active reminders.", ephemeral=True)
return
lines = [f"**{r[0]}**: {r[1]} `{r[2]}`" for r in rows]
await ctx.response.send_message("\n".join(lines), ephemeral=True)
@tree.command(name="reminder-delete")
async def delete_reminder(ctx: discord.Interaction, reminder_id: int):
"""Delete a reminder by ID."""
async with aiosqlite.connect(DATABASE) as db:
async with db.execute("SELECT message FROM reminders WHERE id = ?", (reminder_id,)) as cursor:
rows = list(await cursor.fetchall())
if not rows:
await ctx.response.send_message(f"No such reminder {reminder_id}")
return
await db.execute("DELETE FROM reminders WHERE id = ?", (reminder_id,))
await db.commit()
job = scheduled_jobs.pop(reminder_id, None)
if job:
job.stop()
await ctx.response.send_message(f"🗑️ Reminder {reminder_id} ({rows[0][0]}) deleted.")
@tree.command(name="reminder-edit")
async def edit_reminder(ctx: discord.Interaction, reminder_id: int, message: str, cron_expr: str):
try:
aiocron.CronSim(cron_expr, datetime.now())
except CronSimError as e:
await ctx.response.send_message(f"Your cron expression did not parse: {e}", ephemeral=True)
else:
async with aiosqlite.connect(DATABASE) as db:
async with db.execute("SELECT message FROM reminders WHERE id = ?", (reminder_id,)) as cursor:
rows = list(await cursor.fetchall())
if not rows:
await ctx.response.send_message(f"No such reminder {reminder_id}")
return
await db.execute("UPDATE reminders SET message = ?, cron = ? WHERE id = ?", (message, cron_expr, reminder_id))
await db.commit()
job = scheduled_jobs.pop(reminder_id, None)
if job:
job.stop()
await schedule_reminder(reminder_id, message, cron_expr)
await ctx.response.send_message(f"✅ Reminder {reminder_id} updated: {message} `{cron_expr}`")
# ------------------------------------------------------------
# STARTUP
# ------------------------------------------------------------
@client.event
async def on_ready():
await init_db()
# Load all reminders from DB and schedule them
async with aiosqlite.connect(DATABASE) as db:
async with db.execute("SELECT id, message, cron FROM reminders") as cursor:
async for reminder_id, message, cron_expr in cursor:
await schedule_reminder(reminder_id, message, cron_expr)
log.info(f"Loaded {len(scheduled_jobs)} scheduled reminders.")
await tree.sync()
# ------------------------------------------------------------
# RUN
# ------------------------------------------------------------
client.run(TOKEN)