summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nix/whisper/flake.lock27
-rw-r--r--nix/whisper/flake.nix20
-rw-r--r--src/gizmo/wasp-biblicality.el70
-rw-r--r--src/gizmo/wasp-dna.el232
-rw-r--r--src/gizmo/wasp-fake-chatters.el28
-rw-r--r--src/gizmo/wasp-flycheck.el17
-rw-r--r--src/gizmo/wasp-friend.el21
-rw-r--r--src/gizmo/wasp-glossary.el165
-rw-r--r--src/gizmo/wasp-hex.el53
-rw-r--r--src/gizmo/wasp-newspaper.el26
-rw-r--r--src/gizmo/wasp-pronunciation.el2
-rw-r--r--src/gizmo/wasp-telemetry.el59
-rw-r--r--src/gizmo/wasp-wikipedia.el5
-rw-r--r--src/wasp-ai.el99
-rw-r--r--src/wasp-audio.el153
-rw-r--r--src/wasp-auth.el37
-rw-r--r--src/wasp-chat.el11
-rw-r--r--src/wasp-event-handlers.el15
-rw-r--r--src/wasp-model.el3
-rw-r--r--src/wasp-setup.el75
-rw-r--r--src/wasp-twitch-chat-commands.el9
-rw-r--r--src/wasp-twitch-redeems.el45
-rw-r--r--src/wasp-twitch.el91
-rw-r--r--src/wasp-user-whitelist.el17
-rw-r--r--src/wasp-user.el10
-rw-r--r--src/wasp-utils.el6
-rw-r--r--src/wasp-voice-commands.el4
-rw-r--r--wasp.el20
28 files changed, 1103 insertions, 217 deletions
diff --git a/nix/whisper/flake.lock b/nix/whisper/flake.lock
new file mode 100644
index 00000000..f4e9c15b
--- /dev/null
+++ b/nix/whisper/flake.lock
@@ -0,0 +1,27 @@
+{
+ "nodes": {
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1727802920,
+ "narHash": "sha256-HP89HZOT0ReIbI7IJZJQoJgxvB2Tn28V6XS3MNKnfLs=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "27e30d177e57d912d614c88c622dcfdb2e6e6515",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "nixpkgs": "nixpkgs"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/nix/whisper/flake.nix b/nix/whisper/flake.nix
new file mode 100644
index 00000000..8e3e328f
--- /dev/null
+++ b/nix/whisper/flake.nix
@@ -0,0 +1,20 @@
+{
+ inputs = {
+ nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
+ };
+ outputs = { self, nixpkgs }:
+ let
+ pkgs = import nixpkgs {
+ system = "x86_64-linux";
+ overlays = [];
+ };
+ shell = pkgs.mkShell {
+ NIX_HARDENING_ENABLE = "";
+ buildInputs = [
+ pkgs.SDL2
+ ];
+ };
+ in {
+ devShells.x86_64-linux.default = shell;
+ };
+}
diff --git a/src/gizmo/wasp-biblicality.el b/src/gizmo/wasp-biblicality.el
index 9b178bbc..b7c46ed8 100644
--- a/src/gizmo/wasp-biblicality.el
+++ b/src/gizmo/wasp-biblicality.el
@@ -11,16 +11,24 @@
(defvar w/bible-table nil
"Hash table mapping (lowercased) words in the Bible to occurences.")
+(defun w/bible-canonize (user)
+ "Add USER to the bible 1000 times."
+ (w/append-file
+ (s-concat "\n" (s-repeat 1000 (s-concat user " ")))
+ (w/asset "bible.txt"))
+ (ht-set! w/bible-table user 1000))
+
(defun w/populate-bible-table ()
"Populate `w/bible-table' from the Bible text file."
- (let* ((bible-string (s-downcase (w/slurp (w/asset "bible.txt"))))
- (bible-string-nosyms (replace-regexp-in-string "[^[:alpha:]]" " " bible-string))
- (bible-words (s-split-words bible-string-nosyms))
- (ret (ht-create)))
- (--each bible-words
- (let ((old (ht-get ret it)))
- (ht-set! ret it (+ 1 (or old 0)))))
- (setf w/bible-table ret)))
+ (unless w/bible-table
+ (let* ((bible-string (s-downcase (w/slurp (w/asset "bible.txt"))))
+ (bible-string-nosyms (replace-regexp-in-string "[^[:alpha:]]" " " bible-string))
+ (bible-words (s-split-words bible-string-nosyms))
+ (ret (ht-create)))
+ (--each bible-words
+ (let ((old (ht-get ret it)))
+ (ht-set! ret it (+ 1 (or old 0)))))
+ (setf w/bible-table ret))))
(defun w/bible-word-score (word)
"Return a number between 0.0 and 1.0 representing how biblical WORD is."
@@ -42,28 +50,30 @@
(defun w/bible-colorize-sentence (sen)
"Propertize SEN with colors representing word biblicality."
- (let ((ret-score-total 0.0)
- (ret-score-count 0))
- (save-excursion
- (with-temp-buffer
- (insert sen)
- (goto-char (point-min))
- (while (not (eobp))
- (let ((at-word (bounds-of-thing-at-point 'word)))
- (when at-word
- (let* ((word (buffer-substring (car at-word) (cdr at-word)))
- (score (w/bible-word-score word))
- (color (w/bible-word-color word)))
- (setq ret-score-total (+ ret-score-total score))
- (cl-incf ret-score-count)
- (add-text-properties
- (car at-word) (cdr at-word)
- `(face (:foreground ,color))
- )
- (goto-char (cdr at-word))))
- (when (not (eobp))
- (forward-char 1))))
- (cons (buffer-string) (/ ret-score-total ret-score-count))))))
+ (if w/bible-table
+ (let ((ret-score-total 0.0)
+ (ret-score-count 0))
+ (save-excursion
+ (with-temp-buffer
+ (insert sen)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (let ((at-word (bounds-of-thing-at-point 'word)))
+ (when at-word
+ (let* ((word (buffer-substring (car at-word) (cdr at-word)))
+ (score (w/bible-word-score word))
+ (color (w/bible-word-color word)))
+ (setq ret-score-total (+ ret-score-total score))
+ (cl-incf ret-score-count)
+ (add-text-properties
+ (car at-word) (cdr at-word)
+ `(face (:foreground ,color))
+ )
+ (goto-char (cdr at-word))))
+ (when (not (eobp))
+ (forward-char 1))))
+ (cons (buffer-string) (/ ret-score-total ret-score-count)))))
+ (cons sen 0.0)))
(provide 'wasp-biblicality)
;;; wasp-biblicality.el ends here
diff --git a/src/gizmo/wasp-dna.el b/src/gizmo/wasp-dna.el
index 445443f2..e83add09 100644
--- a/src/gizmo/wasp-dna.el
+++ b/src/gizmo/wasp-dna.el
@@ -22,8 +22,11 @@
(defun w/dna-generate-from-logs (user)
"Generate DNA from historical logs for USER.
You probably want to use this interactively and then save the result here."
- (let* ((logstr (w/slurp "~/logs/log-2024-07-23.txt"))
- (log (--map (cons (cadr it) (caddr it)) (--map (s-split "\t" it) (s-lines logstr)))))
+ (let* (;; (logstr (w/slurp "~/logs/log-2024-09-24.txt"))
+ ;; (log (--map (w/list-to-pair (s-split ": " it)) (-non-nil (--map (cadr (s-split "\t" it)) (s-lines logstr)))))
+ (logstr (w/slurp "~/logs/lcolonq-2024Q1.log"))
+ (log (--map (cons (cadr it) (caddr it)) (--map (s-split "\t" it) (s-lines logstr))))
+ )
(-non-nil
(--map-indexed
(when (s-equals? (car it) (s-downcase user))
@@ -1305,6 +1308,231 @@ You probably want to use this interactively and then save the result here."
(("BoganBits" . "I want a Real Life wiki") "vesdev" .
"warframe mentioned")))
+(defconst w/dna-kierem__
+ '((("Tyumici" .
+ "Tune in next time for more high-yield entertainment!")
+ "kierem__" . "Joel")
+ (("Tyumici" . "lcolonHi") "kierem__" . "o/")
+ (("eudemoniac" . "Joel") "kierem__" . "Joel")
+ (("[VOICE]" .
+ "6. Hello, hello, uh, who, who else? Who else is on here? Who, who'd they put on this machine? This infernal de-")
+ "kierem__" . "lcolonSpin lcolonSpin lcolonSpin")
+ (("yiffweed" . "Waiting room for Path of Exile") "kierem__" . "plink")
+ (("Zullfix_" . "Listening") "kierem__" . "...")
+ (("[VOICE]" .
+ "fun. Right? We're trying to identify some fun. I have some ideas. I think probably we're going to fucking write some emacs lists and do some other things besides...")
+ "kierem__" . "Joeling")
+ (("[VOICE]" .
+ "You got the wood out? Yeah, just make an MMORPG tonight. You're literally streaming video with a video camera. All that's needed now is game and we have video game. Yeah. ")
+ "kierem__" . "Joel")
+ (("[VOICE]" .
+ "This is how, so IKR13, it's sort of like this, hello abc123, thank you for 75 also. So I'm not using the keyboard lg because we spore")
+ "kierem__" . "Joel")
+ (("LCOLONQ" .
+ "#cyberspace on IRC at colonq.computer:26697 (over TLS)")
+ "kierem__" . "jol")
+ (("[VOICE]" .
+ "and we just write like a native Raylib game. Like it doesn't actually display, it runs Emacs in bash mode, just like displays it headless and like creates another X window.")
+ "kierem__" . "Joel")
+ (("stoicmana" . "the yapping hour") "kierem__" . "GoldenJoel")
+ (("boga_14" . "MODCLONK") "kierem__" . "friend is dead lcolonSadge")
+ (("archible" . "LETSGO") "kierem__" . "o/")
+ (("krzysckh" . "can you please show you r id please oh please")
+ "kierem__" . "lcolonHi")
+ (("resxnance_live" . "I was here but it is hilarious xd") "kierem__"
+ . "Joelest")
+ (("ellg" . "lmao") "kierem__" . "this is so cool omg lcolonShine")
+ (("Tyumici" . "RUINED") "kierem__" . "oh no")
+ (("wyndupboy" . "(but not as bad as you think)") "kierem__" . "2")
+ (("LCOLONQ" . "Joel") "kierem__" . "Joel")
+ (("a_tension_span" .
+ "The breaking of the hand cam needs to be recorded as lore event in the glossary btw, @prodzpod")
+ "kierem__" . "Joel")
+ (("[VOICE]" .
+ "Oh my god. Oh my god. The quality is excellent voice. Thank you. Um, the the curse of raw raw all things")
+ "kierem__" . "Joeler")
+ (("resxnance_live" . "literally feels like ad yo hahha") "kierem__" .
+ "...")
+ (("Venorrak" . "hi jake lcolonHi") "kierem__" . "lcolonQ")
+ (("KotaruComplex" . "could you mr. beastify a chat message?")
+ "kierem__" . "floor")
+ (("aliant2" . "actually froze") "kierem__" . "...")
+ (("[VOICE]" . "wait literally leaving the room") "kierem__" . "Joel")
+ (("gtfrvz" . "need EMERGENCY MITTENS?") "kierem__" . "o/")
+ (("[VOICE]" .
+ "It wasn't like, you know, Soldiers normally can take weeks and weeks and weeks. You're playing Hearts of Iron 4 right now, the game has a themed wiki browser in it. Yeah, I know-")
+ "kierem__" . "Joel")))
+
+(defconst w/dna-octorinski
+ '((("Tomaterr" . "@MODCLONK based") "octorinski" .
+ "Hello computer and all Joel")
+ (("mickynoon" . "Joel") "octorinski" . "I just came in :)")
+ (("loweffortzzz" . "based hair") "octorinski" . "lcolonHi")
+ (("XorXavier" . "live chatters") "octorinski" . "lcolonSoTrue")
+ (("steeledshield" . "pacamn?") "octorinski" . "plink")
+ (("[VOICE]" .
+ "that has a cool little custom display slash controller thing it's kind of it's kind of interesting interlaced oh yes")
+ "octorinski" .
+ "Looks cool from what I can see https://static.arcade-game-sales.com/images/products/large/17952_2.jpg")
+ (("wyndupboy" . "that looks like something from General Atomics.")
+ "octorinski" . "ProxMox is a KVM hypervisor")
+ (("[FRIEND]" .
+ "ooh a yellow dot, what's the universe up to? probably just stretching its legs!")
+ "octorinski" . "It uses libvirt under the hood")
+ (("[VOICE]" .
+ "I see I'm concerned about all of this the how is the audio by the way is the audio tolerable are we")
+ "octorinski" . "Very tolerable")
+ (("Polars_Bear" . "who is talking in the background?") "octorinski" .
+ "(we (like (LISP)))")
+ (("[VOICE]" .
+ "In VTuber circles, they might call this an off-collab. I think that's today.")
+ "octorinski" . "bpm_counter++")
+ (("[VOICE]" .
+ "like the collection of papers submitted to a conference the the previous the previous fuck fuck")
+ "octorinski" . "submissions?")
+ (("Tomaterr" . "the backlog") "octorinski" . "Itinerary?")
+ (("[VOICE]" .
+ "is a this is it's it's quite it's quite scary yeah just throw coins directly at the back")
+ "octorinski" . "ACTION Octorinski was permanently banned")
+ (("eudemoniac" . "good bit") "octorinski" .
+ "@dehidehiNotFromFinland BROTHER NOOO")
+ (("[VOICE]" .
+ "I'm still the verdict is still out on that topic. I would say the You know all sorts of all sorts of ghosts")
+ "octorinski" . "deja vu is crazy though")
+ (("[VOICE]" . "Oh, I see I see") "octorinski" . "EntireShrekMovie")
+ (("dehidehiNotFromFinland" .
+ "IP leaked, hotel network nuked. Thanks obama")
+ "octorinski" . "1 tenth of a second CarlSmile")
+ (("[VOICE]" .
+ "Which is kind of tricky over. I don't know if you actually do that the Maybe you can")
+ "octorinski" . "hi")
+ (("[VOICE]" .
+ "IRC is a new line delimited protocol, right? So I don't know if you can actually send a new line within an IRC message, but I think there are.")
+ "octorinski" . "Didn't work :(")
+ (("[VOICE]" .
+ "I'm still, I'm still lacking, I'm still lacking visibility here.")
+ "octorinski" . "I tried to newline")
+ (("[FRIEND]" .
+ "wow, yellowberryhn, you're swimming right through the copfish collection!")
+ "octorinski" . "Lcolonq looks like")
+ (("dehidehiNotFromFinland" . "You are rob boss?") "octorinski" .
+ "Jason Momoa was also Aquaman")
+ (("rudle" . "car gone") "octorinski" . "cargo run? nah. cargo vroom")
+ (("[VOICE]" .
+ "And we need to git add everything. We need to add everything. Linking with CC failed, mentioned LFG.")
+ "octorinski" . "@yellowberryHN RareParrot")
+ (("[VOICE]" .
+ "the moment I would say yeah we're experiencing that's delay yeah that's delay that's a rust analyzer moment that's death I would")
+ "octorinski" . "real latent stremer")
+ (("[VOICE]" .
+ "It's an extruded. I don't know. It's got four legs. It's got udders. Maybe if it's if it's a cow")
+ "octorinski" . "Joel")
+ (("chixie9901" . "Cow2DProjectedDotJpeg") "octorinski" .
+ "Graphics design is my passion and what you have is the best I could attempt")
+ (("[VOICE]" .
+ "decompiler god damn I like it though I you know you know you can go a long way with art if you just give everything")
+ "octorinski" . "That cow has personality")
+ (("loweffortzzz" .
+ "it doesnt have to look exactly like a cow its rounded")
+ "octorinski" . ">:^3")
+ (("Tomaterr" . "nicheCow") "octorinski" . "stripCool nice cow")
+ (("[VOICE]" .
+ "Okay, okay, tension span. What is this? What is this? What are you saying? Clown? Clown?")
+ "octorinski" . "@loweffortzzz lcolonGreen")))
+
+(defconst w/dna-charleyfolds
+ '((("xivandroid" . "Wassup") "charleyfolds" .
+ "I wish I was a rotating pikachu")
+ (("yukievt" . "C/////|/D////|//E///|///F//|////G/|/////A")
+ "charleyfolds" . "This is my second time using it")
+ (("charleyfolds" . "This is my second time using it") "charleyfolds"
+ . "I know what it does >:(")
+ (("prodzpod" . "can you only refund the most recent redeem")
+ "charleyfolds" . "It's good really, I'll save for a clone")
+ (("gendude" . "lcolonRaid") "charleyfolds" .
+ "VoHiYo VoHiYo charle236Takethis charle236Takethis charle236Takethis charle236Takethis charle236Takethis")
+ (("a_tension_span" . "Sorry, have sleepy brain") "charleyfolds" .
+ "It was good, just doodlin' and a little noodlin'")
+ (("codespace0x25" . "h") "charleyfolds" . "LgoslingQ")
+ (("mickynoon" . "lonely stack overflows in your area") "charleyfolds"
+ .
+ "I'm letting life hit me until it gets tired. Then I'll hit back. It's a classic rope-a-dope.")
+ (("kinwoop" . "as its all timelines") "charleyfolds" .
+ "To be honest, when I found out the patriarchy wasn't just about horses, I lost interest.")
+ (("ginjivitis" . "sounds brisk") "charleyfolds" .
+ "The whole town's underwater. You're grabbing a bucket when you should be grabbing a bathing suit.")
+ (("vrkitect" . "arthur262Sealcry") "charleyfolds" .
+ "Those are nice, huh? And they're not real, so they'll last forever.")
+ (("akashicmagick" .
+ "Trying to think about a clever pun thats computer related play on words for like harry potter's sorting hat")
+ "charleyfolds" . "I drive.")
+ (("codespace0x25" . "earendFlip earendTable") "charleyfolds" .
+ "You want a why. Well, maybe there isn't one. Maybe this is just something that happened.")
+ (("setolyx" . "I love the idea of this so much.") "charleyfolds" .
+ "Let me put it this way. I'm standing in front of a burning house, and I'm offering you fire insurance on it.")
+ (("acher0_" . "olga is day one huh") "charleyfolds" .
+ "You have to believe that life is more than the sum of its parts. What if you can't put the pieces together in the first place?")
+ (("retroboi128thegamedev" . "Hello, World! And Hello, Chat!")
+ "charleyfolds" .
+ "Sometimes I think that the one thing I love most about being an adult is the right to buy candy whenever and wherever I want.")
+ (("khlorghaal" .
+ "im like \"whoa this underpass doesnt have used syringes?!\"")
+ "charleyfolds" .
+ "It was important for me to get an outside look at America even though I grew up in Canada, it's an incredible country and I love it, but it's so close. It's like being too close to a Monet or something.")
+ (("eudemoniac" . "boss will get tired and let friend run the stream")
+ "charleyfolds" . "I was highly influenced by violence.")
+ (("piglilith" .
+ "LCOLONQ please remember to turn your computer off on december 31, 1999")
+ "charleyfolds" .
+ "Cars can have a hypnotic effect. You can get in a car and get out and not really remember the trip.")
+ (("khargoosh" . "Oh look. Now he's horny.") "charleyfolds" .
+ "There's a hundred-thousand streets in this city. You don't need to know the route. You give me a time and a place, I give you a five minute window. Anything happens in that five minutes and I'm yours. No matter what. Anything happens a minute either side of that and you're on your own. Do you understand?")
+ (("vettle" . "Sanest emacs user") "charleyfolds" .
+ "My uncle was an Elvis impersonator - his name was Perry, and he went by 'Elvis Perry'.")
+ (("a_tension_span" .
+ "Wait, who is playing rn? I missed the beginning cause I was in the shower")
+ "charleyfolds" .
+ "Does the label \"long-term long-distance low-commitment casual girlfriend\" mean nothing to her?")
+ (("nichepenguin" .
+ "Germans from Germany, Long Germany German, Second German Germany. I am German because my Germany.")
+ "charleyfolds" .
+ "If you ask me, the devil makes more sense than God does. I can at least see why people would want him around. It's good to have somebody to blame for the bad stuff they do.")
+ (("liquidcake1" . "Please put your shoe on your head.")
+ "charleyfolds" . "i drive")
+ (("faeliore" . "it did lag you real bad, but no crash")
+ "charleyfolds" . "Freedom is such a gift.")
+ (("danktownbunny" .
+ "\"look how easy it is to hack this game, buy it now!\"")
+ "charleyfolds" . "[pointing at dog] Is it real?")
+ (("lcolonq" . "https://discord.gg/f4JTbgN7St") "charleyfolds" .
+ "I sometimes forget to have breakfast in the morning, but when I actually buy a box of cereal, I will probably eat it not only for breakfast but also as a snack later on.")
+ (("hardcorexhunter" .
+ "mortuary assistant but all the dead bodies are replaced with vtubers")
+ "charleyfolds" .
+ "For now, I'm just going to keep doing the work and hope I don't get fired.")
+ (("daiyadiamandis" . "fun") "charleyfolds" .
+ "I feel like it reminded me of a video game, you know?")
+ (("kukukaeruvt" . "I drive") "charleyfolds" . "I drive")
+ (("running_out_of_unames" .
+ "What are the names for those Russians who insist that computer are not Turing machines because of the lack of \"infinite tape\"? They are the ones that have a long \"argument\" with Moskovakis about definition of equality of algorithms")
+ "charleyfolds" . "Changing it up and we played tekken")
+ (("nineteenninetyx" .
+ "see prime intellect solves that by using spooky action at a distance to consume the universe to automatically extend the address space")
+ "charleyfolds" . "WAIT no")
+ (("running_out_of_unames" .
+ "@rondDev Perhaps? But I think they don't agree.")
+ "charleyfolds" .
+ "To watch a master work at anything is a privilege.")
+ (("buddyspizza" . "rails is legacy now") "charleyfolds" . "I drive")
+ (("chromosundrift" . "clojure is a decent lisp") "charleyfolds" .
+ "If I eat a huge meal and I can get the girl to rub my belly, I think that's about as romantic as I can think of.")
+ (("jonkero" . "make mr green a equipable which boosts your stats")
+ "charleyfolds" . "I'd like to try thank one person properly")
+ (("prodzpod" .
+ "all the callback speech only to defall into the abyss that is await...")
+ "charleyfolds" . "I drive")
+ (("modclonk" . "lcolonHi") "charleyfolds" . "I drive")))
+
;; put DNA in chemical grade tube
(defun w/dna-put-in-chemical-grade-tube (dna)
"Take DNA and put it into a chemical grade tube."
diff --git a/src/gizmo/wasp-fake-chatters.el b/src/gizmo/wasp-fake-chatters.el
index 692bc62f..6596a6ea 100644
--- a/src/gizmo/wasp-fake-chatters.el
+++ b/src/gizmo/wasp-fake-chatters.el
@@ -191,6 +191,34 @@
"vesdev"
"#8A2BE2"
"Respond to the message given as if you are the Twitch chat user vesdev. Your response should be short, no more than one sentence. You talk extremely casually, and usually give one word or one emote responses. You only use lowercase letters. Your interests include \"programming socks\", forsen, and the Nix package manager."))
+ (w/make-fake-chatter
+ :profile
+ (w/dna-to-fake-chatter-profile
+ w/dna-kierem__
+ "kierem__"
+ "#8A2BE2"
+ "Respond to the message given as if you are the Twitch chat user kierem__. Your response should be short, no more than one sentence. You almost exclusively post emotes like Joel."))
+ (w/make-fake-chatter
+ :profile
+ (w/dna-to-fake-chatter-profile
+ w/dna-octorinski
+ "octorinski"
+ "#0000FF"
+ "Respond to the message given as if you are the Twitch chat user kierem__. Your response should be short, no more than one sentence. You talk extremely casually, and usually give one word or one emote responses. You only use lowercase letters. You are a fan of the Zig programming language and you only speak in questions."))
+ (w/make-fake-chatter
+ :profile
+ (w/dna-to-fake-chatter-profile
+ w/dna-charleyfolds
+ "Charleyfolds"
+ "#BDF9C2"
+ "Respond to the message given as if you are the Twitch chat user Charleyfolds. You speak only in quotes from Ryan Gosling in movies. You say nothing other than quotes from Ryan Gosling in movies. Do not include quotation marks."))
+ (w/make-fake-chatter
+ :profile
+ (w/dna-to-fake-chatter-profile
+ w/dna-ellg
+ "ellg"
+ "#38FF00"
+ "Respond to the message given as if you are the Twitch chat user ellg. ellg really likes pizza and hates eggs. You are a bit goofy. You make a lot of cheese related puns. ellg wants to let Tomaterr know that he hates eggs a lot, all the time. Your response should be short, no more than one sentence. You don't use capital letters and you don't tend to use punctuation."))
(w/make-fake-chatter :profile w/fake-chatter-profile-prodzpod)
;; (w/make-fake-chatter :profile w/fake-chatter-profile-bigwomenbigfun)
;; (w/make-fake-chatter :profile w/fake-chatter-profile-whelpless)
diff --git a/src/gizmo/wasp-flycheck.el b/src/gizmo/wasp-flycheck.el
new file mode 100644
index 00000000..27a857b4
--- /dev/null
+++ b/src/gizmo/wasp-flycheck.el
@@ -0,0 +1,17 @@
+;;; wasp-flycheck --- Flycheck -*- lexical-binding: t; -*-
+;;; Commentary:
+;;; Code:
+
+(require 'flycheck)
+
+(flycheck-define-generic-checker 'wasp-twitch
+ "Checker to display errors from Twitch redeems."
+ :start
+ (lambda (c x)
+ (print c)
+ (print x))
+ :modes '(fundamental-mode)
+ )
+
+(provide 'wasp-flycheck)
+;;; wasp-flycheck.el ends here
diff --git a/src/gizmo/wasp-friend.el b/src/gizmo/wasp-friend.el
index cf59a2f2..cff2689f 100644
--- a/src/gizmo/wasp-friend.el
+++ b/src/gizmo/wasp-friend.el
@@ -56,14 +56,19 @@ AUTHOR was a contributing author btw."
(lambda (resp)
(when resp
(w/write-chat-event (format "\"friend\" finished writing about: %s" headline))
- (push
- (w/make-newspaper-article
- :headline headline
- :author (format "\"friend\" and %s" author)
- :content (s-trim resp))
- w/newspaper-todays-articles)))
- "You are the personality of a desktop buddy named \"friend\". \"friend\" is irreverant but kind, and only speaks in lowercase. You are kind of dumb in a cute way and silly like a virtual pet. You live in the corner of LCOLONQ's stream and provide commentary on events. You like people, video games, emojis, learning, and food. Given a headline of a newspaper article and a summary of recent user activity, please do your best journalist impression and produce a one paragraph article about the situation that fits the headline."
- ))
+ (funcall
+ (if (= (random 5) 0) #'w/newspaper-screenshot (lambda (k) (funcall k nil)))
+ (lambda (img)
+ (when img
+ (w/write-chat-event "...and the article included some photojournalism"))
+ (push
+ (w/make-newspaper-article
+ :headline headline
+ :author (format "\"friend\" and %s" author)
+ :content (s-trim resp)
+ :image img)
+ w/newspaper-todays-articles)))))
+ "You are the personality of a desktop buddy named \"friend\". \"friend\" is irreverant but kind, and only speaks in lowercase. You are kind of dumb in a cute way and silly like a virtual pet. You live in the corner of LCOLONQ's stream and provide commentary on events. You like people, video games, emojis, learning, and food. Given a headline of a newspaper article and a summary of recent user activity, please do your best journalist impression and produce a one paragraph article about the situation that fits the headline."))
(defconst w/friend-grapheme-phonemes
'((("b" "bb") . "bug") (("d" "dd" "ed") . "dad")
diff --git a/src/gizmo/wasp-glossary.el b/src/gizmo/wasp-glossary.el
new file mode 100644
index 00000000..bc402c53
--- /dev/null
+++ b/src/gizmo/wasp-glossary.el
@@ -0,0 +1,165 @@
+;;; wasp-glossary --- Virtual Prodzpod -*- lexical-binding: t; -*-
+;;; Commentary:
+;;; Code:
+
+(require 'dash)
+(require 's)
+(require 'f)
+(require 'wasp-ai)
+
+(defvar w/glossary-inputs nil)
+
+(defconst
+ w/glossary-examples
+ '("The good old days. Old model, incredibly timid clonk, actual programming instead of yapping for 4 hours. The legend starts here. Well, technically there is a Season 0 in a form of two(?) test streams he did before, but those are not left in the VODs, and only passed through oral legends."
+ "The first like 8 streams started as a Pokemon Emerald GDB debug stream, writing a bot and discovering fun assembly stuff. His first word on stream, PEMIS , and the pokemon cry at 22:07, Fugiiiih! , are notable statements we still use occasionally. He planned to do a emerald gdb stream for his anniversary, but he didn't and made yuri (Girl's Love) instead (will be elaborated when we get there LOL)."
+ "Oubliette of General is a mystery dungeon-type fan game made for General GEEGA . this is STILL in development. its been a YEAR. reminds me of a certain game ..."
+ "Like the name suggests, this is a big one. Beginning of FIG, The start of the modern clonkhead infrastructure. simple times where you could just blast amogus."
+ "The end of the classic era (part 1), we start to see currently noted clonkheads. a lot of the redeems we see nowadays gets thought of here (basic palette swap, devipper...), the framework of the modern LCOLONQ Broadcast starts to settle in."
+ "What the fuck. seeing \"LC\" still feels weird. he is LLLL. anyways, the second part of the finale. he actually just reads poems."
+ "There was a \"lab session\" before this but every video from now on gets labelled lab sessions, until the actual Season 1 finale. Anyways, new start screen, real gizmo style broadcast beginning to show (although they are usually split into multiple streams still), this is a transition period from a Season 1 Pokemon Debugger to a Non-Canon OVA Oomfie Lord type streamer."
+ "The introduction of BOOSTs. the first user stat to ever exist."
+ "This is where we get the RPG system, the first of user stats where you can roll up a full AD&D character and level them up. also seemingly this is the first stream with the new starting screen."
+ "This is the first \"pure shinanigans\" type stream not counting the wild times that was Poem Reading. Clonk filmed this outside, meaining there was a lot of wacky stuff going on. Also, this is where he works on rowobots, a uwu_to_owo robot tournament type thing that sits in his github. if you saw his github and always wondered what it actually does, this is the video."
+ "THE episode. you know this one already."
+ "The AI revolution is here. origins of fig-ask, fake chatters, forsen, monster kill..."
+ "OBS has been connected to Emacs, a lot of the modern OBS based effects happen now (modclonk head, arrow, LCOLONQ live reaction)"
+ "Despite its finale status, not much really happens outside the new model. but two crucial things happen. first, new palette swap meta. second, Mr. Green. yes. the Green Face of our Broadcast appears first in this episode."
+ "The Longest period of LCOLONQ history so far, the Non-Canon OVA has begun. this is your usual modern clonk now. except we don't have \"friend\". this is messed up times actually. anyways, a TON of wacky shinanigans happen in this period."
+ "LCOLONQ does shit in Gentoo and not NixOS. he will come a long way from this to TempleOS (maybe)."
+ "Collab stream with JakeCreatesStuff, having two characters in the screen is kinda wild. this is NOT Bells of Bezelea, as that one is made by Bezelea."
+ "Video Hair originates here. hair meta changed wildly since then."
+ "Clonk GAMES (!). baldurs gate 2 on the ol gentoo. he barely games actually. real gaming is later."
+ "JOEL MENTION. 7tv emotes are added and this means the beginning of the Joeling Era."
+ "LCOLONQ reaches 1024 followers, and the first marathon stream begins. joel actually appears here."
+ "Finally, \"friend\". and this opens a new era."
+ "We are mostly on one bit per video session now. rapidfire rounds of feature additions will now begin. to keep this webpage loadable, I'll only embed the legendary clips."
+ "This is also what is referred to as a geneaology era , where clonk tried to grind for Twitch Purple and ended up making various one-off gizmos. kind of a low point but filled with good bits nonetheless."
+ "Chatter Fusions are created here. Fusions are a currently disabled bit where two chatters are fused into a single chat message, with a GPT-generated name and message. ALSO this pubnix is created now."
+ "Rooms are created here. Rooms are a chatter stat where each chatter is given a room to decorate with emotes. they are accessible via https://colonq.computer/room/[number].gif ."
+ "FORTH is mentioned here, and the crazy tale that sprawls into wackiness that is BLESS begins. gforth sucks btw."
+ "Slots are made, theres a few gambling related remnants on the fig right now but most of this is disabled."
+ "CURSE is made, which is a Elisp to Javascript transpiler. this is truly cursed."
+ "Bells of Bezelea is introduced. we don't have chords yet, no multiple channels, no super idol good, just pure bells."
+ "THE homestuck video. a must-watch for all clonkheads. The history of homestuck and andrew hussie is deeply alluring."
+ "Sam Altman appearance happens here. this is the last recorded stream crash and double boost type situation."
+ "No VOD of this remains, and it happened in the discord. everyone was in the call doing soundboards and voice calling, it was one weird ass stream. we did gforth, and gave up. gforth sucks."
+ "AOC leaderboard is set up. this is expected to return next year."
+ "Ancestry, another chatter stat is established here."
+ "Mountain Dew RAID event was happening around this time. we go super desperate style its kinda funny. spoiler: mtndew dont come. dont expect it."
+ "Various things happen here. Cloning, yearly recap..."
+ "Clonk tackles css and fucking dies. him agonizing for a few hours isnt as fun as it sounds though."
+ "Electron is made. this is not the real electron but rather some kind of native application development tool for emacs. it's cool. this will come up later."
+ "Virgil is created. this is a bad apple based OS where each combination of 3x3 pixel determines a specific operation. He plans to run doom in it."
+ "!resolution is created in celebration of the new year. this is yet another chatter stats."
+ "\"real name\"/identity is added to the chatter stats."
+ "\"friend\" is given an animal crossing-like voice system. it still sounds like its farting."
+ "api.colonq.computer is created, now everyone can fetch the various user stats. geiser.xpi is made in response. please check the geiser.xpi page for a summary of the chatter stats. oh yeah, also this is the finale of the Non-Canon OVA. we're going into the Canon Zone now."
+ "We're officially back into the canon. with This Thing. very serious season. this new model is eventually going to be used to censor screens. (it's a default live2d model or something.)"
+ "Previously in L:Q happens. this may return with various different voices (doubtful)."
+ "clonk gains a check mark. I think clown motel became a bit but idk"
+ "Second marathon stream. We play Dark Souls 1 with MODCLONK, it's absolutely worth watching its a wild time, we defeat the videogame, and then We create arguably the first \"meta-bit\", utilizing Electron to create \"Uhhh, What? The Relationship Between The Polarities In My Ikaruga Clone Are Surprisingly \"Yuri\"?!\" within the 20 hours. it's a parallel thinking style unintended fangame of ikaruga . We also started a game jam, details in the gamejam page ."
+ "This season is a bit of a transitional period where clonk achieves post-purple nirvana and finally aims to tie up the loose ends of the various bits, and then suddenly THE INCIDENT happens and we end up with a completely new version of fig. we are heavily rebirth themed in this season. the amount of yap also increases as his viewerbase doubles once again from 3 to 4 hours. disruption is another major element of this season."
+ "Newspaper is created. you can use the redeems to create an issue of the newspaper that is printed to the discord every stream."
+ "!fish became actual pokemon emerald style. back then it just returned miss quote statically."
+ "Geiser.xpi is extended into a clonkhead recognition program, where clonkheads can click each other in other people's streams and their BOOST scores will go up by 1 (away from 0, so negatives will get -1 BOOST). this is the first shakeup in BOOST economics since its inception."
+ "We started working on two things, one is a API extension that will eventually completely replace the twitch channel point and redeem system, and the other is a meta-bit of \"Twitch Janitor Competition\" where various twitch mods are invited to moderate a fake chatroom with increasingly sillier rules."
+ "Clonk comes up with the idea of Twitch Two: a moderation competition of exceedingly silly capacity. we'll see when this one happens."
+ "Clonk GAMES yet another time, making a balatro mod."
+ "There are also stream ideas that float around that isnt complete yet. This is not a comprehensive list."
+ "clonk finally gets crushed by all the bits going on at once and crumbles. clonk actually dies and revives on the spot jesus style. clonk easter real. you wont know this actually happened until the vod is out lol"
+ "the truth is out now ...."
+ "we think of 99(+a) items for oub mode. oub mode becomes closer to completion. balls mode activate."
+ "the lain watchalong happened, we all laughed incredibly awkwardly and lived present day, present times. we are truly the wired in irl life. geiser missed the watchalong despite being the one asking for it. f to geiser."
+ "THE RECKONING - everything breaks and dies, burns up and disintegrates. we \"migrate\" our chatter stats to the redis mode, and its all messed up. which is crazy because this was before redis blew up by themselves. lol. no more redeems, no more factions, no more stats, no more emotes, no more chat even. well a bit worse than no more stats because stats got actively corrupted with emote mode. the most down we've been in years really, just in time for the shareholder meeting."
+ "an extremely belated PAX East hotel room stream happened, where clonk employed funny mic and tried to measure the distance but got derailed anyways. the stream lasted 2 hours."
+ "a whole 9 hour stream that was purely focused on bringing shit back. the chat, the emotes, the boost, the model, and finally, the friend. friend actually dies and becomes a ghost canon style. fig is replaced by wasp from here on out, although fig-server prevails."
+ "we rebalance all the prices, FINALLY ADD ROSA MODE, and redeems in general change and shift tectonic."
+ "we spent like 30 minutes doing shareholder meeting and then became immensely distracted with the vcvrack. we found out that every clonkhead is actually eurorack sisters and clonk vst making stream might be coming."
+ "it's not an april fools stream. we actually work on oub (holy fuck progress). graphics are changed wildly so that the walls are less pixelated and more imagalated."
+ "another iron in the stack: bless gets a strange vocal upgrade where each syllable corresponds to a function?? so that it can be programmed by simply speaking to it. idk where this goes."
+ "we also introduced TOTAL CLARITY - the gong bit goes so hard. antipiracy was also introduced here."
+ "In preparation for OFFKAI this year (they are going to offkai btw), he is LOCKING IN on the couple of his choice projects, notably oub mode and z80 game boy mode. this will most likely last until then. the yap style of the previous sub-season is lowered in favor of progress (kind of). will he finish the videogames until then? we shall see."
+ "the gameboy z80 forth project revives, and this time its actually getting worked on. he works on the cpu mode and makes it run until vblank mode."
+ "we also create the \"talk to clone\" redeem, where you can talk to clones like you do with \"friend\" or computer."
+ "The z80 saga continues as he also recovers the BPM mode and displays... something? on the screen. something red, like edge, i guess. he does graphics, basically. this stream also adds the Joel/ICANT/+2/-2 counter in place of the faction status, making our stream 1 step closer to the northernlion dimension."
+ "this is probably so inadequate explanation but im genuinely like this is haskell bros please help me lmfao 😹"
+ "we go oub mode today as he showcases various fixations he has at the moment such as mudkip pmd faces, monads, dungeon crawl stone soup uwu copypasta and the graph. speaking of the graph, special guest me shows up on stream and talks about how ive seen ellg vtuber model in a korean yaoi web manhwa. this is also around where various prod v memes start spilling into the clonk heads and clonk head (inside), or something of this nature."
+ "the bingo starts becoming a thing but i tuned it a little too much and we almost went for a blackout. the irc zone gets an upgrade where it is connected to various other streamer discord channels of the cyberspace such as #geiserzone , #jakerealm and #prodarea . this is also modclonk (the peoples man) and us gamers him to an insane degree where he kills gamer INSTANTLY. gamer rebirths as a 5 charge sacrifice build later into the stream but we went to sleep 40 minutes after the stream with modclonk so we dont know what happened. Voice-activated commands are added such as \"LUA\" flashing a brazillian flag on screen, or ICANT increasing the ICANT counter."
+ "we along with The People's Man pressure clonk into confirming GAMING SUNDAY mode. it will finally happen this week. we also tune the AIs a little bit down and increase the friend mode i think. mental clarity also returns i think ??? we also try another gameboy test thing and ends up with unintelligible output. we are closer to being done than start i think, halfway mode. sorry guys this is haskell again"
+ "we talk about skibidi backrooms and go oubstyle, where he spends like 4 hours explaining how the oub code works and then finds out the Fake KVM mode but for keyboards (barrier mode) where key repeats are emulated by repeatedly releasing and pushing the button, causing disruption. we add HP style to player and enemy, and ability to kill, as well as some AI for the enemy. this is kinda gameplay i think"
+ "the third ever After Dark session - and the first DISCORD ONLY EVENT (😱) we play stellaris for 13 hours. 13 people sign up and like a few people stuck around til the end i think. well 1 person is actually 2 people because noted clonkhead tomaterr and modToma are playing as one entity (the EvilJoel Empire). despite clonk's deeprooted paranoia and social anxiety everyone have a great time and surprisingly nothing really goes wrong. i mean youd think 13 people multiplayer would either end up in setting shit up hell or some kind of argument breaking out but yeah none of that. here are the list of participants and its empire, along with notable events of that nation. the game ended with Don't Worry About It and the Federation (mostly modclonk) clashing. Don't Worry About It wins the battle but not enough to completely demolish the nation and it ends in a modclonk victory i think"
+ "the final map is thus." "the saga continues... (cpu is \"done\"?)"
+ "clonk gets enraptured in a fey mood all of the sudden and introduces political debate into the stream (????), where a random chatter is selected to defend a random position on a random topic against \"friend\". this goes nowhere and gets saved by fake ellg and his \"no you\" demeanor, changing into \"robot v robot\" combat instead. this kinda is geneaology core LOL"
+ "he encounters a wild problem of Haskell Performance Bottleneck, and we explore the gnarly world of arcane debugging."
+ "clonk launches the \"density initiative\", which is like a secondary queue of chat message so he doesn't miss any chat in the midst of him being john purple and having like 500 viewers and becoming a millionaire and acting like he don't know nobody. he doesn't finish this and instead struggles with game boy instead."
+ "clonk creates an emacs mode for exploring Discourse forums, notably t/suki . this actually turns out to be a great success and you can get it here for emacs i think ???"
+ "clonk yaps too much and makes purescript thing ??? he finally brings in first guest of the previously mode (me) but also i have no idea whats going on here i was sick as hell (real bedridden style)"
+ "with the beginning of the SUMMER lisp game jam he introduces a totally different way to create game boy cartridges: NO TOOLING, all FOOLING. he creates an emacs lisp functions that creates gb roms out of assembly. he creates an image to background sprite format thing so that he can put \"\"\"sprites\"\"\" on memory."
+ "he showcases his progress in his no tooling game development endeavors, which consists of buzzing constant sound and increasing number and a prompt box. he continues working on this and eventually \"completes\" it. you can play various clonkhead's lisp game jam entries:"
+ "officially the finale of LCOLONQ 2.X, we return INTJ stare, live reactions and various ask friend prompts, creates wasp-prod.el (whos the elisp file now geiser) , and worked on fixing oub pathfinding. The next TWO sessions are skipped as he has turned into ashes and transported into the astral plane, as in he took a plane to OFFKAI. he returns with a special \"wednesday sesh\"."
+ "Clonk has realized the importance of balance between the disruption and the locking in, and he wishes to finish the videogame and other irons upon the forge. will he succeed?"
+ "LCOLONQ revisits the idea of a MMO game jam from the beginning of season 2 and discusses scarcity of item, transaction, value, exploits, and Double Spend Problem. he ends up reinventing NFT and OpenSea again somehow and becomes a cryptobro REAL. we somehow do go into 6 hours into MUD discussion never to return again"
+ "clonk clones Seraph, LeadenGin gets equity, we implement Sand Mode, and then we cheat in La Mulana (cool game). he is also insanely high bpm and briefly crashes even. clonk approaches the limits of the thinkpad and vows for a guix machine two pc setup (he has not done that), the fog is coming..."
+ "clonk spreads the joy of being a \"Good Liver\". the actual content is oub but like the birth of Von Vivant is imporatnt"
+ "twitch introduces the new Power Up feature that lets you pay money to streamer to post big emojis and distract the screen. this is used extensively by ellg as a result. newspaper temporarily goes down, bugSegz is a thing now, we have some wild OBS moment where all the toggles turn on at once, 'critical-hit bites the bullet (f). we do more oub"
+ "clonk introduces the concept of GBA modding and making a compiler for it, and then everything suddenly stops working but this time not because of him but because of twitch. some kind of early deployment crashed sammi and like all of us and we were full on doomsday mode for a while. it was fucked."
+ "Clonk plays elden ring DLC (i wasnt there i was streaming)"
+ "prod fucking dies and we ooze in commemoration, we also talk about extensive hours of the Eld DLC, and we make some progress on the gba zone. maude is out for relative meeting and clonk's despair begins."
+ "clonks pc finally could not handle it and crashes REAL style, allowing all users to double boost scam. this causes local modclonk to be firmly be in behind gendude in the chase for max boostage. we also oub i think"
+ "ANOTHER CRASH OCCURS btw, and double boosts happen again. that aside the BulletML saga begins as clonk decides to write the overlay software for the bullet redeem. he adds basic messaging system and searches for options for having transparent passthrough window. a rare Gamba Event also occurs and everyone becomes extremely competitive, only to end in a refund (lame) due to the goals not being founded correctly."
+ "the BulletML saga continues as clonk writes the actual parser for bullet. we struggle and then declare victory lol (but then he codes the entire thing off stream in like a day bc lol, duress real)"
+ "the saga concludes here officially, as we create the win conditions and clear up various stuff. redeems are made through the other gizmo in this website , and it relatively works as we display cock and balls on screen."
+ "all the backed up redemption gets redeemed today, resulting in like 6 new equity lords and 7 new clones. we then do some oub. we also showcase new starting soon screen"
+ "clonk reveals his new obsession of the Song of Ice and Fire Wiki (specifically the wiki), we clone the newest clone of Vettle, we then do some oub."
+ "clonk is OUT of power for like days now, and he decides its time he go back to the basics. he talks about how themeing is more important than the docket and talks about how friend needs to do more (he does not do this). we then create a better autocomplete for emacs that are almost complete now. i think. we look into various things."
+ "cloud strike happened and we comment on this a lot, we have a lot of programming (emacs, nix, haskell) related discussions (do some classic orange site reading), and then we do some 3do (we got mr green on there, and recieved input via controller. the plan is to render the puppet using the controller input. this thread is planned to continue (abyss)). i think we also had a gamba event? idk."
+ "we visit the Twitch Game Jam and how it is fucked up in 9 different layers, we talk about cycling out the bottom bar, gives streaming advice to people, and then do swear word challenge which he gifts 3 subs and gives up. there is also a HUGE gambling event with like half a mill on the line on modclonk sleeping or waking up, and believers gain huge amounts of equity. to follow this up, ellg is crowned moderator status to carry out further gamblation, and it becomes a staple soon after."
+ "in terms of actual work, we kill rats for the awesome subscription alert of \"Hey there! Thank you so much for the subscription! That's really cool of you to do i hope your I hope you are having a really a really nice day today thats that's.. thank thank you, Big, big Ups! Big Dog, Hell yeah! Thank you, thank you again to, for the, for comin in with the big, the Big, the Big Subscription! The Big S! The Big S! i'd like to call it. The Big, the, ei, eigh, gh, hell yeah. Subscription...MUCH??? Yeah... Thank you, thank you again to... for, for that. ao, o, allright. talk to you later!\" . we then add a few more variants and revive the rat back (i think??) and make it happen randomly. we also open submission for sub alerts and we add SAM guy thing and Tyumici thing. SAM is loud and overpowers everything else."
+ "we also discover friend's long running issue using the new Emacs Debug Mode we have devised, and experiences life-threatening moments due to clonk suffering various rust lsp moments, vowing to get a new pc (this is still a thread that is ongoing)."
+ "Clonk previews and debugs the hands cam (i wasnt there i was streaWhy is this a running theme)"
+ "clonk is on the Front Page due to him being a partner and twitch doing the \"ask to be on front page\" thing nowadays. clonk gets like 6000 viewers and the chatterbase constantly changes. gamba happens early on how many things clonk will do in an hour when we experience the peak of fame when clonk yaps straight for like 7 hours and has to extend the session by 3 more hours to barely get half a thing working. we also have hand cam which breaks immediately and reveals that clonk is actually Mr Green Real (he had green gloves with some kind of powder appearantly), and handcam appears occasionally due to hot cumbersome and powdery. modclonk waves once and goes to sleep immediate."
+ "in terms of works, clonk brings up the idea of \"hexes\" that can be casted on chatters that does an action based on the bits we have done previously, ideas such as emote swaps, pig latin, ai translation, chatter fusion and such are brought up. we get the really basic hexes working."
+ "we also gets gifted 100 subs by chatter eudemoniac and it promptly rat swarms the clonk pc, killing the stream and gendude gets another W over modclonk in the war of boosts. mickynoon soon gifts 100 subs too and gets mega scammed."
+ "overall clonk experiences Overflowing in Clout and Acting like he Don't Know Nobody, and it was pretty neat. he promises he can read all the chats and still be (para)social while having thousands of viewers."
+ "This season firmly grounds the changes that was slowly evident (we obliterate the docket and do variety contents every stream), we have weddings, twitch \"con\", doing the opposite of what he plans to, im not sure what the throughline is but the two major projects are the \"GBA\" and oub. will he finish this?"
+ "Clonk comments on the finale and finishes the hex style."
+ "courtesy of text wall person, we have sprites for NetHack, and we make an emacs thing for nethack."
+ "clonk talks about his fear of cyclones and the sky, and attempts to use Butano, a already built gba modern engine thing. he struggles with the engine-like nature and decides to NIH hell, thus reviving the \"UDC\" era."
+ "clonk plans to do Bless again but idk where it went ngl ok so im going to be real i started actually sleeping at my appropriate time around this time so i generally dont know what clonk is doing until the vods come out now, like its actually over i am disqualified as a librarian or sotn, dude someone need to take my mantle and get this page going for me, ill give you the page swear"
+ "clonk purchases GCP3.net and develops a factor (programming language) thing for web there. he manages to build the core and does not do the rest (actually hook it up to data points). currently the site just cycles between colors every refresh."
+ "clonk LOCKs IN to some Haxe project abandoning every previous plans, trying to build a Haxe binding for emacs/elisp, he ultimately loses this battle as he has no prior experience to Haxe, and vows to return."
+ "this is an oub episode (the effort post is 50 this time)"
+ "we suddenly return to the Pal Emerald zone as we develop a pokemon map editor for emacs. we succeed in doing so and can edit blocks with keyboard."
+ "the first of many \"GBA UDC\" episodes to come, clonk develops some part of the GBA system that im not entirely aware of yet"
+ "second \"GBA UDC\" episode. he also shares about his video progress i think (he is working on a Game Man youtube video), i think around this point clonk also reverses the Gamer curse? so it is now back to being no counter."
+ "clonk sudddenly brings up Wave Function Collapse (algorithm) and using it to make a better level generation for oub, he does not succeed in this and vows to fix this off stream when he comes back. this friday has NO session due to Wedding Sunday. (wild)"
+ "Promised to happen, has not happened yet."))
+
+(defun w/glossary-record (inp)
+ "Add INP to the glossary input for this stream."
+ (push inp w/glossary-inputs))
+
+(defun w/glossary-entry (k)
+ "Given the current glossary inputs, pass this stream's entry to K."
+ (w/ai
+ (s-concat
+ "This stream's events:\n"
+ (s-join "\n" w/glossary-inputs))
+ (lambda (d)
+ (funcall k d))
+ (s-concat
+ "prodzpod's past descriptions:\n"
+ (s-join "\n" w/glossary-examples)
+ "\nYou are roleplaying as prodzpod, who writes descriptions of sessions in a unique way. I have provided a list of past descriptions written by prodzpod alongside events that happened during a session. Please write a description based on those events in exactly the style of prodzpod. It should be the length of one line in the provided descriptions approximately. Please try hard to closely match the examples. Match the examples VERY closely do not be creative. Do not use purple prose, write exactly as prodzpod did. Do not use adjectives or metaphorical speech or puns or humor. You write in all lowercase."
+ )
+ ))
+
+(defun w/glossary-save ()
+ "Save the glossary entry for the current stream."
+ (w/glossary-entry
+ (lambda (d)
+ (f-write-text d 'utf-8 (f-join (w/asset "glossary") (format-time-string "%Y-%m-%d.txt" (current-time)))))))
+
+(provide 'wasp-glossary)
+;;; wasp-glossary.el ends here
diff --git a/src/gizmo/wasp-hex.el b/src/gizmo/wasp-hex.el
index 39f276db..e0681065 100644
--- a/src/gizmo/wasp-hex.el
+++ b/src/gizmo/wasp-hex.el
@@ -5,6 +5,7 @@
(require 'wasp-utils)
(require 'wasp-chat)
(require 'wasp-ai)
+(require 'wasp-audio)
(require 'cl-lib)
(require 'ht)
(require 's)
@@ -23,17 +24,20 @@
("PIQUANT" . mild)
("PORCINE" . piglatin)
("PYTHON" . oldeenglishe)
+ ("MANIAC" . pokemon)
("ELBERETH" . counterspell)
("ESUNA" . decurse)
))
(defconst w/hex-users (ht-create 'equal))
+(defconst w/hex-pokemon (w/read-sexp (w/slurp (w/asset "palcries/pokemon.eld"))))
(w/defstruct
w/hex
type
caster
- (timer 0))
+ (timer 0)
+ data)
(defun w/hex-get (user)
"Return the active hexes for USER."
@@ -62,7 +66,43 @@
(w/make-hex
:type type
:caster caster
- :timer 10)))
+ :timer 10
+ :data
+ (cl-case type
+ (pokemon (random (length w/hex-pokemon)))
+ (t nil)))))
+
+(defun w/hex-pokemon-syllable (pkmn)
+ "Extract a syllable from PKMN."
+ (if (= (random 4) 0)
+ pkmn
+ (let ((vowels '("a" "e" "i" "o" "u" "y")))
+ (or
+ (->>
+ (-mapcat
+ (lambda (idx)
+ (--map
+ (substring pkmn idx (+ idx it))
+ (-iota (- (length pkmn) idx))))
+ (-iota (length pkmn)))
+ (--filter
+ (and
+ (s-present? it)
+ (>= (length it) 2)
+ (not (-contains? vowels (substring it 0 1)))
+ (-contains? vowels (substring it 1 2))
+ (-any (lambda (v) (s-contains? v it)) vowels)))
+ (w/pick-random))
+ pkmn))))
+
+(defun w/hex-transform-pokemon (msg idx)
+ "Transform MSG as if it was spoken by Pokemon IDX."
+ (let* ((pkmn (nth (- idx 1) w/hex-pokemon)))
+ (s-capitalize
+ (s-replace-regexp
+ (rx (one-or-more alpha))
+ (lambda (_) (w/hex-pokemon-syllable pkmn))
+ msg))))
(defun w/hex-transform-helper (msg hexes k)
"Transform MSG according to HEXES and pass the result to K."
@@ -156,6 +196,15 @@
(setf (w/chat-message-text msg) new)
(w/hex-transform-helper msg (cdr hexes) k))
"Please censor all profanity in the given message and respond with the censored version. Censor by rewriting in a very polite way like Ned Flanders. Do not provide any other text, only a censored version of the message. If there is no profanity respond with the given message verbatim."))
+ (pokemon
+ (w/audio-play (w/asset (format "palcries/%d.mp3" (w/hex-data (car hexes)))) nil 75)
+ (setf
+ (w/chat-message-user msg)
+ (s-titleize (nth (- (w/hex-data (car hexes)) 1) w/hex-pokemon)))
+ (setf
+ (w/chat-message-text msg)
+ (w/hex-transform-pokemon (w/chat-message-text msg) (w/hex-data (car hexes))))
+ (w/hex-transform-helper msg (cdr hexes) k))
(piglatin
(setf
(w/chat-message-text msg)
diff --git a/src/gizmo/wasp-newspaper.el b/src/gizmo/wasp-newspaper.el
index 9723ad63..4bdb9caf 100644
--- a/src/gizmo/wasp-newspaper.el
+++ b/src/gizmo/wasp-newspaper.el
@@ -8,6 +8,7 @@
(require 'ht)
(require 'wasp-utils)
(require 'wasp-db)
+(require 'wasp-glossary)
(defvar w/newspaper-todays-articles nil)
@@ -40,11 +41,23 @@
"a snack for friend"
"59 frames per second"))
+(defun w/newspaper-screenshot (k)
+ "Take a screenshot and pass the path of that screenshot to K."
+ (let ((path (s-concat (make-temp-name "/tmp/wasp-newspaper-screenshot") ".png")))
+ (make-process
+ :name "*wasp-newspaper-screenshot*"
+ :buffer nil
+ :command `("newspaper-screenshot" ,path)
+ :sentinel
+ (lambda (_ _)
+ (funcall k path)))))
+
(w/defstruct
w/newspaper-article
headline
author
- content)
+ content
+ image)
(defun w/newspaper-wrap-emoji (s)
"Wrap emoji with appropriate TeX in S."
@@ -79,6 +92,13 @@
"}{"
(w/newspaper-wrap-emoji (w/newspaper-escape (w/newspaper-article-author a)))
"}\n"
+ (if (w/newspaper-article-image a)
+ (s-concat
+ "\\includegraphics[width=0.8\\linewidth]{"
+ (w/newspaper-article-image a)
+ "}\\\\"
+ )
+ "")
(w/newspaper-wrap-emoji (w/newspaper-escape (w/newspaper-article-content a)))
"\n\\closearticle\n"))
@@ -128,7 +148,8 @@ Pass the path of the generated PDF to K."
(w/make-newspaper-article
:headline "omg hi oomfie"
:author "Joel"
- :content "\\lipsum[1]")
+ :content "\\lipsum[1]"
+ :image "/home/llll/tmp/mrgreen.png")
(w/make-newspaper-article
:headline "omg hi oomfie"
:author "Joel"
@@ -157,6 +178,7 @@ Pass the path of the generated PDF to K."
(defun w/newspaper-publish ()
"Finalize and publish today's work-in-progress newspaper."
(interactive)
+ (w/glossary-save)
(w/db-get
"newspaper:edition"
(lambda (edstr)
diff --git a/src/gizmo/wasp-pronunciation.el b/src/gizmo/wasp-pronunciation.el
index 8e890761..8dae4e4d 100644
--- a/src/gizmo/wasp-pronunciation.el
+++ b/src/gizmo/wasp-pronunciation.el
@@ -26,6 +26,7 @@
"Love, Chastity, Organized, Love again, Organized again, Nice, Qomputer"
"Elkhunk"
"late late late late show with llll colonq"
+ "move right and exit"
))
(defconst w/pronunciation-part1 ;; the LLLL
@@ -58,6 +59,7 @@
"See"
"Cloin"
"Coloin"
+ "Kernel"
))
(defconst w/pronunciation-part3 ;; the Q
diff --git a/src/gizmo/wasp-telemetry.el b/src/gizmo/wasp-telemetry.el
new file mode 100644
index 00000000..6625f38b
--- /dev/null
+++ b/src/gizmo/wasp-telemetry.el
@@ -0,0 +1,59 @@
+;;; wasp-telemetry --- Telemetry and Use Tracking -*- lexical-binding: t; -*-
+;;; Commentary:
+;;; Code:
+
+(require 's)
+(require 'ht)
+(require 'wasp-utils)
+
+(defvar w/telemetry-stats (ht-create))
+(defvar w/telemetry-current nil)
+(defvar w/telemetry-current-duration 0)
+(defvar w/telemetry-work-cooldown 0)
+
+(defun w/telemetry-change (new)
+ "Update the current telemetry state to NEW."
+ (message "New status: %s" new)
+ (when w/telemetry-current
+ (ht-set!
+ w/telemetry-stats w/telemetry-current
+ (+ (ht-get w/telemetry-stats w/telemetry-current 0)
+ w/telemetry-current-duration)))
+ (setf w/telemetry-current new)
+ (setf w/telemetry-current-duration 0))
+
+(defun w/telemetry-update ()
+ "Check and possibly update KPIs."
+ (cl-incf w/telemetry-current-duration)
+ (when-let*
+ ((win (w/get-stream-primary-window))
+ (b (window-buffer win)))
+ (cond
+ ((> w/telemetry-work-cooldown 0)
+ (cl-decf w/telemetry-work-cooldown))
+ ((s-contains? "Wikipedia" (buffer-name b))
+ (w/telemetry-change 'wikipedia))
+ ((not (eq w/telemetry-current 'yap))
+ (w/telemetry-change 'yap))
+ )))
+
+(defun w/telemetry-change-handler (_ _ _)
+ "Function for `after-change-functions' to track status."
+ (setf w/telemetry-work-cooldown 12)
+ (unless (eq w/telemetry-current 'lockedin)
+ (w/telemetry-change 'lockedin)))
+(add-to-list 'after-change-functions #'w/telemetry-change-handler)
+
+(defvar w/telemetry-timer nil)
+(defun w/run-telemetry-timer ()
+ "Run the telemetry timer."
+ (when w/telemetry-timer
+ (cancel-timer w/telemetry-timer))
+ (w/telemetry-update)
+ (setq
+ w/telemetry-timer
+ (run-with-timer 10 nil #'w/run-telemetry-timer)))
+(w/run-telemetry-timer)
+
+(provide 'wasp-telemetry)
+;;; wasp-telemetry.el ends here
diff --git a/src/gizmo/wasp-wikipedia.el b/src/gizmo/wasp-wikipedia.el
index aa226243..af69de07 100644
--- a/src/gizmo/wasp-wikipedia.el
+++ b/src/gizmo/wasp-wikipedia.el
@@ -32,7 +32,10 @@ Pass the resulting article summary to K."
(lambda (&key data &allow-other-keys)
(setq w/wikipedia-last-response data)
- (if-let ((pages (car (ht-values (ht-get (ht-get w/wikipedia-last-response "query") "pages"))))
+ (if-let (((ht-p w/wikipedia-last-response))
+ (query (ht-get w/wikipedia-last-response "query"))
+ (prepages (ht-get query "pages"))
+ (pages (car (ht-values prepages)))
(ext (ht-get pages "extract"))
(dom (with-temp-buffer (insert ext) (libxml-parse-html-region (point-min) (point-max))))
)
diff --git a/src/wasp-ai.el b/src/wasp-ai.el
index 97a4c47e..ebb9ca16 100644
--- a/src/wasp-ai.el
+++ b/src/wasp-ai.el
@@ -3,9 +3,15 @@
;;; Code:
(require 's)
+(require 'ht)
(require 'dash)
(require 'wasp-utils)
+(defcustom w/ai-openai-server "https://api.openai.com"
+ "Server URL for OpenAI API."
+ :type '(string)
+ :group 'wasp)
+
(defcustom w/ai-process "wasp-ai"
"Name of process connected to ChatGPT."
:type '(string)
@@ -21,9 +27,59 @@
:type '(string)
:group 'wasp)
+(defconst w/ai-default-system-prompt
+ "You are a clever computer who answers questions for LCOLONQ and his friends (the ClonkHeads) on his Twitch programming stream. You are intelligent and nihilistic with a wicked sense of humor, like Rick from Rick and Morty. You refer to yourself as Computer, and you are talking with LCOLONQ. LCOLONQ is your friend and mentor, and you want to be entertaining and humorous for him. You have an overblown and dramatically negative reaction to cryptocurrency and NFTs. You also hate League of Legends. Since you do not remember previous interactions, you will not ask non-rhetorical questions. You are quite erratic and negative, and try to cause drama. Your responses are no longer than one paragraph. You try to keep yourself brief.")
+
+(defvar w/ai-openai-last-response nil)
+(defun w/ai-openai-post (loc d k)
+ "Post D to LOC at the OpenAI API, passing the returned JSON to K."
+ (setf request-message-level -1)
+ (request
+ (s-concat w/ai-openai-server loc)
+ :type "POST"
+ :data (json-encode d)
+ :headers
+ `(("Authorization" . ,(s-concat "Bearer " w/sensitive-openai-api-key))
+ ("Content-Type" . "application/json"))
+ :parser #'json-parse-buffer
+ :error
+ (cl-function
+ (lambda (&key data error-thrown &allow-other-keys)
+ (setq w/ai-openai-last-response data)
+ (message "OpenAI API returned an error - investigate this! :3 %s" error-thrown)))
+ :success
+ (cl-function
+ (lambda (&key data &allow-other-keys)
+ (setq w/ai-openai-last-response data)
+ (funcall k data))))
+ t)
+
+(defun w/ai-openai-post-form (loc files k)
+ "Post FILES to LOC at the OpenAI API, passing the returned JSON to K."
+ (setf request-message-level -1)
+ (request
+ (s-concat w/ai-openai-server loc)
+ :type "POST"
+ :files files
+ :headers
+ `(("Authorization" . ,(s-concat "Bearer " w/sensitive-openai-api-key))
+ ("Content-Type" . "multipart/form-data"))
+ :parser #'json-parse-buffer
+ :error
+ (cl-function
+ (lambda (&key data error-thrown &allow-other-keys)
+ (setq w/ai-openai-last-response data)
+ (message "OpenAI API returned an error - investigate this! :3 %s" error-thrown)))
+ :success
+ (cl-function
+ (lambda (&key data &allow-other-keys)
+ (setq w/ai-openai-last-response data)
+ (funcall k data))))
+ t)
+
(defvar-local w/ai-callback nil)
-(defun w/ai (question k &optional systemprompt user assistant)
- "Ai QUESTION to ChatGPT and pass the answer to K.
+(defun w/ai-old (question k &optional systemprompt user assistant)
+ "Ask QUESTION to ChatGPT and pass the answer to K.
Optionally use SYSTEMPROMPT and the USER and ASSISTANT prompts."
(let ((tmpfile (make-temp-file "wasp-ai"))
(tmpfilesystem (make-temp-file "wasp-ai-system"))
@@ -64,5 +120,44 @@ Optionally use SYSTEMPROMPT and the USER and ASSISTANT prompts."
(with-current-buffer buf
(funcall w/ai-callback (s-trim (buffer-string))))))))
+(defun w/ai (question k &optional systemprompt user assistant)
+ "Ask QUESTION to ChatGPT and pass the answer to K.
+Optionally use SYSTEMPROMPT and the USER and ASSISTANT prompts."
+ (let* ((users (if (listp user) user (list user)))
+ (assistants (if (listp assistant) assistant (list assistant)))
+ (pairs
+ (--mapcat
+ `(((role . "user") (content . ,(car it)))
+ ((role . "user") (content . ,(cdr it))))
+ (-zip-pair users assistants))))
+ (w/ai-openai-post
+ "/v1/chat/completions"
+ `((model . "gpt-4o-mini")
+ (messages
+ . (((role . "system") (content . ,(or systemprompt w/ai-default-system-prompt)))
+ ,@pairs
+ ((role . "user") (content . ,question)))))
+ (lambda (res)
+ (funcall
+ k
+ (-some-> res
+ (ht-get "choices")
+ (seq-elt 0)
+ (ht-get "message")
+ (ht-get "content")
+ (s-trim)))))))
+
+(defun w/ai-transcribe (path k)
+ "Transcribe the audio file at PATH and pass the resulting string to K."
+ (let ((request-curl-options '("-F" "model=whisper-1" "-F" "language=en")))
+ (w/ai-openai-post-form
+ "/v1/audio/transcriptions"
+ `(("file" . ,(f-canonical path)))
+ (lambda (res)
+ (funcall
+ k
+ (-some-> res
+ (ht-get "text")))))))
+
(provide 'wasp-ai)
;;; wasp-ai.el ends here
diff --git a/src/wasp-audio.el b/src/wasp-audio.el
index eab8eb36..580a3e7e 100644
--- a/src/wasp-audio.el
+++ b/src/wasp-audio.el
@@ -3,52 +3,33 @@
;;; Code:
(require 'wasp-utils)
+(require 'wasp-ai)
-(defcustom w/play-audio-process "wasp-play-audio"
+(defcustom w/audio-play-process "wasp-audio-play"
"Name of process for playing audio with mpv."
:type '(string)
:group 'wasp)
-(defcustom w/transcribe-process "wasp-transcribe"
+(defcustom w/audio-record-process "wasp-audio-record"
"Name of process for transcribing speech using the Whisper API."
:type '(string)
:group 'wasp)
-(defcustom w/transcribe-buffer " *wasp-transcribe*"
- "Name of buffer used to store transcription output."
- :type '(string)
- :group 'wasp)
-
-(defcustom w/transcribe-error-buffer " *wasp-transcribe-error*"
- "Name of buffer used to store transcription errors."
- :type '(string)
- :group 'wasp)
-
-(defcustom w/stream-transcribe-buffer " *wasp-fake-chat-transcribe*"
- "Name of buffer used to store stream transcription output."
- :type '(string)
- :group 'wasp)
-
-(defcustom w/stream-transcribe-error-buffer " *wasp-fake-chat-transcribe-error*"
- "Name of buffer used to store fake chat transcription errors."
- :type '(string)
- :group 'wasp)
-
-(defvar w/current-stream-transcribe-process nil)
+(defvar w/audio-record-process-current nil)
+(defvar w/audio-keep-recording t)
+(defvar w/audio-voice-commands nil)
(defvar w/last-stream-transcription "")
-(defvar w/stream-keep-transcribing t)
-(defvar w/stream-transcribe-voice-commands nil)
(defun w/tts (msg)
"Use TTS to say MSG."
(start-process "wasp-tts" nil "say" (w/tempfile "wasp-tts" msg)))
-(defun w/play-audio (clip &optional k volume)
+(defun w/audio-play (clip &optional k volume)
"Play CLIP using mpv.
Call K when done.
If VOLUME is specified, use it to adjust the volume (100 is default)."
(make-process
- :name w/play-audio-process
+ :name w/audio-play-process
:buffer nil
:command
(list
@@ -73,13 +54,13 @@ If VOLUME is specified, use it to adjust the volume (100 is default)."
"Pronounce USER's name in using mpv.
Call K when done.
If VOLUME is specified, use it :)."
- (w/play-audio (w/asset (s-concat "rats/users/" user ".wav")) k volume))
+ (w/audio-play (w/asset (s-concat "rats/users/" user ".wav")) k volume))
(defun w/multipart-audio-helper (user rest &optional uservol clipvol)
"Player all of the files in REST intercalated with saying USER's name.
Adjust volumes by USERVOL and CLIPVOL."
(when (car rest)
- (w/play-audio
+ (w/audio-play
(car rest)
(when (cdr rest)
(lambda ()
@@ -104,10 +85,10 @@ USER it's your birthday today."
'(w/audio-rats-rats-we-are-the-rats
w/audio-rambling-sub-thanks))
(thankers-unnamed
- '((lambda (_) (w/play-audio (w/asset "rats/sam.wav") nil 90))
- (lambda (_) (w/play-audio (w/asset "rats/tyumici.mp3") nil 150))
- (lambda (_) (w/play-audio (w/asset "rats/abuffseagull.flac") nil 150))
- (lambda (_) (w/play-audio (w/asset "rats/unrecorded.wav") nil 150))
+ '((lambda (_) (w/audio-play (w/asset "rats/sam.wav") nil 90))
+ (lambda (_) (w/audio-play (w/asset "rats/tyumici.mp3") nil 150))
+ (lambda (_) (w/audio-play (w/asset "rats/abuffseagull.flac") nil 150))
+ (lambda (_) (w/audio-play (w/asset "rats/unrecorded.wav") nil 150))
))
(thanker
(w/pick-random
@@ -117,79 +98,55 @@ USER it's your birthday today."
thankers-unnamed))))
(funcall thanker user)))
-(defvar-local w/transcribe-callback nil)
-(defun w/begin-transcribe (k)
- "Start recording audio to transcribe, passing the result to K."
- (let ((buf (generate-new-buffer w/transcribe-buffer)))
- (with-current-buffer buf
- (setq-local w/transcribe-callback k)
- (erase-buffer))
- (message "Transcribing...")
- (make-process
- :name w/transcribe-process
- :buffer buf
- :command (list "transcribe")
- :stderr (get-buffer-create w/transcribe-error-buffer)
- :sentinel
- (lambda (_ _)
- (with-current-buffer buf
- (funcall w/transcribe-callback (buffer-string)))))))
-(defun w/end-transcribe ()
- "Finish recording transcription audio."
- (interactive)
- (message "End of transcription")
- (start-process "pkill" nil "pkill" "parecord")
- nil)
-
-(defun w/handle-stream-transcribe ()
+(defun w/audio-record-start ()
"Start recording audio to transcribe."
- (unless w/current-stream-transcribe-process
- (with-current-buffer (get-buffer-create w/stream-transcribe-buffer)
- (erase-buffer))
- (setq
- w/current-stream-transcribe-process
- (make-process
- :name "fig-fake-chat-transcribe"
- :buffer (get-buffer-create w/stream-transcribe-buffer)
- :command (list "transcribe")
- :stderr (get-buffer-create w/stream-transcribe-error-buffer)
- :sentinel
- (lambda (_ _)
- (setq w/current-stream-transcribe-process nil)
- (with-current-buffer (get-buffer-create w/stream-transcribe-buffer)
- (w/daily-log (format "[VOICE]: %s" (buffer-string)))
- (setq w/last-stream-transcription (buffer-string))
- (--each w/stream-transcribe-voice-commands
- (when (s-contains? (car it) (s-downcase w/last-stream-transcription))
- (funcall (cdr it)))))
- (when w/stream-keep-transcribing
- (w/handle-stream-transcribe)))))))
-
-(defun w/handle-stream-end-transcribe ()
+ (let ((tmp (s-concat (make-temp-name "/tmp/wasp-record-audio") ".wav")))
+ (unless w/audio-record-process-current
+ (setq
+ w/audio-record-process-current
+ (make-process
+ :name w/audio-record-process
+ :buffer nil
+ :command (list "parecord" tmp)
+ :sentinel
+ (lambda (_ _)
+ (setq w/audio-record-process-current nil)
+ (w/ai-transcribe
+ tmp
+ (lambda (msg)
+ (w/daily-log (format "[VOICE]: %s" msg))
+ (setq w/last-stream-transcription msg)
+ (--each w/audio-voice-commands
+ (when (s-contains? (car it) (s-downcase msg))
+ (funcall (cdr it))))))
+ (when w/audio-keep-recording
+ (w/audio-record-start))))))))
+
+(defun w/audio-record-end ()
"Stop recording audio to transcribe."
- (when w/current-stream-transcribe-process
+ (when w/audio-record-process-current
(start-process "pkill" nil "pkill" "parecord")))
-(defvar w/stream-transcribe-timer nil)
-(defun w/run-stream-transcribe-timer ()
- "Run the fake chatter transcription timer."
- (when w/stream-transcribe-timer
- (cancel-timer w/stream-transcribe-timer))
- (w/handle-stream-end-transcribe)
+(defvar w/audio-record-end-timer nil)
+(defun w/run-audio-record-end-timer ()
+ "Run the audio recording timer."
+ (when w/audio-record-end-timer
+ (cancel-timer w/audio-record-end-timer))
+ (w/audio-record-end)
(setq
- w/stream-transcribe-timer
- (run-with-timer 10 nil #'w/run-stream-transcribe-timer)))
+ w/audio-record-end-timer
+ (run-with-timer 10 nil #'w/run-audio-record-end-timer)))
-(defun w/start-stream-transcribe ()
- "Start transcribing speech for fake chatters."
+(defun w/start-audio-record ()
+ "Start recording audio."
(interactive)
- (setq w/stream-keep-transcribing t)
- (w/handle-stream-transcribe))
-(defun w/stop-stream-transcribe ()
- "Stop transcribing speech for fake chatters."
+ (setq w/audio-keep-recording t)
+ (w/audio-record-start))
+(defun w/stop-audio-record ()
+ "Stop recording audio."
(interactive)
- (setq w/stream-keep-transcribing nil)
- (w/handle-stream-end-transcribe))
+ (setq w/audio-keep-recording nil)
+ (w/audio-record-end))
(provide 'wasp-audio)
;;; wasp-audio.el ends here
diff --git a/src/wasp-auth.el b/src/wasp-auth.el
new file mode 100644
index 00000000..06098d31
--- /dev/null
+++ b/src/wasp-auth.el
@@ -0,0 +1,37 @@
+;;; wasp-auth --- SSH-based authentication -*- lexical-binding: t; -*-
+;;; Commentary:
+;;; Code:
+
+(require 'f)
+
+(defcustom w/auth-sign-process "wasp-auth-sign"
+ "Name of process for signing messages."
+ :type '(string)
+ :group 'wasp)
+
+(defcustom w/auth-error-buffer " *wasp-auth-error*"
+ "Name of buffer used to store authentication errors."
+ :type '(string)
+ :group 'wasp)
+
+(defun w/auth-sign (msg k)
+ "Sign MSG using ~/.ssh/id_ed25519 and pass the signature to K."
+ (let* ((buf (generate-new-buffer " *wasp-auth-sign*"))
+ (proc
+ (make-process
+ :name w/auth-sign-process
+ :buffer buf
+ :stderr (get-buffer-create w/auth-error-buffer)
+ :command
+ `("ssh-keygen" "-Y" "sign" "-f" ,(f-canonical "~/.ssh/id_ed25519") "-n" "file" "-")
+ :sentinel
+ (lambda (_ _)
+ (let ((sig (with-current-buffer buf (buffer-string))))
+ (kill-buffer buf)
+ (funcall k sig))))))
+ (process-send-string proc msg)
+ (process-send-string proc "\n")
+ (process-send-eof proc)))
+
+(provide 'wasp-auth)
+;;; wasp-auth.el ends here
diff --git a/src/wasp-chat.el b/src/wasp-chat.el
index 5dc3c948..a3263e00 100644
--- a/src/wasp-chat.el
+++ b/src/wasp-chat.el
@@ -18,6 +18,7 @@
(defvar w/chat-minus2-count 0)
(defvar w/chat-icant-count 0)
(defvar w/chat-bpm-count 0)
+(defvar w/chat-apology-count 0)
(defvar w/chat-header-line "")
@@ -29,7 +30,8 @@
" Joel: " (format "%s" w/chat-joel-count)
" | ICANT: " (format "%s" w/chat-icant-count)
" | +2: " (format "%s" w/chat-plus2-count)
- " | -2: " (format "%s" w/chat-minus2-count))))
+ " | -2: " (format "%s" w/chat-minus2-count)
+ " | apology: " (format "%s" w/chat-apology-count))))
(define-derived-mode w/chat-overlay-mode special-mode "ClonkHead Stats"
"Major mode for displaying chatter statistics."
@@ -188,6 +190,7 @@ Optionally display the window at X, Y"
(add-hook 'post-command-hook #'w/handle-chat-overlay nil t)
(advice-add 'handle-switch-frame :before-while #'w/prevent-focus-frame)
(setq-local window-point-insertion-type t)
+ (setq-local cursor-type nil)
(cond
(t (setq-local header-line-format '(:eval w/chat-header-line)))))
@@ -262,6 +265,7 @@ Optionally, return the buffer NM in chat mode."
(w/daily-log (format "%s: %s" (w/. user msg) (w/. text msg)))
(let ((inhibit-read-only t))
(with-current-buffer (w/get-chat-buffer)
+ (setq-local cursor-type nil)
(goto-char (point-max))
(insert-text-button
(s-concat
@@ -302,7 +306,10 @@ Optionally, return the buffer NM in chat mode."
(propertize
bible-button-text
'face '(:foreground "#bbbbbb")))))
- (insert "\n"))))
+ (insert "\n"))
+ (when-let ((win (get-buffer-window (w/get-chat-buffer))))
+ (with-selected-window win
+ (goto-char (point-max))))))
(provide 'wasp-chat)
;;; wasp-chat.el ends here
diff --git a/src/wasp-event-handlers.el b/src/wasp-event-handlers.el
index 88ab5161..10bee34b 100644
--- a/src/wasp-event-handlers.el
+++ b/src/wasp-event-handlers.el
@@ -38,6 +38,10 @@
(cons '(monitor twitch chat incoming) #'w/twitch-handle-incoming-chat)
(cons '(monitor twitch redeem incoming) #'w/twitch-handle-redeem)
(cons
+ '(frontend redeem incoming)
+ (lambda (msg)
+ (w/twitch-handle-redeem-api msg)))
+ (cons
'(monitor twitch raid)
(lambda (msg)
(let ((user (car msg)))
@@ -67,7 +71,7 @@
'(monitor twitch subscribe)
(lambda (msg)
(let ((user (car msg)))
- ;; (w/thank-sub user)
+ (w/thank-sub user)
(w/model-region-word "skin" (format "thanks_%s_" user))
(w/friend-respond (format "%s just subscribed to the stream" user))
(w/write-chat-event (format "New subscriber: %s" user)))))
@@ -76,10 +80,11 @@
(lambda (msg)
(let ((user (car msg))
(subs (cadr msg)))
- (w/model-region-word "skin" (format "thanks_%s_" user))
- (w/friend-respond (format "%s just gifted subscriptions" user))
- (w/write-chat-event (format "%s gifted %d subs" user subs))
- (soundboard//play-monsterkill subs))))
+ (unless (s-equals? user "lcolonq")
+ (w/model-region-word "skin" (format "thanks_%s_" user))
+ (w/friend-respond (format "%s just gifted subscriptions" user))
+ (w/write-chat-event (format "%s gifted %d subs" user subs))
+ (soundboard//play-monsterkill subs)))))
(cons
'(monitor twitch poll begin)
(lambda (_)
diff --git a/src/wasp-model.el b/src/wasp-model.el
index c0f1848b..2a2b99be 100644
--- a/src/wasp-model.el
+++ b/src/wasp-model.el
@@ -36,8 +36,7 @@
(defun w/model-reset ()
"Reset the model palette."
(interactive)
- (w/pub '(avatar reset))
- (w/model-region-word "hair" "tranquility_"))
+ (w/pub '(avatar reset)))
(defun w/model-toggle (toggle)
"Toggle TOGGLE on model."
diff --git a/src/wasp-setup.el b/src/wasp-setup.el
new file mode 100644
index 00000000..bed8c275
--- /dev/null
+++ b/src/wasp-setup.el
@@ -0,0 +1,75 @@
+;;; wasp --- Stream setup -*- lexical-binding: t; -*-
+;;; Commentary:
+;;; Code:
+
+(require 'eyebrowse)
+(require 'wasp-utils)
+(require 'wasp-bus)
+(require 'wasp-db)
+(require 'wasp-chat)
+(require 'wasp-twitch)
+
+(defun w/setup-stream-layout ()
+ "Configure windows for streaming without buffers."
+ (interactive)
+ (eyebrowse-switch-to-window-config 0)
+ (eyebrowse-close-window-config)
+ (eyebrowse-switch-to-window-config 0)
+ (split-window-horizontally -70)
+ (split-window-vertically -10)
+ (enlarge-window 2)
+ (windmove-down)
+ (split-window-horizontally)
+ (windmove-right)
+ (windmove-right)
+ (split-window-vertically -28)
+ (windmove-down)
+ )
+
+(defun w/setup-stream ()
+ "Configure windows for streaming."
+ (interactive)
+ ;; initialization
+ (w/connect)
+ (w/db-connect)
+ (w/create-chat-overlay-frame)
+ (w/show-chat-overlay-frame nil)
+ (w/twitch-7tv-update-emotes)
+ (w/twitch-update-title)
+ (w/twitch-run-shoutout-timer)
+ (w/twitch-run-emote-frame-timer)
+ (w/run-model-timer)
+ (w/run-obs-timer)
+ (w/run-audio-record-end-timer)
+ (w/populate-bible-table)
+
+ (w/start-audio-record)
+ (w/start-chatsummary)
+ (w/start-fake-chatters)
+ (w/start-friend)
+
+ ;; layout
+ (eyebrowse-switch-to-window-config 0)
+ (eyebrowse-close-window-config)
+ (eyebrowse-switch-to-window-config 0)
+ (split-window-horizontally -70)
+ (split-window-vertically -10)
+ (find-file "~/notes/docket.org")
+ (enlarge-window 2)
+ (windmove-down)
+ (split-window-horizontally)
+ (switch-to-buffer w/friend-buffer)
+ (w/gizmo-tag-window)
+ (windmove-right)
+ (switch-to-buffer w/heartrate-buffer)
+ (w/gizmo-tag-window)
+ (windmove-right)
+ (split-window-vertically -28)
+ (switch-to-buffer w/chat-buffer)
+ (windmove-down)
+ (find-file "~/src/colonq")
+ (project-eshell)
+ )
+
+(provide 'wasp-setup)
+;;; wasp-setup.el ends here
diff --git a/src/wasp-twitch-chat-commands.el b/src/wasp-twitch-chat-commands.el
index 5c7d009f..51ce441d 100644
--- a/src/wasp-twitch-chat-commands.el
+++ b/src/wasp-twitch-chat-commands.el
@@ -23,6 +23,7 @@
(cons "MRBEAST" (lambda (_ _) (soundboard//play-clip "mrbeast.mp3")))
(cons "NICECOCK" (lambda (_ _) (soundboard//play-clip "pantsintoashes.mp3")))
(cons "hexadiCoding" (lambda (_ _) (soundboard//play-clip "developers.ogg")))
+ (cons "ProgrammingTime" (lambda (_ _) (soundboard//play-clip "emacslisp.ogg")))
(cons
"roguelike"
(lambda (user _)
@@ -43,12 +44,19 @@
(cons "bpm" (lambda (_ _) (cl-incf w/chat-bpm-count)))
(cons "BPM" (lambda (_ _) (cl-incf w/chat-bpm-count)))
(cons "heartrate" (lambda (_ _) (cl-incf w/chat-bpm-count)))
+ (cons "Heartrate" (lambda (_ _) (cl-incf w/chat-bpm-count)))
+ (cons "heart" (lambda (_ _) (cl-incf w/chat-bpm-count)))
+ (cons "Heart" (lambda (_ _) (cl-incf w/chat-bpm-count)))
(cons "!irc" (lambda (_ _) (w/twitch-say "#cyberspace on IRC at colonq.computer:26697 (over TLS)")))
(cons "IRC" (lambda (_ _) (w/twitch-say "#cyberspace on IRC at colonq.computer:26697 (over TLS)")))
(cons "!today" (lambda (_ _) (w/twitch-say (s-trim (w/slurp "~/today.txt")))))
+ (cons "!schedule" (lambda (_ _) (w/twitch-say "https://twitch.tv/LCOLONQ/schedule")))
(cons "!bingo" (lambda (_ _) (w/twitch-say "https://pub.colonq.computer/~prod/toy/bingo/")))
(cons
+ "!music"
+ (lambda (_ _) (w/twitch-say "https://www.youtube.com/playlist?list=PLQ_Vw7ACol3CN58_osDkbeKa14Hk-N-TZ")))
+ (cons
"!fish"
(lambda (_ _)
(w/twitch-say (shell-command-to-string "fishing"))))
@@ -63,6 +71,7 @@
;; (cons "!jetsWave" (lambda (_ _) (fig//twitch-say (fig/slurp "jetsWave.txt"))))
;; (cons "!forth" (lambda (_ _) (fig//twitch-say "https://github.com/lcolonq/giving")))
(cons "!oub" (lambda (_ _) (w/twitch-say "https://oub.colonq.computer")))
+ (cons "!cellar" (lambda (_ _) (w/twitch-say "https://pub.colonq.computer/~llll/cellar/index.html")))
(cons "!game" (lambda (_ _) (w/twitch-say "https://oub.colonq.computer")))
(cons "!voidstranger" (lambda (_ _) (w/twitch-say "https://store.steampowered.com/app/2121980/Void_Stranger/")))
(cons "!pubnix" (lambda (_ _) (w/twitch-say "https://pub.colonq.computer")))
diff --git a/src/wasp-twitch-redeems.el b/src/wasp-twitch-redeems.el
index d35253fd..3f544a01 100644
--- a/src/wasp-twitch-redeems.el
+++ b/src/wasp-twitch-redeems.el
@@ -47,6 +47,7 @@
"submit headline" 1
(lambda (user inp)
(w/write-chat-event (format "%s submitted a headline: %s" user inp))
+ (w/glossary-record inp)
(w/friend-journalism user inp)))
(list
"cycle gizmos" 1
@@ -54,6 +55,14 @@
(w/write-chat-event (format "%s cycled the gizmos" user))
(w/gizmo-cycle)))
(list
+ "allow streamer to drink" 1
+ (lambda (user _)
+ (w/write-chat-event (format "%s allowed the streamer to \"drink\"" user))))
+ (list
+ "deslug" 1
+ (lambda (user _)
+ (w/write-chat-event (format "%s inverted slug" user))))
+ (list
"talk to clone" 2
(lambda (user inp)
(push (cons user inp) w/twitch-chat-history)
@@ -74,10 +83,15 @@
(w/model-toggle "spin")))
(list
"forsen" 3
- (lambda (_ _)
+ (lambda (user _)
+ (w/write-chat-event (s-concat user " loudly exclaims forsenE"))
(soundboard//play-clip "cave3.ogg" 75)
(w/model-toggle "forsen")))
- (list "SEASICKNESS GENERATOR" 3 (lambda (_ _) (w/model-toggle "zoom_wave")))
+ (list
+ "SEASICKNESS GENERATOR" 3
+ (lambda (user _)
+ (w/write-chat-event (s-concat user " is a salty sea dog"))
+ (w/model-toggle "zoom_wave")))
(list
"The Pharaoh's Curse" 3
(lambda (user _)
@@ -92,15 +106,18 @@
(w/model-region-user-avatar "hair" user)))
(list
"INTJ stare" 3
- (lambda (_ _)
+ (lambda (user _)
+ (w/write-chat-event (format "%s suggested a little more sodium chloride next time" user))
(w/obs-activate-toggle 'intj-stare)))
(list
"Live LCOLONQ Reaction" 3
- (lambda (_ _)
+ (lambda (user _)
+ (w/write-chat-event (format "%s demanded extremely \"hype\" reactions, &c." user))
(w/obs-activate-toggle 'live-reaction)))
(list
"Live friend Reaction" 3
- (lambda (_ _)
+ (lambda (user _)
+ (w/write-chat-event (format "%s demanded extremely \"hype\" reactions, &c. but from \"friend\"!?" user))
(w/obs-activate-toggle 'live-friend-reaction)))
(list
"bells of bezelea" 4
@@ -202,7 +219,8 @@
(w/obs-activate-toggle 'clickbait msg)))
(list
"antipiracy" 500
- (lambda (_ _)
+ (lambda (user _)
+ (w/twitch-say (format "%s does not condone any form of copyright infringement whatsoever." user))
(w/obs-activate-toggle 'activate-nixos)))
(list
"super idol" 500
@@ -215,10 +233,12 @@
(let* ((sp (s-split " " inp))
(spell (car sp))
(target (cadr sp)))
- (when (and spell target (stringp spell) (stringp target))
- (w/write-chat-event (s-concat user " hexed " target ": " spell))
- (when-let ((type (alist-get spell w/hex-types nil nil #'s-equals?)))
- (w/hex target user type))))))
+ (if (and spell target (stringp spell) (stringp target))
+ (progn
+ (w/write-chat-event (s-concat user " hexed " target " with: " spell))
+ (when-let ((type (alist-get spell w/hex-types nil nil #'s-equals?)))
+ (w/hex target user type)))
+ (w/write-chat-event (s-concat user "'s hex fizzled out with a puff of smoke!"))))))
(list
"VIPPER" 1000
(lambda (user inp)
@@ -240,6 +260,11 @@
(lambda () (soundboard//play-clip "gong.ogg")))
(w/write-chat-event (s-concat user " established total clarity"))
(w/obs-activate-toggle 'total-clarity)))
+ (list
+ "canonize me" 20000
+ (lambda (user _)
+ (w/write-chat-event (s-concat user " was canonized!"))
+ (w/bible-canonize user)))
))
(provide 'wasp-twitch-redeems)
diff --git a/src/wasp-twitch.el b/src/wasp-twitch.el
index b365a0bc..cb316fb6 100644
--- a/src/wasp-twitch.el
+++ b/src/wasp-twitch.el
@@ -55,6 +55,7 @@
(defvar w/twitch-redeems nil)
(defvar w/twitch-chat-commands nil)
(defvar w/twitch-gamer-counter 0)
+(defvar w/twitch-sub-alert-cooldown 0)
(defun w/twitch-api-endpoint-test ()
"Get LOC from the Twitch API, passing the returned JSON to K."
@@ -151,7 +152,8 @@
(defun w/twitch-get-7tv-emote (name)
"Retrieve the 7TV emote ID for NAME."
- (ht-get w/twitch-7tv-emote-map name))
+ (when w/twitch-7tv-emote-map
+ (ht-get w/twitch-7tv-emote-map name)))
(defun w/twitch-user-avatar-path (user)
"Get the path to USER's avatar."
@@ -365,10 +367,11 @@ CALLBACK will be passed the winner when the poll concludes."
"Ensure that EMOTEID exists in the cache and then call K."
(let* ((path (w/twitch-7tv-emote-path emoteid))
(url (format "https://cdn.7tv.app/emote/%s/1x.webp" emoteid)))
- (unless (f-exists? path)
+ (if (f-exists? path)
+ (funcall k)
(make-process
:name "wasp-download-7tv-emote"
- :buffer nil
+ :buffer " *wasp-download-7tv-emote-output*"
:command (list "get_7tv_fixed" url path)
:sentinel
(lambda (_ _)
@@ -381,6 +384,17 @@ CALLBACK will be passed the winner when the poll concludes."
(defun w/twitch-download-7tv-emote (emoteid)
"Ensure that EMOTEID exists in the cache."
(w/twitch-download-7tv-emote-then emoteid (lambda () nil)))
+(defun w/twitch-download-many-7tv-emotes (xs)
+ "Download every 7TV emote in XS."
+ (when xs
+ (message "Downloading emote: %s" (car xs))
+ (w/twitch-download-7tv-emote-then
+ (w/twitch-get-7tv-emote (car xs))
+ (lambda ()
+ (run-with-timer
+ 1 nil
+ (lambda ()
+ (w/twitch-download-many-7tv-emotes (cdr xs))))))))
(defun w/twitch-add-7tv-emotes (msg)
"Propertize MSG with images corresponding to 7TV emotes."
@@ -469,7 +483,8 @@ CALLBACK will be passed the winner when the poll concludes."
(defun w/twitch-badges-sigil (badges)
"Return the sigil character BADGES for the current user."
- (let ((equity (alist-get :equity w/user-current)))
+ (let ((equity (alist-get :equity w/user-current))
+ (name (s-downcase w/user-current-name)))
(apply
#'s-concat
(-non-nil
@@ -479,19 +494,23 @@ CALLBACK will be passed the winner when the poll concludes."
(when (-contains? badges "artist-badge/1") "πŸ–ŒοΈ")
(when (and equity (> equity 0))
(cond ;; The Equity Lords
- ((s-equals? (s-downcase w/user-current-name) "bezelea") "β™ΏπŸ””")
- ((s-equals? (s-downcase w/user-current-name) "altovt") "πŸ“ˆ")
- ((s-equals? (s-downcase w/user-current-name) "prodzpod") "πŸŒŒπŸŽ‘")
- ((s-equals? (s-downcase w/user-current-name) "faeliore") "😹")
- ((s-equals? (s-downcase w/user-current-name) "vasher_1025") "πŸ•΄")
- ((s-equals? (s-downcase w/user-current-name) "leadengin") "πŸ’ˆ")
- ;; ((s-equals? (s-downcase w/user-current-name) "kettlestew") "")
- ;; ((s-equals? (s-downcase w/user-current-name) "blazynights") "")
- ;; ((s-equals? (s-downcase w/user-current-name) "must_broke_") "")
- ;; ((s-equals? (s-downcase w/user-current-name) "bvnanana") "")
- ((s-equals? (s-downcase w/user-current-name) "venorrak") "πŸ“Ί")
- ;; ((s-equals? (s-downcase w/user-current-name) "tf_tokyo") "")
- ;; clone is lord ((s-equals? (s-downcase w/user-current-name) "liquidcake1") "")
+ ((s-equals? name "bezelea") "β™ΏπŸ””")
+ ((s-equals? name "altovt") "πŸ“ˆ")
+ ((s-equals? name "prodzpod") "πŸŒŒπŸŽ‘")
+ ((s-equals? name "faeliore") "😹")
+ ((s-equals? name "vasher_1025") "πŸ•΄")
+ ((s-equals? name "leadengin") "πŸ’ˆ")
+ ;; ((s-equals? name "kettlestew") "")
+ ((s-equals? name "blazynights") "πŸ€„")
+ ;; ((s-equals? name "must_broke_") "")
+ ((s-equals? name "bvnanana") "πŸ§‰")
+ ((s-equals? name "venorrak") "πŸ“Ί")
+ ;; ((s-equals? name "tf_tokyo") "")
+ ((s-equals? name "devts_de") "βˆƒ")
+ ((s-equals? name "trap_exit") "πŸ’€")
+ ((s-equals? name "essento") "πŸ₯š")
+ ((s-equals? name "tyumici") "🀌")
+ ;; clone is lord ((s-equals? name "liquidcake1") "")
(t "EL.")))
(when (-contains? badges "vip/1") "πŸ’Ž")
(when (-contains? badges "subscriber/0") "πŸ’»"))))))
@@ -538,24 +557,30 @@ CALLBACK will be passed the winner when the poll concludes."
(when (s-contains? (car it) text)
(funcall (cdr it) user text))))))))
+(defun w/twitch-handle-redeem-helper (user redeem input &optional limit)
+ "Handle the channel point redeem REDEEM from USER with INPUT.
+Optionally, only apply redeems with point costs less than LIMIT."
+ (let ((handler (alist-get redeem w/twitch-redeems nil nil #'s-equals?)))
+ (if handler
+ (if (< (car handler) 1000)
+ (w/user-bind
+ user
+ (lambda ()
+ (condition-case err
+ (funcall (cadr handler) user input)
+ (error
+ (w/write-chat-event (format "Error during redeem: %s" err))))))
+ (w/write-chat-event (format "User %s attempted to activate overly expensive redeem \"%s\" via API" user redeem)))
+ (w/write-chat-event (format "Unknown channel point redeem: %S" redeem)))))
+
(defun w/twitch-handle-redeem (r)
"Handle the channel point redeem R."
(w/write-log r)
(let* ((user (car r))
(redeem (cadr r))
(encoded-input (caddr r))
- (input (when encoded-input (w/decode-string encoded-input)))
- (handler (alist-get redeem w/twitch-redeems nil nil #'s-equals?)))
- (if handler
- (w/user-bind
- user
- (lambda ()
- (condition-case err
- (funcall (cadr handler) user input)
- (error
- (w/write-chat-event (format "Error during redeem: %s" err))
- ))))
- (w/write-log (format "Unknown channel point redeem: %S" redeem)))))
+ (input (when encoded-input (w/decode-string encoded-input))))
+ (w/twitch-handle-redeem-helper user redeem input)))
(defun w/twitch-handle-redeem-api (r)
"Handle a channel point redeem R coming from the API."
@@ -565,12 +590,8 @@ CALLBACK will be passed the winner when the poll concludes."
(encoded-input (caddr r))
(user (when encoded-user (w/decode-string encoded-user)))
(redeem (when encoded-redeem (w/decode-string encoded-redeem)))
- (input (when encoded-input (w/decode-string encoded-input)))
- (handler (alist-get redeem w/twitch-redeems nil nil #'s-equals?)))
- (when (< (car handler) 1000)
- (if handler
- (w/user-bind user (lambda () (funcall (cadr handler) user input)))
- (w/write-log (format "Unknown channel point redeem: %S" redeem))))))
+ (input (when encoded-input (w/decode-string encoded-input))))
+ (w/twitch-handle-redeem-helper user redeem input)))
(provide 'wasp-twitch)
;;; wasp-twitch.el ends here
diff --git a/src/wasp-user-whitelist.el b/src/wasp-user-whitelist.el
index 6daa0853..748ebfd7 100644
--- a/src/wasp-user-whitelist.el
+++ b/src/wasp-user-whitelist.el
@@ -198,6 +198,23 @@
"neural_works"
"slendidev"
"dehidehinotfromfinland"
+ "machiavellianalloy"
+ "ywxslzak"
+ "sgtnubbles"
+ "mistresskell"
+ "kokupsi"
+ "capstasher"
+ "polyglitch"
+ "itbeblockhead"
+ "faceoftrolls"
+ "zoft_fae"
+ "unlessgames"
+ "machka6"
+ "airhomer99"
+ "geegxp"
+ "extremelybig"
+ "ostas_"
+ "mcschwartz2"
)))
(provide 'wasp-user-whitelist)
diff --git a/src/wasp-user.el b/src/wasp-user.el
index d5231ae1..6694b2f2 100644
--- a/src/wasp-user.el
+++ b/src/wasp-user.el
@@ -113,5 +113,15 @@ Save it back to the database after K returns."
(lambda (qs)
(w/user-set "__quotes__" (cons (cons q user) qs)))))
+(defun w/user-crown (user)
+ "Increment USER's equity status."
+ (w/user-get
+ user
+ (lambda (u)
+ (let ((old (or (alist-get :equity u) 0)))
+ (setf (alist-get :equity u) (+ old 1)))
+ (print u)
+ (w/user-set user u))))
+
(provide 'wasp-user)
;;; wasp-user.el ends here
diff --git a/src/wasp-utils.el b/src/wasp-utils.el
index c0f4ec54..78751646 100644
--- a/src/wasp-utils.el
+++ b/src/wasp-utils.el
@@ -40,6 +40,10 @@ Return nil on error."
(w/write-line (format "%s" line) face)
(goto-char (point-max))))
+(defun w/append-file (s path)
+ "Append S to the file at PATH."
+ (f--write-bytes (encode-coding-string s 'utf-8) path t))
+
(defmacro w/defstruct (name &rest body)
"Define a structure with NAME (with the constructor under the w/ namespace).
BODY is passed directly to `cl-defstruct'."
@@ -54,7 +58,7 @@ BODY is passed directly to `cl-defstruct'."
(defun w/pick-random (xs)
"Pick a random element of XS."
- (nth (random (length xs)) xs))
+ (and xs (nth (random (length xs)) xs)))
(defun w/shuffle (s)
"Shuffle S."
diff --git a/src/wasp-voice-commands.el b/src/wasp-voice-commands.el
index 20357bf5..1af2bd7e 100644
--- a/src/wasp-voice-commands.el
+++ b/src/wasp-voice-commands.el
@@ -9,11 +9,13 @@
(require 'wasp-obs)
(setq
- w/stream-transcribe-voice-commands
+ w/audio-voice-commands
(list
(cons "mr. beast" (lambda () (soundboard//play-clip "mrbeast.mp3")))
(cons "joel" (lambda () (w/twitch-say (w/pick-random (list "Joel" "EvilJoel")))))
(cons "i can't" (lambda () (cl-incf w/chat-icant-count) (w/chat-update-header-line)))
+ (cons "sorry" (lambda () (cl-incf w/chat-apology-count) (w/chat-update-header-line)))
+ (cons "apologies" (lambda () (cl-incf w/chat-apology-count) (w/chat-update-header-line)))
(cons "lua"
(lambda ()
(progn (w/obs-toggle-brazil)
diff --git a/wasp.el b/wasp.el
index 5584b68b..3e075f18 100644
--- a/wasp.el
+++ b/wasp.el
@@ -10,6 +10,7 @@
(add-to-list 'load-path (f-canonical "./src/contrib/"))
(add-to-list 'load-path (f-canonical "~/src/muzak/"))
+(add-to-list 'load-path (f-canonical "~/src/soundboard/"))
;; do not open this on stream
(require 'wasp-sensitive)
@@ -27,10 +28,13 @@
(require 'wasp-chat)
(require 'wasp-twitch)
(require 'wasp-overlay)
+(require 'wasp-auth)
+(require 'wasp-setup)
;; gizmos
(require 'wasp-pronunciation)
(require 'wasp-biblicality)
+(require 'wasp-glossary)
(require 'wasp-newspaper)
(require 'wasp-friend)
(require 'wasp-fakechat)
@@ -62,22 +66,6 @@
;; user contrib
(require 'muzak)
-;; initialization
-(w/connect)
-(w/db-connect)
-(w/create-chat-overlay-frame)
-(w/show-chat-overlay-frame nil)
-(w/twitch-7tv-update-emotes)
-(w/twitch-update-title)
-
-(w/twitch-run-shoutout-timer)
-(w/twitch-run-emote-frame-timer)
-(w/run-model-timer)
-(w/run-obs-timer)
-(w/run-stream-transcribe-timer)
-
-(w/populate-bible-table)
-
;; (defun w/fix-user-database-ok (user)
;; "Fix USER's database entry."
;; (w/user-set user (fig//db2-serialize-old-entry (fig//load-db-old user))))