|
@@ -71,6 +71,7 @@
|
|
|
(:postcheckins (handle-cmd-post-checkins chat-id id args))
|
|
(:postcheckins (handle-cmd-post-checkins chat-id id args))
|
|
|
(:friends (handle-cmd-fsq-friends chat-id id args))
|
|
(:friends (handle-cmd-fsq-friends chat-id id args))
|
|
|
(:checkins (handle-cmd-checkins chat-id id args))
|
|
(:checkins (handle-cmd-checkins chat-id id args))
|
|
|
|
|
+ (:rss (handle-cmd-rss chat-id id args))
|
|
|
(otherwise (handle-admin-cmd chat-id text cmd args))))
|
|
(otherwise (handle-admin-cmd chat-id text cmd args))))
|
|
|
(send-dont-understand chat-id (preprocess-input text))))
|
|
(send-dont-understand chat-id (preprocess-input text))))
|
|
|
(when location
|
|
(when location
|
|
@@ -322,6 +323,80 @@
|
|
|
(error (e) (log:error e))))
|
|
(error (e) (log:error e))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+;; RSS
|
|
|
|
|
+(defvar *rss-feeds* nil "All aggragated RSS feeds")
|
|
|
|
|
+(defvar *rss-chat-feeds* (make-hash-table) "Chat->Feeds mapping")
|
|
|
|
|
+
|
|
|
|
|
+(defun %send-feeds (chat-id feeds)
|
|
|
|
|
+ (telegram-send-message
|
|
|
|
|
+ chat-id
|
|
|
|
|
+ (if (null feeds)
|
|
|
|
|
+ "Пока ничего не постим"
|
|
|
|
|
+ (format nil "Постим:~%~{~A (~A)~^~%~}"
|
|
|
|
|
+ (loop for feed in feeds
|
|
|
|
|
+ append (list (feed-title feed) (feed-url feed)))))))
|
|
|
|
|
+
|
|
|
|
|
+(defun %get-feed (url)
|
|
|
|
|
+ (when url
|
|
|
|
|
+ (or (find url *rss-feeds* :key #'feed-url :test #'equal)
|
|
|
|
|
+ (let ((feed (build-feed url)))
|
|
|
|
|
+ (fetch-new-items feed)
|
|
|
|
|
+ (push feed *rss-feeds*)
|
|
|
|
|
+ feed))))
|
|
|
|
|
+
|
|
|
|
|
+(defun %used-feed-p (feed)
|
|
|
|
|
+ (loop for feeds being the hash-values in *rss-chat-feeds*
|
|
|
|
|
+ when (member feed feeds)
|
|
|
|
|
+ do (return t)))
|
|
|
|
|
+
|
|
|
|
|
+(defun %refresh-feeds ()
|
|
|
|
|
+ (setf *rss-feeds*
|
|
|
|
|
+ (remove-if-not #'%used-feed-p *rss-feeds*)))
|
|
|
|
|
+
|
|
|
|
|
+(defun handle-cmd-rss (chat-id message-id args)
|
|
|
|
|
+ (log:info "handle-cmd-rss" chat-id message-id args)
|
|
|
|
|
+ (handler-case
|
|
|
|
|
+ (let ((feeds (gethash chat-id *rss-chat-feeds*)))
|
|
|
|
|
+ (if (null args)
|
|
|
|
|
+ (%send-feeds chat-id feeds)
|
|
|
|
|
+ (progn
|
|
|
|
|
+ (dolist (url args)
|
|
|
|
|
+ (alexandria:when-let ((feed (%get-feed (find-rss-url url))))
|
|
|
|
|
+ (if (member feed feeds)
|
|
|
|
|
+ (setf feeds (remove feed feeds))
|
|
|
|
|
+ (push feed feeds))))
|
|
|
|
|
+ (setf (gethash chat-id *rss-chat-feeds*) feeds)
|
|
|
|
|
+ (%refresh-feeds)
|
|
|
|
|
+ (save-settings)
|
|
|
|
|
+ (%send-feeds chat-id feeds))))
|
|
|
|
|
+ (error (e)
|
|
|
|
|
+ (log:error e)
|
|
|
|
|
+ (telegram-send-message chat-id "Ошибочка вышла"))))
|
|
|
|
|
+
|
|
|
|
|
+(defun %feed-send-to (feed)
|
|
|
|
|
+ (loop for chat-id being the hash-keys in *rss-chat-feeds* using (hash-value feeds)
|
|
|
|
|
+ when (member feed feeds)
|
|
|
|
|
+ collect chat-id))
|
|
|
|
|
+
|
|
|
|
|
+(defun process-feeds ()
|
|
|
|
|
+ (handler-case
|
|
|
|
|
+ (dolist (feed (remove-if-not #'need-fetch-p *rss-feeds*))
|
|
|
|
|
+ (log:info "Fetching new items" (feed-url feed))
|
|
|
|
|
+ (dolist (item (fetch-new-items feed))
|
|
|
|
|
+ (dolist (chat-id (%feed-send-to feed))
|
|
|
|
|
+ (telegram-send-message chat-id (format-feed-item item)))))
|
|
|
|
|
+ (error (e) (log:error e))))
|
|
|
|
|
+
|
|
|
|
|
+(defun %load-rss-feeds (alist)
|
|
|
|
|
+ (alexandria:alist-hash-table
|
|
|
|
|
+ (loop for (chat-id . urls) in alist
|
|
|
|
|
+ collect (cons chat-id (mapcar #'%get-feed urls)))))
|
|
|
|
|
+
|
|
|
|
|
+(defun %save-rss-feeds ()
|
|
|
|
|
+ (loop for chat-id being the hash-keys in *rss-chat-feeds* using (hash-value feeds)
|
|
|
|
|
+ collect (cons chat-id (mapcar #'feed-url feeds))))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
(defun save-settings()
|
|
(defun save-settings()
|
|
|
(with-open-file (s (merge-pathnames "settings.lisp"
|
|
(with-open-file (s (merge-pathnames "settings.lisp"
|
|
|
(asdf:component-pathname
|
|
(asdf:component-pathname
|
|
@@ -334,7 +409,8 @@
|
|
|
`(setf *fsq-send-to* (alexandria:alist-hash-table ',(alexandria:hash-table-alist *fsq-send-to*))
|
|
`(setf *fsq-send-to* (alexandria:alist-hash-table ',(alexandria:hash-table-alist *fsq-send-to*))
|
|
|
*chat-locations* ',*chat-locations*
|
|
*chat-locations* ',*chat-locations*
|
|
|
*akb-send-to* ',*akb-send-to*
|
|
*akb-send-to* ',*akb-send-to*
|
|
|
- *akb-last-id* ,*akb-last-id*)
|
|
|
|
|
|
|
+ *akb-last-id* ,*akb-last-id*
|
|
|
|
|
+ *rss-chat-feeds* (%load-rss-feeds ',(%save-rss-feeds)))
|
|
|
:stream s)))
|
|
:stream s)))
|
|
|
|
|
|
|
|
(defun start ()
|
|
(defun start ()
|
|
@@ -371,6 +447,12 @@
|
|
|
(clon:make-typed-cron-schedule :minute '* :hour '*)
|
|
(clon:make-typed-cron-schedule :minute '* :hour '*)
|
|
|
:allow-now-p t)
|
|
:allow-now-p t)
|
|
|
:thread t)
|
|
:thread t)
|
|
|
|
|
+ (clon:schedule-function
|
|
|
|
|
+ (lambda () (process-feeds))
|
|
|
|
|
+ (clon:make-scheduler
|
|
|
|
|
+ (clon:make-typed-cron-schedule :minute '* :hour '*)
|
|
|
|
|
+ :allow-now-p t)
|
|
|
|
|
+ :thread t)
|
|
|
;; Start getUpdates thread
|
|
;; Start getUpdates thread
|
|
|
(bordeaux-threads:make-thread
|
|
(bordeaux-threads:make-thread
|
|
|
(lambda ()
|
|
(lambda ()
|