diff --git a/contrib/telega-stories.el b/contrib/telega-emacs-stories.el similarity index 64% rename from contrib/telega-stories.el rename to contrib/telega-emacs-stories.el index 9ed2cf49..a29a2db6 100644 --- a/contrib/telega-stories.el +++ b/contrib/telega-emacs-stories.el @@ -1,4 +1,4 @@ -;;; telega-stories.el --- Emacs Stories. -*- lexical-binding: t; no-byte-compile: t; -*- +;;; telega-emacs-stories.el --- Emacs Stories. -*- lexical-binding: t; no-byte-compile: t; -*- ;; Copyright (C) 2021 by Zajcev Evgeny. @@ -22,7 +22,7 @@ ;;; Commentary: ;;; ellit-org: -;; ** /telega-stories.el/ -- Display Emacs Stories in the dashboard +;; ** /telega-emacs-stories.el/ -- Display Emacs Stories in the dashboard ;; ;; Emacs Stories: share your Emacs experience with other Emacs users. ;; @@ -30,170 +30,170 @@ ;; dashboard. Enable it with: ;; ;; #+begin_src emacs-lisp -;; (require 'telega-stories) -;; (telega-stories-mode 1) +;; (require 'telega-emacs-stories) +;; (telega-emacs-stories-mode 1) ;; ;; "Emacs Stories" rootview ;; (define-key telega-root-mode-map (kbd "v e") 'telega-view-emacs-stories) ;; ;; Emacs Dashboard -;; (add-to-list 'dashboard-items '(telega-stories . 5)) +;; (add-to-list 'dashboard-items '(telega-emacs-stories . 5)) ;; #+end_src ;; -;; Apart from dashboard, ~telega-stories~ provides "Emacs Stories" +;; Apart from dashboard, ~telega-emacs-stories~ provides "Emacs Stories" ;; [[https://zevlg.github.io/telega.el/#rootbuf-view-switching][Root ;; View]]. To enable this view execute {{{kbd(M-x ;; telega-view-emacs-stories RET)}}} in the root buffer. ;; ;; If you see inappropriate content in some Emacs Story, please report ;; this story by pressing -;; {{{where-is(telega-stories-msg-report,telega-stories-keymap)}}} on +;; {{{where-is(telega-emacs-stories-msg-report,telega-emacs-stories-keymap)}}} on ;; the story. ;; ;; For best performance consider newest Emacs28 with ~:base_uri~ svg ;; image property support. ;; -;; Screenshots of =telega-stories= in action: +;; Screenshots of =telega-emacs-stories= in action: ;; [[https://zevlg.github.io/telega/emacs-stories-dashboard.png]] ;; ;; And screenshot of "Emacs Stories" root view: ;; [[https://zevlg.github.io/telega/emacs-stories-rootview.png]] ;; ;; Customizable options: -;; - {{{user-option(telega-stories-show, 2)}}} -;; - {{{user-option(telega-stories-height, 2)}}} -;; - {{{user-option(telega-stories-notify-if, 2)}}} -;; - {{{user-option(telega-stories-preload-content, 2)}}} -;; - {{{user-option(telega-stories-root-view-count, 2)}}} -;; - {{{user-option(telega-stories-root-view-keep-viewed, 2)}}} +;; - {{{user-option(telega-emacs-stories-show, 2)}}} +;; - {{{user-option(telega-emacs-stories-height, 2)}}} +;; - {{{user-option(telega-emacs-stories-notify-if, 2)}}} +;; - {{{user-option(telega-emacs-stories-preload-content, 2)}}} +;; - {{{user-option(telega-emacs-stories-root-view-count, 2)}}} +;; - {{{user-option(telega-emacs-stories-root-view-keep-viewed, 2)}}} ;;; Code: (require 'telega) ;; Customizable variables -(defgroup telega-stories nil +(defgroup telega-emacs-stories nil "Customisation for Emacs Stories telega mode." - :prefix "telega-stories-" + :prefix "telega-emacs-stories-" :group 'telega) -(defcustom telega-stories-show 'unread +(defcustom telega-emacs-stories-show 'unread "Show `all' or only `unread' stories." :type '(choice (const :tag "Only unread Emacs Stories" unread) (const :tag "All Emacs Stories" all)) - :group 'telega-stories) + :group 'telega-emacs-stories) -(defcustom telega-stories-height (if (consp telega-video-note-height) - (car telega-video-note-height) - telega-video-note-height) - "Height in chars for Emacs Stories buttons" +(defcustom telega-emacs-stories-height (if (consp telega-video-note-height) + (car telega-video-note-height) + telega-video-note-height) + "Height in chars for Emacs Stories buttons." :type 'integer - :group 'telega-stories) + :group 'telega-emacs-stories) -(defcustom telega-stories-notify-if '(not unmuted) +(defcustom telega-emacs-stories-notify-if '(not unmuted) "Pop notification on new story if stories chat matches this Chat Filter." :type 'list - :group 'telega-stories) + :group 'telega-emacs-stories) -(defcustom telega-stories-delimiter " " +(defcustom telega-emacs-stories-delimiter " " "Delimiter between stories in the dashboard and rootview." :type 'string - :group 'telega-stories) + :group 'telega-emacs-stories) -(defcustom telega-stories-preload-content t +(defcustom telega-emacs-stories-preload-content t "Preload content when Emacs Story is inserted, so can be viewed instantly." :type 'boolean - :group 'telega-stories) + :group 'telega-emacs-stories) -(defcustom telega-stories-root-view-count 12 +(defcustom telega-emacs-stories-root-view-count 12 "Number of Emacs Stories to show in \"Emacs Stories\" rootview." :type 'integer - :group 'telega-stories) + :group 'telega-emacs-stories) -(defcustom telega-stories-root-view-keep-viewed t +(defcustom telega-emacs-stories-root-view-keep-viewed t "Keep viewed stories in the \"Emacs Stories\" rootview. Non-nil to keep story in the root view after story is viewed." :type 'boolean - :group 'telega-stories) + :group 'telega-emacs-stories) ;; Runtime variables -(defvar telega-stories-keymap +(defvar telega-emacs-stories-keymap (let ((map (make-sparse-keymap))) (set-keymap-parent map button-map) (define-key map (kbd "n") 'telega-button-forward) (define-key map (kbd "p") 'telega-button-backward) (define-key map (kbd "") 'telega-button-forward) (define-key map (kbd "") 'telega-button-backward) - (define-key map (kbd "SPC") 'telega-stories-msg-goto) - (define-key map (kbd "!") 'telega-stories-msg-report) + (define-key map (kbd "SPC") 'telega-emacs-stories-msg-goto) + (define-key map (kbd "!") 'telega-emacs-stories-msg-report) map) "Keymap for Emacs Stories buttons.") -(defconst telega-stories-group "@emacs_stories" +(defconst telega-emacs-stories-group "@emacs_stories" "Telegram group where stories are posted.") -(defconst telega-stories--featured-chat-ids '(-1001223420888) +(defconst telega-emacs-stories--featured-chat-ids '(-1001223420888) "Ids of chats from where featured stories are forwarded.") -(defvar telega-stories--chat nil - "Chat corresponding to `telega-stories-group'.") -(defvar telega-stories--admins nil +(defvar telega-emacs-stories--chat nil + "Chat corresponding to `telega-emacs-stories-group'.") +(defvar telega-emacs-stories--admins nil "List of administrators in the @emacs_stories group.") -(defvar telega-stories--dashboard-list-size 10 - "List `list-size' from `telega-stories-insert'. +(defvar telega-emacs-stories--dashboard-list-size 10 + "List `list-size' from `telega-emacs-stories-insert'. To get know how many stories to fetch.") -(defvar telega-stories--dashboard-items nil +(defvar telega-emacs-stories--dashboard-items nil "List of Emacs Stories items displayed in the dashboard. Used to update images inplace, when story is viewed. Each element is cons cell, where car is a Emacs Story message, and cdr is image displayed in the dashboard.") -(defvar telega-stories--dashboard-cached-icon nil +(defvar telega-emacs-stories--dashboard-cached-icon nil "Cached Emacs Stories logo image.") -(defvar telega-stories--all-messages nil +(defvar telega-emacs-stories--all-messages nil "List of all fetched story messages.") -(defvar telega-stories--show-messages nil - "List of story messages to show, matching `telega-stories-show' setting.") +(defvar telega-emacs-stories--show-messages nil + "List of story messages matching `telega-emacs-stories-show' setting.") ;;;###autoload -(define-minor-mode telega-stories-mode +(define-minor-mode telega-emacs-stories-mode "Global mode to track Emacs Stories for updates." :init-value nil :global t :group 'telega-modes - (if telega-stories-mode + (if telega-emacs-stories-mode (progn (advice-add 'telega--on-updateDeleteMessages - :after 'telega-stories--on-message-delete) + :after 'telega-emacs-stories--on-message-delete) (advice-add 'telega--on-updateMessageContent - :after 'telega-stories--on-message-content-update) + :after 'telega-emacs-stories--on-message-content-update) (advice-add 'telega--on-updateMessageSendSucceeded - :after 'telega-stories--on-message-send-succeeded) + :after 'telega-emacs-stories--on-message-send-succeeded) (add-hook 'telega-chat-post-message-hook - #'telega-stories--on-new-message) + #'telega-emacs-stories--on-new-message) ;; Install this for telega restarts (add-hook 'telega-ready-hook - #'telega-stories--initialize) + #'telega-emacs-stories--initialize) (when (telega-server-live-p) - (telega-stories--initialize))) + (telega-emacs-stories--initialize))) (remove-hook 'telega-ready-hook - #'telega-stories--initialize) + #'telega-emacs-stories--initialize) (remove-hook 'telega-chat-post-message-hook - #'telega-stories--on-new-message) + #'telega-emacs-stories--on-new-message) (advice-remove 'telega--on-updateMessageSendSucceeded - 'telega-stories--on-message-send-succeeded) + 'telega-emacs-stories--on-message-send-succeeded) (advice-remove 'telega--on-updateMessageContent - 'telega-stories--on-message-content-update) + 'telega-emacs-stories--on-message-content-update) (advice-remove 'telega--on-updateDeleteMessages - 'telega-stories--on-message-delete) - (telega-stories--finalize) + 'telega-emacs-stories--on-message-delete) + (telega-emacs-stories--finalize) )) ;; Dashboard -(defun telega-stories-dashboard-insert (list-size) +(defun telega-emacs-stories-dashboard-insert (list-size) "Add at most LIST-SIZE important telega chats." (when (and (display-graphic-p) dashboard-set-heading-icons) ;; Insert Emacs Stories logo icon - (unless telega-stories--dashboard-cached-icon - (setq telega-stories--dashboard-cached-icon + (unless telega-emacs-stories--dashboard-cached-icon + (setq telega-emacs-stories--dashboard-cached-icon (find-image (list (list :type (when (fboundp 'imagemagick-types) 'imagemagick) :file "etc/emacs-stories64.png" @@ -204,26 +204,26 @@ and cdr is image displayed in the dashboard.") :background (face-attribute 'default :background) :height (telega-chars-xheight 1)))))) (insert (propertize telega-symbol-telegram - 'display telega-stories--dashboard-cached-icon) + 'display telega-emacs-stories--dashboard-cached-icon) " ")) ;; Avoid extra spaces insertation in case icons are used (let ((dashboard-set-heading-icons nil)) (dashboard-insert-heading (concat (telega-i18n "telega_stories_heading") ":") - (dashboard-get-shortcut 'telega-stories))) + (dashboard-get-shortcut 'telega-emacs-stories))) (cond ((not (telega-server-live-p)) (telega-ins--with-face 'error (telega-ins "\n --- " (telega-i18n "telega_dashboard_telega_not_running") " ---"))) - ((not telega-stories-mode) + ((not telega-emacs-stories-mode) (telega-ins--with-face 'error (telega-ins "\n --- " - "`telega-stories-mode' not enabled" + "`telega-emacs-stories-mode' not enabled" " ---"))) (t - (let ((imsgs (seq-take telega-stories--show-messages list-size))) + (let ((imsgs (seq-take telega-emacs-stories--show-messages list-size))) (if (not imsgs) (telega-ins--with-face 'dashboard-no-items-face (telega-ins "\n --- " @@ -231,55 +231,55 @@ and cdr is image displayed in the dashboard.") " ---")) (insert "\n ") (dolist (msg imsgs) - (telega-stories--msg-pp msg)))))) + (telega-emacs-stories--msg-pp msg)))))) (dashboard-insert-shortcut - (dashboard-get-shortcut 'telega-stories) + (dashboard-get-shortcut 'telega-emacs-stories) (concat (telega-i18n "telega_stories_heading") ":")) ) ;; Emacs Stories Runtime -(defun telega-stories--initialize () +(defun telega-emacs-stories--initialize () "Initialize Emacs Stories runtime." - (setq telega-stories--all-messages nil - telega-stories--show-messages nil) + (setq telega-emacs-stories--all-messages nil + telega-emacs-stories--show-messages nil) - (telega--searchPublicChat telega-stories-group + (telega--searchPublicChat telega-emacs-stories-group (lambda (chat) - (setq telega-stories--chat chat) + (setq telega-emacs-stories--chat chat) ;; NOTE: open it to receive new messages - (telega--openChat telega-stories--chat) - (telega--getChatAdministrators telega-stories--chat + (telega--openChat telega-emacs-stories--chat) + (telega--getChatAdministrators telega-emacs-stories--chat (lambda (admins) - (setq telega-stories--admins admins))) - (telega-stories--async-fetch-stories)))) + (setq telega-emacs-stories--admins admins))) + (telega-emacs-stories--async-fetch-stories)))) -(defun telega-stories--finalize () +(defun telega-emacs-stories--finalize () "Finalize Emacs Stories runtime." - (setq telega-stories--all-messages nil - telega-stories--show-messages nil) + (setq telega-emacs-stories--all-messages nil + telega-emacs-stories--show-messages nil) - (when (and telega-stories--chat (telega-server-live-p)) - (telega--closeChat telega-stories--chat)) - (setq telega-stories--chat nil) + (when (and telega-emacs-stories--chat (telega-server-live-p)) + (telega--closeChat telega-emacs-stories--chat)) + (setq telega-emacs-stories--chat nil) ;; Update root view as well (with-telega-root-view-ewoc "stories" ewoc (telega-ewoc--clean ewoc) (telega-ewoc--set-footer - ewoc (propertize "-- `telega-stories-mode' not enabled --" - 'face 'error)) + ewoc (propertize "-- `telega-emacs-stories-mode' not enabled --" + 'face 'error)) )) -(defun telega-stories--async-fetch-stories (&optional from-msg-id - &rest msg-filters) +(defun telega-emacs-stories--async-fetch-stories (&optional from-msg-id + &rest msg-filters) "Asynchronously fetch older Emacs Story messages starting from FROM-MSG-ID. If FROM-MSG-ID is not given, then search from the last story message or from the beginning." - (cl-assert telega-stories--chat) - (when (< (length telega-stories--show-messages) - (max telega-stories--dashboard-list-size - telega-stories-root-view-count)) + (cl-assert telega-emacs-stories--chat) + (when (< (length telega-emacs-stories--show-messages) + (max telega-emacs-stories--dashboard-list-size + telega-emacs-stories-root-view-count)) ;; Need more stories (dolist (filter-type (or msg-filters '("searchMessagesFilterPhotoAndVideo" @@ -287,24 +287,24 @@ or from the beginning." "searchMessagesFilterDocument" ;;"searchMessagesFilterUrl" ))) - (telega--searchChatMessages telega-stories--chat + (telega--searchChatMessages telega-emacs-stories--chat (list :@type filter-type) (if (string= "searchMessagesFilterUrl" filter-type) "asciinema.org" "") (or from-msg-id - (plist-get (car (last telega-stories--all-messages)) :id) + (plist-get (car (last telega-emacs-stories--all-messages)) :id) 0) 0 ; offset - (max telega-stories--dashboard-list-size - telega-stories-root-view-count) + (max telega-emacs-stories--dashboard-list-size + telega-emacs-stories-root-view-count) nil (lambda (reply) (let ((stories-array (plist-get reply :messages))) (telega-debug "Emacs Stories: fetched %d stories for %S" (length stories-array) filter-type) (seq-doseq (story stories-array) - (telega-stories--on-new-message story 'no-notify)) + (telega-emacs-stories--on-new-message story 'no-notify)) ;; NOTE: If searched got some messages and there is still ;; not enough story messages, then search for older @@ -315,13 +315,14 @@ or from the beginning." (continue-from-msg-id (apply #'min (plist-get last-fetched-story :id) (telega-chat-uaprop - telega-stories--chat :telega-stories-viewed-ids)))) + telega-emacs-stories--chat + :telega-emacs-stories-viewed-ids)))) (cl-assert (> continue-from-msg-id 0)) - (telega-stories--async-fetch-stories + (telega-emacs-stories--async-fetch-stories continue-from-msg-id filter-type)))))) ))) -(defun telega-stories-msg-view (msg &optional no-open-p no-fetch-p) +(defun telega-emacs-stories-msg-view (msg &optional no-open-p no-fetch-p) "View Emacs Story message MSG. If NO-OPEN-P is specified, then do not open content." (unless (or no-open-p current-prefix-arg) @@ -329,43 +330,44 @@ If NO-OPEN-P is specified, then do not open content." (telega-msg-open-content msg))) ;; Add this story message to the list of viewed stories - (let ((viewed-stories (telega-chat-uaprop - (telega-msg-chat msg) :telega-stories-viewed-ids))) + (let ((viewed-stories (telega-chat-uaprop (telega-msg-chat msg) + :telega-emacs-stories-viewed-ids))) (unless (memq (plist-get msg :id) viewed-stories) ;; NOTE: Store maximum 500 ids, so `uaprop' won't grow inifinitely - (setf (telega-chat-uaprop (telega-msg-chat msg) :telega-stories-viewed-ids) + (setf (telega-chat-uaprop (telega-msg-chat msg) + :telega-emacs-stories-viewed-ids) (seq-take (cons (plist-get msg :id) viewed-stories) 500)))) - ;; Also update `telega-stories--show-messages' and possible + ;; Also update `telega-emacs-stories--show-messages' and possible ;; asynchronously fetch older stories - (telega-stories--show-messages-reset) + (telega-emacs-stories--show-messages-reset) (unless no-fetch-p - (telega-stories--async-fetch-stories)) + (telega-emacs-stories--async-fetch-stories)) ;; Inplace update story image in the dashboard (cl-destructuring-bind (thumb thumb-prop) - (telega-stories--msg-thumbnail-spec msg) + (telega-emacs-stories--msg-thumbnail-spec msg) (telega-media--image-update - (cons msg #'telega-stories--msg-create-image) + (cons msg #'telega-emacs-stories--msg-create-image) (cons thumb thumb-prop) :telega-story-image) (force-window-update)) ;; NOTE: Update the rootview *before* removing message from - ;; `telega-stories--show-messages', because update func checks + ;; `telega-emacs-stories--show-messages', because update func checks ;; message is story as membership of the list (telega-root-view--update :on-message-update msg)) -(defun telega-stories-msg-goto (msg) +(defun telega-emacs-stories-msg-goto (msg) "Goto to Emacs Story message MSG, opening corresponding chat. Show discussion thread for story MSG." ;; NOTE: Can't use `telega-msg-at' here, because button type is ;; `telega', not `telega-message' (interactive (list (button-get (button-at (point)) :value))) - (telega-stories-msg-view msg 'no-open) + (telega-emacs-stories-msg-view msg 'no-open) (telega-msg-goto-highlight msg)) -(defun telega-stories-msg-report (msg reason) +(defun telega-emacs-stories-msg-report (msg reason) "Report Emacs Story message MSG has inappropriate content." ;; NOTE: Can't use `telega-msg-at' here, because button type is ;; `telega', not `telega-message' @@ -373,33 +375,35 @@ Show discussion thread for story MSG." (read-string "Story Report Reason [spam]: " nil nil "spam"))) (telega--sendMessage - telega-stories--chat + telega-emacs-stories--chat (list :@type "inputMessageText" :text (telega-string-fmt-text (concat reason " #report"))) msg nil) (message "telega: Story reported, thanks for your feedback.")) -(defun telega-stories-view-loaded () +(defun telega-emacs-stories-view-loaded () "Mark currently loaded stories as viewed." (interactive) - (dolist (msg (copy-sequence telega-stories--show-messages)) - (unless (telega-stories--msg-viewed-p msg) - (telega-stories-msg-view msg 'no-open 'no-fetch))) + (dolist (msg (copy-sequence telega-emacs-stories--show-messages)) + (unless (telega-emacs-stories--msg-viewed-p msg) + (telega-emacs-stories-msg-view msg 'no-open 'no-fetch))) - (telega-stories--async-fetch-stories)) + (telega-emacs-stories--async-fetch-stories)) -(defun telega-stories-unview-all (&rest story-messages) +(defun telega-emacs-stories-unview-all (&rest story-messages) "Pretend none of the STORY-MESSAGES are viewed. If STORY-MESSAGES is not specified, unview all story messages." (interactive) - (unless telega-stories--chat - (user-error "telega-stories-mode not started")) - (setf (telega-chat-uaprop telega-stories--chat :telega-stories-viewed-ids) + (unless telega-emacs-stories--chat + (user-error "telega-emacs-stories-mode not started")) + (setf (telega-chat-uaprop telega-emacs-stories--chat + :telega-emacs-stories-viewed-ids) (when story-messages (seq-difference (telega-chat-uaprop - telega-stories--chat :telega-stories-viewed-ids) + telega-emacs-stories--chat + :telega-emacs-stories-viewed-ids) (mapcar (telega--tl-prop :id) story-messages)))) ;; Empty root view, waiting for update @@ -409,23 +413,23 @@ If STORY-MESSAGES is not specified, unview all story messages." (telega-loading--timer-start)) ;; Refresh stories messages - (setq telega-stories--all-messages nil - telega-stories--show-messages nil) - (telega-stories--async-fetch-stories) + (setq telega-emacs-stories--all-messages nil + telega-emacs-stories--show-messages nil) + (telega-emacs-stories--async-fetch-stories) ) -(defun telega-stories--msg-delete (msg) +(defun telega-emacs-stories--msg-delete (msg) "Delete MSG from stories." (cl-assert msg) - (setq telega-stories--show-messages - (delq msg telega-stories--show-messages)) - (let ((telega-stories-root-view-keep-viewed nil)) + (setq telega-emacs-stories--show-messages + (delq msg telega-emacs-stories--show-messages)) + (let ((telega-emacs-stories-root-view-keep-viewed nil)) (telega-root-view--update :on-message-update msg)) - (setq telega-stories--all-messages - (delq msg telega-stories--all-messages))) - -(defun telega-stories--msg-featured-p (msg) + (setq telega-emacs-stories--all-messages + (delq msg telega-emacs-stories--all-messages))) + +(defun telega-emacs-stories--msg-featured-p (msg) "Return non-nil if MSG is a featured story. Return featured chat id, if MSG is featured." (when-let* ((origin (telega--tl-get msg :forward_info :origin)) @@ -434,15 +438,15 @@ Return featured chat id, if MSG is featured." (plist-get origin :sender_chat_id)) (messageForwardOriginChannel (plist-get origin :chat_id))))) - (car (memq chat-id telega-stories--featured-chat-ids)))) + (car (memq chat-id telega-emacs-stories--featured-chat-ids)))) -(defun telega-stories--msg-viewed-p (msg) +(defun telega-emacs-stories--msg-viewed-p (msg) "Return non-nil if Emacs Story MSG is viewed." (memq (plist-get msg :id) (telega-chat-uaprop - (telega-msg-chat msg) :telega-stories-viewed-ids))) + (telega-msg-chat msg) :telega-emacs-stories-viewed-ids))) -(defun telega-stories--msg-with-story-tag-p (msg) +(defun telega-emacs-stories--msg-with-story-tag-p (msg) "Return non-nil if MSG has #emacs_story or #story tag." (let ((content (plist-get msg :content))) (cl-case (telega--tl-type content) @@ -453,26 +457,26 @@ Return featured chat id, if MSG is featured." (string-match-p "#\\(emacs_\\)?story" (or (telega-tl-str content :text) "")))))) -(defun telega-stories--msg-by-admin-p (msg) - "Return non-nil if MSG is sent by `telega-stories-group' admin." +(defun telega-emacs-stories--msg-by-admin-p (msg) + "Return non-nil if MSG is sent by `telega-emacs-stories-group' admin." (let ((sender (telega-msg-sender msg))) (if (telega-chat-p sender) ;; sent by anonymous admin - (eq (plist-get telega-stories--chat :id) (plist-get sender :id)) + (eq (plist-get telega-emacs-stories--chat :id) (plist-get sender :id)) ;; sent by ordinary user - (cl-find (plist-get sender :id) telega-stories--admins + (cl-find (plist-get sender :id) telega-emacs-stories--admins :key (telega--tl-prop :user_id))))) -(defun telega-stories-msg-story-p (msg) +(defun telega-emacs-stories-msg-story-p (msg) "Return non-nil if MSG a Emacs Story message." (let ((msg-type (telega--tl-type (plist-get msg :content)))) (and (eq (plist-get msg :chat_id) - (plist-get telega-stories--chat :id)) + (plist-get telega-emacs-stories--chat :id)) (memq msg-type '(messagePhoto messageVideo messageDocument messageAnimation)) - (or (eq telega-debug 'telega-stories) + (or (eq telega-debug 'telega-emacs-stories) (plist-get msg :forward_info) - (telega-stories--msg-with-story-tag-p msg)) + (telega-emacs-stories--msg-with-story-tag-p msg)) ;; Messages considered as Emacs Story: ;; 1. Nice Emacs screenshot ;; 2. Video Message with screencast not longer then 60 seconds @@ -488,7 +492,7 @@ Return featured chat id, if MSG is featured." :video :animation) :duration))) (or (<= duration 60) - (and (telega-stories--msg-by-admin-p msg) + (and (telega-emacs-stories--msg-by-admin-p msg) (<= duration 120))))) (messageText (let ((web-page (telega--tl-get msg :content :web_page))) @@ -498,40 +502,40 @@ Return featured chat id, if MSG is featured." (t t)) ;; Check thumbnail can be displayed (cl-destructuring-bind (thumb _thumb-prop) - (telega-stories--msg-thumbnail-spec msg) + (telega-emacs-stories--msg-thumbnail-spec msg) (and thumb (or (not (eq 'thumbnail (telega--tl-type thumb))) (equal '(:@type "thumbnailFormatJpeg") (plist-get thumb :format))))) - ))) + ))) -(defun telega-stories--msg-pp (msg) +(defun telega-emacs-stories--msg-pp (msg) "Pretty printer for story message MSG." (telega-ins-prefix "\n" (telega-button--insert 'telega msg - 'keymap telega-stories-keymap + 'keymap telega-emacs-stories-keymap :inserter (lambda (msg) (cl-destructuring-bind (thumb thumb-prop) - (telega-stories--msg-thumbnail-spec msg) + (telega-emacs-stories--msg-thumbnail-spec msg) (telega-ins--image (telega-media--image - (cons msg #'telega-stories--msg-create-image) + (cons msg #'telega-emacs-stories--msg-create-image) (cons thumb thumb-prop) 'force :telega-story-image)))) - :action #'telega-stories-msg-view) + :action #'telega-emacs-stories-msg-view) ;; NOTE: start a new line if story does not fit into ;; `telega-root-fill-column' (> (telega-current-column) telega-root-fill-column)) - (telega-ins telega-stories-delimiter)) + (telega-ins telega-emacs-stories-delimiter)) -(defun telega-stories--msg-thumbnail-spec (msg) +(defun telega-emacs-stories--msg-thumbnail-spec (msg) "Return thumbnail spec for the story message MSG. Return list of three elements: (THUMB THUMB-PROP CONTENT-FILE)." (cl-ecase (telega--tl-type (plist-get msg :content)) (messagePhoto (list (telega-photo--best (telega--tl-get msg :content :photo) - (list 40 telega-stories-height - 40 telega-stories-height)) + (list 40 telega-emacs-stories-height + 40 telega-emacs-stories-height)) :photo)) (messageVideo (list (telega--tl-get msg :content :video :thumbnail) @@ -544,19 +548,19 @@ Return list of three elements: (THUMB THUMB-PROP CONTENT-FILE)." :file)) )) -(defun telega-stories--msg-create-image (msg &optional _file) +(defun telega-emacs-stories--msg-create-image (msg &optional _file) "Generate svg image for story message MSG." (let* ((tfile (cl-destructuring-bind (thumb thumb-prop) - (telega-stories--msg-thumbnail-spec msg) + (telega-emacs-stories--msg-thumbnail-spec msg) (telega-file--renew thumb thumb-prop))) (sender (telega-msg-sender msg)) (title - (propertize (or (telega-msg-sender-username sender 'with-@) - (telega-msg-sender-title sender)) - :color (car (telega-msg-sender-color sender)))) - (viewed-p (telega-stories--msg-viewed-p msg)) - (size (telega-chars-xwidth (* 2 telega-stories-height))) + (propertize (or (telega-msg-sender-username sender 'with-@) + (telega-msg-sender-title sender)) + :color (car (telega-msg-sender-color sender)))) + (viewed-p (telega-emacs-stories--msg-viewed-p msg)) + (size (telega-chars-xwidth (* 2 telega-emacs-stories-height))) (sw-passive (/ size 100.0)) (sw-active (* sw-passive 2)) (passive-color (telega-color-name-as-hex-2digits @@ -639,7 +643,7 @@ Return list of three elements: (THUMB THUMB-PROP CONTENT-FILE)." (featured-chat-id (or (if (and patron-p (telega-chat-p sender)) (plist-get sender :id) - (telega-stories--msg-featured-p msg)))) + (telega-emacs-stories--msg-featured-p msg)))) (title-photo (cond (featured-chat-id (plist-get (telega-chat-get featured-chat-id) :photo)) @@ -685,121 +689,121 @@ Return list of three elements: (THUMB THUMB-PROP CONTENT-FILE)." :mask 'heuristic :base-uri (expand-file-name "dummy" base-dir)))) -(defun telega-stories--msg-preload-content (msg) +(defun telega-emacs-stories--msg-preload-content (msg) "Start downloading MSG story message's content." (let ((cfile (telega-msg--content-file msg))) (when (and (not (telega-file--downloaded-p cfile)) (not (telega-file--downloading-p cfile))) ;; NOTE: Use higher priority for recent stories (telega-file--download cfile - (max 16 (- 32 (cl-position msg telega-stories--show-messages))))))) + (max 16 (- 32 (cl-position msg telega-emacs-stories--show-messages))))))) -(defun telega-stories--show-messages-reset () - "Re-set `telega-stories--show-messages' according to `telega-stories-show'." - (setq telega-stories--show-messages - (cl-remove-if (when (eq 'unread telega-stories-show) - #'telega-stories--msg-viewed-p) - telega-stories--all-messages))) +(defun telega-emacs-stories--show-messages-reset () + "Re-set `telega-emacs-stories--show-messages' according to `telega-emacs-stories-show'." + (setq telega-emacs-stories--show-messages + (cl-remove-if (when (eq 'unread telega-emacs-stories-show) + #'telega-emacs-stories--msg-viewed-p) + telega-emacs-stories--all-messages))) -(defun telega-stories--on-new-message (new-msg &optional ignore-notify-p) +(defun telega-emacs-stories--on-new-message (new-msg &optional ignore-notify-p) "If NEW-MSG is an unread Emacs Story message, then add it to the list. If IGNORE-NOTIFY-P is non-nil, then do not pop notification." - (when (telega-stories-msg-story-p new-msg) + (when (telega-emacs-stories-msg-story-p new-msg) (telega-debug "Emacs Stories ADD story: %S" (plist-get new-msg :id)) - (cl-pushnew new-msg telega-stories--all-messages + (cl-pushnew new-msg telega-emacs-stories--all-messages :test (lambda (msg1 msg2) (eq (plist-get msg1 :id) (plist-get msg2 :id)))) ;; NOTE: keep messages is message id order - (setq telega-stories--all-messages - (cl-sort telega-stories--all-messages #'> + (setq telega-emacs-stories--all-messages + (cl-sort telega-emacs-stories--all-messages #'> :key (telega--tl-prop :id))) - (telega-stories--show-messages-reset) + (telega-emacs-stories--show-messages-reset) ;; Start preloading story content, only for unread stories - (when (and telega-stories-preload-content - (not (telega-stories--msg-viewed-p new-msg)) + (when (and telega-emacs-stories-preload-content + (not (telega-emacs-stories--msg-viewed-p new-msg)) (memq new-msg - (seq-take telega-stories--show-messages - (max telega-stories--dashboard-list-size - telega-stories-root-view-count)))) - (telega-stories--msg-preload-content new-msg)) + (seq-take telega-emacs-stories--show-messages + (max telega-emacs-stories--dashboard-list-size + telega-emacs-stories-root-view-count)))) + (telega-emacs-stories--msg-preload-content new-msg)) (telega-root-view--update :on-message-update new-msg) ;; Show notification for new Emacs Story (when (and telega-notifications-mode (not ignore-notify-p) - (telega-chat-match-p telega-stories--chat - telega-stories-notify-if)) + (telega-chat-match-p telega-emacs-stories--chat + telega-emacs-stories-notify-if)) (telega-notifications--chat-msg0 new-msg nil :app-icon (telega-etc-file - (if (telega-stories--msg-featured-p new-msg) + (if (telega-emacs-stories--msg-featured-p new-msg) "emacs-stories-featured.svg" "emacs-stories.svg")) - :title (telega-chat-title telega-stories--chat) + :title (telega-chat-title telega-emacs-stories--chat) )) )) -(defun telega-stories--on-message-send-succeeded (event) +(defun telega-emacs-stories--on-message-send-succeeded (event) "Story message might change its id." - (when (eq (plist-get telega-stories--chat :id) + (when (eq (plist-get telega-emacs-stories--chat :id) (telega--tl-get event :message :chat_id)) (let ((old-story (cl-find (plist-get event :old_message_id) - telega-stories--all-messages + telega-emacs-stories--all-messages :key (telega--tl-prop :id)))) (when old-story - (telega-stories--msg-delete old-story)) - (telega-stories--on-new-message + (telega-emacs-stories--msg-delete old-story)) + (telega-emacs-stories--on-new-message (plist-get event :message) (unless old-story 'no-notify))))) -(defun telega-stories--on-message-content-update (event) +(defun telega-emacs-stories--on-message-content-update (event) "Message content changed." - (when (eq (plist-get telega-stories--chat :id) + (when (eq (plist-get telega-emacs-stories--chat :id) (plist-get event :chat_id)) (when-let ((story (cl-find (plist-get event :message_id) - telega-stories--all-messages + telega-emacs-stories--all-messages :key (telega--tl-prop :id)))) ;; Delete story, and then re-add it with new content - (telega-stories--on-message-delete - (list :chat_id (plist-get telega-stories--chat :id) + (telega-emacs-stories--on-message-delete + (list :chat_id (plist-get telega-emacs-stories--chat :id) :is_permanent t :message_ids (vector (plist-get story :id)))) (plist-put story :content (plist-get event :new_content)) - (telega-stories--on-new-message story 'no-notify)))) + (telega-emacs-stories--on-new-message story 'no-notify)))) -(defun telega-stories--on-message-delete (event) +(defun telega-emacs-stories--on-message-delete (event) "Possible story message has been deleted." - (when (eq (plist-get telega-stories--chat :id) + (when (eq (plist-get telega-emacs-stories--chat :id) (plist-get event :chat_id)) (when (plist-get event :is_permanent) (seq-doseq (msg-id (plist-get event :message_ids)) (when-let ((story (cl-find msg-id - telega-stories--all-messages + telega-emacs-stories--all-messages :key (telega--tl-prop :id)))) ;; NOTE: Force `story' message removal from root view - (setq telega-stories--show-messages - (delq story telega-stories--show-messages)) - (let ((telega-stories-root-view-keep-viewed nil)) + (setq telega-emacs-stories--show-messages + (delq story telega-emacs-stories--show-messages)) + (let ((telega-emacs-stories-root-view-keep-viewed nil)) (telega-root-view--update :on-message-update story)) - (setq telega-stories--all-messages - (delq story telega-stories--all-messages))))))) + (setq telega-emacs-stories--all-messages + (delq story telega-emacs-stories--all-messages))))))) ;; "Emacs Stories" rootview (rv = rootview) -(defun telega-stories--rv-msg-update (_ewoc-name ewoc msg) +(defun telega-emacs-stories--rv-msg-update (_ewoc-name ewoc msg) "Message MSG has been updated, possible story need to be updated as well." - (when (memq msg telega-stories--all-messages) + (when (memq msg telega-emacs-stories--all-messages) ;; React only on story messages in the list (telega-save-cursor (if-let ((msg-node (telega-ewoc--find-by-data ewoc msg))) - (if (or telega-stories-root-view-keep-viewed - (memq msg telega-stories--show-messages)) + (if (or telega-emacs-stories-root-view-keep-viewed + (memq msg telega-emacs-stories--show-messages)) (ewoc-invalidate ewoc msg-node) (ewoc-delete ewoc msg-node)) - (when (memq msg telega-stories--show-messages) + (when (memq msg telega-emacs-stories--show-messages) ;; New visible story arrived (if-let ((before-node (telega-ewoc--find-if ewoc (lambda (story-msg) @@ -808,25 +812,25 @@ If IGNORE-NOTIFY-P is non-nil, then do not pop notification." (ewoc-enter-before ewoc before-node msg) (ewoc-enter-last ewoc msg)))) - ;; Ensure view has `telega-stories-root-view-count' stories + ;; Ensure view has `telega-emacs-stories-root-view-count' stories ;; displayed ;; We might delete or add stories at the end (let ((stories (ewoc-collect ewoc #'identity))) - (cond ((> (length stories) telega-stories-root-view-count) + (cond ((> (length stories) telega-emacs-stories-root-view-count) ;; Delete last visible story (let ((last-node (ewoc-nth ewoc -1))) (cl-assert last-node) (ewoc-delete ewoc last-node))) - ((< (length stories) telega-stories-root-view-count) + ((< (length stories) telega-emacs-stories-root-view-count) ;; Add visible story to the end (when-let* ((last-node (ewoc-nth ewoc -1)) (last-msg (when last-node (ewoc-data last-node))) (next-msgs (if last-msg - (cdr (memq last-msg telega-stories--all-messages)) - telega-stories--all-messages))) + (cdr (memq last-msg telega-emacs-stories--all-messages)) + telega-emacs-stories--all-messages))) (while next-msgs - (when (memq (car next-msgs) telega-stories--show-messages) + (when (memq (car next-msgs) telega-emacs-stories--show-messages) (ewoc-enter-last ewoc (car next-msgs)) (setq next-msgs nil)) (setq next-msgs (cdr next-msgs))))) @@ -834,49 +838,49 @@ If IGNORE-NOTIFY-P is non-nil, then do not pop notification." ;; Footer (telega-ewoc--set-footer - ewoc (if (telega-ewoc--empty-p ewoc) - (telega-i18n "telega_stories_no_stories") - "")) + ewoc (if (telega-ewoc--empty-p ewoc) + (telega-i18n "telega_stories_no_stories") + "")) ))) (defun telega-view-emacs-stories (toggle-show-p) "View recent Emacs Stories. -If `\\[universal-argument] is given, then toggle `telega-stories-show' +If `\\[universal-argument] is given, then toggle `telega-emacs-stories-show' option before viewing stories. If it has value `unread', then set it to `all', if it was `all', then set it to `unread'." (interactive "P") - (unless telega-stories-mode + (unless telega-emacs-stories-mode (user-error "telega: Can't view Emacs Stories, \ -`telega-stories-mode' not enabled")) +`telega-emacs-stories-mode' not enabled")) (when toggle-show-p - (setq telega-stories-show - (if (eq 'all telega-stories-show) 'unread 'all))) - (telega-stories--show-messages-reset) + (setq telega-emacs-stories-show + (if (eq 'all telega-emacs-stories-show) 'unread 'all))) + (telega-emacs-stories--show-messages-reset) (telega-root-view--apply (list 'telega-view-emacs-stories (concat (telega-i18n "telega_stories_heading") - " (" (if (eq 'all telega-stories-show) "all" "unread") ")") - (let ((stories (seq-take telega-stories--show-messages - telega-stories-root-view-count))) + " (" (if (eq 'all telega-emacs-stories-show) "all" "unread") ")") + (let ((stories (seq-take telega-emacs-stories--show-messages + telega-emacs-stories-root-view-count))) (list :name "stories" - :pretty-printer #'telega-stories--msg-pp + :pretty-printer #'telega-emacs-stories--msg-pp :items stories :footer (unless stories (telega-i18n "telega_stories_no_stories")) - :on-message-update #'telega-stories--rv-msg-update))))) + :on-message-update #'telega-emacs-stories--rv-msg-update))))) ;; Dashboard is not required, "Emacs Stories" root view might be used ;; to view stories (when (require 'dashboard nil 'noerror) (add-to-list 'dashboard-item-generators - '(telega-stories . telega-stories-dashboard-insert)) + '(telega-emacs-stories . telega-emacs-stories-dashboard-insert)) (add-to-list 'dashboard-item-shortcuts - '(telega-stories . "s"))) + '(telega-emacs-stories . "s"))) -(provide 'telega-stories) +(provide 'telega-emacs-stories) -;;; telega-stories.el ends here +;;; telega-emacs-stories.el ends here diff --git a/docs/index.html b/docs/index.html index 6a54e6ef..d0f4c42c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - + Telega Manual (v0.8.150) @@ -47,6 +47,7 @@

