<commit_before>#|
 This file is a part of Colleen
 (c) 2014 TymoonNET/NexT http://tymoon.eu (<EMAIL>)
 Author: <NAME> <<EMAIL>>
|#

(in-package :org.tymoonnext.colleen)
(defpackage org.tymoonnext.colleen.mod.twitter
  (:use :cl :colleen :events :chirp-objects)
  (:shadowing-import-from :events :version :parameters :users :reason :sender :mode :user :parameter :address :language :resource :query :code :target)
  (:shadowing-import-from :colleen :message)
  (:shadowing-import-from :chirp-objects :start :name))
(in-package :org.tymoonnext.colleen.mod.twitter)

(defvar *config-file* (merge-pathnames "twitter.json" (merge-pathnames "config/" (asdf:system-source-directory :colleen))))

(define-module twitter ()
    ((streams :initform () :accessor streams))
  (:documentation "Provides access to the twitter API."))

(defmethod start ((twitter twitter))
  (with-open-file (stream *config-file* :if-does-not-exist NIL)
    (when stream
      (let ((config (yason:parse stream)))
        (setf chirp:*oauth-api-key* (gethash "api-key" config)
              chirp:*oauth-api-secret* (gethash "api-secret" config) 
              chirp:*oauth-access-token* (gethash "access-token" config)
              chirp:*oauth-access-secret* (gethash "access-secret" config)))
      (v:info :twitter "Loaded keys from config."))))

(defmethod stop ((twitter twitter))
  (with-open-file (stream *config-file* :direction :output :if-does-not-exist :create :if-exists :supersede)
    (let ((config (make-hash-table :test 'equal)))
      (setf (gethash "api-key" config) chirp:*oauth-api-key*)
      (setf (gethash "api-secret" config) chirp:*oauth-api-secret*)
      (setf (gethash "access-token" config) chirp:*oauth-access-token*)
      (setf (gethash "access-secret" config) chirp:*oauth-access-secret*)
      (yason:encode config stream))
    (v:info :twitter "Saved keys to config.")))

(define-group twitter :documentation "Interact with the linked twitter account.")

(define-command (twitter verify) () (:documentation "Perform an ACCOUNT/VERIFY-CREDENTIALS call to see if the account was linked successfully.")
  (let ((user (chirp:account/verify-credentials)))
    (respond event "Linked account: ~a" (screen-name user))))

(define-command (twitter initiate-authentication) (&optional api-key api-secret) (:authorization T :documentation "Initiate the authentication process.")
  (respond event "Please visit: ~a" (chirp:initiate-authentication :api-key (or api-key chirp:*oauth-api-key*) :api-secret (or api-secret chirp:*oauth-api-secret*))))

(define-command (twitter complete-authentication) (pin) (:authorization T :documentation "Complete the authentication process.")
  (chirp:complete-authentication pin)
  (let ((user (chirp:account/verify-credentials)))
    (respond event "Successfully authenticated as ~a" (screen-name user))))

(define-command (twitter tweet) (&rest text) (:authorization T :documentation "Tweet on behalf of the linked user.")
  (chirp:tweet (format NIL "~{~a~^ ~}" text)))

(define-command (twitter stream-home) () (:authorization T :documentation "Stream the home timeline to the current channel.")
  (push (list (with-module-thread (get-module :twitter)
                (chirp:stream/user #'(lambda (o)
                                       (when (and o (typep o 'chirp:status))
                                         (respond event "[Twitter] ~a: ~a" (chirp:screen-name (chirp:user o)) (text o)))
                                       T)))
              (colleen:name (server event))
              (channel event))
        (streams module)))

(define-command (twitter list-streams) () (:authorization T :documentation "List all working streams.")
  (respond event "~a" (streams module)))

(define-command (twitter stop-stream) (id) (:authorization T :documentation "Stop the given stream.")
  (bordeaux-threads:destroy-thread (gethash id (threads module)))
  (setf (threads module) (delete id (threads module) :key #'first :test #'string-equal))
  (respond event "Stream stopped."))<commit_msg>Added follow commands Fixed stream-stop Updated streaming to new chirp spec.<commit_after>#|
 This file is a part of Colleen
 (c) 2014 TymoonNET/NexT http://tymoon.eu (<EMAIL>)
 Author: <NAME> <<EMAIL>>
|#

(in-package :org.tymoonnext.colleen)
(defpackage org.tymoonnext.colleen.mod.twitter
  (:use :cl :colleen :events :chirp-objects)
  (:shadowing-import-from :events :version :parameters :users :reason :sender :mode :user :parameter :address :language :resource :query :code :target)
  (:shadowing-import-from :colleen :message)
  (:shadowing-import-from :chirp-objects :start :name))
(in-package :org.tymoonnext.colleen.mod.twitter)

(defvar *config-file* (merge-pathnames "twitter.json" (merge-pathnames "config/" (asdf:system-source-directory :colleen))))

(define-module twitter ()
    ((streams :initform () :accessor streams))
  (:documentation "Provides access to the twitter API."))

(defmethod start ((twitter twitter))
  (with-open-file (stream *config-file* :if-does-not-exist NIL)
    (when stream
      (let ((config (yason:parse stream)))
        (setf chirp:*oauth-api-key* (gethash "api-key" config)
              chirp:*oauth-api-secret* (gethash "api-secret" config) 
              chirp:*oauth-access-token* (gethash "access-token" config)
              chirp:*oauth-access-secret* (gethash "access-secret" config)))
      (v:info :twitter "Loaded keys from config."))))

(defmethod stop ((twitter twitter))
  (with-open-file (stream *config-file* :direction :output :if-does-not-exist :create :if-exists :supersede)
    (let ((config (make-hash-table :test 'equal)))
      (setf (gethash "api-key" config) chirp:*oauth-api-key*)
      (setf (gethash "api-secret" config) chirp:*oauth-api-secret*)
      (setf (gethash "access-token" config) chirp:*oauth-access-token*)
      (setf (gethash "access-secret" config) chirp:*oauth-access-secret*)
      (yason:encode config stream))
    (v:info :twitter "Saved keys to config.")))

(define-group twitter :documentation "Interact with the linked twitter account.")

(define-command (twitter verify) () (:documentation "Perform an ACCOUNT/VERIFY-CREDENTIALS call to see if the account was linked successfully.")
  (let ((user (chirp:account/verify-credentials)))
    (respond event "Linked account: ~a" (screen-name user))))

(define-command (twitter initiate-authentication) (&optional api-key api-secret) (:authorization T :documentation "Initiate the authentication process.")
  (respond event "Please visit: ~a" (chirp:initiate-authentication :api-key (or api-key chirp:*oauth-api-key*) :api-secret (or api-secret chirp:*oauth-api-secret*))))

(define-command (twitter complete-authentication) (pin) (:authorization T :documentation "Complete the authentication process.")
  (chirp:complete-authentication pin)
  (let ((user (chirp:account/verify-credentials)))
    (respond event "Successfully authenticated as ~a" (screen-name user))))

(define-command (twitter tweet) (&rest text) (:authorization T :documentation "Tweet on behalf of the linked user.")
  (chirp:tweet (format NIL "~{~a~^ ~}" text)))

(define-command (twitter stream-home) () (:authorization T :documentation "Stream the home timeline to the current channel.")
  (push (list (with-module-thread (get-module :twitter)
                (chirp:stream/user #'(lambda (o)
                                       (when (and o (typep o 'chirp:status))
                                         (respond event "[Twitter] ~a: ~a"
                                                  (chirp:screen-name (chirp:user o))
                                                  (chirp:xml-decode (chirp:text-with-expanded-urls o))))
                                       T)))
              (colleen:name (server event))
              (channel event))
        (streams module)))

(define-command (twitter list-streams) () (:authorization T :documentation "List all working streams.")
  (respond event "~a" (streams module)))

(define-command (twitter stop-stream) (id) (:authorization T :documentation "Stop the given stream.")
  (let ((thread (gethash id (threads module))))
    (bordeaux-threads:interrupt-thread thread #'(lambda () (error "STOP STREAM!")))
    (when (bordeaux-threads:thread-alive-p thread)
      (bordeaux-threads:destroy-thread thread))
    (if (bordeaux-threads:thread-alive-p thread)
        (respond event "FIXME: Destroying the stream thread failed. Thread still alive.")
        (progn
          (setf (streams module) (delete id (streams module) :key #'first :test #'string-equal))
          (respond event "Stream stopped.")))))

(define-command (twitter follow) (screen-name) (:authorization T :documentation "Follow the specified user.")
  (chirp:friendships/create :screen-name screen-name)
  (respond event "~a followed." screen-name))

(define-command (twitter unfollow) (screen-name) (:authorization T :documentation "Unfollow the specified user.")
  (chirp:friendships/destroy :screen-name screen-name)
  (respond event "~a unfollowed." screen-name))
{'fraction_non_alphanumeric': 0.14562569213732005, 'fraction_numerical': 0.0008859357696566999, 'mean_word_length': 3.718390804597701, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 1}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '73451', 'n_tokens_mistral': 2811, 'n_tokens_neox': 2717, 'n_words': 783}