import feedparser import requests import textwrap import logging import pnutpy import click import time import re import os import models as zdb from PIL import ImageFile SNAP_USER_DATA = os.environ.get('SNAP_USER_DATA') dr = False @click.group(invoke_without_command=True) @click.pass_context @click.option('--db') @click.option('--prime', is_flag=True) @click.option('--debug', is_flag=True) @click.option('--dryrun', is_flag=True) @click.version_option(version='0.2.2') def main(ctx, db, prime, debug, dryrun): global dr if debug: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) if dryrun: dr = dryrun 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") @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() @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: if not dr: entry = zdb.Entries(feedid=fid, link=link) entry.save() if prime: logging.debug(f"saving {link}...") elif user.pnut_enabled: logging.debug(f"posting {link}...") pnutpost(post, source, user.pnut_token) else: logging.debug(f"pnut disabled, saving {link}...") 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] if hasattr(entry, 'media_content'): for media in entry.media_content: if media["medium"] == "image": raw.append(embed_image(media["url"])) try: rx = re.compile('<.*?>') text = re.sub(rx, '', entry.summary) 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 + ")" if dr: logging.info({'text': text, 'raw': raw}) else: p, meta = pnutpy.api.create_post(data={'text': text, 'raw': raw}) except Exception: logging.exception("bad stuff") def embed_image(link): resume_header = {'Range': 'bytes=0-2000000'} r = requests.get(link, stream=True, headers=resume_header) 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, 'url': link } return {'type': "io.pnut.core.oembed", 'value': embed} else: return {}