diff options
Diffstat (limited to 'lisp')
-rw-r--r-- | lisp/mastodon-notifications.el | 4 | ||||
-rw-r--r-- | lisp/mastodon-tl.el | 174 | ||||
-rw-r--r-- | lisp/mastodon-toot.el | 42 | ||||
-rw-r--r-- | lisp/mastodon-views.el | 45 | ||||
-rw-r--r-- | lisp/mastodon.el | 11 |
5 files changed, 175 insertions, 101 deletions
diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index fd48a65..bed2d9a 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -76,7 +76,7 @@ ("Posted a poll" . "that has now ended") ("Requested to follow" . "you") ("Posted" . "a post") - ("Edited" . "a post")) + ("Edited" . "a post from")) "Alist of subjects for notification types.") (defvar mastodon-notifications--map @@ -126,7 +126,7 @@ follow-requests view." (lambda () (if f-reqs-view-p (mastodon-views--view-follow-requests) - (mastodon-notifications-get)) + (mastodon-tl--reload-timeline-or-profile)) (message "Follow request of %s (@%s) %s!" name handle (if reject "rejected" diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 3c66176..794b198 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -39,6 +39,9 @@ (require 'mastodon-iso) (require 'mpv nil :no-error) +(autoload 'mastodon-mode "mastodon") +(autoload 'mastodon-notifications-get "mastodon") +(autoload 'mastodon-url-lookup "mastodon") (autoload 'mastodon-auth--get-account-id "mastodon-auth") (autoload 'mastodon-auth--get-account-name "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") @@ -55,10 +58,8 @@ (autoload 'mastodon-media--get-avatar-rendering "mastodon-media") (autoload 'mastodon-media--get-media-link-rendering "mastodon-media") (autoload 'mastodon-media--inline-images "mastodon-media") -(autoload 'mastodon-mode "mastodon") (autoload 'mastodon-notifications--filter-types-list "mastodon-notifications") -(autoload 'mastodon-notifications-get "mastodon-notifications" - "Display NOTIFICATIONS in buffer." t) ; interactive +(autoload 'mastodon-notifications--get-mentions "mastodon-notifications") (autoload 'mastodon-profile--account-field "mastodon-profile") (autoload 'mastodon-profile--account-from-id "mastodon-profile") (autoload 'mastodon-profile--extract-users-handles "mastodon-profile") @@ -67,6 +68,7 @@ (autoload 'mastodon-profile--lookup-account-in-status "mastodon-profile") (autoload 'mastodon-profile--make-author-buffer "mastodon-profile") (autoload 'mastodon-profile--my-profile "mastodon-profile") +(autoload 'mastodon-profile--open-statuses-no-reblogs "mastodon-profile") (autoload 'mastodon-profile--profile-json "mastodon-profile") (autoload 'mastodon-profile--search-account-by-handle "mastodon-profile") (autoload 'mastodon-profile--toot-json "mastodon-profile") @@ -82,7 +84,6 @@ (autoload 'mastodon-toot--schedule-toot "mastodon-toot") (autoload 'mastodon-toot--set-toot-properties "mastodon-toot") (autoload 'mastodon-toot--update-status-fields "mastodon-toot") -(autoload 'mastodon-url-lookup "mastodon") (defvar mastodon-toot--visibility) (defvar mastodon-toot-mode) @@ -347,50 +348,79 @@ Used on initializing a timeline or thread." ;;; TIMELINES -(defun mastodon-tl--get-federated-timeline () - "Opens federated timeline." - (interactive) - (message "Loading federated timeline...") - (mastodon-tl--init - "federated" "timelines/public" 'mastodon-tl--timeline nil - `(("limit" . ,mastodon-tl--timeline-posts-count)) - (when current-prefix-arg t))) - -(defun mastodon-tl--get-home-timeline () - "Opens home timeline." - (interactive) +(defun mastodon-tl--get-federated-timeline (&optional prefix local) + "Open federated timeline. +If LOCAL, get only local timeline. +With a single PREFIX arg, hide-replies. +With a double PREFIX arg, only show posts with media." + (interactive "p") + (let ((params + `(("limit" . ,mastodon-tl--timeline-posts-count)))) + ;; avoid adding 'nil' to our params alist: + (when (eq prefix 16) + (push '("only_media" . "true") params)) + (when local + (push '("local" . "true") params)) + (message "Loading federated timeline...") + (mastodon-tl--init + (if local "local" "federated") + "timelines/public" 'mastodon-tl--timeline nil + params + (when (eq prefix 4) t)))) + +(defun mastodon-tl--get-home-timeline (&optional arg) + "Open home timeline. +With a single prefix ARG, hide replies." + (interactive "p") (message "Loading home timeline...") (mastodon-tl--init "home" "timelines/home" 'mastodon-tl--timeline nil `(("limit" . ,mastodon-tl--timeline-posts-count)) - (when current-prefix-arg t))) + (when (eq arg 4) t))) -(defun mastodon-tl--get-local-timeline () - "Opens local timeline." - (interactive) +(defun mastodon-tl--get-local-timeline (&optional prefix) + "Open local timeline. +With a single PREFIX arg, hide-replies. +With a double PREFIX arg, only show posts with media." + (interactive "p") (message "Loading local timeline...") - (mastodon-tl--init - "local" "timelines/public" 'mastodon-tl--timeline - nil `(("local" . "true") - ("limit" . ,mastodon-tl--timeline-posts-count)) - (when current-prefix-arg t))) + (mastodon-tl--get-federated-timeline prefix :local)) -(defun mastodon-tl--get-tag-timeline (&optional tag) +(defun mastodon-tl--get-tag-timeline (&optional prefix tag) "Prompt for tag and opens its timeline. -Optionally load TAG timeline directly." - (interactive) +Optionally load TAG timeline directly. +With a single PREFIX arg, only show posts with media. +With a double PREFIX arg, limit results to your own instance." + (interactive "p") (let* ((word (or (word-at-point) "")) (input (or tag (read-string (format "Load timeline for tag (%s): " word)))) (tag (or tag (if (string-empty-p input) word input)))) (message "Loading timeline for #%s..." tag) - (mastodon-tl--show-tag-timeline tag))) - -(defun mastodon-tl--show-tag-timeline (tag) - "Opens a new buffer showing the timeline of posts with hastag TAG." - (mastodon-tl--init - (concat "tag-" tag) (concat "timelines/tag/" tag) - 'mastodon-tl--timeline nil - `(("limit" . ,mastodon-tl--timeline-posts-count)))) + (mastodon-tl--show-tag-timeline prefix tag))) + +(defun mastodon-tl--show-tag-timeline (&optional prefix tag) + "Opens a new buffer showing the timeline of posts with hastag TAG. +If TAG is a list, show a timeline for all tags. +With a single PREFIX arg, only show posts with media. +With a double PREFIX arg, limit results to your own instance." + (let ((params + `(("limit" . ,mastodon-tl--timeline-posts-count)))) + ;; avoid adding 'nil' to our params alist: + (when (eq prefix 4) + (push '("only_media" . "true") params)) + (when (eq prefix 16) + (push '("local" . "true") params)) + (when (listp tag) + (let ((list (mastodon-http--build-array-params-alist "any[]" (cdr tag)))) + (while list + (push (pop list) params)))) + (mastodon-tl--init (concat "tag-" (if (listp tag) "followed-tags" tag)) + (concat "timelines/tag/" (if (listp tag) + ;; endpoint needs to be /tag/:sometag + (car tag) tag)) + 'mastodon-tl--timeline + nil + params))) ;;; BYLINES, etc. @@ -875,7 +905,7 @@ Used for hitting RET on a given link." (cond ((eq link-type 'content-warning) (mastodon-tl--toggle-spoiler-text position)) ((eq link-type 'hashtag) - (mastodon-tl--show-tag-timeline (get-text-property position 'mastodon-tag))) + (mastodon-tl--show-tag-timeline nil (get-text-property position 'mastodon-tag))) ;; 'account / 'account-id is not set for mentions, only bylines ((eq link-type 'user-handle) (let ((account-json (get-text-property position 'account)) @@ -2044,15 +2074,25 @@ If TAG is provided, unfollow it." (lambda () (message "tag #%s unfollowed!" tag))))) -(defun mastodon-tl--list-followed-tags () - "List followed tags. View timeline of tag user choses." - (interactive) +(defun mastodon-tl--list-followed-tags (&optional prefix) + "List followed tags. View timeline of tag user choses. +Prefix is sent to `mastodon-tl--get-tag-timeline', which see." + (interactive "p") (let* ((followed-tags-json (mastodon-tl--followed-tags)) (tags (mastodon-tl--map-alist 'name followed-tags-json)) (tag (completing-read "Tag: " tags nil))) (if (null tag) (message "You have to follow some tags first.") - (mastodon-tl--get-tag-timeline tag)))) + (mastodon-tl--get-tag-timeline prefix tag)))) + +(defun mastodon-tl--followed-tags-timeline (&optional prefix) + "Open a timeline of all your followed tags. +Prefix is sent to `mastodon-tl--show-tag-timeline', which see." + (interactive "p") + (let* ((followed-tags-json (mastodon-tl--followed-tags)) + (tags (mastodon-tl--map-alist 'name followed-tags-json))) + (mastodon-tl--show-tag-timeline prefix tags))) + ;;; UPDATING, etc. @@ -2083,25 +2123,37 @@ the current view." (mastodon-http--get-json url args))) ;; TODO: add this to new posts in some cases, e.g. in thread view. -(defun mastodon-tl--reload-timeline-or-profile () +(defun mastodon-tl--reload-timeline-or-profile (&optional pos) "Reload the current timeline or profile page. -For use after e.g. deleting a toot." - (cond ((mastodon-tl--buffer-type-eq 'home) - (mastodon-tl--get-home-timeline)) - ((mastodon-tl--buffer-type-eq 'federated) - (mastodon-tl--get-federated-timeline)) - ((mastodon-tl--buffer-type-eq 'local) - (mastodon-tl--get-local-timeline)) - ((mastodon-tl--buffer-type-eq 'notifications) - (mastodon-notifications-get)) - ((mastodon-tl--buffer-type-eq 'own-profile) - (mastodon-profile--my-profile)) - ((save-match-data - (string-match - "statuses/\\(?2:[[:digit:]]+\\)/context" - (mastodon-tl--get-endpoint)) - (mastodon-tl--thread - (match-string 2 (mastodon-tl--get-endpoint))))))) +For use after e.g. deleting a toot. +POS is a number, where point will be placed." + (let ((type (mastodon-tl--get-buffer-type))) + (cond ((eq type 'home) + (mastodon-tl--get-home-timeline)) + ((eq type 'federated) + (mastodon-tl--get-federated-timeline)) + ((eq type 'local) + (mastodon-tl--get-local-timeline)) + ((eq type 'mentions) + (mastodon-notifications--get-mentions)) + ((eq type 'notifications) + (mastodon-notifications-get nil nil :force)) + ((eq type 'profile-statuses-no-boosts) + (mastodon-profile--open-statuses-no-reblogs)) + ((eq type 'profile-statuses) + (mastodon-profile--my-profile)) + ((eq type 'thread) + (save-match-data + (let ((endpoint (mastodon-tl--get-endpoint))) + (string-match + "statuses/\\(?2:[[:digit:]]+\\)/context" + endpoint) + (mastodon-tl--thread + (match-string 2 endpoint)))))) + ;; TODO: sends point to POS, which was where point was in buffer before reload. This is very rough; we may have removed an item (deleted a toot, cleared a notif), so the buffer will be smaller, point will end up past where we were, etc. + (when pos + (goto-char pos) + (mastodon-tl--goto-prev-item)))) (defun mastodon-tl--build-link-header-url (str) "Return a URL from STR, an http Link header." @@ -2353,8 +2405,8 @@ This location is defined by a non-nil value of (goto-char (or mastodon-tl--update-point (point-min))) (funcall update-function json) (when mastodon-tl--after-update-marker - (goto-char mastodon-tl--after-update-marker)))) - (message "nothing to update"))))) + (goto-char mastodon-tl--after-update-marker))) + (message "nothing to update")))))) ;;; LOADING TIMELINES diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 3cab565..c2c391d 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -568,7 +568,8 @@ NO-REDRAFT means delete toot only." (url (mastodon-http--api (format "statuses/%s" id))) (toot-cw (alist-get 'spoiler_text toot)) (toot-visibility (alist-get 'visibility toot)) - (reply-id (alist-get 'in_reply_to_id toot))) + (reply-id (alist-get 'in_reply_to_id toot)) + (pos (point))) (if (not (mastodon-toot--own-toot-p toot)) (message "You can only delete (and redraft) your own toots.") (when (y-or-n-p (if no-redraft @@ -581,7 +582,7 @@ NO-REDRAFT means delete toot only." (if no-redraft (progn (when mastodon-tl--buffer-spec - (mastodon-tl--reload-timeline-or-profile)) + (mastodon-tl--reload-timeline-or-profile pos)) (message "Toot deleted!")) (mastodon-toot--redraft response reply-id @@ -773,11 +774,12 @@ instance to edit a toot." (let* ((toot (mastodon-toot--remove-docs)) (scheduled mastodon-toot--scheduled-for) (scheduled-id mastodon-toot--scheduled-id) + (edit-id mastodon-toot--edit-toot-id) (endpoint - (if mastodon-toot--edit-toot-id + (if edit-id ;; we are sending an edit: (mastodon-http--api (format "statuses/%s" - mastodon-toot--edit-toot-id)) + edit-id)) (mastodon-http--api "statuses"))) (spoiler (when (and (not (mastodon-toot--empty-p)) mastodon-toot--content-warning) @@ -819,22 +821,25 @@ instance to edit a toot." ((mastodon-toot--empty-p) (message "Empty toot. Cowardly refusing to post this.")) (t - (let ((response (if mastodon-toot--edit-toot-id + (let ((response (if edit-id ;; we are sending an edit: (mastodon-http--put endpoint args) (mastodon-http--post endpoint args)))) - (mastodon-http--triage response - (lambda () - (mastodon-toot--kill) - (if scheduled - (message "Toot scheduled!") - (message "Toot toot!")) - ;; cancel scheduled toot if we were editing it: - (when scheduled-id - (mastodon-views--cancel-scheduled-toot - scheduled-id :no-confirm)) - (mastodon-toot--restore-previous-window-config - prev-window-config)))))))) + (mastodon-http--triage + response + (lambda () + (mastodon-toot--kill) + (if scheduled + (message "Toot scheduled!") + (message "Toot toot!")) + ;; cancel scheduled toot if we were editing it: + (when scheduled-id + (mastodon-views--cancel-scheduled-toot + scheduled-id :no-confirm)) + (mastodon-toot--restore-previous-window-config prev-window-config) + (when edit-id + (let ((pos (marker-position (cadr prev-window-config)))) + (mastodon-tl--reload-timeline-or-profile pos)))))))))) ;; EDITING TOOTS: @@ -1609,7 +1614,8 @@ Added to `after-change-functions'." (defun mastodon-toot--compose-buffer-p () "Return t if compose buffer is current." - (mastodon-tl--buffer-type-eq 'new-toot)) + (or (mastodon-tl--buffer-type-eq 'edit-toot) + (mastodon-tl--buffer-type-eq 'new-toot))) ;; NB: now that we have toot drafts, to ensure offline composing remains ;; possible, avoid any direct requests here: diff --git a/lisp/mastodon-views.el b/lisp/mastodon-views.el index 5576b14..38344b3 100644 --- a/lisp/mastodon-views.el +++ b/lisp/mastodon-views.el @@ -325,7 +325,10 @@ If ID is provided, use that list." (endpoint (format "timelines/list/%s" id)) (name (mastodon-views--get-list-name id)) (buffer-name (format "list-%s" name))) - (mastodon-tl--init buffer-name endpoint 'mastodon-tl--timeline))) + (mastodon-tl--init buffer-name endpoint + 'mastodon-tl--timeline + nil + `(("limit" . ,mastodon-tl--timeline-posts-count))))) (defun mastodon-views--create-list () "Create a new list. @@ -458,7 +461,7 @@ If ID is provided, use that list." JSON is the data returned by the server." (mastodon-views--minor-view "follow requests" - "a/r - accept/reject request at point\n n/p - go to next/prev request" + "a/j - accept/reject request at point\n n/p - go to next/prev request" #'mastodon-views--insert-users-propertized-note json)) @@ -717,6 +720,25 @@ BRIEF means show fewer details." (interactive) (mastodon-views--view-instance-description nil :brief)) +(defun mastodon-views--get-instance-url (url username &optional instance) + "Return an instance base url from a user account URL. +USERNAME is the name to cull. +If INSTANCE is given, use that." + (cond (instance + (concat "https://" instance)) + ;; pleroma URL is https://instance.com/users/username + ((string-suffix-p "users/" (url-basepath url)) + (string-remove-suffix "/users/" + (url-basepath url))) + ;; friendica is https://instance.com/profile/user + ((string-suffix-p "profile/" (url-basepath url)) + (string-remove-suffix "/profile/" + (url-basepath url))) + ;; mastodon is https://instance.com/@user + (t + (string-remove-suffix (concat "/@" username) + url)))) + (defun mastodon-views--view-instance-description (&optional user brief instance) "View the details of the instance the current post's author is on. USER means to show the instance details for the logged in user. @@ -757,20 +779,7 @@ INSTANCE is an instance domain name." (mastodon-tl--property 'profile-json)) (alist-get 'username toot) ;; profile (alist-get 'username account))) - (instance (cond (instance - (concat "https://" instance)) - ;; pleroma URL is https://instance.com/users/username - ((string-suffix-p "users/" (url-basepath url)) - (string-remove-suffix "/users/" - (url-basepath url))) - ;; friendica is https://instance.com/profile/user - ((string-suffix-p "profile/" (url-basepath url)) - (string-remove-suffix "/profile/" - (url-basepath url))) - ;; mastodon: - (t - (string-remove-suffix (concat "/@" username) - url)))) + (instance (mastodon-views--get-instance-url url username instance)) (response (mastodon-http--get-json (if user (mastodon-http--api "instance") @@ -806,7 +815,9 @@ INSTANCE is the instance were are working with." (assoc 'rules response) (assoc 'stats response)))) (mastodon-views--print-json-keys response) - (mastodon-mode) + ;; (mastodon-mode) ; breaks our 'q' binding that avoids leaving + ;; split window + (setq mastodon-account--data account) (mastodon-tl--set-buffer-spec (buffer-name buf) "instance" nil) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index fa822a0..81a0092 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -64,6 +64,7 @@ (autoload 'mastodon-profile--view-favourites "mastodon-profile") (autoload 'mastodon-tl--block-user "mastodon-tl") (autoload 'mastodon-tl--follow-user "mastodon-tl") +(autoload 'mastodon-tl--followed-tags-timeline "mastodon-tl") (autoload 'mastodon-tl--get-buffer-type "mastodon-tl") (autoload 'mastodon-tl--get-federated-timeline "mastodon-tl") (autoload 'mastodon-tl--get-home-timeline "mastodon-tl") @@ -152,6 +153,7 @@ Use. e.g. \"%c\" for your locale's date and time format." ;; navigation between timelines (define-key map (kbd "#") #'mastodon-tl--get-tag-timeline) (define-key map (kbd ":") #'mastodon-tl--list-followed-tags) + (define-key map (kbd "C-:") #'mastodon-tl--followed-tags-timeline) (define-key map (kbd "A") #'mastodon-profile--get-toot-author) (define-key map (kbd "F") #'mastodon-tl--get-federated-timeline) (define-key map (kbd "H") #'mastodon-tl--get-home-timeline) @@ -273,15 +275,18 @@ If REPLY-JSON is the json of the toot being replied to." (mastodon-toot--compose-buffer user reply-to-id reply-json)) ;;;###autoload -(defun mastodon-notifications-get (&optional type buffer-name) +(defun mastodon-notifications-get (&optional type buffer-name force) "Display NOTIFICATIONS in buffer. Optionally only print notifications of type TYPE, a string. -BUFFER-NAME is added to \"*mastodon-\" to create the buffer name." +BUFFER-NAME is added to \"*mastodon-\" to create the buffer name. +FORCE means do not try to update an existing buffer, but fetch +from the server and load anew." (interactive) (let ((buffer (if buffer-name (concat "*mastodon-" buffer-name "*") "*mastodon-notifications*"))) - (if (get-buffer buffer) + (if (and (not force) + (get-buffer buffer)) (progn (switch-to-buffer buffer) (mastodon-tl--update)) (message "Loading your notifications...") |