|
;;; thebutton.el --- display r/thebutton's status on the modeline |
|
|
|
;; This is free and unencumbered software released into the public domain. |
|
|
|
;;; Commentary: |
|
|
|
;; Unfortunately the URL's hash changes regularly, so you may need to |
|
;; update `thebutton-url' to the new when first start the mode. |
|
|
|
;; Dependency: https://github.com/ahyatt/emacs-websocket |
|
|
|
;;; Code: |
|
|
|
(require 'json) |
|
(require 'websocket) |
|
|
|
(defvar thebutton-url "http://www.reddit.com/r/thebutton" |
|
"URL of the main subreddit.") |
|
|
|
(defvar thebutton-interval 0.11 |
|
"Period in seconds at which the mode line is updated.") |
|
|
|
(defvar thebutton-timer nil |
|
"Time object used to update the mode line.") |
|
|
|
(defvar thebutton-ws nil |
|
"Websocket object connection to reddit.") |
|
|
|
(defvar thebutton--regex |
|
"wss://wss.redditmedia.com/thebutton\\?h=[0-9a-z]+&e=[0-9]+" |
|
"Matches the current websocket URL from the subreddit.") |
|
|
|
(defvar thebutton--string "" |
|
"Current mode line text (dynamic variable needed for mode line API).") |
|
|
|
(defvar thebutton--finish nil |
|
"Epoch time when the timer will hit zero.") |
|
|
|
(defun thebutton--get-url () |
|
"Fetch the current websocket URL." |
|
(save-match-data |
|
(with-current-buffer (url-retrieve-synchronously thebutton-url t t) |
|
(when (re-search-forward thebutton--regex nil t) |
|
(match-string 0))))) |
|
|
|
(defun thebutton--handler () |
|
"Handles events from the timer." |
|
(when (and thebutton-mode thebutton--finish) |
|
(setf thebutton--string |
|
(format " %.2f" (- thebutton--finish (float-time))))) |
|
(force-mode-line-update 'all)) |
|
|
|
(defun thebutton--on-message (_ f) |
|
"Handles updates from the websocket." |
|
(let* ((json-object-type 'plist) |
|
(json-key-type 'keyword) |
|
(json (json-read-from-string (websocket-frame-payload f))) |
|
(payload (plist-get json :payload)) |
|
(seconds-left (plist-get payload :seconds_left))) |
|
(setf thebutton--finish (+ (float-time) seconds-left)))) |
|
|
|
(define-minor-mode thebutton-mode |
|
"Display the current countdown for r/thebutton in the mode line." |
|
:global t |
|
(when thebutton-timer |
|
(cancel-timer thebutton-timer) |
|
(setf thebutton-timer nil)) |
|
(when thebutton-ws |
|
(websocket-close thebutton-ws) |
|
(setf thebutton-ws nil)) |
|
(unless (member 'thebutton--string global-mode-string) |
|
(setf global-mode-string (nconc global-mode-string `(thebutton--string)))) |
|
(if (not thebutton-mode) |
|
(setf thebutton--string "" |
|
thebutton-timer nil |
|
thebutton--finish nil) |
|
(setf thebutton-timer |
|
(run-at-time t thebutton-interval #'thebutton--handler) |
|
thebutton-ws |
|
(websocket-open |
|
(thebutton--get-url) :on-message #'thebutton--on-message)))) |
|
|
|
;;; thebutton.el ends here |