pesos with oauth1 and 2 working

This commit is contained in:
Peter Molnar 2017-07-04 11:30:32 +00:00
parent 06a2051f8d
commit 68c796f924
4 changed files with 729 additions and 96 deletions

70
nasg.py
View file

@ -157,6 +157,7 @@ class Indexer(object):
singular.fname, singular.fname,
singular.summary, singular.summary,
singular.content, singular.content,
singular.reactions.values()
] ]
content_remote = [] content_remote = []
@ -164,7 +165,7 @@ class Indexer(object):
#content_remote.append("%s" % offlinecopy) #content_remote.append("%s" % offlinecopy)
weight = 1 weight = 1
if singular.isbookmark: if singular.isbookmark or singular.isfav:
weight = 10 weight = 10
if singular.ispage: if singular.ispage:
weight = 100 weight = 100
@ -250,6 +251,24 @@ class OfflineArchive(object):
self.exists = os.path.isfile(self.target) self.exists = os.path.isfile(self.target)
#def read(self):
#if not self.exists:
#return ''
#with open(self.target, 'rt') as f:
#self.fm = frontmatter.loads(f.read())
#readable = ''
#try:
#readable = Document(self.fm.content)
#readable = shared.Pandoc(False).convert(readable.summary())
#readable = shared.Pandoc().convert(readable)
#except Exception as e:
#logging.error('Failed to readable %s', self.target)
#return readable
def _getimage(self, src): def _getimage(self, src):
imgname, imgext = os.path.splitext(os.path.basename(src)) imgname, imgext = os.path.splitext(os.path.basename(src))
imgtarget = os.path.join( imgtarget = os.path.join(
@ -396,11 +415,11 @@ class OfflineArchive(object):
return None return None
def read(): #def read():
if os.path.isfile(self.target): #if os.path.isfile(self.target):
with open(self.target) as f: #with open(self.target) as f:
self.fm = frontmatter.loads(f.read()) #self.fm = frontmatter.loads(f.read())
return #return
def run(self): def run(self):
@ -1394,7 +1413,6 @@ class Singular(BaseRenderable):
self.content, self.content,
self.photo self.photo
) )
# REMOVE THIS
trigger = self.offlinecopies trigger = self.offlinecopies
@ -1406,16 +1424,25 @@ class Singular(BaseRenderable):
) )
) )
) )
img = self.meta.get('image', False)
if not img:
return
if not url: if not url:
return return
c = '[![%s](/%s/%s)](%s){.favurl}' % ( img = self.meta.get('image', False)
imgs = self.meta.get('images', [])
if img:
imgs.append(img)
if not imgs or not len(imgs):
return
c = ''
for i in imgs:
c = '%s\n[![%s](/%s/%s)](%s){.favurl}' % (
c,
self.title, self.title,
shared.config.get('source', 'files'), shared.config.get('source', 'files'),
img, i,
url url
) )
@ -1674,7 +1701,9 @@ class Singular(BaseRenderable):
for maybe in ['title', 'bookmark-of', 'in-reply-to', 'repost-of']: for maybe in ['title', 'bookmark-of', 'in-reply-to', 'repost-of']:
maybe = self.meta.get(maybe, False) maybe = self.meta.get(maybe, False)
if maybe: if maybe:
self._title = maybe if isinstance(maybe, list):
maybe = maybe.pop()
self._title = maybe.replace('\n', ' ').replace('\r', '')
break break
return self._title return self._title
@ -1717,18 +1746,19 @@ class Singular(BaseRenderable):
return self.copies return self.copies
copies = {} copies = {}
for maybe in ['bookmark-of', 'in-reply-to', 'repost-of']: for maybe in ['bookmark-of', 'in-reply-to', 'repost-of', 'favorite-of']:
maybe = self.meta.get(maybe, False) maybe = self.meta.get(maybe, False)
if not maybe: if not maybe:
continue continue
if not isinstance(maybe, list): if not isinstance(maybe, list):
maybe = [maybe] maybe = [maybe]
for url in maybe: for url in maybe:
copies[url] = OfflineArchive(url) arch = OfflineArchive(url)
copies[url].run() arch.run()
#copies[url] = arch.read()
self.copies = copies #self.copies = copies
return copies #return copies
@property @property
@ -1768,8 +1798,8 @@ class Singular(BaseRenderable):
'slug': self.fname, 'slug': self.fname,
'shortslug': self.shortslug, 'shortslug': self.shortslug,
'rssenclosure': self.rssenclosure, 'rssenclosure': self.rssenclosure,
#'copies': self.offlinecopies, #'offlinecopies': self.offlinecopies,
'copies': [], #'copies': [],
'comments': self.comments, 'comments': self.comments,
'replies': self.replies, 'replies': self.replies,
'reacjis': self.reacjis, 'reacjis': self.reacjis,

289
oauth.py Executable file
View file

@ -0,0 +1,289 @@
#!/usr/bin/env python3
import asyncio
import uvloop
import os
import json
from sanic import Sanic
import sanic.response
from sanic.log import log as logging
import shared
import requests
from requests_oauthlib import OAuth1Session, oauth1_session, OAuth2Session, oauth2_session
from oauthlib.oauth2 import BackendApplicationClient
import json
import tempfile
from pprint import pprint
class TokenDB(object):
def __init__(self, uuid='tokens'):
self.db = os.path.abspath(os.path.join(
tempfile.gettempdir(),
"%s.json" % uuid
))
self.tokens = {}
self.refresh()
def refresh(self):
self.tokens = {}
if os.path.isfile(self.db):
with open(self.db, 'rt') as f:
self.tokens = json.loads(f.read())
def save(self):
with open(self.db, 'wt') as f:
f.write(json.dumps(
self.tokens, indent=4, sort_keys=True
))
self.refresh()
def get_token(self, token):
return self.tokens.get(token, None)
def get_service(self, service):
token = self.tokens.get(service, None)
#if token:
#token = self.get_token(token)
return token
def set_service(self, service, tokenid):
self.tokens.update({
service: tokenid
})
self.save()
def update_token(self,
token,
oauth_token_secret=None,
access_token=None,
access_token_secret=None,
verifier=None):
t = self.tokens.get(token, {})
if oauth_token_secret:
t.update({
'oauth_token_secret': oauth_token_secret
})
if access_token:
t.update({
'access_token': access_token
})
if access_token_secret:
t.update({
'access_token_secret': access_token_secret
})
if verifier:
t.update({
'verifier': verifier
})
self.tokens.update({
token: t
})
self.save()
def clear(self):
self.tokens = {}
self.save()
def clear_service(self, service):
t = self.tokens.get(service)
if t:
del(self.tokens[t])
del(self.tokens[service])
self.save()
class Oauth2Flow(object):
token_url = ''
def __init__(self, service):
self.service = service
self.key = shared.config.get(service, 'api_key')
self.secret = shared.config.get(service, 'api_secret')
client = BackendApplicationClient(
client_id=self.key
)
client.prepare_request_body(scope=['browse'])
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(
token_url=self.token_url,
client_id=self.key,
client_secret=self.secret
)
self.client = OAuth2Session(
self.key,
token=token
)
def request(self, url, params={}):
return self.client.get(url, params=params)
class DAOauth(Oauth2Flow):
token_url = 'https://www.deviantart.com/oauth2/token'
def __init__(self):
super(DAOauth, self).__init__('deviantart')
class Oauth1Flow(object):
request_token_url = ''
access_token_url = ''
authorize_url = ''
def __init__(self, service):
self.service = service
self.key = shared.config.get(service, 'api_key')
self.secret = shared.config.get(service, 'api_secret')
self.tokendb = TokenDB()
self.t = self.tokendb.get_service(self.service)
self.oauth_init()
def oauth_init(self):
if not self.t:
self.request_oauth_token()
t = self.tokendb.get_token(self.t)
if not t.get('access_token', None) or not t.get('access_token_secret', None):
self.request_access_token()
def request_oauth_token(self):
client = OAuth1Session(
self.key,
client_secret=self.secret,
callback_uri="%s/oauth1/" % shared.config.get('site', 'url')
)
r = client.fetch_request_token(self.request_token_url)
logging.debug('setting token to %s', r.get('oauth_token'))
self.t = r.get('oauth_token')
logging.debug('updating secret to %s', r.get('oauth_token_secret'))
self.tokendb.update_token(
self.t,
oauth_token_secret=r.get('oauth_token_secret')
)
self.tokendb.set_service(
self.service,
self.t
)
existing = self.tokendb.get_token(self.t)
verified = existing.get('verifier', None)
while not verified:
logging.debug('verifier missing for %s', self.t)
self.auth_url(existing)
self.tokendb.refresh()
existing = self.tokendb.get_token(self.t)
verified = existing.get('verifier', None)
def auth_url(self, existing):
t = self.tokendb.get_token(self.t)
client = OAuth1Session(
self.key,
client_secret=self.secret,
resource_owner_key=self.t,
resource_owner_secret=t.get('oauth_token_secret'),
callback_uri="%s/oauth1/" % shared.config.get('site', 'url')
)
input('Visit: %s and press any key after' % (
client.authorization_url(self.authorize_url)
))
def request_access_token(self):
try:
t = self.tokendb.get_token(self.t)
client = OAuth1Session(
self.key,
client_secret=self.secret,
callback_uri="%s/oauth1/" % shared.config.get('site', 'url'),
resource_owner_key=self.t,
resource_owner_secret=t.get('oauth_token_secret'),
verifier=t.get('verifier')
)
r = client.fetch_access_token(self.access_token_url)
self.tokendb.update_token(
self.t,
access_token=r.get('oauth_token'),
access_token_secret=r.get('oauth_token_secret')
)
except oauth1_session.TokenRequestDenied as e:
logging.error('getting access token was denied, clearing former oauth tokens and re-running everyting')
self.tokendb.clear_service(self.service)
self.oauth_init()
def request(self, url, params):
t = self.tokendb.get_token(self.t)
client = OAuth1Session(
self.key,
client_secret=self.secret,
resource_owner_key=t.get('access_token'),
resource_owner_secret=t.get('access_token_secret')
)
return client.get(url, params=params)
class FlickrOauth(Oauth1Flow):
request_token_url = 'https://www.flickr.com/services/oauth/request_token'
access_token_url = 'https://www.flickr.com/services/oauth/access_token'
authorize_url = 'https://www.flickr.com/services/oauth/authorize'
def __init__(self):
super(FlickrOauth, self).__init__('flickr')
class TumblrOauth(Oauth1Flow):
request_token_url = 'https://www.tumblr.com/oauth/request_token'
access_token_url = 'https://www.tumblr.com/oauth/access_token'
authorize_url = 'https://www.tumblr.com/oauth/authorize'
def __init__(self):
super(TumblrOauth, self).__init__('tumblr')
#class WPOauth(Oauth1Flow):
#request_token_url = 'https://public-api.wordpress.com/oauth2/token'
#access_token_url = 'https://public-api.wordpress.com/oauth2/authenticate'
#authorize_url = 'https://public-api.wordpress.com/oauth2/authorize'
#def __init__(self):
#super(WPOauth, self).__init__('wordpress.com')
if __name__ == '__main__':
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
app = Sanic()
@app.route("/oauth1", methods=["GET"])
async def oa(request):
token = request.args.get('oauth_token')
verifier = request.args.get('oauth_verifier')
tokendb = TokenDB()
tokendb.update_token(
token,
verifier=verifier
)
return sanic.response.text(
"OK",
status=200
)
#@app.route("/oauth2", methods=["GET"])
#async def oa2(request):
##token = request.args.get('oauth_token')
##verifier = request.args.get('oauth_verifier')
##tokendb = TokenDB()
##tokendb.update_token(
##token,
##verifier=verifier
##)
#return sanic.response.text(
#json.dumps(request.args),
#status=200
#)
app.run(host="127.0.0.1", port=8006, debug=True)

