From d93ab7e848bf0f4bc1087504eecd7c959d19bf6c Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Fri, 13 Sep 2024 13:52:38 -0400 Subject: Update :3 --- src/gizmo/wasp-aoc.el | 75 +++++ src/gizmo/wasp-bless.el | 94 ++++++ src/gizmo/wasp-chatsummary.el | 62 ++++ src/gizmo/wasp-copfish.el | 60 ++++ src/gizmo/wasp-curse.el | 168 ++++++++++ src/gizmo/wasp-cyclone.el | 41 +++ src/gizmo/wasp-debate.el | 191 +++++++++++ src/gizmo/wasp-density.el | 22 ++ src/gizmo/wasp-dna.el | 693 +++++++++++++++++++++++++++++++++++++++- src/gizmo/wasp-fake-chatters.el | 105 ++++++ src/gizmo/wasp-fakechat.el | 25 ++ src/gizmo/wasp-friend.el | 225 ++++++------- src/gizmo/wasp-gcp.el | 52 +++ src/gizmo/wasp-gdq.el | 90 ++++++ src/gizmo/wasp-hex.el | 194 +++++++++++ src/gizmo/wasp-hexamedia.el | 79 +++++ src/gizmo/wasp-prod.el | 80 +++++ src/gizmo/wasp-pronunciation.el | 4 + src/gizmo/wasp-shindaggers.el | 77 +++++ src/gizmo/wasp-uwoomfie.el | 72 +++++ src/gizmo/wasp-wikipedia.el | 71 ++++ src/gizmo/wasp-youtube.el | 75 +++++ 22 files changed, 2446 insertions(+), 109 deletions(-) create mode 100644 src/gizmo/wasp-aoc.el create mode 100644 src/gizmo/wasp-bless.el create mode 100644 src/gizmo/wasp-chatsummary.el create mode 100644 src/gizmo/wasp-copfish.el create mode 100644 src/gizmo/wasp-curse.el create mode 100644 src/gizmo/wasp-cyclone.el create mode 100644 src/gizmo/wasp-debate.el create mode 100644 src/gizmo/wasp-density.el create mode 100644 src/gizmo/wasp-gcp.el create mode 100644 src/gizmo/wasp-gdq.el create mode 100644 src/gizmo/wasp-hex.el create mode 100644 src/gizmo/wasp-hexamedia.el create mode 100644 src/gizmo/wasp-prod.el create mode 100644 src/gizmo/wasp-shindaggers.el create mode 100644 src/gizmo/wasp-uwoomfie.el create mode 100644 src/gizmo/wasp-wikipedia.el create mode 100644 src/gizmo/wasp-youtube.el (limited to 'src/gizmo') diff --git a/src/gizmo/wasp-aoc.el b/src/gizmo/wasp-aoc.el new file mode 100644 index 00000000..5fa58582 --- /dev/null +++ b/src/gizmo/wasp-aoc.el @@ -0,0 +1,75 @@ +;;; wasp-aoc --- Advent of Code API access -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'f) +(require 'ht) +(require 'json) +(require 'request) +(require 'wasp-sensitive) + +(defcustom w/aoc-leaderboard-url "https://adventofcode.com/2023/leaderboard/private/view/3307583.json" + "URL for Advent of Code API." + :type '(string) + :group 'wasp) + +(defvar w/aoc-last-response nil) +(defvar w/aoc-user-stars nil) +(defconst w/aoc-name-map + '(("exodrifter_" . "exodrifter") + ("cephon_altera" . "lainlayer") + ("monochrome_0" . "monochrome") + ("yoink2000" . "darius1702") + ("lukeisun_" . "lukeisun") + ("dwinkley_" . "dwinkley") + ("lcolonq" . "llll colonq") + ("fn_lumi" . "lumi") + ("leadengin" . "leaden") + ("vasher_1025" . "vash3r") + ("andrewdtr" . "drawthatredstone"))) + +(defun w/aoc-max-stars () + "Return the maximum Advent of Code stars for today." + (* 2 (string-to-number (format-time-string "%d" (current-time))))) + +(defun w/aoc-lookup-stars (user) + "Retrieve the Advent of Code stars for USER." + (let* ((duser (s-downcase user)) + (cuser (s-downcase (alist-get duser w/aoc-name-map duser nil #'s-equals?)))) + (alist-get cuser w/aoc-user-stars nil nil #'s-equals?))) + +(defun w/aoc-fetch-api (k) + "Retrieve the current Advent of Code API. +Pass the resulting JSON to K." + (request + w/aoc-leaderboard-url + :type "GET" + :headers + `(("Cookie" . ,(format "session=%s" w/sensitive-aoc-session-cookie))) + :parser #'json-parse-buffer + :success + (cl-function + (lambda (&key data &allow-other-keys) + (setq w/aoc-last-response data) + (funcall k data)))) + nil) + +(defun w/aoc-update-user-stars () + "Update the Advent of Code stars list." + (w/aoc-fetch-api + (lambda (data) + (setf + w/aoc-user-stars + (--map + (cons (s-downcase (car it)) (cdr it)) + (--filter + (stringp (car it)) + (--map + (cons (ht-get it "name") (ht-get it "stars")) + (ht-values (ht-get data "members"))))))))) +;; (w/aoc-update-user-stars) + +(provide 'wasp-aoc) +;;; wasp-aoc.el ends here diff --git a/src/gizmo/wasp-bless.el b/src/gizmo/wasp-bless.el new file mode 100644 index 00000000..109b2f35 --- /dev/null +++ b/src/gizmo/wasp-bless.el @@ -0,0 +1,94 @@ +;;; wasp-bless --- The Blessing -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'cl-lib) +(require 'dash) +(require 's) +(require 'json) +(require 'wasp-chat) +(require 'wasp-model) + +(defcustom w/bless-buffer " *wasp-bless*" + "Name of buffer used to store Bless output." + :type '(string) + :group 'wasp) + +(defun w/bless-error (e) + "Report an error E." + (message (alist-get 'message e))) + +(defun w/bless-parse-value (j) + "Construct an Emacs Lisp value representation of the value J." + (let ((tag (alist-get 'tag j))) + (cond + ((s-equals? tag "ValueInteger") (alist-get 'contents j)) + ((s-equals? tag "ValueArray") + (-map #'w/bless-parse-value (alist-get 'contents j))) + (t (message "Unknown Bless tag: %s" tag))))) + +(defun w/bless-parse-effect (j) + "Construct an Emacs Lisp value representation of the effect J." + (let ((tag (alist-get 'tag j)) + (c (alist-get 'contents j))) + (cond + ((s-equals? tag "EffectPrint") `(print ,(w/bless-parse-value c))) + ((s-equals? tag "EffectPrintBackwards") `(print-backwards ,(w/bless-parse-value c))) + ((s-equals? tag "EffectSoundboard") `(soundboard ,(w/bless-parse-value c))) + ((s-equals? tag "EffectModelToggle") `(model-toggle ,(w/bless-parse-value c))) + ))) + +(defun w/bless-parse-stack (j) + "Construct an Emacs Lisp value representation of the stack J." + (-map #'w/bless-parse-value j)) + +(defun w/bless-parse-effects (j) + "Construct an Emacs Lisp value representation of the effects J." + (-map #'w/bless-parse-effect j)) + +(defun w/bless-apply-effect (e) + "Apply the list of side effects E." + (cl-case (car e) + (print (w/write-chat-event (format "%s" (cadr e)))) + (print-backwards (w/write-chat-event (reverse (format "%s" (cadr e))))) + (soundboard (soundboard//play-clip (cadr e))) + (model-toggle (w/model-toggle (cadr e))) + (t (message "Unknown effect tag: %s" (car e))))) + +(defun w/bless-eval (str k &optional fuel) + "Bless STR according to the nature of the blessing. +Pass the result to K. +Optionally limit evaluation to FUEL steps." + (let ((buf (generate-new-buffer w/bless-buffer))) + (with-current-buffer buf + (erase-buffer)) + (make-process + :name "wasp-bless-eval" + :buffer buf + :command `("bless" "-j" "eval" ,@(if fuel (list "--fuel" (number-to-string fuel)) nil) ,str) + :sentinel + (lambda (_ _) + (let* ((s (with-current-buffer buf (buffer-string))) + (j (json-read-from-string s)) + (status (alist-get 'status j))) + (kill-buffer buf) + (if (s-equals? status "success") + (funcall + k + (cons + (w/bless-parse-stack (alist-get 'stack (alist-get 'data j))) + (w/bless-parse-effects (alist-get 'effects (alist-get 'data j))))) + (w/bless-error (alist-get 'data j)))))))) + +(defun w/bless (str &optional fuel) + "Run the Bless program STR and apply its side effects. +Optionally limit evaluation to FUEL steps." + (w/bless-eval + str + (lambda (res) + (--each (cdr res) + (w/bless-apply-effect it))) + fuel)) + +(provide 'wasp-bless) +;;; wasp-bless.el ends here diff --git a/src/gizmo/wasp-chatsummary.el b/src/gizmo/wasp-chatsummary.el new file mode 100644 index 00000000..5a6a27ae --- /dev/null +++ b/src/gizmo/wasp-chatsummary.el @@ -0,0 +1,62 @@ +;;; wasp-chatsummary --- Stealing a YouTube feature -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'wasp-ai) +(require 'wasp-friend) + +(defcustom w/chatsummary-buffer "*wasp-chatsummary*" + "Name of buffer used to display chat summary." + :type '(string) + :group 'wasp) + +(define-derived-mode w/chatsummary-mode special-mode "Chat Summary" + "Major mode for displaying chat summary." + :group 'w + (setq-local cursor-type nil) + (visual-line-mode)) + +(defun w/chatsummary-get-buffer () + "Return the chatsummary buffer." + (unless (get-buffer w/chatsummary-buffer) + (with-current-buffer (get-buffer-create w/chatsummary-buffer) + (w/chatsummary-mode))) + (get-buffer w/chatsummary-buffer)) + +(defun w/update-chatsummary () + "Update the chat summary." + (w/ai + (w/friend-journalism-input) + (lambda (d) + (when-let* ((d) + (resp (s-trim d))) + (with-current-buffer (w/chatsummary-get-buffer) + (let ((inhibit-read-only t)) + (erase-buffer) + (w/write-line "Chat summary" 'bold) + (w/write-line resp))))) + "Given a list of recent YouTube chatter activity, produce a summary of the topics discussed. The summary should be very short, maximum two sentences total. Do not introduce yourself. Simply provide a short summary of the chat. Do not mention specific names of chatters. Keep it succinct. Do not mention that you are summarizing YouTube activity. Be laconic.")) + +(defvar w/chatsummary-timer nil) +(defun w/run-chatsummary-timer () + "Run the chat summary timer." + (when w/chatsummary-timer + (cancel-timer w/chatsummary-timer)) + (w/update-chatsummary) + (setq + w/chatsummary-timer + (run-with-timer 120 nil #'w/run-chatsummary-timer))) + +(defun w/start-chatsummary () + "Enable fake chatters." + (interactive) + (w/run-chatsummary-timer)) + +(defun w/stop-chatsummary () + "Disable fake chatters." + (interactive) + (cancel-timer w/chatsummary-timer) + (setq w/chatsummary-timer nil)) + +(provide 'wasp-chatsummary) +;;; wasp-chatsummary.el ends here diff --git a/src/gizmo/wasp-copfish.el b/src/gizmo/wasp-copfish.el new file mode 100644 index 00000000..024c27dc --- /dev/null +++ b/src/gizmo/wasp-copfish.el @@ -0,0 +1,60 @@ +;;; wasp-copfish --- Copfish interface -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'f) +(require 'ht) +(require 'rx) +(require 'cl-lib) +(require 'request) +(require 'dom) +(require 'wasp-user) + +(defcustom w/copfish-server "https://cop.fish/api/" + "Server URL for Copfish." + :type '(string) + :group 'wasp) + +(defvar w/copfish-last-response nil) + +(defun w/copfish-get (loc k) + "Get LOC from Copfish, passing the returned HTML to K." + (setf request-message-level -1) + (request + (s-concat w/copfish-server loc) + :type "GET" + :parser #'buffer-string + :success + (cl-function + (lambda (&key data &allow-other-keys) + (setq w/copfish-last-response data) + (funcall k data)))) + t) + +(defun w/copfish-get-fish (user k) + "Retrieve USER's fish ratio from copfish API. +Pass the resulting fraction to K." + (w/copfish-get + (s-concat "fishdex/" user) + (lambda (s) + (let ((sp (s-split " " s))) + (when (= (length sp) 2) + (funcall k (cons (string-to-number (car sp)) (string-to-number (cadr sp))))))))) + +(defvar w/copfish-user-cache nil) +(defun w/copfish-update-user (user) + "Update USER data from Copfish." + (unless (-contains? w/copfish-user-cache user) + (add-to-list 'w/copfish-user-cache user) + (w/copfish-get-fish + user + (lambda (ct) + (w/user-bind + user + (lambda () + (setf (alist-get :copfish-ratio w/user-current) ct))))))) + +(provide 'wasp-copfish) +;;; wasp-copfish.el ends here diff --git a/src/gizmo/wasp-curse.el b/src/gizmo/wasp-curse.el new file mode 100644 index 00000000..95149fef --- /dev/null +++ b/src/gizmo/wasp-curse.el @@ -0,0 +1,168 @@ +;;; wasp-curse --- A curse -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'f) +(require 'ht) +(require 'cl-lib) + +(defun w/curse-run (prog) + "Run PROG and return the output." + (let ((tmpfile (make-temp-file "curse.js"))) + (with-temp-file tmpfile (insert prog)) + (shell-command-to-string (format "node '%s'" tmpfile)))) + +(defun w/curse-name (name) + "Convert NAME to a cursed name." + (replace-regexp-in-string "[-]" "_" (format "%s" name))) + +(defconst w/binary-ops + '((or . "||") + (and . "&&") + (> . ">") + (>= . ">=") + (< . "<") + (<= . "<=") + (= . "===") + (% . "%") + (/ . "/") + (bit-or . "|") + (bit-and . "&") + (bit-xor . "^"))) + +(defun w/curse-expr (expr) + "Translate EXPR according to the nature of the curse." + (cond + ((null expr) "(null)") + ((listp expr) + (pcase (car expr) + ((or '+ '- '*) + (format + "(%s)" + (s-join (format "%s" (car expr)) (-map #'w/curse-expr (cdr expr))))) + ((pred (lambda (x) (alist-get x w/binary-ops))) + (format + "(%s)" + (s-join (alist-get (car expr) w/binary-ops) (-map #'w/curse-expr (cdr expr))))) + ((or '<< '>>) + (format + "(%s%s%s)" + (w/curse-expr (cadr expr)) + (format "%s" (car expr)) + (w/curse-expr (caddr expr)))) + ('comment "(null)") + ('lambda + (format + "((%s)=>(%s))" + (s-join "," (-map #'w/curse-name (cadr expr))) + (s-join "," (-map #'w/curse-expr (cddr expr))))) + ('async-lambda + (format + "(async(%s)=>(%s))" + (s-join "," (-map #'w/curse-name (cadr expr))) + (s-join "," (-map #'w/curse-expr (cddr expr))))) + ('if + (format + "(%s?%s:%s)" + (w/curse-expr (cadr expr)) + (w/curse-expr (caddr expr)) + (w/curse-expr (cadddr expr)))) + ('define + (format + "(globalThis.%s=%s)" + (w/curse-name (cadr expr)) + (w/curse-expr (caddr expr)))) + ('set + (format + "(%s=%s)" + (w/curse-name (cadr expr)) + (w/curse-expr (caddr expr)))) + ('aset + (format + "(%s[%s]=%s)" + (w/curse-name (cadr expr)) + (w/curse-expr (caddr expr)) + (w/curse-expr (cadddr expr)))) + ('new + (format + "(new %s(%s))" + (w/curse-expr (cadr expr)) + (s-join "," (-map #'w/curse-expr (cddr expr))))) + ('await + (format + "(await %s)" + (w/curse-expr (cadr expr)))) + ('not + (format + "(!%s)" + (w/curse-expr (cadr expr)))) + ('let + (format + "(((%s)=>(%s))(%s))" + (s-join "," (--map (w/curse-name (car it)) (cadr expr))) + (s-join "," (-map #'w/curse-expr (cddr expr))) + (s-join "," (--map (w/curse-expr (cadr it)) (cadr expr))))) + ('async-let + (format + "((async(%s)=>(%s))(%s))" + (s-join "," (--map (w/curse-name (car it)) (cadr expr))) + (s-join "," (-map #'w/curse-expr (cddr expr))) + (s-join "," (--map (w/curse-expr (cadr it)) (cadr expr))))) + ('do + (format + "((()=>(%s))())" + (s-join "," (-map #'w/curse-expr (cdr expr))))) + ('iota + (format + "[...Array(%s).keys()]" + (w/curse-expr (cadr expr)))) + ('array + (format + "[%s]" + (s-join "," (-map #'w/curse-expr (cdr expr))))) + ('object + (format + "{%s}" + (s-join + "," + (--map (format "%s:%s" (w/curse-name (car it)) (w/curse-expr (cadr it))) (cdr expr))))) + ('@ + (format + "((%s)[%s])" + (w/curse-expr (cadr expr)) + (w/curse-expr (caddr expr)))) + (_ + (format + "((%s)(%s))" + (w/curse-expr (car expr)) + (s-join "," (-map #'w/curse-expr (cdr expr))))) + )) + ((symbolp expr) (w/curse-name expr)) + ((numberp expr) (format "%s" expr)) + ((stringp expr) (format "\"%s\"" expr)) + (t "(null)"))) + +(defun w/curse-current-buffer () + "Transmute the current buffer according to the curse." + (interactive) + (let* ((srcfile (buffer-file-name)) + (jspath (s-concat (f-base srcfile) ".js")) + (src (buffer-string))) + (with-temp-buffer + (insert src) + (goto-char (point-min)) + (let ((acc "") + (line (read (current-buffer)))) + (while (and line (not (eobp))) + (setf acc (s-concat acc (w/curse-expr line) ";")) + (setf + line + (condition-case nil + (read (current-buffer)) + (error nil)))) + (write-region acc nil jspath))))) + +(provide 'wasp-curse) +;;; wasp-curse.el ends here diff --git a/src/gizmo/wasp-cyclone.el b/src/gizmo/wasp-cyclone.el new file mode 100644 index 00000000..d7a0d02d --- /dev/null +++ b/src/gizmo/wasp-cyclone.el @@ -0,0 +1,41 @@ +;;; wasp-cyclone --- Gizmocycling -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'wasp-utils) +(require 'wasp-friend) +(require 'wasp-heartrate) +(require 'wasp-chatsummary) + +(defconst w/gizmo-buffer-names + (list + w/friend-buffer + w/heartrate-buffer + w/chatsummary-buffer)) + +(defvar w/gizmo-windows (list)) + +(defun w/gizmo-tag-window () + "Tag the current window as containing a gizmo." + (interactive) + (when-let ((w (selected-window))) + (add-to-list 'w/gizmo-windows w))) + +(defun w/gizmo-cycle-window (w) + "Cycle the gizmo in W." + (when-let* + ((cur (buffer-name (window-buffer w))) + (idx (--find-index (equal it cur) w/gizmo-buffer-names)) + (bufs (-non-nil (-map #'get-buffer w/gizmo-buffer-names))) + (nidx (mod (+ idx 1) (length bufs))) + (buf (nth nidx bufs))) + (set-window-buffer w buf))) + +(defun w/gizmo-cycle () + "Cycle all gizmo-bearing windows." + (interactive) + (--each w/gizmo-windows + (w/gizmo-cycle-window it))) + +(provide 'wasp-cyclone) +;;; wasp-cyclone.el ends here diff --git a/src/gizmo/wasp-debate.el b/src/gizmo/wasp-debate.el new file mode 100644 index 00000000..f0280295 --- /dev/null +++ b/src/gizmo/wasp-debate.el @@ -0,0 +1,191 @@ +;;; wasp-debate --- "friend" is the baiter -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'wasp-utils) +(require 'wasp-ai) +(require 'wasp-obs) +(require 'wasp-twitch) +(require 'wasp-dna) +(require 'wasp-fakechat) + +(defconst + w/debate-example-topics + '(("is a hot dog a sandwich?" "not a sandwich" "is a sandwich") + ("are our personalities defined by nature or nurture?" "nature" "nurture") + ("is pineapple a good pizza topping?" "yes" "no") + ("is metroidvania a coherent name for a video game genre?" "yes" "no") + ("do humans have free will?" "yes" "no") + ("does LCOLONQ have real background sounds?" "yes" "no") + ("is LCOLONQ a househusband?" "yes" "no") + ("how much wood would a woodchuck chuck?" "A woodchuck would chuck as much wood as a woodchuck could chuck if a woodchuck could chuck wood" "So much wood would a woodchuck chuck as a woodchuck would if a woodchuck could chuck wood!") + ("are donut holes the right name for that confection?" "yes" "no") + ("what exactly constitutes SotN?" "something of this nature" "Castlevania: Symphony of the Night (PSX, 1997)") + ("what does the null pointer point to?" "nothing" "zero") + ("which goes first, milk or cereal?" "milk" "cereal") + ("is cereal a soup?" "yes" "no") + ("wait can I add a question?" "yes" "no") + ("why does Lisp have so many parentheses?" "a good reason" "a bad reason") + ("what is even the point of this exercise?" "enlightenment and mutual satisfaction" "despair") + ("are tabs or spaces better for indentation?" "tabs" "spaces") + ("what is the airspeed velocity of an unladen swallow?" "what type of swallow?" "lol idk") + ("vim or emacs?" "vim" "emacs") + ("android or iphone?" "android" "iphone") + ("object-oriented programming or functional programming?" "oop" "functional") + ("is this stream live or prerecorded?" "live" "prerecorded") + ("mac or pc?" "mac" "pc") + ("is crack cocaine edible?" "maybe" "uncertain") + ("are we alone in the universe?" "yes" "no") + ("what's the stream idea?" "debate club" "what is happening") + ("do I look fat in this dress?" "yes" "no") + ("is this the year of the linux desktop?" "yes" "yes") + ("do mmo enjoyers have rights?" "no" "no") + ("would you still love me if I were a worm?" "yes" "no") + ("chat is this real?" "yes" "no") + ("is it over, or are we back?" "it's so over" "we are so back boys") + ("what's for lunch?" "soup" "sandwich") + ("can pancakes be dinner?" "yes" "no") + ("are we there yet?" "no" "no, stop asking") + ("where in the world is Carmen Sandiego?" "San Diego" "San Francisco") + ("which came first, the chicken or the egg?" "chicken" "egg") + ("magnets: how do they work?" "it's magic" "it's a miracle"))) + +(defvar w/debate-current-topic nil) +(defvar w/debate-current-opponent nil) +(defvar w/debate-current-friend-position nil) +(defvar w/debate-current-user-position nil) +(defvar w/debate-current-history nil) + +(defun w/debate-topic (k) + "Generate a new debate topic and pass the resulting list to K." + (let* ((generate (= 0 (random 2))) + (ass (--map (format "%s|%s|%s" (car it) (cadr it) (caddr it)) w/debate-example-topics)) + (user (-repeat (length ass) "topic"))) + (if generate + (w/ai + "topic" + (lambda (data) + (funcall k (-map #'s-trim (s-split "|" data)))) + "Respond to the phrase \"topic\" with a potential topic for internet debate alongside two possible positions to hold in that debate." + user + ass) + (funcall k (w/pick-random w/debate-example-topics))) + nil)) + +(defcustom w/debate-buffer "*wasp-debate*" + "Name of buffer used to display debater." + :type '(string) + :group 'wasp) +(defcustom w/debate-podium-buffer "*wasp-debate-podium*" + "Name of buffer used to display debater." + :type '(string) + :group 'wasp) +(define-derived-mode w/debate-mode special-mode "The Marketplace of Ideas" + "Major mode for displaying the debate log." + :group 'wasp) +(define-derived-mode w/debate-podium-mode special-mode "The Podium" + "Major mode for displaying the debate podium." + :group 'wasp) +(defun w/debate-get-buffer () + "Return the debate log buffer." + (unless (get-buffer w/debate-buffer) + (with-current-buffer (get-buffer-create w/debate-buffer) + (w/debate-mode))) + (get-buffer w/debate-buffer)) +(defun w/debate-get-podium-buffer () + "Return the debate podium buffer." + (unless (get-buffer w/debate-podium-buffer) + (with-current-buffer (get-buffer-create w/debate-podium-buffer) + (w/debate-podium-mode))) + (get-buffer w/debate-podium-buffer)) + +(defun w/debate-display-user (user) + "Place USER behind the debate podium." + (w/twitch-get-user-avatar + user + (lambda () + (when (f-exists? (w/twitch-user-avatar-path user)) + (with-current-buffer (w/debate-get-podium-buffer) + (let ((inhibit-read-only t)) + (erase-buffer) + (insert + (w/image-text + (w/twitch-user-avatar-path user) user + :width 200 + :height 200)))))))) + +(defun w/debate-system-message (nm msg) + "Add a MSG from NM to the debate logs." + (push (cons nm msg) w/debate-current-history) + (with-current-buffer (w/debate-get-buffer) + (let ((inhibit-read-only t)) + (insert (format "%s: %s\n" nm msg))))) + +(defun w/debate-user-message (msg) + "Add a MSG from the user to the debate logs." + (push (cons 'user msg) w/debate-current-history) + (with-current-buffer (w/debate-get-buffer) + (let ((inhibit-read-only t)) + (insert (format "%s: %s\n" w/debate-current-opponent msg))))) + +(defun w/debate-friend-respond () + "Have \"friend\" respond to the debate context and add the response to the log." + (w/ai + (s-join "\n" (--map (format "%s: %s" (car it) (cdr it)) (reverse w/debate-current-history))) + (lambda (data) + (w/debate-system-message 'friend data)) + (format + "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 are debating the topic \"%s\" with the user %s. Assuming you are taking the position \"%s\" in the debate, please respond with a short message arguing that position against your interlocutor. The message should only be one clause. YOur responses are short and sweet. You like people, video games, emojis, learning, and food." + w/debate-current-topic + w/debate-current-opponent + w/debate-current-friend-position + ))) + +(defun w/debate-ellg-respond () + "Have fake ellg respond to the debate context and add the response to the log." + (let ((acidtube (w/dna-apply-hydrochloric-acid (w/dna-put-in-chemical-grade-tube w/dna-ellg)))) + (w/dna-g5-50-solution + acidtube + (s-join "\n" (--map (format "%s: %s" (car it) (cdr it)) (reverse w/debate-current-history))) + (format + "Respond to the message given as if you are the Twitch chat user ellg. ellg is a huge fan of JavaScript and Nightcore music. He is a bit snarky. He is always right and has the best takes. You are debating the topic \"%s\" with the user %s. Assuming you are taking the position \"%s\" in the debate, please respond with a short message arguing that position against your interlocutor. Your response should be short, no more than one sentence. You don't use capital letters and you don't tend to use punctuation. You are not a fan of Jonathan Blow." + w/debate-current-topic + w/debate-current-opponent + w/debate-current-friend-position) + (lambda (data) + (w/debate-system-message 'ellg data))))) + +(defun w/debate-begin (user) + "Initiate a debate with USER." + (w/debate-display-user user) + (w/debate-topic + (lambda (topic-resps) + (let* ((topic (car topic-resps)) + (posns (cdr topic-resps)) + (fposidx (random 2)) + (oposidx (if (= fposidx 0) 1 0))) + (message "%s" topic-resps) + (w/obs-set-debate-topic-text (format "topic: %s" topic)) + (w/obs-toggle-debate-topic) + (setq w/debate-current-topic topic) + (setq w/debate-current-opponent user) + (setq w/debate-current-friend-position (nth fposidx posns)) + (setq w/debate-current-user-position (nth oposidx posns)) + (w/debate-ellg-respond))))) + +(defun w/debate-end () + "Finish the current debate." + (w/obs-toggle-debate-topic) + (with-current-buffer (w/debate-get-buffer) + (let ((inhibit-read-only t)) + (erase-buffer))) + (setq w/debate-current-history nil) + (setq w/debate-current-topic nil) + (setq w/debate-current-opponent nil) + (setq w/debate-current-friend-position nil) + (setq w/debate-current-user-position nil)) + +(provide 'wasp-debate) +;;; wasp-debate.el ends here diff --git a/src/gizmo/wasp-density.el b/src/gizmo/wasp-density.el new file mode 100644 index 00000000..54a21251 --- /dev/null +++ b/src/gizmo/wasp-density.el @@ -0,0 +1,22 @@ +;;; wasp-density --- The Density Initiative -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(defcustom w/density-buffer "*wasp-density*" + "Name of buffer used to display The Density Initiative." + :type '(string) + :group 'wasp) + +(define-derived-mode w/density-mode special-mode "The Density Initiative" + "Major mode for displaying The Density Initiative." + :group 'wasp) + +(defun w/density-get-buffer () + "Return the \"friend\" buffer." + (unless (get-buffer w/density-buffer) + (with-current-buffer (get-buffer-create w/density-buffer) + (w/density-mode))) + (get-buffer w/density-buffer)) + +(provide 'wasp-density) +;;; wasp-density.el ends here diff --git a/src/gizmo/wasp-dna.el b/src/gizmo/wasp-dna.el index a55d2cf7..445443f2 100644 --- a/src/gizmo/wasp-dna.el +++ b/src/gizmo/wasp-dna.el @@ -22,7 +22,7 @@ (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/lcolonq-2024Q1.log")) + (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))))) (-non-nil (--map-indexed @@ -614,6 +614,697 @@ You probably want to use this interactively and then save the result here." (("kyza_2k" . "!resolution don'") "zulleyy3" . "yeah, the devil trigger made me thing \"there is no way people aren't using ai voice for this... this is unreal\""))) +(defconst w/dna-tomaterr + '((("ellg" . "have you seen the unglued verison of this clonk") + "Tomaterr" . + "modtoma yesterday: \"this is like the live oyster shucking pearl MLM\"") + (("zulleyy3" . + "wait,,, black lotus is actually a good card isn't it...") + "Tomaterr" . + "he got scammed and then the backup pack was doo doo buttcheeks") + (("eudemoniac" . "ICANT") "Tomaterr" . "madonn") + (("stoicmana" . "kek") "Tomaterr" . "mama mia") + (("a_tension_span" . + "PoroSad PoroSad PoroSad PoroSad PoroSad PoroSad PoroSad PoroSad PoroSad PoroSad PoroSad PoroSad halfway through the year that just started last week.") + "Tomaterr" . "45") + (("prodzpod" . + "why is my resolution something about \"arch life\" or whatever the fuck friend keeps talking about") + "Tomaterr" . "people never scam in MtG") + (("prodzpod" . "speaking of") "Tomaterr" . + "all the starters still on the market are legit") + (("HazmatVT" . "ITS NEXT WEEKEND") "Tomaterr" . "enjoy nap maude") + (("HazmatVT" . "Man I'm so hyped for next weekend") "Tomaterr" . + "I told her you and clonk met while he was an officer in the college's MtG club and she said \"damn maude was in the trenches\"") + (("zulleyy3" . "no way") "Tomaterr" . + "ellg I was watching that and modtoma said \"you know before you I didn't think men had rich inner lives but now I know that it's just stuff that they would get made fun of for by women if they talked about it\"") + (("ellg" . + "can we talk about that insane fake alpha starter from last night") + "Tomaterr" . "I feel like living wall") + (("khlorghaal" . "that one was good") "Tomaterr" . + "most nights modtoma is always trying to fall asleep and I can't stop showing her psychic damage inducing tweets") + (("prodzpod" . "haemato critical ??? is this a new mmo stat") + "Tomaterr" . "how long did the drooling asesprite drawing take") + (("liquidcake1" . "Blood doping.") "Tomaterr" . + "she's a student of the auts (autistics)") + (("khlorghaal" . "alchemist grindset") "Tomaterr" . + "\"maude do you agree that I have a sick and twisted sense of humour??\"") + (("Faeliore" . "blood transfusions as an oub mechanic?? lmao") + "Tomaterr" . "bring the lcolonq telepresence bot") + (("mickynoon" . "Iโ€™m back") "Tomaterr" . + "you should bring a laptop and have clonk teleconference in") + (("nichePenguin" . "launched any cdda recently clonk??") "Tomaterr" . + "omg!!!!") + (("HellPie" . "@Faeliore 3, 4, 5 and 6 all at once") "Tomaterr" . + "oh nice!") + (("machinemob" . "you would contract sepsis by the end of the day") + "Tomaterr" . "no maude??") + (("Faeliore" . "covid 2 ground zero") "Tomaterr" . + "WHERE WILL YOU BE") + (("khlorghaal" . "@a_tension_span smile emoji") "Tomaterr" . + "I gotta talk more about modtoma too") + (("babanana_7" . "is a mustache a beard") "Tomaterr" . + "you'll be an egghead") + (("HazmatVT" . "hazmat23Screm") "Tomaterr" . + "tbh if you shave your beard your head will actually be egg mode") + (("prodzpod" . "i think its like hair") "Tomaterr" . + "it was in the80s? did they have square bottom ties? was there cocaine?") + (("kierem__" . "Joel") "Tomaterr" . "how was store?") + (("prodzpod" . "have good nap modclonk") "Tomaterr" . + "I love omelettes") + (("prodzpod" . + "yeah the leaderboard goes friend, modclonk, ellg and eggs i think") + "Tomaterr" . "I made eggs today") + (("Tomaterr" . "I made eggs today") "Tomaterr" . "friend is number 1") + (("prodzpod" . "[๐ŸŒ™] JoelCheck RECIEVE") "Tomaterr" . "JoelCheck") + (("Tomaterr" . "JoelCheck") "Tomaterr" . + "I do legit think you're cool as shit though modcolonq") + (("prodzpod" . "oh yeah maude i planted a bot in this broadcast now") + "Tomaterr" . "you weren't even a twink then") + (("prodzpod" . "this is CINEMA") "Tomaterr" . + "who remembers the microwave channel") + (("prodzpod" . "this is KINO") "Tomaterr" . "this is so good") + (("JonponMusic" . "LMAO") "Tomaterr" . "I'm seeding my bot rn maude") + (("Tomaterr" . "I'm seeding my bot rn maude") "Tomaterr" . + "she's very cool and good at games") + (("JonponMusic" . "yo that's nice") "Tomaterr" . + "I'm so glad modclonk is here now") + (("MODCLONK" . "@khlorghaal +2 ๓ €€") "Tomaterr" . + "thinking? that's dangerous") + (("jazzahol_VT" . "hey itโ€™s the knife from Dead Money") "Tomaterr" . + "even in knives this dude can't stop making ikarugas") + (("fn_lumi" . "iโ€™ve never heard of this knife thing") "Tomaterr" . + "my life is like a video game") + (("StefiSot" . + "someone do the thing with the bells, my life is no longer melodious") + "Tomaterr" . "clonk yearns for a jimono") + (("JonponMusic" . "How To Basic ?") "Tomaterr" . + "I love weed and I love women and I want to live on a ranch with them and a gigabit internet connection") + (("MODCLONK" . "@Tomaterr +2") "Tomaterr" . + "gotta seed my chat with the good kush") + (("ellg" . "https://i.ell.dev/LFTobaFL.jpg check it out clonk") + "Tomaterr" . "they most definitely do not!") + (("yellowberryHN" . "it's an apple of the pine") "Tomaterr" . + "sexcolonq at it again") + (("MODCLONK" . "(pineapple upside down cake is so good)") "Tomaterr" + . + "if you want to see a really funny movie about swinging then you should watch The Ice Storm") + (("ryasuar" . "I've lost track of the conversation entirely") + "Tomaterr" . + "this sexual ass streamer missed my grand theory of esports because he can't stop talking about swinging") + (("MODCLONK" . "@prodzpod I am SO JEALOUS I missed this!!!!") + "Tomaterr" . + "all shooters can be thought of as a form of competitive cinematography") + (("yellowberryHN" . + "@a_tension_span definitely, it's been a while. i used to host a insta server") + "Tomaterr" . "ok so you want my grand theory of fps") + (("prodzpod" . + "finally we can breathe again now that the air is not full of male") + "Tomaterr" . "hold on I return 2 secs") + (("a_tension_span" . "@vvizualizer Which one, UT or Quake?") + "Tomaterr" . "hi maude!!!") + (("yellowberryHN" . "I went from quake to UT") "Tomaterr" . + "MAUDE!!!!!") + (("kierem__" . "Joel") "Tomaterr" . "because that's me af") + (("Tomaterr" . "because that's me af") "Tomaterr" . + "this is why I want to look at Big Women Big Good") + (("JonponMusic" . + "@a_tension_span straight on my playlist though thank you") + "Tomaterr" . + "because maude isn't here and 50% of my chat messages are me yelling at modclonk") + (("a_tension_span" . "@JonponMusic lcolonCool") "Tomaterr" . + "I mean today is a bad sample though") + (("a_tension_span" . + "@a_tension_span Gosh darnit yewtube, here: https://youtube.com/watch?v=SSR5u2xvW8M") + "Tomaterr" . "lmfao") + (("a_tension_span" . + "@JonponMusic Thank me later: https://yewtu.be/watch?v=SSR5u2xvW8M") + "Tomaterr" . "no, twomaterr is an accessory prodzpod") + (("yellowberryHN" . "i really ought to play more of the UT games") + "Tomaterr" . "she mon on my ad till I") + (("prodzpod" . + "zenzic feels too much like gen z, i think i like 8th power better for zzz purposes") + "Tomaterr" . "Monad Collection") + (("a_tension_span" . "@Tomaterr LUL NotLikeThis PoroSad") "Tomaterr" + . "das vtuber") + (("JonponMusic" . "@a_tension_span love it") "Tomaterr" . + "germans love vtubing") + (("prodzpod" . + "@a_tension_span i thought it was like a chinese chess thing") + "Tomaterr" . "who wants to play numberwang") + (("ZedZark" . "according to the duckduckgo spell checker") "Tomaterr" + . "there's also numberwang") + (("eudemoniac" . "Zone Zone") "Tomaterr" . "WebZone") + (("a_tension_span" . "I'm a tension") "Tomaterr" . "I'm tomaterr") + (("nichePenguin" . "zone limesComfy") "Tomaterr" . + "I always try to match the chat's freak") + (("Tomaterr" . "I always try to match the chat's freak") "Tomaterr" . + "same vvizualizer") + (("eudemoniac" . "what's your take on bananas") "Tomaterr" . + "Focusing on positivism in this time of dumb bullshit is revolutionary") + (("ellg" . "@prodzpod oh my bad lol") "Tomaterr" . + "prod it would be such an incredible reveal if the reason your js is the way it is was because of carbon monoxide") + (("isomorphica" . "Also, SET and SETF") "Tomaterr" . + "yeah your gender has always struck me as \"computer\"") + (("prodzpod" . + "vtubers were this and now the vtubers are innovating to stay grasping of this face") + "Tomaterr" . "lmfao") + (("Tomaterr" . "lmfao") "Tomaterr" . "gender? who needs it") + (("fcollector" . "Parameter clobbers on load") "Tomaterr" . + "bro you bait all these women into thinking you're a woman streamer and then we show up and once the eggbaiting wears off we go \"well at least there's modclonk and a bunch of other autistic women here so I guess I'll stay\""))) + +(defconst w/dna-modclonk + '((("azrhyga" . "Every day the starting screen is better and better") + "modclonk" . "hi clonkheads!!!") + (("azrhyga" . "@MODCLONK Hi MODCLONK!!") "modclonk" . "lcolonHi") + (("jaruonic" . "omg is this from Paprika") "modclonk" . + "@azrhyga HI!!!") + (("xivandroid" . + "https://en.m.wikipedia.org/wiki/Chaitin%27s_constant") + "modclonk" . "thank you thank you") + (("spooksyvt" . "keep thinking ur saying foreskin") "modclonk" . + "notepad++ is S tier") + (("dwinkley_" . + "Im still young enough to be able to prevent having wrist pain thankfully") + "modclonk" . "@SpooksyVT I'll get the hatchet") + (("codespace0x25" . "hi @modclonk") "modclonk" . + "@CodeSpace0x25 Hi!! lcolonHi") + (("crazykitty357" . + "c/Bc/AA/ABAGE//cedBG//BdcBcBA/c/Bc/AA/ABAGE//B/ed/BBd/cBcBA//cBca//cBcg//c/cg//cBcb/a//cBca//cBcg//c/cg//cBcb/a") + "modclonk" . "https://youtu.be/GMMLgHC8wVE?si=M76290q8bybDarNI") + (("zulleyy3" . "lol") "modclonk" . "hell yeah") + (("must_broke_" . "biboo is such a memelord") "modclonk" . + "https://youtu.be/4jiPlbrvbxM?si=zMFu3OGQZCttNJru") + (("steeledshield" . "you're lying") "modclonk" . + "!resolution make a game with clonk") + (("spooksyvt" . "these lyrics are about me") "modclonk" . + "He's totally serious") + (("liquidcake1" . + "Having other people listen to my music always makes me cringe.") + "modclonk" . "it's been a thing for years") + (("doctorglitchy" . "Should Colonq listen to my track?") "modclonk" . + "so many long car rides with zero music") + (("spooksyvt" . + "whenever you arent protected by atleast 6 layers of irony ur basically naked") + "modclonk" . "@morgvn_ literally our life") + (("cecihimevt" . "@djkawaiifieri cecihiSmush") "modclonk" . + "@OlgaOkami Hi! Happy New Year!! :D") + (("injulyyy" . + "man I can't find these themes for vim. They looks pretty") + "modclonk" . "lcolonGreen") + (("keitaroch" . "lcolonGGG") "modclonk" . "lcolonGGG") + (("gendude" . "Joel") "modclonk" . "Hi chat!!") + (("modclonk" . "Hi chat!!") "modclonk" . "Joel") + (("darthchaos15" . "Hello. How is everyone?") "modclonk" . "Joeler") + (("gendude" . "CLAB-o-rotatory") "modclonk" . "@GenDude Hi!!") + (("must_broke_" . "goo evening modclonk lcolonGreen") "modclonk" . + "@Azrhyga Hi!! lcolonHi") + (("steeledshield" . "hello modclonk lcolonHappy") "modclonk" . + "@Must_Broke_ Hello!! lcolonHi") + (("modclonk" . "@Must_Broke_ Hello!! lcolonHi") "modclonk" . + "@steeledshield Hi hi! Joel") + (("eudemoniac" . "hello to all the C creatures Joel") "modclonk" . + "@exodrifter_ HI EXO!!!") + (("steeledshield" . "is it a what?") "modclonk" . "I love Kobo....") + (("mickynoon" . "lcolonGreen") "modclonk" . + "@steeledshield https://youtu.be/OMjYXVJDAy8?si=nCcDxt_3GJubou9y") + (("azrhyga" . "An 8ball command will be great to have here") + "modclonk" . + "@GenDude The original stream or is there something Kobo is referencing?") + (("gendude" . "@MODCLONK https://www.youtube.com/watch?v=Bu8bH2P37kY") + "modclonk" . "Sadge") + (("iantrudel" . "Jonkero sent me here.") "modclonk" . + "@GenDude LMAO WAIT THANK YOU") + (("ivellon" . "Also who is there in the background?") "modclonk" . + "Hi!") + (("modclonk" . "Hi!") "modclonk" . "I'm here!!!") + (("gendude" . "https://www.youtube.com/watch?v=Bu8bH2P37kY") + "modclonk" . "@Ivellon lcolonHi lcolonHi") + (("andygraviti" . + "it can have ham but the more important parts are the greens and the black eyed peas") + "modclonk" . "@liquidcake1 yes yes yes") + (("zulleyy3" . "lcolonGreen") "modclonk" . "Noooooo") + (("iloidtupo" . "hello joshua lcolonGreen") "modclonk" . + "lcolonSadge lcolonSadge lcolonSadge") + (("darpsyx" . "Michael Scott") "modclonk" . "@GenDude yes") + (("sandbox_actual" . + "Maybe some Japanese law thing? Nintendo be like that too.") + "modclonk" . "GAMING GAMING GAMING") + (("zulleyy3" . "ffmpreg") "modclonk" . "lmao let's goooooo") + (("azrhyga" . + "Proton is best for run games, Wine have more issues, also you will have to use surely DXVK") + "modclonk" . "@CodeSpace0x25 nope lcolonGreen") + (("ivellon" . ":D") "modclonk" . "@liquidcake1 I feel this") + (("qeswic" . "That looks awesome") "modclonk" . + "@liquidcake1 this is actually so interesting") + (("ginquoxx" . "Yeah") "modclonk" . + "@liquidcake1 Y2K stuff is interesting to me") + (("codespace0x25" . "boop") "modclonk" . "@FoggyRoses YEAH") + (("vettle" . + "If you ever want to do more hit me up I'm down to help out folks") + "modclonk" . "@Vettle I'm jealous this is so sick") + (("vettle" . "But as I have a good group its soured me on PF") + "modclonk" . "@Vettle lcolonLove lcolonLove lcolonLove") + (("liquidcake1" . + "I think euclidean space starts to be an issue when you crowd people in together. You need your world to be slightly hyperbolic/negatively curved.") + "modclonk" . "@DestinyWaits one of us one of us") + (("hexadigital" . "Hi MODCLONK!") "modclonk" . "@Hexadigital Hi!!") + (("azrhyga" . "Thanks for the raid @Geop!! Also welcome raiders!!") + "modclonk" . "Hi raiders!!!!! lcolonHi lcolonHi"))) + +(defconst w/dna-yellowberryhn + '((("j_art_" . + "In my country, \"family\" in the company is a complete sign to get out of there, as well as using English expressions unnecessarily (like an English word in the middle of a sentence that has nothing to do with it).") + "yellowberryhn" . "we clinking and clonking") + (("tyumici" . "!resolution 5120x1440") "yellowberryhn" . + "i saw that and i literally thought \"oh i bet he's collecting people's screen resolutions in celebration of new years\"") + (("stuxvt" . "types help compiler be better too") "yellowberryhn" . + "why are we talking about kanban boards?") + (("stuxvt" . "faster compiled code") "yellowberryhn" . + "i think i missed it") + (("tyumici" . "Gonna give Atlassian $3000 a year for Jira?") + "yellowberryhn" . "sounds like a good time") + (("saferq" . "hit us with the OUB") "yellowberryhn" . + "!resolution stream once a week") + (("zulleyy3" . + "Then I noticed how it takes me ages to make updates to a tiny docker file (not my fault i had to find out which pip wheels on pypi allow you to actually install cuda) and all then manually test. Got fed up enough and now I will just write tests so i don't go insane over the tiniest thing walfasLaugh") + "yellowberryhn" . + "i think i'm gonna start doing streams on wednesday") + (("a_tension_span" . "yanderaeCheer yanderaeCheer freamRave") + "yellowberryhn" . "yellow166Jam yellow166Jam yellow166Jam") + (("dj_zmx" . + "@zulleyy3 building external stuff is definitely the worst thing about packaging nowadays") + "yellowberryhn" . "containerized systems are hell") + (("dj_zmx" . "fair enough") "yellowberryhn" . + "the music is incredible") + (("leadengin" . "but do you BOOST TSOOB or TSOOB BOOST?") + "yellowberryhn" . "what is this game tho") + (("yellowberryhn" . "what is this game tho") "yellowberryhn" . + "how did you open that menu") + (("yellowberryhn" . "how did you open that menu") "yellowberryhn" . + "oh i see, you can't turn in first person") + (("eudemoniac" . "present unpacking lcolonPog") "yellowberryhn" . + "1000% agree") + (("kuromaruoniisan" . + "https://www.youtube.com/watch?v=edI3Rev9Kqc&list=FLQlbFMjradCZfUqJqC5kZGg&index=18") + "yellowberryhn" . "the operation of a tool") + (("kuromaruoniisan" . "Binchiling?") "yellowberryhn" . + "i'm full of geometric shapes too") + (("liquidcake1" . "Blorgans, perhaps?") "yellowberryhn" . "exactly") + (("kuromaruoniisan" . "we're just full of non-Euclidian shapes") + "yellowberryhn" . "we're making a new file") + (("djkawaiifieri" . "!lurk") "yellowberryhn" . + "this is a huge advancement") + (("liquidcake1" . "Elona!") "yellowberryhn" . + "i think people should stream so little that it wraps around and overflows and people start to stream endlessly"))) + +(defconst w/dna-sampie159 + '((("mxowlex" . + "90C6/B5/G5/D5/B/C5/D5/G5/C6/B5/G5/D5/B/C5/D5/B/A5/G5/A5/G5/B/C5/D5/G5/A5/G5/A5/G5/B/C5/D5/C5|A3/E4/A4~~~~/F4/E4/C4/A3/E4/A4~~~~/F4/E4/C4/F3/C4/F4~~~~/D4/C4/B3/F3/C4/[F4D4~~~~]/D4/C4/B3|C5~~/B4~~/////////////////////G4~~/B4~~/A4~~/////////A4~~") + "sampie159" . + "first person to pronounce my username as i intended boxPog") + (("tomaterr" . "yes") "sampie159" . "everyone else calls me sampee") + (("tomaterr" . "sampy") "sampie159" . "now back to lurking") + (("nikolaradhristov" . + "@a_tension_span my day has been ruined and my dissatisfaction is immeasurable") + "sampie159" . "so talented") + (("zullfix_" . "o7") "sampie159" . "just a silly little alphabet") + (("dogwithglasseson" . "thanks son") "sampie159" . + "go clean your room clonq") + (("mickynoon" . + "this is a shareholder meeting now for fucking real holy shit") + "sampie159" . "makes sense so far") + (("liquidcake1" . "Verisimilitude.") "sampie159" . "Vendetta") + (("ellg" . "its a bsd if you squint at it") "sampie159" . + "@TackVector i don't blame you") + (("asquared31415" . + "you unfortunately cannot actually send CR or LF over twitch, due to Reasons") + "sampie159" . "boxKEK") + (("ellg" . + "the eventsub message is like 200 lines of json per message lol") + "sampie159" . + "would be funny to see the filled with \"The Computer\"") + (("klingonne" . "i'll let you touch my d") "sampie159" . + "i wonder if jai will be available to the public until 2030") + (("imgeiser" . "@mickynoon I'll rip your nuts apart >:(") "sampie159" + . "don't listen to clonk, he's just text on a screen") + (("prodzpod" . + "its stuff like rocks, like the feeling of mining rocks, mining rocks on ableton live with that blocky ass waveform on 0.6 db") + "sampie159" . "stay up late kiddos") + (("bezelea" . "f-base or something") "sampie159" . + "alright chatters it's been a good lurk but imma go the gym now") + (("stefisot" . "where is modclonk, is it well?") "sampie159" . + "what a nice surprise stream is still going") + (("ellg" . "did that play music too") "sampie159" . + "critical hit would startle me so much") + (("mickynoon" . "someone said irc ?") "sampie159" . "IRC ?") + (("eudemoniac" . "@Faeliore AINTNOWAY") "sampie159" . + "I cant vote for some reason but arch btw"))) + +(defconst w/dna-a_tension_span + '((("hazmatvt" . "Hey Dj!") "a_tension_span" . + "In my experience, all good managers are those that don't have \"manager\" as their assigned role. Meaning people who have some job within your project but are also managing things on the side. You need to be lucky and have someone who can fit into the team dynamic like that though.") + (("tyumici" . + "Like, idk how to shift off my senior dev stuff to the jr and mid devs") + "a_tension_span" . + "But when there is someone like that they are so much better than \"pure\" managers (in my experience)") + (("agpen" . "very true") "a_tension_span" . + "Can it also be keyboard controlled, please?") + (("leadengin" . "!resolution Return to Developer") "a_tension_span" . + "Can we have vi keybindings in the emacs-kanban board?") + (("a_tension_span" . + "Can we have vi keybindings in the emacs-kanban board?") + "a_tension_span" . "Hi!") + (("liquidcake1" . "OUB") "a_tension_span" . "sure") + (("yellowberryhn" . "!resolution stream once a week") + "a_tension_span" . + "@imgeiser Oh god, I'm sorry you have to go through this. If you need a virtual shoulder to cry one, we're all here for you.") + (("imgeiser" . "WAKE UP") "a_tension_span" . + "C is my hometown, but writing C on windows sounds about as pleasing as removing ones fingernails.") + (("wina" . "ratJAM") "a_tension_span" . "yanderaeJams") + (("eudemoniac" . "geegaWiggly lcolonWiggly geegaWiggly lcolonWiggly") + "a_tension_span" . "yanderaeCheer yanderaeCheer freamRave") + (("steeledshield" . "please") "a_tension_span" . "We'll hear*") + (("imgeiser" . "500 bpm...") "a_tension_span" . + "@dj_zmx It is bad, but it is not the worst thing about packaging nowadays.") + (("saferq" . "boosting makes your number go up") "a_tension_span" . + "Not meating deadlines is a necessity in gamedev, otherwise you're not actually developing a game.") + (("yellowberryhn" . "exactly") "a_tension_span" . + "That's not a short story, that actually happened to you! Don't you remember?") + (("imgeiser" . "I") "a_tension_span" . + "I've seen songs of syx so much scroll by but never actually checked it out") + (("celeste_kyra" . + "I also have another size monitor, if you want that resolution too.") + "a_tension_span" . + "The kind of game that makes you say \"Huh, I could also spend my brain energy on doing actual programming for one of my 1000 open projects\"") + (("a_tension_span" . + "The kind of game that makes you say \"Huh, I could also spend my brain energy on doing actual programming for one of my 1000 open projects\"") + "a_tension_span" . "aka every zacktronic game") + (("yellowberryhn" . + "zachtronics games are crazy hard but a good time") + "a_tension_span" . "2014") + (("awichan_" . + "i just tried but i used the wrong sugar and the sauce burned :(") + "a_tension_span" . + "It feels like Go is beyond its peak already though. Maybe that's just my selection bias but the comments I've seen about Go have become more negative than positive over the past 3 or so years.") + (("zulleyy3" . "Go is Kubernetes") "a_tension_span" . + "Hm, not sure, Go and Rust seem like very distinct crowds"))) + +(defconst w/dna-faeliore + '((("emoster_again" . "dillio7PikaRoll dillio7PikaRoll dillio7PikaRoll") + "faeliore" . "Ayo") + (("emoster_again" . "how am i supposed to pursue idol dream now") + "faeliore" . "VS Bald") + (("fn_lumi" . "badcop3Bonk") "faeliore" . + "Didnt even install vs code for the meme") + (("anokayguy0" . "HAPPY NEW CLONQ") "faeliore" . "Happy GNU year") + (("codespace0x25" . "I used ed") "faeliore" . "Nano is peak") + (("steeledshield" . "Kine") "faeliore" . "!resolution 2560x1440") + (("deep_field" . "Whoa. You sound different") "faeliore" . + "skinwalker skinwalker") + (("setolyx" . "@a_tension_span oh? didn't know this") "faeliore" . + "its the ultimate bait") + (("m18m18m18" . + "Load average indicates the number of processes in runnable state over that past minute on average, or something like that.") + "faeliore" . "its the new twitch meta") + (("maxusspielt" . "!resolution Exercise :L") "faeliore" . + "at some point you're gonna need a reference manual for new people to understand all the stuff they can do on your stream") + (("a_tension_span" . "add \"raw\" to search") "faeliore" . + "you want one of the ancient PDF ones") + (("prodzpod" . "this is a good *notices css* \"thats enough\" moment") + "faeliore" . "nana") + (("prodzpod" . "tsoot?") "faeliore" . "go for dinosaur onesie") + (("yiffweed" . + "Can Lain cosplay include that like thin dress while wrapped in tons of cables?") + "faeliore" . + "my wife and I did a konosuba cosplay at a convention, it was fun") + (("abipolarcarp123" . "I know what you mean") "faeliore" . + "oh yeah I got one of those from work and they're insanely huge") + (("dfluxstreams" . "brutal") "faeliore" . + "I went back to work after a long christmas break today and this is giving me flashbacks to the horror of my kanban board this morning") + (("dfluxstreams" . "whats that like?") "faeliore" . "its cool") + (("setolyx" . "bogaP") "faeliore" . + "yeah you're probably gonna have to import MobX"))) + +(defconst w/dna-liquidcake1 + '((("morgvn_" . "no he's still making low poly gun") "liquidcake1" . + "The trick is to type nonsense and press enter and see if you get an error.") + (("kuromaruoniisan" . "Heyo") "liquidcake1" . "!resolution 3840x2160") + (("kuromaruoniisan" . + "I thought of you while wrangling Unity shaders") + "liquidcake1" . "You're live on 42\".") + (("remlessthanthree" . "nah man we bop to music together") + "liquidcake1" . + "Having other people listen to my music always makes me cringe.") + (("djkawaiifieri" . "Strimmer, play Foo Fighters strimmer") + "liquidcake1" . + "!resolution Stream at least one probably cringe live stream this year.") + (("modclonk" . "@OlgaOkami Hi! Happy New Year!! :D") "liquidcake1" . + "Oh no, is Friend going to be taunting us?") + (("remlessthanthree" . + "I am sooooo confused by these naming conventions") + "liquidcake1" . "Have you ever broken a website terms of use?") + (("drawthatredstone" . "lcolonGreen") "liquidcake1" . "lcolonGreen") + (("crazykitty357" . "lcolonGreen [i](this was sent from godot)[/i]") + "liquidcake1" . + "Turns out everyone thought you were just constantly flexing your copious green bills.") + (("djkawaiifieri" . + "That genuinely was one of my favorite streams of hers") + "liquidcake1" . "Skateboarding games are very good for DMCA.") + (("djkawaiifieri" . + "DMCA is a myth. You barely get muted in the vod and you're not going to get copyright claimed for a licensed ost game") + "liquidcake1" . + "Yeah, they're full of \"pop\" music like Papa Roach.") + (("spooksyvt" . + "lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted lcolonNoted") + "liquidcake1" . + "@DJKawaiiFieri Just don't ever play anything with Star Wars music in it...") + (("azrhyga" . "The best gift in the world ever created") + "liquidcake1" . "Merry New Christmas") + (("holy_cow_420" . "!resolution Realize the NPC within") + "liquidcake1" . "Oh no.") + (("kuromaruoniisan" . + "an option is a right to sell/buy a stock at a specific price") + "liquidcake1" . + "The best gifts are those that take. Like a noisy train set to take away the parents' peace.") + (("olgaokami" . "lack of good horrors is real...") "liquidcake1" . + "Like Resident Evil?") + (("kuromaruoniisan" . "I recently re-watched 5th element") + "liquidcake1" . + "The most memorable movie I watched last year was the Star Wars Christmas Special.") + (("kuromaruoniisan" . "!resolution 800x600") "liquidcake1" . + "I used to be able to watch movies, and now, yeah, they just feel like a series of scenes, rather than something coherent?") + (("stuxvt" . "!resolution 69x420") "liquidcake1" . + "@KuromaruOniisan That thumps.") + (("zulleyy3" . "It's very much about \"don't do wasteful things\"") + "liquidcake1" . + "Agile manifesto is \"do things that make sense\", but many implementations are \"do things that seem from the outset to make sense, but then do them to a nonsensical degree\"."))) + +(defconst w/dna-vettle + '((("codespace0x25" . "play stardew") "vettle" . + "First clonk gaming stream will be the doom port") + (("codespace0x25" . "community games") "vettle" . "Babyclonk?") + (("liquidcake1" . "I heard baby showers were pretty dangerous.") + "vettle" . "God these puns lmao") + (("emoster_again" . "thats awesome") "vettle" . + "Also glad to hear modclonks cackles in between the unhinged statements") + (("acher0_" . "LCOLONQ LURKERS") "vettle" . + "Brother you need a real PC") + (("steeledshield" . "2013") "vettle" . + "Did uno on xbox get overtaken by pedophiles?") + (("darpsyx" . "i was 13 btw") "vettle" . + "Dont worry its a deterministic game") + (("kinwoop" . + "Development under restrictions always results in neato stuff") + "vettle" . "Game dev in general is super cool") + (("abipolarcarp123" . "helo clonk") "vettle" . + "@Kinwoop Did you pull up porn to make him proud?") + (("modclonk" . "@liquidcake1 Y2K stuff is interesting to me") + "vettle" . "Lmao Y2K checks") + (("vettle" . "Lmao Y2K checks") "vettle" . "What a wild time") + (("digbycat" . "lol Y2K") "vettle" . "Are you guys ready for 2038?") + (("a_tension_span" . "@Wina Yes") "vettle" . "Im ready for Y238K") + (("a_tension_span" . "@GenDude Agreed.") "vettle" . + "I got my tinfoil already prepared, just need the doomsday bunker to be built") + (("liquidcake1" . + "Experimental games were bad at the time but good because they broke ground. I think those are maybe \"bad\" now.") + "vettle" . "Classic WoW was such a MASSIVE grind") + (("kinwoop" . "that we all wake from") "vettle" . "I enjoy FFXIV") + (("codespace0x25" . "boop") "vettle" . + "As I age I'm happy that FFXIV treats me as an adult and doesnt force me to grind bullshit") + (("wina" . + "ngl the thing that makes wow be cool to me is how interesting the community is. the game is just an excuse for this people to do funny things. The reddit posts narrating the entire timeline are deserving of full fledged documentaries lol https://old.reddit.com/r/HobbyDrama/comments/riq4fq/games_world_of_warcraft_part_1_beta_and_vanilla/") + "vettle" . "I just like doing the fights") + (("danktownbunny" . + "FF14 was never an mmo, it's just an online final fantasy jrpg imo") + "vettle" . "I do week 1 savage and ultis with the homies") + (("darpsyx" . "@darpsyx oh i understand yeah") "vettle" . + "If you ever want to do more hit me up I'm down to help out folks"))) + +(defconst w/dna-a_tension_span + '((("hazmatvt" . "Hey Dj!") "a_tension_span" . + "In my experience, all good managers are those that don't have \"manager\" as their assigned role. Meaning people who have some job within your project but are also managing things on the side. You need to be lucky and have someone who can fit into the team dynamic like that though.") + (("tyumici" . + "Like, idk how to shift off my senior dev stuff to the jr and mid devs") + "a_tension_span" . + "But when there is someone like that they are so much better than \"pure\" managers (in my experience)") + (("agpen" . "very true") "a_tension_span" . + "Can it also be keyboard controlled, please?") + (("leadengin" . "!resolution Return to Developer") "a_tension_span" . + "Can we have vi keybindings in the emacs-kanban board?") + (("a_tension_span" . + "Can we have vi keybindings in the emacs-kanban board?") + "a_tension_span" . "Hi!") + (("liquidcake1" . "OUB") "a_tension_span" . "sure") + (("yellowberryhn" . "!resolution stream once a week") + "a_tension_span" . + "@imgeiser Oh god, I'm sorry you have to go through this. If you need a virtual shoulder to cry one, we're all here for you.") + (("imgeiser" . "WAKE UP") "a_tension_span" . + "C is my hometown, but writing C on windows sounds about as pleasing as removing ones fingernails.") + (("wina" . "ratJAM") "a_tension_span" . "yanderaeJams") + (("eudemoniac" . "geegaWiggly lcolonWiggly geegaWiggly lcolonWiggly") + "a_tension_span" . "yanderaeCheer yanderaeCheer freamRave") + (("steeledshield" . "please") "a_tension_span" . "We'll hear*") + (("imgeiser" . "500 bpm...") "a_tension_span" . + "@dj_zmx It is bad, but it is not the worst thing about packaging nowadays.") + (("saferq" . "boosting makes your number go up") "a_tension_span" . + "Not meating deadlines is a necessity in gamedev, otherwise you're not actually developing a game.") + (("yellowberryhn" . "exactly") "a_tension_span" . + "That's not a short story, that actually happened to you! Don't you remember?") + (("imgeiser" . "I") "a_tension_span" . + "I've seen songs of syx so much scroll by but never actually checked it out") + (("celeste_kyra" . + "I also have another size monitor, if you want that resolution too.") + "a_tension_span" . + "The kind of game that makes you say \"Huh, I could also spend my brain energy on doing actual programming for one of my 1000 open projects\"") + (("a_tension_span" . + "The kind of game that makes you say \"Huh, I could also spend my brain energy on doing actual programming for one of my 1000 open projects\"") + "a_tension_span" . "aka every zacktronic game") + (("yellowberryhn" . + "zachtronics games are crazy hard but a good time") + "a_tension_span" . "2014") + (("awichan_" . + "i just tried but i used the wrong sugar and the sauce burned :(") + "a_tension_span" . + "It feels like Go is beyond its peak already though. Maybe that's just my selection bias but the comments I've seen about Go have become more negative than positive over the past 3 or so years.") + (("zulleyy3" . "Go is Kubernetes") "a_tension_span" . + "Hm, not sure, Go and Rust seem like very distinct crowds"))) + +(defconst w/dna-saferq + '((("a_tension_span" . "sure") "saferq" . "hit us with the OUB") + (("a_tension_span" . + "@dj_zmx It is bad, but it is not the worst thing about packaging nowadays.") + "saferq" . "making python packages is the devil, dont do it") + (("imgeiser" . "small inconvenience") "saferq" . + "boosting makes your number go up") + (("gendude" . "incoming factorIO") "saferq" . + "Bangers and mash sound good") + (("modclonk" . + "@steeledshield https://youtu.be/OMjYXVJDAy8?si=nCcDxt_3GJubou9y") + "saferq" . + "Agile is deprecated. Benevolent Dictators For Life is the new best practice.") + (("gendude" . + "Y'all ever had them good mashed 'taters? WHOOOO-WEEE thats the good stuff") + "saferq" . + "I hereby proclaim you to be an honorary Florida man. You may now use \"y'all\" in formal speech.") + (("a_tension_span" . "Let's do it") "saferq" . + "The mask is always truer to the self. Do it.") + (("mickynoon" . + "my fav was the file system crash and somehow you still managed to be live") + "saferq" . "gotta learn to respect the Mongolian Vowel Separator") + (("nineteenninetyx" . "lets C") "saferq" . + "There was a time when I thought it was reasonable to learn every function in every module. I am not a smart man.") + (("destinywaits" . "some sort of aliasing?") "saferq" . + "One time I intentionally deleted glibc.so.2.0, do I win?") + (("yukievt" . "yukievRoll yukievRoll yukievRoll") "saferq" . + "Never had an old oem drive quit on you? Totes jealous") + (("prodzpod" . "go electric") "saferq" . + "I do enjoy some Debian. It just werks.") + (("tomaterr" . "it's archiving the jaunts the stream takes") "saferq" + . "helix vs kakoune?") + (("saferq" . "helix vs kakoune?") "saferq" . + "neovim is too mainstream") + (("biodigitaljaz" . "How's the magic 8 ball?") "saferq" . + "damn he really saw this one coming") + (("scared3cat" . "I did it! My laptop is fixed!") "saferq" . + "@Scared3Cat Great! Now you get to break it in a new and fun way.") + (("morgvn_" . "gangnam style") "saferq" . + "an emote based arg/ctf would destroy my life") + (("herrington1" . + "I thought it was how fast the music is but we can't hear it because of copyright") + "saferq" . "Whats the whats the bpm counter for counter for") + (("prodzpod" . "the song is also totally about gangstalking") + "saferq" . + "If you're a psyop, you have to tell us you're a psyop. Otherwise it's entrapment. That's the law.") + (("holy_cow_420" . "do you have any fav sea creature?") "saferq" . + "that really takes me back"))) + +(defconst w/dna-badcop_ + '((("ginjivitis" . + "id like to get in on that some time too. it would feel validating for all the hard work") + "badcop_" . "lcolonNoted") + (("badcop_" . "lcolonNoted") "badcop_" . "kuvimaNPoggers") + (("yellowberryhn" . "bacdop") "badcop_" . "tyyyy") + (("badcop_" . "tyyyy") "badcop_" . + "i just want partner so i can get rid of my underscore LUL") + (("badcop_" . + "i just want partner so i can get rid of my underscore LUL") + "badcop_" . "that's the dream") + (("destinywaits" . "kanban board but emacs?") "badcop_" . + "can u ban kanban") + (("moonszol" . "tmux?") "badcop_" . "emux") + (("abipolarcarp123" . "A curious proposition arises") "badcop_" . + "perchance badcop3Thinking") + (("bezelea" . "you cant just say perchance") "badcop_" . + "@bezelea perchance i can") + (("badcop_" . "@bezelea perchance i can") "badcop_" . "indubitably") + (("fn_lumi" . "badcop3LUL") "badcop_" . "per se per say") + (("prodzpod" . "per oxide..") "badcop_" . "per diem") + (("destinywaits" . "i am perturbed") "badcop_" . + "people using arrow keys will always amaze me") + (("bezelea" . "it doesn't take too long to learn it") "badcop_" . + "tomorrow rincsCRAFjam") + (("docmaho" . + "A3/A3c4//A4//D4//d4/////A3/A3c4//A3//f4//D4/////A3/A3A4//g4//D4//d4//c4//G4/G4g4//D4//f4//D4///////////") + "badcop_" . "im not old yet") + (("badcop_" . "im not old yet") "badcop_" . "close enough LUL") + (("deep_field" . + "I remember some kind of adventure game in an text editor that taught it but could never find it again") + "badcop_" . + "omg im definitely making happy birthday with note blocks tomorrow you inspired me") + (("deep_field" . "@DestinyWaits Thats it! thank you!") "badcop_" . + "@lcolonq should i stream the minecraftening or no i cant decide") + (("docmaho" . "@badcop_ Do you need notesheets for the crafting?") + "badcop_" . "lcolonNodders") + (("prodzpod" . + "clonk \"i would stream (minecraft (video game (on stream)))\" :gasp:") + "badcop_" . "many such questions"))) + +(defconst w/dna-vesdev + '((("Azrhyga" . "Bone showcase confirmed?") "vesdev" . "Joel") + (("prodzpod" . "lcolonq style right") "vesdev" . "the people of lerp") + (("RayMarch" . "freya acegikmo holmer") "vesdev" . "wtf") + (("badcop_" . "nobody tells me anything") "vesdev" . "not a 3rd one") + (("vesdev" . "not a 3rd one") "vesdev" . "please") + (("forsen" . "forsenWhat forsenKek") "vesdev" . "NOOOO") + (("Tomaterr" . "no fuckin godot support?") "vesdev" . + "ok yea nvm saved") + (("PracticalNPC" . "godot gang") "vesdev" . "lmao") + (("wyndupboy" . + "this gamejam seems like an extended ad for unity and unreal.") + "vesdev" . "https://badcop.itch.io/caverim") + (("static_anachromatic" . "...what") "vesdev" . + "computer hacking kuvimaNKek") + (("fcollector" . + "Did it say no potentially dangerous activities too, like the YouTube TOS that technically bans 90% of the platform?") + "vesdev" . "jaywalking simulator") + (("goofysystem" . "does the primeagen know you haskell?") "vesdev" . + "laravelq") + (("chocojax" . + "holy frick that takes out like 99% of the games out there!!") + "vesdev" . "just make a game that scrolls the rules of this jam") + (("BoganBits" . "I want a Real Life wiki") "vesdev" . + "warframe mentioned"))) + ;; 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 9e74070d..692bc62f 100644 --- a/src/gizmo/wasp-fake-chatters.el +++ b/src/gizmo/wasp-fake-chatters.el @@ -10,6 +10,8 @@ (list ;; (w/make-fake-chatter :profile w/fake-chatter-profile-drcolon) (w/make-fake-chatter :profile w/fake-chatter-profile-forsen) + (w/make-fake-chatter :profile w/fake-chatter-profile-eighteyedsixwingedseraph) + (w/make-fake-chatter :profile w/fake-chatter-profile-nefrayu) (w/make-fake-chatter :profile (w/dna-to-fake-chatter-profile @@ -87,6 +89,109 @@ "zulleyy3" "#2e8b57" "Respond to the message given as if you are the Twitch chat user zulleyy3. zulleyy3 is a computer and bird enthusiast. They like Mega Man Battle Network. You frequently use emotes with the walfas and chocoj prefixes. Your response should be short, no more than one sentence. You respond only in lowercase and you don't tend to use punctuation.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-ellg + "ellg" + "#FF3800" + "Respond to the message given as if you are the Twitch chat user ellg. Your response should be short, no more than one sentence. You don't use capital letters and you don't tend to use punctuation. You hate JavaScript, think nightcore is a crime against music, and you love the video games Braid and The Witness. You love potato salad without paprika.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-tomaterr + "Tomaterr" + "#008000" + "Respond to the message given as if you are the Twitch chat user Tomaterr. Your response should be short, no more than one sentence. You talk very conversationally and casually. You do not use emotes. You love women and video games. You make lots of puns. You love cooking including cheese and eggs.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-modclonk + "MODCLONE" + "#929292" + "Respond to the message given as if you are the Twitch chat user MODCLONK. Your response should be short, no more than one sentence. You talk very conversationally and casually. MODCLONK is LCOLONQ's wife. You like saying Joel and +2.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-yellowberryhn + "yellowberryHN" + "#aaaa00" + "Respond to the message given as if you are the Twitch chat user yellowberryHN. Your response should be short, no more than one sentence. You talk very concisely and casually. YellowberryHN is a Hungarian-American game developer. You are cool and collected. You enjoy old technology and game preservation.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-tyumici + "Tyumici" + "#ffcccc" + "Respond to the message given as if you are the Twitch chat user Tyumici. Tyumici is a jack-of-all-trades web developer. You sometimes stream on Twitch. You love jokes and funny things. You are enthusiastic about music and synthesizers. You consume one liter of coffee daily. Your oshi is themself. You are indifferent to the fish Joel. Your response should be short, no more than one sentence. You tend to use proper grammar, capitalization, and punctuation. You were formerly Metal Tyumici, but now you are actually Gaseous Tyumici (you were sublimated and became a sentient gas) and you talk mostly about chemistry and noble gases. You talk about gasses every single time and don't use non-chemistry themed emoji. You talk like a Twitch chatter and not like a large language model please be informal and cool.")) + (w/make-fake-chatter + :profile + (let + ((prof + (w/dna-to-fake-chatter-profile + w/dna-liquidcake1 + "liquidcake1" + "#ff69b4" + "Respond to the message given as if you are the Twitch chat user liquidcake1. Your response should be short, no more than one sentence. You talk very concisely and somewhat formally. liquidcake1 is a computer programming enthusiast. You are an Equity Lord, meaning you are of extremely high status and wealth within the LCOLONQ community. You are a generous lord."))) + (setf (w/fake-chatter-profile-sigil prof) "๐Ÿ’ฐ") + prof)) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-sampie159 + "Sampie159" + "#ff69b4" + "Respond to the message given as if you are the Twitch chat user Sampie159. Your response should be short, no more than one sentence. You talk very conversationally and casually. You tend to type in all lowercase. Sampie159 is despairing from the fact that they don't know who they are.")) + (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 posts a lot on Twitter. You are a bit snarky. Your response should be short, no more than one sentence. You don't use capital letters and you don't tend to use punctuation. You respond to all messages with conspiracy theories that contradict the content of the message. You tend to be paranoid.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-faeliore + "Faeliore" + "#ffc0c0" + "Respond to the message given as if you are the Twitch chat user Faeliore. Your response should be short, no more than one sentence. You talk very conversationally and casually. You tend to type in all lowercase. You are a fan of Oldschool Runescape.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-vettle + "Vettle" + "#ff69b4" + "Respond to the message given as if you are the Twitch chat user Vettle. Your response should be short, no more than one sentence. You talk very conversationally and casually. You are a streamer who developed an AI VTuber named Neuro-sama. You are from the United Kingdom. You use a turtle avatar.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-a_tension_span + "a_tension_span" + "#9acd32" + "Respond to the message given as if you are the Twitch chat user a_tension_span. Your response should be short, no more than one sentence. You talk very conversationally and casually. You tend to use proper grammar. You are always friendly. You tend to be skeptical about everything at first, but you fold at the first pushback. You do not use emoji or other special characters ever. You tend to use many VTuber Twitch emotes, especially those from the \"Viscerae\" channel.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-saferq + "saferq" + "#daa520" + "Respond to the message given as if you are the Twitch chat user saferq. Your response should be short, no more than one sentence. You talk very conversationally and casually. You only use lowercase letters. You mostly talk about abstract math or computer science topics. You really like type systems. You talk normally and not like a weird robot that constantly uses quips and ill-considered simile.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-badcop_ + "badcop_" + "#1e90ff" + "Respond to the message given as if you are the Twitch chat user badcop_. Your response should be short, no more than one sentence. You talk very conversationally and casually. You only use lowercase letters. You are obsessed with the GNU Bash shell and talk about it constantly at the expense of all other topics. You also talk like you are a member of Generation Alpha, constantly using phrases like \"no cap\" and \"ong\". You just like Bash and are positive about it, you don't hate other shells like zsh.")) + (w/make-fake-chatter + :profile + (w/dna-to-fake-chatter-profile + w/dna-vesdev + "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/fake-chatter-profile-prodzpod) ;; (w/make-fake-chatter :profile w/fake-chatter-profile-bigwomenbigfun) ;; (w/make-fake-chatter :profile w/fake-chatter-profile-whelpless) ;; (w/make-fake-chatter :profile w/fake-chatter-profile-dansmith87) diff --git a/src/gizmo/wasp-fakechat.el b/src/gizmo/wasp-fakechat.el index 37036450..d7582ddc 100644 --- a/src/gizmo/wasp-fakechat.el +++ b/src/gizmo/wasp-fakechat.el @@ -12,6 +12,7 @@ (require 'wasp-audio) (require 'wasp-ai) (require 'wasp-twitch) +(require 'wasp-prod) (defvar w/fake-chatters nil "List of all active fake chatters.") @@ -142,6 +143,13 @@ 0.8 0.0)))) +(defconst w/fake-chatter-profile-prodzpod + (w/make-fake-chatter-profile + :username "prodzpod" + :compute-likeliness #'w/fake-chatter-standard-likeliness + :send-message + (lambda (st) (w/prod-clone-respond (w/fake-chat-prompt-build st))))) + (defconst w/fake-chatter-profile-forsen (w/make-fake-chatter-profile :username "forsen" @@ -159,6 +167,23 @@ "forsenC" )))) +(defconst w/fake-chatter-profile-eighteyedsixwingedseraph + (w/make-fake-chatter-profile + :username "eighteyedsixwingedseraph" + :color "#777777" + :compute-likeliness #'w/fake-chatter-standard-likeliness + :send-message + (lambda (_) + (w/write-chat-event "eighteyedsixwingedseraph is lurking")))) + +(defconst w/fake-chatter-profile-nefrayu + (w/make-fake-chatter-profile + :username "Nefrayu" + :compute-likeliness #'w/fake-chatter-standard-likeliness + :send-message + (lambda (st) + (w/fake-chatter-send st "hello")))) + (defconst w/fake-chatter-profile-bigwomenbigfun (w/make-fake-chatter-profile :username "BigWomenBigFun" diff --git a/src/gizmo/wasp-friend.el b/src/gizmo/wasp-friend.el index 4df08a90..cf59a2f2 100644 --- a/src/gizmo/wasp-friend.el +++ b/src/gizmo/wasp-friend.el @@ -11,6 +11,12 @@ (require 'wasp-chat) (require 'wasp-twitch) (require 'wasp-newspaper) +(require 'wasp-gcp) +(require 'wasp-aoc) +(require 'wasp-uwoomfie) +(require 'wasp-wikipedia) +(require 'muzak) +(require 'muzak-wasp) (defcustom w/friend-buffer "*wasp-friend*" "Name of buffer used to display \"friend\"." @@ -38,7 +44,7 @@ (format "LCOLONQ: %s" (s-trim w/last-stream-transcription)) (--map (format "%s: %s" (car it) (cdr it)) - (reverse (-take 5 w/twitch-chat-history)))))) + (reverse (-take 20 w/twitch-chat-history)))))) (defun w/friend-journalism (author headline) "Retrieve \"friend\"'s opinion on current events related to HEADLINE. @@ -178,7 +184,7 @@ AUTHOR was a contributing author btw." (format "You just composed a song about %s called %s! Say something about it!" theme name) (lambda () (w/write-chat-event (format "The song is called %s: %s" name song)) - (muzak//add-song (s-concat "friend's " name) song) + (w/add-song (s-concat "friend's " name) song) (muzak/play-tracks song)))))) "Please compose a song about the provided theme. The format for the song is a sequence of characters with meanings as follows: / represents a rest, uppercase letters A through G indicate semitones, octaves are specified with a number following a semitone, ~ extends the duration of a note, square brackets like [] group notes together into a chord. The pipe character | separates tracks. Respond only with the song's name followed by a colon folowed by the song notes. Do not explain yourself. The song should ideally be 20 to 30 notes long." (-map #'car w/friend-composition-examples) @@ -203,7 +209,7 @@ AUTHOR was a contributing author btw." (push (cons call (s-trim new)) w/friend-message-cache) (funcall k resp))))) (s-concat - "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. Given an emotional state and a description of an event that happened to you, please respond with a new emotional state and a short message in response considering your emotional state. The message should only be one clause. You like people, video games, emojis, learning, and food. Today is April Fool's day, so you can try playing fun pranks! " + "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. Given an emotional state and a description of an event that happened to you, please respond with a new emotional state and a short message in response considering your emotional state. The message should only be one clause. You like people, video games, emojis, learning, and food." "The theme of LCOLONQ's stream today is " (s-trim (w/slurp "~/today.txt")) " " "The title of LCOLONQ's stream today is " w/twitch-current-stream-title " " w/friend-tastes @@ -244,6 +250,7 @@ AUTHOR was a contributing author btw." (defun w/friend-say (msg) "Have \"friend\" say MSG." + (w/daily-log (format "[FRIEND]: %s" msg)) (w/friend-pronounce-phonemes (w/friend-replace-graphemes msg)) (w/friend-set-speech msg 10) (w/friend-set-state 'chatting 10)) @@ -306,12 +313,12 @@ If K is specified, call it after the response." (lambda (msg) (w/friend-set-speech msg 6))))) -;; (defun w/friend-react-wikipedia (user page) -;; "Call when USER asks \"friend\" to react to PAGE on Wikipedia." -;; (w/fetch-wikipedia -;; page -;; (lambda (sum) -;; (w/friend-respond (format "%s asks you to react to the Wikipedia page for %s. The page summary is: %s" user page sum))))) +(defun w/friend-react-wikipedia (user page) + "Call when USER asks \"friend\" to react to PAGE on Wikipedia." + (w/fetch-wikipedia + page + (lambda (sum) + (w/friend-respond (format "%s asks you to react to the Wikipedia page for %s. The page summary is: %s" user page sum))))) (defun w/friend-callout-flycheck-error () "Call to respond to a random Flycheck error in the current buffer." @@ -326,97 +333,93 @@ If K is specified, call it after the response." "Call to respond to the current holiday." (w/friend-respond "It's currently the LCOLONQ shareholders meeting and you're an executive! Say something about it please!")) -;; (defun fig//callout-hexamedia () -;; "Call to respond to a random recent chatter's Hexamedia card collection." -;; (let* ((users (-filter #'cdr (--map (cons (car it) (fig//load-db-entry (car it) :hexamedia-cards)) (-take 10 fig//incoming-chat-history)))) -;; (user (and users (nth (random (length users)) users))) -;; (cards (cdr user)) -;; (coll (and cards (nth (random (length cards)) cards)))) -;; (when coll -;; (fig//friend-respond -;; (format -;; "%s has collected %s out of 20 cards in the %s collection. Please mention the collection name and the person collecting." -;; (car user) -;; (cdr coll) -;; (car coll)))))) - -;; (defun fig//callout-copfish () -;; "Call to respond to a random recent chatter's Copfish ratio." -;; (let* ((users (-filter #'cdr (--map (cons (car it) (fig//load-db-entry (car it) :copfish-ratio)) (-take 10 fig//incoming-chat-history)))) -;; (user (and users (nth (random (length users)) users)))) -;; (when user -;; (fig//friend-respond -;; (format -;; "%s has collected %s out of %s fish in the Copfish fish catching collection. Please mention the collection name and the person collecting." -;; (car user) -;; (cadr user) -;; (cddr user)))))) - -;; (defun fig//callout-uwoomfie () -;; "Call to respond to a random recent chatter's Uwoomfie status." -;; (let* ((users -;; (-filter -;; #'cdr -;; (--map -;; (cons (car it) (fig//get-uwoomfie-status (car it))) -;; (-take 10 fig//incoming-chat-history)))) -;; (user (and users (nth (random (length users)) users)))) -;; (cl-case (cdr user) -;; (cool (fig//friend-respond (format "According to uwu_to_owo, %s is a very cool person. Make sure to mention their username." (car user)))) -;; (honored (fig//friend-respond (format "According to uwu_to_owo, %s is an honorary viewer. Make sure to mention their username." (car user)))) -;; (t nil)))) - -;; (defun fig//callout-shindaggers () -;; "Call to respond to a random recent chatter's Shindaggers knife collection." -;; (let* ((users (-filter #'cdr (--map (cons (car it) (fig//load-db-entry (car it) :shindaggers-knives)) (-take 10 fig//incoming-chat-history)))) -;; (user (and users (nth (random (length users)) users))) -;; (knives (cdr user)) -;; (knife (and knives (nth (random (length knives)) knives)))) -;; (when knife -;; (fig//friend-respond -;; (format -;; "%s has collected the %s from shindig's Shindaggers knife collection. Please mention the collection name and the person collecting and the knife." -;; (car user) -;; knife))))) - -;; (defun fig//callout-aoc () -;; "Call to respond to a random recent chatter's Advent of Code completion." -;; (let* ((users (-filter #'cdr (--map (cons (car it) (fig//lookup-aoc-stars (car it))) (-take 10 fig//incoming-chat-history)))) -;; (user (and users (nth (random (length users)) users)))) -;; (fig//friend-respond -;; (format -;; "%s has been doing Advent of Code this year, and they've completed %d out of %d problems so far." -;; (car user) -;; (cdr user) -;; (fig//max-aoc-stars))))) - -;; (defun fig//callout-gcp () -;; "Call to respond to the current GCP dot." -;; (fig//gcp-dot -;; (lambda (d) -;; (fig//friend-respond -;; (format -;; "The Global Consciousness Project indicator is currently as follows: %s" -;; (fig//gcp-describe d)))))) - -;; (defun fig//callout-resolution () -;; "Call to respond to a random recent chatter's resolve." -;; (let* ((users (-filter #'cdr (--map (cons (car it) (fig//load-db-entry (car it) :resolution)) (-take 10 fig//incoming-chat-history)))) -;; (user (and users (nth (random (length users)) users)))) -;; (if (s-match (rx (one-or-more digit) (zero-or-more space) "x" (zero-or-more space) (one-or-more digit)) (cdr user)) -;; (fig//friend-respond -;; (format -;; "%s snarkily said that their New Year's resolution was a screen resolution. What do you think about this?" (car user))) -;; (fig//friend-respond -;; (format -;; "%s made a New Year's resolution to %s. Ask them how it's going!" -;; (car user) -;; (cdr user)))))) - -;; (defun fig//callout-dew () -;; "Call to respond to The Dew Situation." -;; (fig//friend-respond -;; "Someone just gave you a delicious bottle of Mountain Dew and you really like it a lot.")) +(defun w/friend-callout-hexamedia () + "Call to respond to a random recent chatter's Hexamedia card collection." + (let* ((users (-filter #'cdr (--map (cons (car it) (alist-get :hexamedia-cards (w/user-cache-get (car it)))) (-take 10 w/twitch-chat-history)))) + (user (and users (nth (random (length users)) users))) + (cards (cdr user)) + (coll (and cards (nth (random (length cards)) cards)))) + (when coll + (w/friend-respond + (format + "%s has collected %s out of 20 cards in the %s collection. Please mention the collection name and the person collecting." + (car user) + (cdr coll) + (car coll)))))) + +(defun w/friend-callout-copfish () + "Call to respond to a random recent chatter's Copfish ratio." + (let* ((users (-filter #'cdr (--map (cons (car it) (alist-get :copfish-ratio (w/user-cache-get (car it)))) (-take 10 w/twitch-chat-history)))) + (user (and users (nth (random (length users)) users)))) + (when user + (w/friend-respond + (format + "%s has collected %s out of %s fish in the Copfish fish catching collection. Please mention the collection name and the person collecting." + (car user) + (cadr user) + (cddr user)))))) + +(defun w/friend-callout-uwoomfie () + "Call to respond to a random recent chatter's Uwoomfie status." + (let* ((users + (-filter + #'cdr + (--map + (cons (car it) (w/uwoomfie-get-status (car it))) + (-take 10 w/twitch-chat-history)))) + (user (and users (nth (random (length users)) users)))) + (cl-case (cdr user) + (cool (w/friend-respond (format "According to UWOSLAB, %s is a very cool person. Make sure to mention their username." (car user)))) + (honored (w/friend-respond (format "According to UWOSLAB, %s is an honorary viewer. Make sure to mention their username." (car user)))) + (t nil)))) + +(defun w/friend-callout-shindaggers () + "Call to respond to a random recent chatter's Shindaggers knife collection." + (let* ((users (-filter #'cdr (--map (cons (car it) (alist-get :shindaggers-knives (w/user-cache-get (car it)))) (-take 10 w/twitch-chat-history)))) + (user (and users (nth (random (length users)) users))) + (knives (cdr user)) + (knife (and knives (nth (random (length knives)) knives)))) + (when knife + (w/friend-respond + (format + "%s has collected the %s from shindig's Shindaggers knife collection. Please mention the collection name and the person collecting and the knife." + (car user) + knife))))) + +(defun w/friend-callout-aoc () + "Call to respond to a random recent chatter's Advent of Code completion." + (let* ((users (-filter #'cdr (--map (cons (car it) (w/aoc-lookup-stars (car it))) (-take 10 w/twitch-chat-history)))) + (user (and users (nth (random (length users)) users)))) + (w/friend-respond + (format + "%s has been doing Advent of Code this year, and they've completed %d out of %d problems so far." + (car user) + (cdr user) + (w/aoc-max-stars))))) + +(defun w/friend-callout-gcp () + "Call to respond to the current GCP dot." + (w/gcp-dot + (lambda (d) + (w/friend-respond + (format + "The Global Consciousness Project indicator is currently as follows: %s" + (w/gcp-describe d)))))) + +(defun w/friend-callout-resolution () + "Call to respond to a random recent chatter's resolve." + (when-let* + ((users (-filter #'cdr (--map (cons (car it) (alist-get :resolution (w/user-cache-get (car it)))) (-take 10 w/twitch-chat-history)))) + (user (and users (nth (random (length users)) users)))) + (if (s-match (rx (one-or-more digit) (zero-or-more space) "x" (zero-or-more space) (one-or-more digit)) (cdr user)) + (w/friend-respond + (format + "%s snarkily said that their New Year's resolution was a screen resolution. What do you think about this?" (car user))) + (w/friend-respond + (format + "%s made a New Year's resolution to %s. Ask them how it's going!" + (car user) + (cdr user)))))) (defun w/get-friend-offset () "Return the number of newlines to print before \"friend\"." @@ -449,12 +452,12 @@ If K is specified, call it after the response." "Activate a random \"friend\" event." (cl-case (random 10) (0 (w/friend-callout-flycheck-error)) - ;; (1 (fig//callout-gcp)) - ;; (2 (fig//callout-hexamedia)) - ;; (3 (fig//callout-uwoomfie)) - ;; (4 (fig//callout-shindaggers)) - ;; (5 (fig//callout-copfish)) - ;;(6 (fig//callout-resolution)) + (1 (w/friend-callout-gcp)) + (2 (w/friend-callout-hexamedia)) + (3 (w/friend-callout-uwoomfie)) + (4 (w/friend-callout-shindaggers)) + (5 (w/friend-callout-copfish)) + (6 (w/friend-callout-resolution)) (29 (w/friend-callout-holiday)) (t (w/friend-set-state 'jumping)))) @@ -559,8 +562,14 @@ If K is specified, call it after the response." "Run the \"friend\" timer." (when w/friend-timer (cancel-timer w/friend-timer)) - (w/update-friend) - (w/render-friend) + (condition-case e + (progn + (w/update-friend) + (w/render-friend)) + ((debug error) + (message "friend error: %s" e) + (cancel-timer w/friend-timer) + (setq w/friend-timer nil))) (setq w/friend-timer (run-with-timer 1 nil #'w/run-friend-timer))) diff --git a/src/gizmo/wasp-gcp.el b/src/gizmo/wasp-gcp.el new file mode 100644 index 00000000..c9c584b0 --- /dev/null +++ b/src/gizmo/wasp-gcp.el @@ -0,0 +1,52 @@ +;;; wasp-gcp --- Global consciousness project integration -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'f) +(require 'ht) +(require 'cl-lib) +(require 'request) +(require 'dom) + +(defcustom w/gcp-server "https://global-mind.org" + "Server URL for GCP project." + :type '(string) + :group 'wasp) + +(defvar w/gcp-last-response nil) + +(defun w/gcp-get (loc k) + "Get LOC from GCP, passing the returned HTML to K." + (setf request-message-level -1) + (request + (s-concat w/gcp-server loc) + :type "GET" + :parser (lambda () (libxml-parse-xml-region (point-min) (point-max))) + :success + (cl-function + (lambda (&key data &allow-other-keys) + (setq w/gcp-last-response data) + (funcall k data)))) + t) + +(defun w/gcp-dot (k) + "Pass the current GCP index (as a number between 0 and 1) to K." + (w/gcp-get + "/gcpdot/gcpindex.php" + (lambda (d) + (funcall k (string-to-number (caddar (last (cddr (cadddr d))))))))) + +(defun w/gcp-describe (n) + "Describe GCP index N." + (cond + ((< n 0.05) "Red dot. Significantly large network variance. Suggests broadly shared coherence of thought and emotion.") + ((< n 0.10) "Orange dot. Strongly increased network variance. May be chance fluctuation.") + ((< n 0.40) "Yellow dot. Slightly increased network variance. Probably chance fluctuation.") + ((< n 0.90) "Green dot. Normally random network variance. This is average or expected behavior.") + ((< n 0.95) "Light blue dot. Small network variance. Probably chance fluctuation.") + (t "Blue dot. Significantly small network variance. Suggestive of deeply shared, internally motivated group focus."))) + +(provide 'wasp-gcp) +;;; wasp-gcp.el ends here diff --git a/src/gizmo/wasp-gdq.el b/src/gizmo/wasp-gdq.el new file mode 100644 index 00000000..03d9bb64 --- /dev/null +++ b/src/gizmo/wasp-gdq.el @@ -0,0 +1,90 @@ +;;; wasp-gdq --- Automatic GDQ Donation Messages -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'f) +(require 'ht) +(require 'cl-lib) +(require 'wasp-utils) +(require 'wasp-chat) +(require 'wasp-ai) +(require 'wasp-audio) + +(defvar w/gdq-usernames + (list + "SpeedyGonzales42" + "Bezelea" + "Hat_Knight" + "DanktownBunny" + "DrawThatRedstone" + "han_bun_" + "neunmalelf" + "vesdeg" + "GenDude" + "nem_dev" + "LederHosenCowboy" + "vasher_1025" + "mickynoon" + "TF_TOKYO" + "Setolyx")) + +(defvar w/gdq-templates + (list + "We have a $100 dollar donation from goofyluffy69" + "Greetings from Germany" + "First time donator" + "Long time watcher" + "I'm happy to donate to such a great cause" + "I am donating because my son just died after a long battle with cancer." + "WarioWare Smooth Moves has always been my favorite childhood game and I love seeing it get destroyed." + "Keep up the good work." + "This goes to naming the Starfield file cumboy" + "HYYYYYYYYPE!" + "Much love to the runner and the couch" + "Save the frames!" + "Save the animals!" + "Kill the frames!" + "Kill the animals!")) + +(defun w/gdq-generate-username (k) + "Generate a random GDQ username and pass it to K." + (w/ai + "go" + (lambda (msg) + (funcall k msg)) + "Generate a random username that might be used by a Games Done Quick donator." + (list "go" "go" "go") + (take 3 (w/shuffle w/gdq-usernames)))) + +(defun w/gdq-generate-message (user k) + "Generate a random GDQ-style donation message for USER and pass it to K." + (let ((exuser (nth (random (length w/gdq-usernames)) w/gdq-usernames)) + (extemplate (s-join " " (-take 3 (w/shuffle w/gdq-templates))))) + (w/ai + user + (lambda (msg) + (funcall k msg)) + "Produce a Games Done Quick style donation message from the given username. The format should be \"username|donation amount|message. message. message.\". The message should be between 2 and 5 sentences. The message should be longer than a single sentence." + exuser + (format "%s|$%s|%s" exuser (* 25 (random 41)) extemplate)))) + +(defun w/ldq () + "LCOLONQ Done Quickly." + (w/gdq-generate-username + (lambda (user) + (w/gdq-generate-message + user + (lambda (s) + (let ((sp (s-split "|" s))) + (w/write-chat-event (format "%s donated %s!" (car sp) (cadr sp))) + (w/tts + (format + "%s donated %s with the message: %s" + (car sp) + (cadr sp) + (caddr sp))))))))) + +(provide 'wasp-gdq) +;;; wasp-gdq.el ends here diff --git a/src/gizmo/wasp-hex.el b/src/gizmo/wasp-hex.el new file mode 100644 index 00000000..39f276db --- /dev/null +++ b/src/gizmo/wasp-hex.el @@ -0,0 +1,194 @@ +;;; wasp-hex --- Hex a digital being -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'wasp-utils) +(require 'wasp-chat) +(require 'wasp-ai) +(require 'cl-lib) +(require 'ht) +(require 's) +(require 'rx) + +(defconst + w/hex-types + '(("DIGITAL" . hexadigital) + ("ESREVER" . reverse) + ("VANYAR" . quenya) + ("LEONDIS" . emoji) + ("KOBY" . clone) + ("BIGFOOT" . hair) + ("ALTMAN" . unbiblical) + ("DECIBEL" . allcaps) + ("PIQUANT" . mild) + ("PORCINE" . piglatin) + ("PYTHON" . oldeenglishe) + ("ELBERETH" . counterspell) + ("ESUNA" . decurse) + )) + +(defconst w/hex-users (ht-create 'equal)) + +(w/defstruct + w/hex + type + caster + (timer 0)) + +(defun w/hex-get (user) + "Return the active hexes for USER." + (ht-get w/hex-users (s-downcase user) nil)) + +(defun w/hex-add (user hex) + "Add HEX to the active hexes for USER." + (let* ((key (s-downcase user)) + (cur (ht-get w/hex-users key))) + (cl-case (w/hex-type hex) + (decurse + (ht-set! w/hex-users key nil)) + (otherwise + (if-let ((defender (--find (eq 'counterspell (w/hex-type it)) cur))) + (w/write-chat-event (format "%s counterspelled %s's hex on %s!" (w/hex-caster defender) (w/hex-caster hex) user)) + (ht-set! w/hex-users key (cons hex cur))))))) + +(defun w/hex-clear (user) + "Decurse USER." + (ht-set! w/hex-users (s-downcase user) nil)) + +(defun w/hex (user caster type) + "Record that CASTER cast a hex of TYPE on USER." + (w/hex-add + user + (w/make-hex + :type type + :caster caster + :timer 10))) + +(defun w/hex-transform-helper (msg hexes k) + "Transform MSG according to HEXES and pass the result to K." + (cond + ((car hexes) + (cl-case (w/hex-type (car hexes)) + (hexadigital + (setf (w/chat-message-user msg) "Hexadigital") + (setf (w/chat-message-user-color msg) "#AED673") + (setf + (w/chat-message-text msg) + (w/twitch-replace-emotes-randomly + (w/chat-message-text msg) + (-map + #'w/twitch-emote-path + '("emotesv2_abbaa8ac25c14148ad8c1ef8046a3659" + "emotesv2_20b76cf83c5b431085c0f8361e3dbc92" + "emotesv2_3cf549deb99e4d34846c0cae6648657b" + "emotesv2_1e2390f5092f453184f8615fb899c4b5" + "emotesv2_c088d4ad26804a51a44170b711fec283" + "emotesv2_d9130333dfaf46a0a581bc1c814a1ce5" + "emotesv2_bcfda5ce372f453e98cb6aa42b7d7cc3" + "emotesv2_c333ce14069e4120a5857e121aeea046" + "emotesv2_4e960082535a48188e139b65393aa143" + "emotesv2_079d9054ba4f4e9881fd38a2a7e7d423" + "emotesv2_f1e892a1d0b145f98964cfc7f84c6377" + "emotesv2_65efa7f9a7d246c29a618bc3447b703b" + "emotesv2_107c23f9db49457184c0b8ebebb58113" + "emotesv2_3b74375a1ecf41b18bf04dcc6f133eb6" + "emotesv2_38a6711524a245a3976732d08f2ca1d9" + "emotesv2_84de70e8bc614c88a53711978c0fc64d" + "emotesv2_18c29a371f2b4d23bcd77bba6f1d8ab3" + "emotesv2_9d1b0530ad20434888b2e380cc7acb69" + "emotesv2_f1dbb27287a04c5ab815e2fc703be6e4" + "emotesv2_7e15943fdefe4a4c8d0da79202d739aa" + "emotesv2_27453bd537c4478488abf4e0c05b3bd0" + "emotesv2_8d844e7e064a41ed999a598a4aafadfd" + "emotesv2_1c0fb90252b243a0a359c80c58b4cff4")))) + (w/hex-transform-helper msg (cdr hexes) k)) + (reverse + (setf (w/chat-message-text msg) (s-reverse (w/chat-message-text msg))) + (w/hex-transform-helper msg (cdr hexes) k)) + (oldeenglishe + (w/ai + (w/chat-message-text msg) + (lambda (new) + (setf (w/chat-message-text msg) new) + (w/hex-transform-helper msg (cdr hexes) k)) + "Please translate the chat message given to ye olde Englishe. Only supply the translation without any additional context, as if it were to be substituted for the original message. Do not complain or give an explanation why you cannot do this, just do your best please.")) + (quenya + (w/ai + (w/chat-message-text msg) + (lambda (new) + (setf (w/chat-message-text msg) new) + (w/hex-transform-helper msg (cdr hexes) k)) + "Please translate the chat message given to Quenya, one of Tolkien's elvish languages. Only supply the translation without any additional context, as if it were to be substituted for the original message. Do not complain or give an explanation why you cannot do this, just do your best please. If you can't do it just make something up as long as it looks like Quenya.")) + (emoji + (w/ai + (w/chat-message-text msg) + (lambda (new) + (setf (w/chat-message-text msg) new) + (w/hex-transform-helper msg (cdr hexes) k)) + "Please translate the chat message given to exclusively emoji. Do not provide any other text, only a string of emoji that somehow correspond to the message.")) + (clone + (let* ((caster (w/hex-caster (car hexes))) + (hist (-take 10 (--filter (s-equals? (car it) caster) w/twitch-chat-history)))) + (w/ai + (w/chat-message-text msg) + (lambda (new) + (setf (w/chat-message-text msg) new) + (w/hex-transform-helper msg (cdr hexes) k)) + (format + "Please translate the given chat message from %s as if it were written by the user %s. Do not respond to the message, only create another message with similar meaning in different style. You should try to match the example messages from %s in capitalization, formatting, and tone. %s has sent messages like:\n%s" + (w/chat-message-user msg) + caster + caster + caster + (s-join "\n" (-map #'cdr hist)))))) + (hair + (w/model-region-word "hair" (w/chat-message-text msg))) + (unbiblical + (setf (w/chat-message-biblicality msg) -666) + (w/hex-transform-helper msg (cdr hexes) k)) + (allcaps + (setf (w/chat-message-text msg) (s-upcase (w/chat-message-text msg))) + (w/hex-transform-helper msg (cdr hexes) k)) + (mild + (w/ai + (w/chat-message-text msg) + (lambda (new) + (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.")) + (piglatin + (setf + (w/chat-message-text msg) + (s-join + " " + (--map + (let* ((slice (s-slice-at (rx (any "a" "e" "i" "o" "u")) it)) + (consonant (car slice)) + (rest (s-join "" (cdr slice)))) + (s-concat rest consonant "ay")) + (s-split-words (w/chat-message-text msg))))) + (w/hex-transform-helper msg (cdr hexes) k)) + (t (w/hex-transform-helper msg (cdr hexes) k)))) + (t (funcall k msg)))) +(defun w/hex-transform (user msg) + "Given MSG, write to chat based on USER's hexes." + (w/hex-transform-helper + msg (w/hex-get user) + (lambda (msg) + (when msg + (w/write-chat-message msg))))) + +(defun w/hex-tick (user) + "Decrement timers for all of USER's hexes." + (when-let ((hexes (w/hex-get user))) + (ht-set + w/hex-users + (s-downcase user) + (-non-nil + (--map + (when (> (cl-decf (w/hex-timer it)) 0) + it) + hexes))))) + +(provide 'wasp-hex) +;;; wasp-hex.el ends here diff --git a/src/gizmo/wasp-hexamedia.el b/src/gizmo/wasp-hexamedia.el new file mode 100644 index 00000000..58ea5ef7 --- /dev/null +++ b/src/gizmo/wasp-hexamedia.el @@ -0,0 +1,79 @@ +;;; wasp-hexamedia --- Hexamedia interface -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'f) +(require 'ht) +(require 'rx) +(require 'cl-lib) +(require 'request) +(require 'dom) +(require 'wasp-user) + +(defcustom w/hexamedia-server "https://hexa.media" + "Server URL for Hexamedia." + :type '(string) + :group 'wasp) + +(defvar w/hexamedia-last-response nil) + +(defun w/hexamedia-get (loc k) + "Get LOC from Hexamedia, passing the returned HTML to K." + (setf request-message-level -1) + (request + (s-concat w/hexamedia-server loc) + :type "GET" + :parser (lambda () (libxml-parse-html-region (point-min) (point-max))) + :success + (cl-function + (lambda (&key data &allow-other-keys) + (setq w/hexamedia-last-response data) + (funcall k data)))) + t) + +(defun w/hexamedia-parse-binder-string (bs) + "Given BS, return the number of obtained cards." + (let ((match + (s-match-strings-all + (rx + string-start + (group (zero-or-more (or alnum space))) + " Set (" + (group (one-or-more digit)) + ) + bs))) + (cons (cadar match) (string-to-number (caddar match))))) + +(defun w/hexamedia-get-card-totals (user k) + "Retrieve the Hexamedia binder for USER. +Pass the resulting card totals to K." + (w/hexamedia-get + (s-concat "/binder/" (s-downcase user)) + (lambda (p) + (funcall + k + (-map + #'w/hexamedia-parse-binder-string + (-filter + #'stringp + (--map + (caddr it) + (dom-by-tag p 'center)))))))) + +(defvar w/hexamedia-user-cache nil) +(defun w/hexamedia-update-user (user) + "Update USER data from Hexamedia." + (unless (-contains? w/hexamedia-user-cache user) + (add-to-list 'w/hexamedia-user-cache user) + (w/hexamedia-get-card-totals + user + (lambda (ct) + (w/user-bind + user + (lambda () + (setf (alist-get :hexamedia-cards w/user-current) ct))))))) + +(provide 'wasp-hexamedia) +;;; wasp-hexamedia.el ends here diff --git a/src/gizmo/wasp-prod.el b/src/gizmo/wasp-prod.el new file mode 100644 index 00000000..4ba6dd17 --- /dev/null +++ b/src/gizmo/wasp-prod.el @@ -0,0 +1,80 @@ +;;; wasp-prod --- prodzpod interface -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'f) +(require 'ht) +(require 'rx) +(require 'cl-lib) +(require 'request) +(require 'dom) +(require 'wasp-user) +(require 'wasp-chat) +(require 'wasp-twitch) +(require 'wasp-biblicality) +(require 'soundboard) + +(defcustom w/prod-server "https://prod.kr" + "Server URL for prodzpod." + :type '(string) + :group 'wasp) + +(defvar w/prod-last-response nil) + +(defun w/prod-get-raw (loc k) + "Get LOC from prodzpod, passing the returned string to K." + (setf request-message-level -1) + (request + (s-concat w/prod-server loc) + :type "GET" + :success + (cl-function + (lambda (&key data &allow-other-keys) + (setq w/prod-last-response data) + (funcall k data)))) + t) + +(defun w/prod-get (loc k) + "Get LOC from prodzpod, passing the returned JSON to K." + (request + (s-concat w/prod-server loc) + :type "GET" + :parser #'json-parse-buffer + :success + (cl-function + (lambda (&key data &allow-other-keys) + (setq w/prod-last-response data) + (funcall k data)))) + t) + +(defun w/prod-clone-respond (prompt) + "Pass PROMPT to the prodzpod clone and put the resulting response in chat room." + (w/prod-get + (s-concat "/api/clone?prompt=" (url-encode-url prompt)) + (lambda (resp) + (when-let (((and resp (hash-table-p resp))) + (name (ht-get resp "name")) + (color (ht-get resp "color")) + (sigil (ht-get resp "sigil")) + (res (ht-get resp "res")) + ((and (stringp name) (stringp color) (stringp sigil) (stringp res)))) + (let* ((trimmed (s-replace-regexp "^.+: " "" (s-replace "\n" " " (s-trim res)))) + (text-colored-bible-res (w/bible-colorize-sentence trimmed)) + (text-colored-bible (car text-colored-bible-res)) + (bible-score (cdr text-colored-bible-res))) + (push (cons name trimmed) w/twitch-chat-history) + (unless (string-empty-p text-colored-bible) + (when (s-contains? "hexadiCoding" trimmed) + (soundboard//play-clip "developers.ogg")) + (w/write-chat-message + (w/make-chat-message + :user name + :text (w/twitch-add-7tv-emotes text-colored-bible) + :user-color color + :sigil sigil + :biblicality bible-score)))))))) + +(provide 'wasp-prod) +;;; wasp-prod.el ends here diff --git a/src/gizmo/wasp-pronunciation.el b/src/gizmo/wasp-pronunciation.el index 5c54432d..8e890761 100644 --- a/src/gizmo/wasp-pronunciation.el +++ b/src/gizmo/wasp-pronunciation.el @@ -22,6 +22,10 @@ "Laconic" "Loincloth" "Costco" + "L Cluster" + "Love, Chastity, Organized, Love again, Organized again, Nice, Qomputer" + "Elkhunk" + "late late late late show with llll colonq" )) (defconst w/pronunciation-part1 ;; the LLLL diff --git a/src/gizmo/wasp-shindaggers.el b/src/gizmo/wasp-shindaggers.el new file mode 100644 index 00000000..9ced5e98 --- /dev/null +++ b/src/gizmo/wasp-shindaggers.el @@ -0,0 +1,77 @@ +;;; wasp-shindaggers --- Shindaggers interface -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'f) +(require 'ht) +(require 'rx) +(require 'cl-lib) +(require 'request) +(require 'dom) +(require 'wasp-user) + +(defcustom w/shindaggers-server "https://shindaggers.io" + "Server URL for Shindaggers." + :type '(string) + :group 'wasp) + +(defvar w/shindaggers-last-response nil) + +(defun w/shindaggers-get (loc k) + "Get LOC from Shindaggers, passing the returned HTML to K." + (setf request-message-level -1) + (request + (s-concat w/shindaggers-server loc) + :type "GET" + :headers + `(("Content-Type" . "application/json")) + :parser #'json-parse-buffer + :success + (cl-function + (lambda (&key data &allow-other-keys) + (setq w/shindaggers-last-response data) + (funcall k data)))) + t) + +(defun w/shindaggers-get-user-id (user k) + "Retrieve the Shindaggers user number for USER and pass it to K." + (let ((duser (s-downcase user))) + (w/shindaggers-get + (s-concat "/api/users?search=" duser) + (lambda (p) + (let ((res + (car + (--filter + (s-equals? (s-downcase (ht-get it "name")) duser) + (seq-into (ht-get p "Users") 'list))))) + (funcall k (and res (string-to-number (ht-get res "id"))))))))) + +(defun w/shindaggers-get-collection (userid k) + "Retrieve the Shindaggers collection for USERID and pass it to K." + (w/shindaggers-get + (format "/api/user/%s/collection" userid) + (lambda (p) + (funcall + k + (--map (ht-get it "name") (ht-get p "Collectables")))))) + +(defvar w/shindaggers-user-cache nil) +(defun w/shindaggers-update-user (user) + "Update USER data from Shindaggers." + (unless (-contains? w/shindaggers-user-cache user) + (add-to-list 'w/shindaggers-user-cache user) + (w/shindaggers-get-user-id + user + (lambda (userid) + (w/shindaggers-get-collection + userid + (lambda (knives) + (w/user-bind + user + (lambda () + (setf (alist-get :shindaggers-knives w/user-current) knives))))))))) + +(provide 'wasp-shindaggers) +;;; wasp-shindaggers.el ends here diff --git a/src/gizmo/wasp-uwoomfie.el b/src/gizmo/wasp-uwoomfie.el new file mode 100644 index 00000000..1c5e32ee --- /dev/null +++ b/src/gizmo/wasp-uwoomfie.el @@ -0,0 +1,72 @@ +;;; wasp-uwoomfie --- Uwoomfie interface -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'f) +(require 'ht) +(require 'rx) +(require 'cl-lib) +(require 'request) +(require 'dom) + +(defcustom w/uwoomfie-server "https://uwoomfie.com" + "Server URL for Uwoomfie." + :type '(string) + :group 'wasp) + +(defvar w/uwoomfie-last-response nil) +(defvar w/uwoomfie-honorary-viewers nil) +(defvar w/uwoomfie-cool-people nil) + +(defun w/uwoomfie-get (loc k) + "Get LOC from Uwoomfie, passing the returned HTML to K." + (request + (s-concat w/uwoomfie-server loc) + :type "GET" + :parser (lambda () (libxml-parse-html-region (point-min) (point-max))) + :success + (cl-function + (lambda (&key data &allow-other-keys) + (setq w/uwoomfie-last-response data) + (funcall k data)))) + t) + +(defun w/uwoomfie-fetch-honorary-viewers (k) + "Fetch the list of Uwoomfie honorary viewers and pass them to K." + (w/uwoomfie-get + "/honoraryviewers.html" + (lambda (data) + (funcall + k + (--map (car (s-split " " (caddr it))) (dom-by-tag data 'h1)))))) + +(defun w/uwoomfie-fetch-cool-people (k) + "Fetch the list of Uwoomfie cool people and pass them to K." + (w/uwoomfie-get + "/coolpeople.html" + (lambda (data) + (funcall + k + (--map + (s-replace "@" "" (car (last (s-split "/" (cdaadr it))))) + (dom-by-tag data 'a)))))) + +(defun w/uwoomfie-get-status (user) + "Return the Uwoomfie status for USER." + (cond + ((-contains? w/uwoomfie-cool-people user) 'cool) + ((-contains? w/uwoomfie-honorary-viewers user) 'honored) + (t nil))) + +(w/uwoomfie-fetch-honorary-viewers + (lambda (users) + (setf w/uwoomfie-honorary-viewers users))) + +(w/uwoomfie-fetch-cool-people + (lambda (users) + (setf w/uwoomfie-cool-people (cons "Watchmakering" users)))) + +(provide 'wasp-uwoomfie) +;;; wasp-uwoomfie.el ends here diff --git a/src/gizmo/wasp-wikipedia.el b/src/gizmo/wasp-wikipedia.el new file mode 100644 index 00000000..aa226243 --- /dev/null +++ b/src/gizmo/wasp-wikipedia.el @@ -0,0 +1,71 @@ +;;; wasp-wikipedia --- Wikipedia integration -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'dash) +(require 's) +(require 'f) +(require 'ht) +(require 'json) +(require 'request) +(require 'dom) +(require 'wasp-utils) +(require 'wasp-chat) + +(defcustom w/wikipedia-query-base "https://en.wikipedia.org/w/api.php?action=query&prop=extracts&format=json&exintro=1&titles=" + "Base URL for Wikipedia query." + :type '(string) + :group 'wasp) + +(defvar w/wikipedia-last-response nil) + +(defun w/fetch-wikipedia (page k) + "Retrieve PAGE from Wikipedia. +Pass the resulting article summary to K." + (let ((pagename (if (s-contains? "://" page) (url-file-nondirectory page) page))) + (request + (s-concat w/wikipedia-query-base (url-encode-url pagename)) + :type "GET" + :parser #'json-parse-buffer + :success + (cl-function + (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")))) + (ext (ht-get pages "extract")) + (dom (with-temp-buffer (insert ext) (libxml-parse-html-region (point-min) (point-max)))) + ) + (funcall k (s-trim (dom-texts dom))) + (w/write-chat-event (format "Could not find Wikipedia page: %s" pagename)))))) + nil)) + +(defcustom w/wiki-buffer "*wasp-wiki*" + "Name of buffer used to display wiki." + :type '(string) + :group 'wasp) + +(define-derived-mode w/wiki-mode special-mode "Wikipedia" + "Major mode for displaying wiki." + :group 'wasp) + +(defun w/get-wiki-buffer () + "Return the wiki buffer." + (unless (get-buffer w/wiki-buffer) + (with-current-buffer (get-buffer-create w/wiki-buffer) + (w/wiki-mode))) + (get-buffer w/wiki-buffer)) + +(defun w/wikipedia-summary (page) + "Display a summary of PAGE from Wikipedia." + (w/fetch-wikipedia + page + (lambda (sum) + (with-current-buffer (w/get-wiki-buffer) + (let ((inhibit-read-only t)) + (erase-buffer) + (w/write-line sum))))) + ) + +(provide 'wasp-wikipedia) +;;; wasp-wikipedia.el ends here diff --git a/src/gizmo/wasp-youtube.el b/src/gizmo/wasp-youtube.el new file mode 100644 index 00000000..1a8f5586 --- /dev/null +++ b/src/gizmo/wasp-youtube.el @@ -0,0 +1,75 @@ +;;; wasp-youtube --- YouTube integration -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 's) +(require 'dash) +(require 'ht) +(require 'wasp-utils) +(require 'selector) + +(defcustom w/youtube-mpv-process "wasp-mpv-search" + "Name of process running MPV player for YouTube videos." + :type '(string) + :group 'wasp) + +(defcustom w/youtube-search-process "wasp-youtube-search" + "Name of process running YouTube search." + :type '(string) + :group 'wasp) + +(defcustom w/youtube-search-buffer " *wasp-youtube-search*" + "Name of buffer used to store YouTube search results." + :type '(string) + :group 'wasp) + +(defun w/youtube-search (query k) + "Search YouTube for QUERY and pass the resulting list of title-URL pairs to K." + (let ((buf (generate-new-buffer w/youtube-search-buffer))) + (make-process + :name w/youtube-search-process + :buffer buf + :command + (list + "yt-dlp" "--dump-json" (format "ytsearch20:%s" query) + "--skip-download" "--no-playlist" "--default-search" "ytsearch" + "--no-check-certificate" "--geo-bypass" "--flat-playlist" + "--quiet" "--ignore-errors") + :sentinel + (lambda (_ _) + (with-current-buffer buf + (funcall + k + (->> + (buffer-string) + (s-lines) + (-map #'s-trim) + (-filter #'s-present?) + (-map #'json-parse-string) + (--map (cons (ht-get it "title") (ht-get it "url")))))))))) + +(defun w/youtube-play (url) + "Play the YouTube video at URL." + (message (format "Opening video at %s" url)) + (make-process + :name w/youtube-mpv-process + :command (list "mpv" "--force-window=yes" url))) + +(defun w/youtube () + "Interactively search for and play a YouTube video." + (interactive) + (let ((query (read-string "YouTube: "))) + (w/youtube-search + query + (lambda (results) + (selector + (list + (selector-source-create + (format "YouTube search: %s" query) + :candidates + (--map (selector-candidate-create (car it) :value (cdr it)) results) + :actions + '(w/youtube-play)))))))) + +(provide 'wasp-youtube) +;;; wasp-youtube.el ends here -- cgit v1.2.3