seems working
This commit is contained in:
parent
c1c092bea7
commit
c4f7edac42
|
@ -27,6 +27,8 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
# sway stuff
|
# sway stuff
|
||||||
|
programs.ydotool.enable = true;
|
||||||
|
users.users.audrey.extraGroups = [ "ydotool" ];
|
||||||
programs.regreet.enable = true;
|
programs.regreet.enable = true;
|
||||||
services.greetd.settings = {
|
services.greetd.settings = {
|
||||||
default_session.command = "${pkgs.dbus}/bin/dbus-run-session ${lib.getExe config.programs.sway.package} -c /etc/sway/greeter-config";
|
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;
|
xwayland.enable = true;
|
||||||
extraPackages = with pkgs; [
|
extraPackages = with pkgs; [
|
||||||
swaylock
|
swaylock
|
||||||
|
swayr
|
||||||
pavucontrol
|
pavucontrol
|
||||||
pasystray
|
|
||||||
libnotify
|
libnotify
|
||||||
wdisplays
|
wdisplays
|
||||||
playerctl
|
playerctl
|
||||||
|
@ -88,7 +90,6 @@ in
|
||||||
adwaita-icon-theme
|
adwaita-icon-theme
|
||||||
glib
|
glib
|
||||||
kdePackages.kwallet
|
kdePackages.kwallet
|
||||||
swaynotificationcenter
|
|
||||||
];
|
];
|
||||||
extraSessionCommands = ''
|
extraSessionCommands = ''
|
||||||
export ELECTRON_OZONE_PLATFORM_HINT=wayland
|
export ELECTRON_OZONE_PLATFORM_HINT=wayland
|
||||||
|
@ -165,6 +166,16 @@ in
|
||||||
partOf = [ "graphical-environment.target" ];
|
partOf = [ "graphical-environment.target" ];
|
||||||
wantedBy = [ "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 {
|
systemd.user.services.kdeconnect-indicator = lib.mkIf config.programs.sway.enable {
|
||||||
description = "KDE connect indicator";
|
description = "KDE connect indicator";
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
@ -175,6 +186,16 @@ in
|
||||||
partOf = [ "graphical-environment.target" ];
|
partOf = [ "graphical-environment.target" ];
|
||||||
wantedBy = [ "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 = {
|
virtualisation.docker = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -200,6 +221,7 @@ in
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
environment.sessionVariables.TERMINAL = "foot";
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
dino
|
dino
|
||||||
|
|
|
@ -13,7 +13,7 @@ in {
|
||||||
description = "kakoune packages to include in the global editor";
|
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 = {
|
config = {
|
||||||
nixpkgs.config.allowUnfree = true;
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ in {
|
||||||
nix.settings.cores = 0;
|
nix.settings.cores = 0;
|
||||||
nix.settings.secret-key-files = [ "/var/lib/nix/binary-cache-key" ];
|
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.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.
|
# Select internationalisation properties.
|
||||||
i18n.defaultLocale = "en_US.UTF-8";
|
i18n.defaultLocale = "en_US.UTF-8";
|
||||||
|
@ -45,9 +44,9 @@ in {
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
man-pages
|
man-pages
|
||||||
man-pages-posix
|
man-pages-posix
|
||||||
bat
|
|
||||||
gnumake
|
gnumake
|
||||||
wget
|
wget
|
||||||
|
moar
|
||||||
ripgrep
|
ripgrep
|
||||||
fd
|
fd
|
||||||
curl
|
curl
|
||||||
|
@ -55,11 +54,14 @@ in {
|
||||||
file
|
file
|
||||||
nettools
|
nettools
|
||||||
psmisc
|
psmisc
|
||||||
|
units
|
||||||
|
units-desktop
|
||||||
patchelf
|
patchelf
|
||||||
gdb
|
gdb
|
||||||
kubectl
|
kubectl
|
||||||
p7zip
|
p7zip
|
||||||
unzip
|
unzip
|
||||||
|
zip
|
||||||
foremost
|
foremost
|
||||||
binwalk
|
binwalk
|
||||||
jq
|
jq
|
||||||
|
@ -117,7 +119,7 @@ in {
|
||||||
pag = "ps aux | grep -v grep | grep -i";
|
pag = "ps aux | grep -v grep | grep -i";
|
||||||
hd = "hexdump -C";
|
hd = "hexdump -C";
|
||||||
hdc = "hexdump -ve '\"\\\x\" 1/1 \"%02x\"'";
|
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";
|
nose = "pytest -v --capture=no --pdbcls=IPython.terminal.debugger:TerminalPdb";
|
||||||
mkvirtualenv = "mkvirtualenv -r /etc/venv-default.txt";
|
mkvirtualenv = "mkvirtualenv -r /etc/venv-default.txt";
|
||||||
};
|
};
|
||||||
|
@ -140,8 +142,22 @@ in {
|
||||||
url."ssh://git@".insteadOf = "git://";
|
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.zinputrc.text = lib.mkForce (builtins.readFile ./dotfiles/zsh-input.sh);
|
||||||
|
|
||||||
environment.etc."gdb/gdbinit".source = ./dotfiles/gdb-init.gdb;
|
environment.etc."gdb/gdbinit".source = ./dotfiles/gdb-init.gdb;
|
||||||
|
|
|
@ -97,7 +97,7 @@ function precmd-osc-title() {
|
||||||
print -Pn "\e]2;%n@%M | %~\a"
|
print -Pn "\e]2;%n@%M | %~\a"
|
||||||
}
|
}
|
||||||
function preexec-osc-title() {
|
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
|
autoload -Uz add-zsh-hook
|
||||||
|
@ -128,6 +128,8 @@ export PYTHONBREAKPOINT="ipdb.set_trace"
|
||||||
export COLORTERM=1
|
export COLORTERM=1
|
||||||
export SHELL=$(which zsh)
|
export SHELL=$(which zsh)
|
||||||
export npm_config_prefix=~/.local
|
export npm_config_prefix=~/.local
|
||||||
|
export HISTSIZE=100000
|
||||||
|
export SAVEHIST=100000
|
||||||
|
|
||||||
# site vars, functions, and aliases
|
# site vars, functions, and aliases
|
||||||
if [ -e ~/.site_aliases.sh ]; then
|
if [ -e ~/.site_aliases.sh ]; then
|
||||||
|
|
20
flake.lock
20
flake.lock
|
@ -2,11 +2,11 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"bingosync": {
|
"bingosync": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1751571764,
|
"lastModified": 1760739933,
|
||||||
"narHash": "sha256-KEII5eCIBsBJy3eowAmmtRbdmV2aREOjU8AHypPz5y8=",
|
"narHash": "sha256-yhgeHqfn0ZlXYkhZMqccTzWDvzre+DpcYzpk/7a7xec=",
|
||||||
"owner": "rhelmot",
|
"owner": "rhelmot",
|
||||||
"repo": "bingosync",
|
"repo": "bingosync",
|
||||||
"rev": "08ab441fee60360435c263430610fc10406b0602",
|
"rev": "59f0555be4e7679750bc15396dc1b3e559325951",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -23,11 +23,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1745193236,
|
"lastModified": 1759863336,
|
||||||
"narHash": "sha256-1hG3it3DDdn+VXmKUgF/KCbO3VMteEZ8xuh20jXqFus=",
|
"narHash": "sha256-H8NRd03xQVKVunTYsd95pMzZS5nfYTDUw6R78dJESrs=",
|
||||||
"ref": "refs/heads/main",
|
"ref": "refs/heads/main",
|
||||||
"rev": "5cb010a404c5a6c9fe2257aee2afe4aa3b288974",
|
"rev": "bc6337d8f649f5afdc281b64fad2891bb2067a51",
|
||||||
"revCount": 8,
|
"revCount": 11,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.lain.faith/rhelmot/blog.rhelmot.io"
|
"url": "https://git.lain.faith/rhelmot/blog.rhelmot.io"
|
||||||
},
|
},
|
||||||
|
@ -45,11 +45,11 @@
|
||||||
"utils": "utils"
|
"utils": "utils"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1745191548,
|
"lastModified": 1759863318,
|
||||||
"narHash": "sha256-z8BhZIXNNNfGop+k/6+psSKp9BLz5eiuE16fDICdnyE=",
|
"narHash": "sha256-6yXyEllmvAFgSg4KzFqJ3bx6K1+ZBsqOOdX08F29k08=",
|
||||||
"owner": "rhelmot",
|
"owner": "rhelmot",
|
||||||
"repo": "coricamu",
|
"repo": "coricamu",
|
||||||
"rev": "225536eafef6d8de6bdad3bc756587ad3ebaecb7",
|
"rev": "f109bad2add146f3001805a8600b198473b3c9c2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ let overlay = final: prev: {
|
||||||
});
|
});
|
||||||
idapro9 = pkgs.callPackage ../pkgs/idapro9.nix {};
|
idapro9 = pkgs.callPackage ../pkgs/idapro9.nix {};
|
||||||
condition-unmetered-network = pkgs.callPackage ../pkgs/condition-unmetered-network {};
|
condition-unmetered-network = pkgs.callPackage ../pkgs/condition-unmetered-network {};
|
||||||
|
units-desktop = pkgs.callPackage ../pkgs/units-desktop.nix {};
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
|
@ -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
|
||||||
|
'';
|
||||||
|
}
|
|
@ -48,6 +48,7 @@
|
||||||
#} );
|
#} );
|
||||||
|
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
|
pkgs.racket
|
||||||
pkgs.idapro9
|
pkgs.idapro9
|
||||||
pkgs.qemu_kvm
|
pkgs.qemu_kvm
|
||||||
(pkgs.runCommand "OVMF-fd" {} ''
|
(pkgs.runCommand "OVMF-fd" {} ''
|
||||||
|
@ -183,4 +184,19 @@
|
||||||
# enable = true;
|
# enable = true;
|
||||||
# nginxHost = "noscope";
|
# 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,10 +93,6 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.keycloak = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
services.postgresql = {
|
services.postgresql = {
|
||||||
enable = true;
|
enable = true;
|
||||||
ensureDatabases = [
|
ensureDatabases = [
|
||||||
|
@ -246,30 +242,20 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.spamkick = let
|
users.users.reminder-bot = {
|
||||||
src = pkgs.fetchFromGitHub {
|
isSystemUser = true;
|
||||||
owner = "maddie480";
|
group = "nogroup";
|
||||||
repo = "SpamKick";
|
};
|
||||||
rev = "9dd5b5e3cc78e2520b13a0875ae7ef264a5a52c5";
|
systemd.services.reminder-bot = {
|
||||||
hash = "sha256-ZjxnqIiXBaxrZwrCfDPVTpGmRxtrL5kc5ZcDUaQtbZo=";
|
path = [ (pkgs.python3.withPackages (p: with p; [ discordpy aiocron aiosqlite cronsim ])) ];
|
||||||
};
|
|
||||||
env = pkgs.python3.withPackages (ps: with ps; [ discordpy ]);
|
|
||||||
in {
|
|
||||||
path = [ env ];
|
|
||||||
script = ''
|
script = ''
|
||||||
export TOKEN="$(cat /var/lib/spamkick/token.txt)"
|
exec python ${./reminder_bot.py}
|
||||||
exec python ${src}/main.py
|
|
||||||
'';
|
'';
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
|
User = "reminder-bot";
|
||||||
};
|
};
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
environment = {
|
|
||||||
LOG_CHANNEL_ID = "532689319350108160";
|
|
||||||
CHANNEL_COUNT = "4";
|
|
||||||
DELAY_SECONDS = "5";
|
|
||||||
DEBUG = "0";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue