2022-04-30 14:05:18 +00:00
|
|
|
import feedparser
|
|
|
|
import requests
|
2022-04-30 17:01:42 +00:00
|
|
|
import textwrap
|
2022-04-30 14:05:18 +00:00
|
|
|
import logging
|
|
|
|
import pnutpy
|
|
|
|
import click
|
2022-04-30 17:01:42 +00:00
|
|
|
import time
|
2022-04-30 14:05:18 +00:00
|
|
|
import re
|
|
|
|
import os
|
|
|
|
|
|
|
|
import models as zdb
|
|
|
|
|
|
|
|
from PIL import ImageFile
|
|
|
|
|
|
|
|
SNAP_USER_DATA = os.environ.get('SNAP_USER_DATA')
|
2022-04-30 17:01:24 +00:00
|
|
|
dr = False
|
2022-04-30 14:05:18 +00:00
|
|
|
|
|
|
|
@click.group(invoke_without_command=True)
|
|
|
|
@click.pass_context
|
|
|
|
@click.option('--db')
|
|
|
|
@click.option('--prime', is_flag=True)
|
|
|
|
@click.option('--debug', is_flag=True)
|
2022-04-30 17:01:24 +00:00
|
|
|
@click.option('--dryrun', is_flag=True)
|
2022-07-12 18:12:57 +00:00
|
|
|
@click.version_option(version='0.2.2')
|
2022-04-30 17:01:24 +00:00
|
|
|
def main(ctx, db, prime, debug, dryrun):
|
|
|
|
global dr
|
2022-04-30 14:05:18 +00:00
|
|
|
|
|
|
|
if debug:
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
2022-04-30 17:01:24 +00:00
|
|
|
else:
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
|
|
if dryrun:
|
|
|
|
dr = dryrun
|
2022-04-30 14:05:18 +00:00
|
|
|
|
|
|
|
if SNAP_USER_DATA is None and db is not None:
|
|
|
|
db_file = db
|
|
|
|
else:
|
|
|
|
db_file = SNAP_USER_DATA + '/feeds.db'
|
|
|
|
|
|
|
|
zdb.db.init(db_file)
|
|
|
|
zdb.create_tables()
|
|
|
|
|
|
|
|
if ctx.invoked_subcommand is None:
|
|
|
|
for feed in zdb.Feeds.select():
|
|
|
|
fetch(feed.url, feed.pnut_uid, feed.id, prime)
|
|
|
|
|
|
|
|
@main.command()
|
|
|
|
@click.argument('username')
|
|
|
|
@click.argument('token')
|
|
|
|
def adduser(username, token):
|
|
|
|
'''Add a pnut user'''
|
|
|
|
pnutpy.api.add_authorization_token(token)
|
|
|
|
pass
|
|
|
|
try:
|
|
|
|
pnut_user, meta = pnutpy.api.get_user('me')
|
|
|
|
|
|
|
|
user = zdb.User(pnut_uid=pnut_user.id, pnut_token=token, pnut_enabled=True)
|
|
|
|
user.save()
|
|
|
|
|
|
|
|
except pnutpy.errors.PnutAuthAPIException:
|
|
|
|
logging.error(f"pnut user token not valid")
|
|
|
|
|
2022-06-12 17:41:09 +00:00
|
|
|
@main.command()
|
|
|
|
@click.argument('uid')
|
|
|
|
def enable(uid):
|
|
|
|
'''Enable posts to pnut'''
|
|
|
|
user = zdb.User.get(pnut_uid=uid)
|
|
|
|
user.pnut_enabled = 1
|
|
|
|
user.save()
|
|
|
|
|
|
|
|
@main.command()
|
|
|
|
@click.argument('uid')
|
|
|
|
def disable(uid):
|
|
|
|
'''Disable posts to pnut'''
|
|
|
|
user = zdb.User.get(pnut_uid=uid)
|
|
|
|
user.pnut_enabled = 0
|
|
|
|
user.save()
|
|
|
|
|
2022-04-30 14:05:18 +00:00
|
|
|
@main.command()
|
|
|
|
@click.argument('uid')
|
|
|
|
@click.argument('url')
|
|
|
|
def add(uid, url):
|
|
|
|
'''Add a feed'''
|
|
|
|
feed = zdb.Feeds(pnut_uid=uid, url=url)
|
|
|
|
feed.save()
|
|
|
|
|
|
|
|
def fetch(url, pnut_uid, fid, prime):
|
|
|
|
feed = feedparser.parse(url)
|
|
|
|
try:
|
|
|
|
user = zdb.User.get(pnut_uid=pnut_uid)
|
|
|
|
|
|
|
|
source = {
|
|
|
|
'link': feed.feed.link,
|
|
|
|
'username': feed.feed.title,
|
|
|
|
'avatar': feed.feed.image.href
|
|
|
|
}
|
|
|
|
|
|
|
|
for post in reversed(feed.entries):
|
|
|
|
link = post.link
|
|
|
|
|
|
|
|
try:
|
|
|
|
entry = zdb.Entries.get(feedid=fid, link=link)
|
|
|
|
logging.debug(f"skipping {link}...")
|
|
|
|
|
|
|
|
except zdb.Entries.DoesNotExist:
|
2022-04-30 17:01:24 +00:00
|
|
|
if not dr:
|
|
|
|
entry = zdb.Entries(feedid=fid, link=link)
|
|
|
|
entry.save()
|
|
|
|
|
2022-04-30 14:05:18 +00:00
|
|
|
if prime:
|
|
|
|
logging.debug(f"saving {link}...")
|
|
|
|
|
2022-06-12 17:41:09 +00:00
|
|
|
elif user.pnut_enabled:
|
2022-04-30 14:05:18 +00:00
|
|
|
logging.debug(f"posting {link}...")
|
|
|
|
pnutpost(post, source, user.pnut_token)
|
|
|
|
|
2022-06-12 17:41:09 +00:00
|
|
|
else:
|
|
|
|
logging.debug(f"pnut disabled, saving {link}...")
|
|
|
|
|
2022-04-30 14:05:18 +00:00
|
|
|
except zdb.User.DoesNotExist:
|
|
|
|
logging.error(f"user {pnut_uid} not found")
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
logging.exception("bad stuff")
|
|
|
|
|
|
|
|
def pnutpost(entry, source, token):
|
|
|
|
pnutpy.api.add_authorization_token(token)
|
|
|
|
crosspost = {
|
|
|
|
'type': "io.pnut.core.crosspost",
|
|
|
|
'value': {
|
|
|
|
'canonical_url': entry.link,
|
|
|
|
#'source': {'url': source['link']},
|
|
|
|
'user': {
|
|
|
|
'username': source['username'],
|
|
|
|
'avatar_image': source['avatar']
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
raw = [crosspost]
|
2022-07-12 18:12:57 +00:00
|
|
|
if hasattr(entry, 'media_content'):
|
|
|
|
for media in entry.media_content:
|
|
|
|
if media["medium"] == "image":
|
|
|
|
raw.append(embed_image(media["url"]))
|
2022-04-30 14:05:18 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
rx = re.compile('<.*?>')
|
|
|
|
text = re.sub(rx, '', entry.summary)
|
2022-04-30 17:01:24 +00:00
|
|
|
|
2022-04-30 17:01:42 +00:00
|
|
|
lchk = textwrap.wrap(text, 256)
|
|
|
|
if len(lchk) > 1:
|
|
|
|
pretext = textwrap.wrap(text, 250)
|
|
|
|
longpost = {
|
|
|
|
'type': "nl.chimpnut.blog.post",
|
|
|
|
'value': {
|
|
|
|
'body': text,
|
|
|
|
'tstamp': time.time() * 1000
|
|
|
|
}
|
|
|
|
}
|
|
|
|
raw.append(longpost)
|
|
|
|
text = pretext + " [...](" + entry.link + ")"
|
|
|
|
|
2022-04-30 17:01:24 +00:00
|
|
|
if dr:
|
|
|
|
logging.info({'text': text, 'raw': raw})
|
|
|
|
else:
|
|
|
|
p, meta = pnutpy.api.create_post(data={'text': text, 'raw': raw})
|
2022-04-30 14:05:18 +00:00
|
|
|
|
|
|
|
except Exception:
|
|
|
|
logging.exception("bad stuff")
|
|
|
|
|
|
|
|
def embed_image(link):
|
|
|
|
resume_header = {'Range': 'bytes=0-2000000'}
|
2022-06-22 00:01:28 +00:00
|
|
|
r = requests.get(link, stream=True, headers=resume_header)
|
2022-04-30 14:05:18 +00:00
|
|
|
|
|
|
|
p = ImageFile.Parser()
|
|
|
|
p.feed(r.content)
|
|
|
|
if p.image:
|
|
|
|
width, height = p.image.size
|
|
|
|
embed = {
|
|
|
|
'version': "1.0",
|
|
|
|
'type': "photo",
|
|
|
|
'width': width,
|
|
|
|
'height': height,
|
2022-06-22 00:01:28 +00:00
|
|
|
'url': link
|
2022-04-30 14:05:18 +00:00
|
|
|
}
|
|
|
|
return {'type': "io.pnut.core.oembed", 'value': embed}
|
|
|
|
|
|
|
|
else:
|
|
|
|
return {}
|
|
|
|
|