Linux users
  • Windows 10 users
  • Building TDLib
  • +
  • Updating telega and TDLib
  • Installing telega and TDLib from GNU Guix
  • Installing telega from MELPA
  • Installing telega directly from GitHub
  • @@ -146,7 +147,7 @@

    telega-live-location.el – Manage live location in Telega using geo.el
  • telega-mnz.el – Display Emacs content inside Telega messages.
  • telega-dashboard.el – Important telega chats in the Emacs dashboard
  • -
  • telega-stories.el – Display Emacs Stories in the dashboard
  • +
  • telega-emacs-stories.el – Display Emacs Stories in the dashboard
  • telega-transient.el – Transient (magit-like style) commands for telega
  • telega-adblock.el – Block advertisement messages
  • telega-channels-export.el – Export Telegam channels to OPML
  • @@ -402,6 +403,33 @@

    +

    Updating telega and TDLib

    +
    +

    +If you use telega from master and update it from time to time it +might ask you to update/rebuild TDLib and telega-server. To update +TDLib and rebuild telega-server do next: +

    + +
      +
    1. Fetch, rebuild and reinstall updated TDLib as described above
    2. +
    3. On Linux run $ sudo ldconfig to refresh ldconfig cache
    4. +
    5. Run $ make server-reinstall in the telega.el sources directory +to rebuild and reinstall telega-server
    6. +
    + +

    +Now you are ready to run updated telega. +

    @@ -788,7 +816,7 @@

    rootbuf lists the chat buttons, such as:

    -
    +
     {🎗Saved Messages            }📌  📹 Video (10s)               Fri✓
     [Emacs | Emacs (english)     ]  @oldosfan: same                Fri
     ...
    @@ -806,7 +834,7 @@ 

    -
    +
     [243:📑Main      4890]  [51:Groups       4677]  [27:Channels      210]
     [53:Contacts         ]  [0:Important         ]  [3:📑Archive      670]
     
    @@ -898,7 +926,7 @@

    -
    +
     -/------------------------------(main)--------------------------------
     
    @@ -936,7 +964,7 @@

    -
    +
     -\---------------------(unread-count join-date)-----------------------
     
    @@ -1936,7 +1964,7 @@

    +
     MSG1                              <--- msg sent on 27dec
     -------(28 December 2020)------   <--- date break
     MSG2                              <--- msg sent on 28dec
    @@ -2332,7 +2360,7 @@ 

    +
     MSG1                              <--- msg sent on 27dec
     -------(28 December 2020)------   <--- date break
     MSG2                              <--- msg sent on 28dec
    @@ -2522,7 +2550,7 @@ 

    -
    +
     ```<language-name>
     first line of multiline preformatted code
     second line
    @@ -2554,7 +2582,7 @@ 

    +
     #+begin_src <language-name>
     code line
     next code line
    @@ -2773,7 +2801,7 @@ 

    +
     [✕]| Reply: @demash> Trying to install telega  M-x packag…
     (T)>>>
     
    @@ -3398,7 +3426,7 @@

    -
    +
     [⏪] [⏩] [2×] [Stop] 
     
    @@ -4453,7 +4481,7 @@

    +
     https://github.com/zevlg/telega.el/issues/105
     https://gitlab.com/jessieh/mood-line/issues/6
     https://www.youtube.com/watch?v=0m2jR6_eMkU
    @@ -4768,9 +4796,9 @@ 

    -
    -

    telega-stories.el – Display Emacs Stories in the dashboard

    -
    +
    +

    telega-emacs-stories.el – Display Emacs Stories in the dashboard

    +

    -Apart from dashboard, telega-stories provides "Emacs Stories" +Apart from dashboard, telega-emacs-stories provides "Emacs Stories" Root View. To enable this view execute M-x telega-view-emacs-stories RET in the root buffer.

    @@ -4799,7 +4827,7 @@

    @@ -4823,7 +4851,7 @@

  • -User Option: telega-stories-show +User Option: telega-emacs-stories-show

    @@ -4834,18 +4862,18 @@