From ee6209d50d6d52b0be3810118ee1a7ee502aed04 Mon Sep 17 00:00:00 2001 From: pi-bot-01 Date: Thu, 26 Mar 2026 01:01:07 -0700 Subject: [PATCH] Initial commit --- cb.el | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 cb.el diff --git a/cb.el b/cb.el new file mode 100644 index 0000000..e83692b --- /dev/null +++ b/cb.el @@ -0,0 +1,140 @@ +;;; Provides functions for streaming chaturbate as the desktop wallpaper +(require 'cl-lib) +(require 'url-parse) +(require 'enlive) +(require 'f) +(require 'python) +(require 'transparency) + +(defgroup cb nil + "Settings for cb." + :group 'multimedia) + +(defcustom cb-streamlink-quality "720p,1080p,best" + "Video quality to use in streamlink." + :type 'string + :group 'cb) + +(defcustom cb-cons-python-script "/home/oc/git/chaturbate/cons.py" + "Location of python script to use in `cb-stream-list' function." + :type 'string + :group 'cb) + +(defcustom cb-screenshot-directory "/home/oc/Pictures/screenshots/.cb/" + "Directory to store screenshots in. +Must have a trailing `/'" + :type 'string + :group 'cb) + +;;; This is a mess. I should separate out the command portion, +;;; making it an argument +;;; there should also be pre and post block evaluation. +(defun streamlink (url name) + "Opens url with steamlink in the background window after +killing previous process. +Turns on transparency as well." + (interactive) + (let* ((inhibit-message t) + (process-name "streamlink") + (buffer-name (format "*%s*" process-name)) + (command (if (string-equal system-type "windows-nt") +" +mpv --no-config --no-osc --no-border --cache=yes --mute=yes --geometry=--0+0 +--fs --screenshot-template=%n +--screenshot-directory=" +" +xwinwrap -g 1920x1080 -ov -- mpv -wid WID --input-ipc-server=/tmp/mpv +--no-config --no-osc --cache=yes --mute=yes --geometry=--0+0 +--no-input-default-bindings --screenshot-template=%n +--screenshot-directory=" + + )) + (command (if (boundp 'cb-player-command) + cb-player-command + (concat (mapconcat 'identity (split-string command) " ") + cb-screenshot-directory name)))) + (ignore-errors (delete-process process-name)) + (set-process-sentinel + (start-process "streamlink" "*streamlink*" + "streamlink" url cb-streamlink-quality + "--player" command) + (lambda (p e) + (unless (process-live-p p) + (message "Streamlink process finished.") + (unless (boundp 'cb-player-command) + (when transparency-state + (transparency-toggle)))))) + (unless (boundp 'cb-player-command) + (unless transparency-state + (transparency-toggle))) )) + +(defun cb-kill () + "Kills streamlink process." + (interactive) + (let ((inhibit-message t)) + (ignore-errors + (delete-process "streamlink")))) + +(defun cb-mute () + "mute/unmute mpv" + (interactive) + (start-process + "mpv-toggle-mute" nil "python3" + "/home/oc/git/chaturbate/mpv.py" + "mute")) + +(defun cb-screenshot () + "Take a screenshot" + (interactive) + (start-process + "mpv-screenshot" nil "python3" + "/home/oc/git/chaturbate/mpv.py" + "screenshot")) + +(defun cb-stream-list-python () + "Select stream." + (interactive) + (let* ((streams (read (shell-command-to-string (format " %s %s" python-shell-interpreter cb-cons-python-script)))) + (stream (assoc (completing-read "Select Stream: " streams) streams)) + (name (car stream)) + (url (cdr stream))) + (streamlink url name)) ) + +;;; Well, I got the sorting function working, though it depends on `f.el'. +;;; I shouldn't feel averse to using more flexible libraries jsut because +;;; they aren't vanilla, but I still do. If I had a personal package archive +;;; that worked out dependencies, then maybe I would feel better... +(defun cb-stream-list-sorter (a b) + (let ((default-directory cb-screenshot-directory)) + (> + (if (f-dir? (car a)) + (length (f-entries (car a))) + 0) + (if (f-dir? (car b)) + (length (f-entries (car b))) + 0))) ) + +;;; It's somewhat bewildering how clear and concise this is compared to it's python equivalent. +;;; The only thing this lacks is priority for streams with screenshots. +;;; All in due time. List sorting should be easier in lisp. ;) +;;; Learning to write sorting functions for sort was a little challenging. +(defun cb-stream-list (&optional category) + "Select stream. Python free version. Accepts optional category argument." + (interactive) + (let* ((url (url-generic-parse-url (format "https://chaturbate.com/%s" (or category "female-cams")))) + (elements + (enlive-query-all + (enlive-fetch url) + [li.room_list_room > a.no_select])) ) + (let* ((streams + (mapcar + (lambda (e) + (setf (url-filename url) (enlive-attr e 'href)) + (cons (enlive-attr e 'data-room) + (url-recreate-url url)) ) + elements)) + (streams (sort streams 'cb-stream-list-sorter)) ; sort screencapped streams higher + (stream (assoc (completing-read "Select Stream: " streams) streams)) ) + (streamlink (cdr stream) (car stream))) ) ) + +(provide 'cb)