398
pesos.py
View file

@ -11,25 +11,20 @@ import shutil
import arrow import arrow
import bs4 import bs4
from slugify import slugify from slugify import slugify
import oauth
from pprint import pprint from pprint import pprint
""" TODO """ TODO
- following from: - followings?
- tumblr
- deviantart - favs from:
- flickr
- wordpress.com - wordpress.com
- twitter - twitter
- 500px
""" """
class Bookmark(object): class Bookmark(object):
def __init__(self, title, url, fname=None): def __init__(self, title, url, fname=None):
self.fm = frontmatter.loads('') self.fm = frontmatter.loads('')
@ -122,8 +117,8 @@ class Fav(object):
self.imgname self.imgname
) )
def saveimg(self, url): def saveimg(self, url, target=None):
target = self.imgtarget target = target or self.imgtarget
if os.path.isfile(target): if os.path.isfile(target):
logging.error("%s already exists, refusing to overwrite", target) logging.error("%s already exists, refusing to overwrite", target)
return return
@ -259,6 +254,97 @@ class FivehpxFav(Fav):
content = '' content = ''
self.fm.content = content self.fm.content = content
class TumblrFav(Fav):
def __init__(self, like):
super(TumblrFav, self).__init__()
self.like = like
self.blogname = like.get('blog_name')
self.postid = like.get('id')
self.fname = "tumblr-%s-%s.md" % (self.blogname, self.postid)
self.url = like.get('post_url')
self.images = []
def run(self):
icntr = 0
for p in self.like.get('photos', []):
i = p.get('original_size').get('url')
logging.debug('parsing image %s', i)
n = self.fname.replace('.md', '_%d.jpg' % icntr)
self.images.append(n)
nt = os.path.join(
shared.config.get('source', 'filesdir'),
n
)
self.saveimg(i, nt)
icntr = icntr + 1
self.arrow = arrow.get(
self.like.get('liked_timestamp',
self.like.get('date',
arrow.utcnow().timestamp
)
)
)
self.fm.content = self.like.get('caption', '')
title = self.like.get('summary', '').strip()
if not len(title):
title = self.like.get('slug', '').strip()
if not len(title):
title = shared.slugfname(self.like.get('post_url'))
self.fm.metadata = {
'published': self.arrow.format(shared.ARROWISO),
'title': title,
'favorite-of': self.url,
'tumblr_tags': self.like.get('tags'),
'author': {
'name': self.like.get('blog_name'),
'url': 'http://%s.tumblr.com' % self.like.get('blog_name')
},
'images': self.images
}
class DAFav(Fav):
def __init__(self, fav):
super(DAFav, self).__init__()
self.fav = fav
self.deviationid = fav.get('deviationid')
self.url = fav.get('url')
self.title = fav.get('title', False) or self.deviationid
self.author = self.fav.get('author').get('username')
self.fname = "deviantart-%s-by-%s.md" % (
slugify(self.title), slugify(self.author)
)
self.image = fav.get('content', {}).get('src')
def run(self):
self.saveimg(self.image)
self.arrow = arrow.get(
self.fav.get('published_time', arrow.utcnow().timestamp)
)
self.fm.metadata = {
'published': self.arrow.format(shared.ARROWISO),
'title': '%s' % self.title,
'favorite-of': self.url,
'da_tags': [t.get('tag_name') for t in self.fav.get('meta', {}).get('tags', [])],
'author': {
'name': self.author,
'url': 'https://%s.deviantart.com' % (self.author),
},
'image': self.imgname
}
content = self.fav.get('meta', {}).get('description', '')
content = shared.Pandoc(False).convert(content)
self.fm.content = content
class Favs(object): class Favs(object):
def __init__(self, confgroup): def __init__(self, confgroup):
self.confgroup = confgroup self.confgroup = confgroup
@ -327,6 +413,287 @@ class FivehpxFavs(Favs):
fav.write() fav.write()
class TumblrFavs(Favs):
def __init__(self):
super(TumblrFavs, self).__init__('tumblr')
self.oauth = oauth.TumblrOauth()
self.params = {
'after': self.lastpulled
}
self.likes = []
def getpaged(self, offset):
r = self.oauth.request(
self.url,
params={'offset': offset}
)
return json.loads(r.text)
def run(self):
r = self.oauth.request(
self.url,
params=self.params
)
js = json.loads(r.text)
total = int(js.get('response', {}).get('liked_count', 20))
print('total: %d' % total)
offset = 20
cntr = total - offset
likes = js.get('response', {}).get('liked_posts', [])
while cntr > 0:
paged = self.getpaged(offset)
likes = likes + paged.get('response', {}).get('liked_posts', [])
offset = offset + 20
cntr = total - offset
self.likes = likes
for like in self.likes:
fav = TumblrFav(like)
if not fav.exists:
fav.run()
fav.write()
class DAFavs(Favs):
def __init__(self):
from pprint import pprint
super(DAFavs, self).__init__('deviantart')
self.oauth = oauth.DAOauth()
self.params = {
'limit': 24,
'mature_content': 'true',
'username': shared.config.get('deviantart', 'username')
}
self.likes = []
def getpaged(self, offset):
self.params.update({'offset': offset})
r = self.oauth.request(
self.url,
self.params
)
return json.loads(r.text)
def getsinglemeta(self, daid):
r = self.oauth.request(
'https://www.deviantart.com/api/v1/oauth2/deviation/metadata',
params={
'deviationids[]': daid,
'ext_submission': False,
'ext_camera': False,
'ext_stats': False,
'ext_collection': False,
'mature_content': True,
}
)
meta = {}
try:
meta = json.loads(r.text)
return meta.get('metadata', []).pop()
except:
return meta
def has_more(self, q):
if 'True' == q or 'true' == q:
return True
return False
def run(self):
r = self.oauth.request(
self.url,
self.params
)
js = json.loads(r.text)
has_more = js.get('has_more')
offset = js.get('next_offset')
favs = js.get('results', [])
while True == has_more:
logging.debug('iterating over DA results with offset %d', offset)
paged = self.getpaged(offset)
favs = favs + paged.get('results', [])
has_more = paged.get('has_more')
n = paged.get('next_offset')
if n:
offset = offset + n
self.favs = favs
for fav in self.favs:
f = DAFav(fav)
if f.exists:
continue
f.fav.update({'meta': self.getsinglemeta(fav.get('deviationid'))})
f.run()
f.write()
#class WPFavs(Favs):
#def __init__(self):
#from pprint import pprint
#super(DAFavs, self).__init__('wordpress')
#self.oauth = oauth.DAOauth()
#self.params = {
#'limit': 24,
#'mature_content': 'true',
#'username': shared.config.get('deviantart', 'username')
#}
#self.likes = []
#def getpaged(self, offset):
#self.params.update({'offset': offset})
#r = self.oauth.request(
#self.url,
#self.params
#)
#return json.loads(r.text)
#def getsinglemeta(self, daid):
#r = self.oauth.request(
#'https://www.deviantart.com/api/v1/oauth2/deviation/metadata',
#params={
#'deviationids[]': daid,
#'ext_submission': False,
#'ext_camera': False,
#'ext_stats': False,
#'ext_collection': False,
#'mature_content': True,
#}
#)
#meta = {}
#try:
#meta = json.loads(r.text)
#return meta.get('metadata', []).pop()
#except:
#return meta
#def has_more(self, q):
#if 'True' == q or 'true' == q:
#return True
#return False
#def run(self):
#r = self.oauth.request(
#self.url,
#self.params
#)
#js = json.loads(r.text)
#has_more = js.get('has_more')
#offset = js.get('next_offset')
#favs = js.get('results', [])
#while True == has_more:
#logging.debug('iterating over DA results with offset %d', offset)
#paged = self.getpaged(offset)
#favs = favs + paged.get('results', [])
#has_more = paged.get('has_more')
#n = paged.get('next_offset')
#if n:
#offset = offset + n
#self.favs = favs
#for fav in self.favs:
#f = DAFav(fav)
#if f.exists:
#continue
#f.fav.update({'meta': self.getsinglemeta(fav.get('deviationid'))})
#f.run()
#f.write()
#class Following(object):
#def __init__(self, confgroup):
#self.confgroup = confgroup
#self.url = shared.config.get(confgroup, 'following_api')
#self.followings = []
#class FlickrFollowing(Following):
#def __init__(self):
#super(FlickrFollowing, self).__init__('flickr')
#self.oauth = oauth.FlickrOauth()
#def run(self):
#r = self.oauth.request(self.url, params={
#'method': 'flickr.contacts.getList',
#'format': 'json',
#'nojsoncallback': 1,
#'api_key': shared.config.get(self.confgroup, 'api_key')
#})
#try:
#contacts = json.loads(r.text)
#for c in contacts.get('contacts', {}).get('contact', []):
#self.followings.append({
#'url': "https://www.flickr.com/people/%s/" % c.get('nsid'),
#'name': c.get('realname'),
#'username': c.get('username'),
#'userid': c.get('nsid')
#})
#except Exception as e:
#logging.error('getting following from flickr failed: %s', e)
#class TumblrFollowing(Following):
#def __init__(self):
#super(TumblrFollowing, self).__init__('tumblr')
#self.oauth = oauth.FlickrOauth()
#def run(self):
#r = self.oauth.request(self.url, params={
#'method': 'flickr.contacts.getList',
#'format': 'json',
#'nojsoncallback': 1,
#'api_key': shared.config.get(self.confgroup, 'api_key')
#})
#try:
#contacts = json.loads(r.text)
#for c in contacts.get('contacts', {}).get('contact', []):
#self.followings.append({
#'url': "https://www.flickr.com/people/%s/" % c.get('nsid'),
#'name': c.get('realname'),
#'username': c.get('username'),
#'userid': c.get('nsid')
#})
#except Exception as e:
#logging.error('getting following from flickr failed: %s', e)
#class FlickrFollowing(object):
#def __init__(self):
#super(FlickrFollowing, self).__init__('flickr')
#self.params = {
#'consumer_key': shared.config.get('500px', 'api_key'),
#'rpp': 100,
#'image_size': 4,
#'include_tags': 1,
#'include_geo': 1
#}
#def run(self):
#r = requests.get(self.url,params=self.params)
#js = json.loads(r.text)
#for photo in js.get('photos', []):
#fav = FivehpxFav(photo)
#if not fav.exists:
#fav.run()
#fav.write()
#def run(self):
#https://api.flickr.com/services/rest/?method=flickr.contacts.getList&api_key=27d8a5bf7dabf882ff1c710894041f64&format=json&nojsoncallback=1&auth_token=72157682938907284-9c5f21debeec9833&api_sig=8ac87b900f44debea06a3765ed223680
#class Following(object): #class Following(object):
#def __init__(self, confgroup): #def __init__(self, confgroup):
#self.confgroup = confgroup #self.confgroup = confgroup
@ -357,7 +724,7 @@ if __name__ == '__main__':
logging.root.removeHandler(logging.root.handlers[-1]) logging.root.removeHandler(logging.root.handlers[-1])
logging.basicConfig( logging.basicConfig(
level=20, level=10,
format='%(asctime)s - %(levelname)s - %(message)s' format='%(asctime)s - %(levelname)s - %(message)s'
) )
@ -370,5 +737,12 @@ if __name__ == '__main__':
fivehpx = FivehpxFavs() fivehpx = FivehpxFavs()
fivehpx.run() fivehpx.run()
tumblr = TumblrFavs()
tumblr.run()
da = DAFavs()
da.run()
#flickrfollow = FlickrFollowing() #flickrfollow = FlickrFollowing()
#flickrfollow.run() #flickrfollow.run()

View file

@ -107,66 +107,6 @@ config = configparser.ConfigParser(
config.read('config.ini') config.read('config.ini')
config = __expandconfig(config) config = __expandconfig(config)
class TokenDB(object):
def __init__(self):
self.db = os.path.abspath(os.path.join(
config.get('common', 'basedir'),
'tokens.json'
))
self.tokens = {}
self.refresh()
def refresh(self):
if os.path.isfile(self.db):
with open(self.db, 'rt') as f:
self.tokens = json.loads(f.read())
def save(self):
with open(self.db, 'wt') as f:
f.write(
json.dumps(
self.tokens, indent=4, sort_keys=True
)
)
self.refresh()
def get_token(self, token):
return self.tokens.get(token, None)
def get_service(self, service):
s = self.tokens.get(service, None)
if s:
s = self.get_token(s)
return s
def set_service(self, service, token):
self.tokens.update({
service: token
})
#self.save()
def set_token(self, token, secret):
self.tokens.update({
token: {
'oauth_token': token,
'oauth_token_secret': secret
}
})
#self.save()
def set_verifier(self, token, verifier):
t = self.tokens.get(token)
t.update({
'verifier': verifier
})
self.tokens.update({
token: t
})
#self.save()
tokendb = TokenDB()
class CMDLine(object): class CMDLine(object):
def __init__(self, executable): def __init__(self, executable):
self.executable = self._which(executable) self.executable = self._which(executable)