[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
facebook.el v 0.0.3
From: |
paul . huff |
Subject: |
facebook.el v 0.0.3 |
Date: |
Wed, 07 Oct 2009 09:31:26 -0600 |
User-agent: |
Gnus/5.11 (Gnus v5.11) Emacs/22.3 (darwin) |
Hey there,
This version of facebook.el is working for me on Mac OS X and ubuntu, and has a
few patches from Rudi Schlatte. Let me know if you like it, have
questions, comments, concerns, etc.
-Paul
;;; facebook.el --- Access the Facebook API from emacs
;;; Copyright (C) 2009 Paul Huff
;;; Author: Paul Huff <address@hidden>
;;; Maintainer: Paul Huff <address@hidden>
;;; Created: 5 Oct 2007
;;; Last modified: 3 Oct 2009
;;; Version: 0.0.3
;;; Package-Requires: ((json "0"))
;;; Keywords: facebook, frivolity
;; This file is NOT part of GNU Emacs.
;; This is free software; you can redistribute it and/or modify it under
;; the terms of the GNU General Public License as published by the Free
;; Software Foundation; either version 2, or (at your option) any later
;; version.
;; This file is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with Emacs; see the file COPYING, or type `C-h C-c'. If not,
;; write to the Free Software Foundation at this address:
;; Free Software Foundation
;; 51 Franklin Street, Fifth Floor
;; Boston, MA 02110-1301
;; USA
;;; Commentary:
;;; Version 0.0.3 A slight tweak to get login working properly no matter what.
;;;
;;; Version 0.0.2 Came out and had a bunch of patches from Rudi Schlatte.
Thanks, Rudi! Seems like it works on ubuntu and mac os x for me now.
;;;
;;; First pass at interfacing with facebook. You must add the "developers
;;; app" and get your own application api-key and application secret key to
;;; use this. Also, facebook's authentication scheme is, well, ridiculous,
;;; so you've got to have gnutls or openssl installed, as well as a working
;;; browser that handles https to log in and give your app permissions.
;;; Also, it requires hober's excellent json.el which can be obtained here:
;;; http://edward.oconnor.cx/elisp/json.el
;;; To log into facebook, call (facebook-login)
;;; To check credentials/optionally login call (facebook-check-creds)
;;; To make api calls call (facebook-call-function "<funcname>" (list (cons
"of" "args") (cons "more" "args")))
;;; Only two actual api functions are present right now, (though you can
;;; use facebook-call-function to call whatever you'd like...):
;;; facebook-users-has-app-permission = users.hasAppPermission
;;; facebook-users-set-status = users.setStatus
;;; facbeook-users-set-status checks for the applicable app permission
;;; redirects the user to the permission page if needed and then goes and
;;; updates the status.
;;; The sf.net project homepage for this project can be found here:
;;; http://sf.net/projects/facebook-el
;;; Code:
(require 'json)
(defcustom facebook-api-key "" "Your facebook api-key")
(defcustom facebook-api-secret "" "Your facebook api secret")
(defcustom facebook-session-info nil "Your facebook session info. This will be
set by facebook.el")
(defun facebook-current-time ()
(let ((current-time (current-time)))
(+ (* (car current-time) (float (expt 2 16))) (cadr current-time))))
(defun facebook-call-function-post (method-name args)
"Send ARGS to URL as a POST request."
(let* ((url "http://api.facebook.com/restserver.php")
(url-request-method "POST")
(url-request-extra-headers
'(("Content-Type" . "application/x-www-form-urlencoded")))
(full-args `(("method" . ,method-name)
("v" . "1.0")
("format" . "JSON")
("api_key" . ,facebook-api-key)
("call_id" . ,(mapconcat 'number-to-string
(current-time) ""))
,@args))
(sorted-full-args (sort full-args
(lambda (a b) (string< (car a) (car b)))))
(secret
(if (and facebook-session-info
(or (equal (assoc-default 'expires facebook-session-info) 0)
(<= (facebook-current-time)
(if (null (assoc-default 'expires
facebook-session-info))
0
(assoc-default 'expires facebook-session-info))
))
(not (string= method-name "auth.createToken")))
(assoc-default 'secret facebook-session-info)
facebook-api-secret))
(sig-full-args `(("sig" . ,(facebook-create-sig sorted-full-args
secret))
,@sorted-full-args))
(url-request-data
(mapconcat (lambda (arg)
(concat (url-hexify-string (car arg))
"="
(url-hexify-string (cdr arg))))
sig-full-args
"&"))
(result
(save-excursion
(set-buffer (url-retrieve-synchronously url))
(progn (goto-char (point-min))
(delete-region (point-min) (search-forward "\n\n"))
(buffer-substring (point-min) (point-max))))))
(setq facebook-last-raw-json-result result)
(json-read-from-string result)))
(defun facebook-create-sig (args-array secret)
(let* ((request-str (mapconcat (lambda (arg)
(concat (car arg) "=" (cdr arg)))
args-array
"")))
(md5 (concat request-str secret))))
;;;###autoload
(defun facebook-login ()
(interactive)
(let* ((auth-token (facebook-call-function-post "auth.createToken" '()))
(login-url (concat
"https://login.facebook.com/login.php?v=1.0&api_key="
facebook-api-key "&auth_token=" auth-token)))
(browse-url login-url)
(read-string (format "Hit enter here after you've logged into facebook
(this is their lame scheme, not facebook.el's %s" login-url))
(customize-save-variable 'facebook-session-info
(facebook-call-function-post "auth.getSession"
(list (cons
"auth_token"
auth-token)))
)))
(defun facebook-check-creds ()
(interactive)
(let* ((session-expires
(assoc-default 'expires facebook-session-info nil -1))
(current-time (facebook-current-time)))
(if (not (equal session-expires 0))
(if (or (null session-expires)
(<= session-expires current-time))
(facebook-login)
t)
t)))
(defun facebook-users-has-app-permission (permission)
(interactive)
(let ((result
(facebook-call-function-post "users.hasAppPermission"
(list (cons "session_key"
(assoc-default
'session_key
facebook-session-info))
(cons "ext_perm" permission)))))
(setq facebook-last-app-permission result)))
;;;###autoload
(defun facebook-users-set-status (status_message)
(interactive)
(progn
(facebook-check-creds)
(if (equal (facebook-users-has-app-permission "status_update") 0)
(let* ((auth-url (concat
"http://www.facebook.com/authorize.php?api_key="
facebook-api-key "&v=1.0&ext_perm=status_update")))
(progn
(browse-url auth-url)
(read-string "Hit enter here after you've granted your app_key
permission to update your status (should only have to do this once... this is
their lame scheme, not facebook.el's)")
)))
(message "Setting status to: %s" status_message)
(let ((result
(facebook-call-function-post "users.setStatus"
(list
(cons "session_key"
(assoc-default
'session_key
facebook-session-info))
(cons "status" status_message)))))
(setq facebook-set-status-result result))))
;;;###autoload
(defun facebook-status (status_message)
(interactive "sStatus message: ")
(facebook-users-set-status status_message))
(defun facebook-users-get-info (uids fields)
"Run users.getInfo. uids are expected to be strings."
(interactive)
(progn
(facebook-check-creds)
(facebook-call-function-post "users.getInfo"
(list
(cons "session_key"
(assoc-default
'session_key
facebook-session-info))
(cons "uids" (mapconcat 'identity uids ","))
(cons "fields" (mapconcat 'identity fields
","))))))
(defun facebook-friends-get ()
(interactive)
(progn
(facebook-check-creds)
(facebook-call-function-post "friends.get"
(list
(cons "session_key"
(assoc-default
'session_key
facebook-session-info)
)))))
(defun facebook-get-friends-status ()
(interactive)
(progn
(facebook-check-creds)
(let* ((friends-uids (mapcar 'facebook-string-hack (facebook-friends-get)))
(friends-statuses (mapcar
'identity
(facebook-users-get-info
friends-uids
(list "name" "status")))))
(with-output-to-temp-buffer "*Facebook status*"
(set-buffer "*Facebook status*")
(mapc (lambda (item)
(let* ((status-time
(assoc-default 'time
(assoc-default 'status item)))
(status-message
(assoc-default 'message
(assoc-default 'status item)))
(ago (if status-time
(- (float-time)
(assoc-default 'time
(assoc-default
'status item)))
nil)))
(if (and status-time (not (string= status-message "")))
(if (< ago (* 24 3600))
(insert (concat (assoc-default 'name item) " "
status-message
" ("
(facebook-truncate (/ ago 3600.0))
" hours ago)\n"))))))
friends-statuses)
)
(setq facebook-last-friends-statuses friends-statuses))))
;;(facebook-friends-get-info)
(defun facebook-truncate (num)
(let* ((my-string (number-to-string num))
(start (string-match (rx (group (1+ digit) "." (** 1 2 digit)))
my-string))
(end (match-end 0)))
(substring my-string start end)))
(defun facebook-string-hack (num)
"Function for handling ridiculously large float to int conversions in emacs"
"because facebook uses numbers larger than fs-most-positive-fixnum"
(replace-regexp-in-string (rx "." (one-or-more digit) line-end) ""
(number-to-string num)))
;;(setq my-facebook-update-time (facebook-users-get-info (list "723430982")
(list "name" "status")))
;;(mapcar 'facebook-status-checker-mapfunc my-facebook-update-time)
;;(- current-time my-facebook-update-time)
(provide 'facebook)
;;; facebook.el ends here
- facebook.el v 0.0.3,
paul . huff <=