Add full FB API (Graph API) support
parent
e5fc9786f6
commit
3664879d92
80
feedify.py
80
feedify.py
|
@ -11,6 +11,8 @@ import lxml.html
|
||||||
import json
|
import json
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
def toclass(query):
|
def toclass(query):
|
||||||
pattern = r'\[class=([^\]]+)\]'
|
pattern = r'\[class=([^\]]+)\]'
|
||||||
repl = r'[@class and contains(concat(" ", normalize-space(@class), " "), " \1 ")]'
|
repl = r'[@class and contains(concat(" ", normalize-space(@class), " "), " \1 ")]'
|
||||||
|
@ -59,7 +61,6 @@ def formatString(string, getter, error=False):
|
||||||
elif re.search(r'^([^{}<>" ]+)(?:<"([^>]+)">)?(.*)$', string):
|
elif re.search(r'^([^{}<>" ]+)(?:<"([^>]+)">)?(.*)$', string):
|
||||||
match = re.search(r'^([^{}<>" ]+)(?:<"([^>]+)">)?(.*)$', string).groups()
|
match = re.search(r'^([^{}<>" ]+)(?:<"([^>]+)">)?(.*)$', string).groups()
|
||||||
rawValue = getter(match[0])
|
rawValue = getter(match[0])
|
||||||
print repr(rawValue)
|
|
||||||
if not isinstance(rawValue, basestring):
|
if not isinstance(rawValue, basestring):
|
||||||
if match[1] is not None:
|
if match[1] is not None:
|
||||||
out = match[1].join(rawValue)
|
out = match[1].join(rawValue)
|
||||||
|
@ -76,9 +77,69 @@ def formatString(string, getter, error=False):
|
||||||
else:
|
else:
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
def PreWorker(url, cache):
|
||||||
|
if urlparse.urlparse(url).netloc == 'graph.facebook.com':
|
||||||
|
facebook = cache.new('facebook', True)
|
||||||
|
token = urlparse.parse_qs(urlparse.urlparse(url).query)['access_token'][0]
|
||||||
|
|
||||||
|
if 't'+token not in facebook:
|
||||||
|
# this token ain't known, look for info about it
|
||||||
|
eurl = "https://graph.facebook.com/debug_token?input_token={token}&access_token={app_token}".format(token=token, app_token=morss.FBAPPTOKEN)
|
||||||
|
data = json.loads(urllib2.urlopen(eurl).read())['data']
|
||||||
|
|
||||||
|
app_id = str(data['app_id'])
|
||||||
|
user_id = str(data['user_id'])
|
||||||
|
expires = data['expires_at']
|
||||||
|
short = 'issued_at' not in data
|
||||||
|
|
||||||
|
facebook.set('t'+token, user_id)
|
||||||
|
facebook.set('e'+token, expires)
|
||||||
|
|
||||||
|
good = True
|
||||||
|
|
||||||
|
# do some woodoo to know if we already have sth better
|
||||||
|
|
||||||
|
if 'u'+user_id not in facebook:
|
||||||
|
# grab a new one anyway, new user
|
||||||
|
facebook.set('o'+user_id, token)
|
||||||
|
good = True
|
||||||
|
else:
|
||||||
|
# maybe it's a better one
|
||||||
|
last = facebook.get('u'+user_id)
|
||||||
|
last_expires = facebook.get('e'+last, int)
|
||||||
|
|
||||||
|
if expires > last_expires:
|
||||||
|
# new is better
|
||||||
|
good = True
|
||||||
|
|
||||||
|
if good and short and app_id == morss.FBAPPID:
|
||||||
|
eurl = "https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id={app_id}&client_secret={app_secret}&fb_exchange_token={short_lived_token}".format(app_id=morss.FBAPPID, app_secret=morss.FBSECRET, short_lived_token=token)
|
||||||
|
values = urlparse.parse_qs(urllib2.urlopen(eurl).read().strip())
|
||||||
|
|
||||||
|
token = values['access_token'][0]
|
||||||
|
expires = int(time.time() + int(values['expires'][0]))
|
||||||
|
|
||||||
|
facebook.set('t'+token, user_id)
|
||||||
|
facebook.set('e'+token, expires)
|
||||||
|
|
||||||
|
if good:
|
||||||
|
facebook.set('u'+user_id, token)
|
||||||
|
|
||||||
|
# hey look for a newer token and use it
|
||||||
|
token = urlparse.parse_qs(urlparse.urlparse(url).query)['access_token'][0]
|
||||||
|
user_id = facebook.get('t'+token)
|
||||||
|
last = facebook.get('u'+user_id)
|
||||||
|
original = facebook.get('o'+user_id)
|
||||||
|
|
||||||
|
nurl = url.replace(token, last)
|
||||||
|
ncache = url.replace(token, original)
|
||||||
|
cache.set('redirect', nurl)
|
||||||
|
cache.set('cache', ncache)
|
||||||
|
|
||||||
class Builder(object):
|
class Builder(object):
|
||||||
def __init__(self, link, data=None):
|
def __init__(self, link, data=None, cache=False):
|
||||||
self.link = link
|
self.link = link
|
||||||
|
self.cache = cache
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = urllib2.urlopen(link).read()
|
data = urllib2.urlopen(link).read()
|
||||||
|
@ -167,3 +228,18 @@ class Builder(object):
|
||||||
feedItem['updated'] = self.string(item, 'item_time')
|
feedItem['updated'] = self.string(item, 'item_time')
|
||||||
|
|
||||||
self.feed.items.append(feedItem)
|
self.feed.items.append(feedItem)
|
||||||
|
|
||||||
|
|
||||||
|
if urlparse.urlparse(self.link).netloc == 'graph.facebook.com':
|
||||||
|
if self.cache:
|
||||||
|
facebook = self.cache.new('facebook', True)
|
||||||
|
token = urlparse.parse_qs(urlparse.urlparse(self.link).query)['access_token'][0]
|
||||||
|
expires = facebook.get('e'+token, int)
|
||||||
|
lifespan = expires - time.time()
|
||||||
|
|
||||||
|
if lifespan < 5*24*3600:
|
||||||
|
new = self.feed.items.append()
|
||||||
|
new.title = "APP AUTHORISATION RENEWAL NEEDED"
|
||||||
|
new.link = "https://www.facebook.com/dialog/oauth?client_id={app_id}&redirect_uri=http://test.morss.it/:facebook/".format(app_id=morss.FBAPPID)
|
||||||
|
new.desc = "Please renew your Facebook app token for this app to keep working for this feed.<br/><a href='{}'>Go!</a>".format(new.link)
|
||||||
|
new.time = cache.get(expires, int)
|
||||||
|
|
56
morss.py
56
morss.py
|
@ -42,6 +42,10 @@ UA_HTML = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.11) G
|
||||||
MIMETYPE = { 'xml': ['text/xml', 'application/xml', 'application/rss+xml', 'application/rdf+xml', 'application/atom+xml'],
|
MIMETYPE = { 'xml': ['text/xml', 'application/xml', 'application/rss+xml', 'application/rdf+xml', 'application/atom+xml'],
|
||||||
'html': ['text/html', 'application/xhtml+xml']}
|
'html': ['text/html', 'application/xhtml+xml']}
|
||||||
|
|
||||||
|
FBAPPID = "<insert yours>"
|
||||||
|
FBSECRET = "<insert yours>"
|
||||||
|
FBAPPTOKEN = FBAPPID + '|' + FBSECRET
|
||||||
|
|
||||||
PROTOCOL = ['http', 'https', 'ftp']
|
PROTOCOL = ['http', 'https', 'ftp']
|
||||||
|
|
||||||
if 'REQUEST_URI' in os.environ:
|
if 'REQUEST_URI' in os.environ:
|
||||||
|
@ -360,9 +364,14 @@ def Fill(item, cache, feedurl='/', fast=False):
|
||||||
else:
|
else:
|
||||||
link = None
|
link = None
|
||||||
|
|
||||||
# facebook, do nothing for now FIXME
|
# facebook
|
||||||
if urlparse.urlparse(feedurl).netloc == 'graph.facebook.com':
|
if urlparse.urlparse(feedurl).netloc == 'graph.facebook.com':
|
||||||
link = None
|
match = lxml.html.fromstring(item.content).xpath('//a/@href')
|
||||||
|
if len(match) and urlparse.urlparse(match[0]).netloc != 'www.facebook.com':
|
||||||
|
link = match[0]
|
||||||
|
log(link)
|
||||||
|
else:
|
||||||
|
link = None
|
||||||
|
|
||||||
if link is None:
|
if link is None:
|
||||||
log('no used link')
|
log('no used link')
|
||||||
|
@ -423,6 +432,9 @@ def Gather(url, cachePath, options):
|
||||||
|
|
||||||
log(cache._hash)
|
log(cache._hash)
|
||||||
|
|
||||||
|
# do some useful facebook work
|
||||||
|
feedify.PreWorker(url, cache)
|
||||||
|
|
||||||
if 'redirect' in cache:
|
if 'redirect' in cache:
|
||||||
url = cache.get('redirect')
|
url = cache.get('redirect')
|
||||||
log('url redirect')
|
log('url redirect')
|
||||||
|
@ -466,7 +478,7 @@ def Gather(url, cachePath, options):
|
||||||
if style == 'normal':
|
if style == 'normal':
|
||||||
rss = feeds.parse(xml)
|
rss = feeds.parse(xml)
|
||||||
elif style == 'feedify':
|
elif style == 'feedify':
|
||||||
feed = feedify.Builder(url, xml)
|
feed = feedify.Builder(url, xml, cache)
|
||||||
feed.build()
|
feed.build()
|
||||||
rss = feed.feed
|
rss = feed.feed
|
||||||
elif style == 'html':
|
elif style == 'html':
|
||||||
|
@ -526,7 +538,7 @@ if __name__ == '__main__':
|
||||||
HOLD = True
|
HOLD = True
|
||||||
|
|
||||||
if 'HTTP_IF_NONE_MATCH' in os.environ:
|
if 'HTTP_IF_NONE_MATCH' in os.environ:
|
||||||
if not options.force and time.time() - int(os.environ['HTTP_IF_NONE_MATCH'][1:-1]) < DELAY:
|
if not options.force and not options.facebook and time.time() - int(os.environ['HTTP_IF_NONE_MATCH'][1:-1]) < DELAY:
|
||||||
print 'Status: 304'
|
print 'Status: 304'
|
||||||
print
|
print
|
||||||
log(url)
|
log(url)
|
||||||
|
@ -538,6 +550,42 @@ if __name__ == '__main__':
|
||||||
else:
|
else:
|
||||||
cachePath = os.path.expanduser('~') + '/.cache/morss'
|
cachePath = os.path.expanduser('~') + '/.cache/morss'
|
||||||
|
|
||||||
|
if options.facebook:
|
||||||
|
facebook = Cache(cachePath, 'facebook', True)
|
||||||
|
|
||||||
|
# get real token from code
|
||||||
|
code = urlparse.parse_qs(urlparse.urlparse(url).query)['code'][0]
|
||||||
|
eurl = "https://graph.facebook.com/oauth/access_token?client_id={app_id}&redirect_uri={redirect_uri}&client_secret={app_secret}&code={code_parameter}".format(app_id=FBAPPID, app_secret=FBSECRET, code_parameter=code, redirect_uri="http://test.morss.it/:facebook/")
|
||||||
|
token = urlparse.parse_qs(urllib2.urlopen(eurl).read().strip())['access_token'][0]
|
||||||
|
|
||||||
|
# get long-lived access token
|
||||||
|
eurl = "https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id={app_id}&client_secret={app_secret}&fb_exchange_token={short_lived_token}".format(app_id=FBAPPID, app_secret=FBSECRET, short_lived_token=token)
|
||||||
|
values = urlparse.parse_qs(urllib2.urlopen(eurl).read().strip())
|
||||||
|
|
||||||
|
ltoken = values['access_token'][0]
|
||||||
|
expires = int(time.time() + int(values['expires'][0]))
|
||||||
|
|
||||||
|
# get user id
|
||||||
|
iurl = "https://graph.facebook.com/me?fields=id&access_token={token}".format(ltoken)
|
||||||
|
user_id = json.loads(urllib2.urlopen(iurl).read())['id']
|
||||||
|
|
||||||
|
# do sth out of it
|
||||||
|
facebook.set('t'+ltoken, user_id)
|
||||||
|
facebook.set('e'+ltoken, expires)
|
||||||
|
facebook.set('u'+user_id, ltoken)
|
||||||
|
|
||||||
|
if 'o'+user_id not in token:
|
||||||
|
facebook.set('o'+user_id, ltoken)
|
||||||
|
|
||||||
|
if 'REQUEST_URI' in os.environ:
|
||||||
|
print 'Status: 200'
|
||||||
|
print 'Content-Type: text/plain'
|
||||||
|
print ''
|
||||||
|
|
||||||
|
print "token updated"
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
if 'REQUEST_URI' in os.environ:
|
if 'REQUEST_URI' in os.environ:
|
||||||
print 'Status: 200'
|
print 'Status: 200'
|
||||||
print 'ETag: "%s"' % int(time.time())
|
print 'ETag: "%s"' % int(time.time())
|
||||||
|
|
Loading…
Reference in New Issue