initial commit - email2post.py

This commit is contained in:
Morgan McMillian 2020-08-15 16:37:53 -07:00
commit 6babc1b53b
4 changed files with 189 additions and 0 deletions

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Morgan McMillian
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7
README.md Normal file
View file

@ -0,0 +1,7 @@
# blarp - a collection of my social posting bits
## email2post.py
Parse email from STDIN and create a post on one or more social network.
Currently supports mastodon and pnut.io.

159
email2post.py Executable file
View file

@ -0,0 +1,159 @@
#!/usr/bin/env python3
import sys
import os
import email
import email.header
import textwrap
import logging
import argparse
import configparser
import pnutpy
from mastodon import Mastodon
logger = logging.getLogger()
def parse(data, pnut, mstdn):
body = ""
attachments = []
for part in data.walk():
disposition = part.get_content_disposition()
contentType = part.get_content_type()
if contentType == "multipart/mixed":
continue
if disposition == "inline":
body = part.get_payload(decode=True).decode("utf-8")
elif disposition == "attachment":
attachment = part.get_payload(decode=True)
filename = part.get_filename()
attachments.append({
'type': contentType,
'filename': filename,
'file': attachment
})
else:
logger.debug("unknown disposition")
logger.debug(disposition)
if pnut:
post_pnut(data['Subject'], body, attachments)
if mstdn:
post_mastodon(data['Subject'], body, attachments)
def post_pnut(title, text, attachments):
post = {'text': text, 'raw': []}
mtext = textwrap.wrap(text, 254)
if len(mtext) > 1:
longpost = {
'title': title,
'body': text,
'tstamp': time.time() * 1000
}
pretext = textwrap.wrap(text, 100)
post['text'] = pretext[0]
post['text'] += "... - https://longpo.st/p/{object_id} - #longpost"
post['raw'].append({
'type': "nl.chimpnut.blog.post",
'value': longpost
})
for attachment in attachments:
try:
file_, meta = pnutpy.api.create_file(
files={'content': attachment['file']},
data={
'name': attachment['filename'],
'type': 'dev.thrrgilag.blarp',
'is_public': 'true'
}
)
value = {
'+io.pnut.core.file': {
'file_id': file_.id,
'file_token': file_.file_token,
'format': 'oembed'
}
}
post['raw'].append({
'type': "io.pnut.core.oembed",
'value': value
})
except Exception:
logger.error("problem handling an attachment")
logger.exception("pnut attachment")
return
try:
response, meta = pnutpy.api.create_post(data=post)
logger.debug(response)
except Exception:
logger.error("problem posting to pnut")
logger.exception("create_post")
def post_mastodon(title, text, attachments):
media_ids = []
for attachment in attachments:
file_ = mastodon.media_post(attachment['file'], attachment['type'])
media_ids.append(file_['id'])
response = mastodon.status_post(text, media_ids=media_ids)
logger.debug(response)
if __name__ == "__main__":
if "XDG_CONFIG_HOME" in os.environ:
config_home = os.path.expanduser(os.environ["XDG_CONFIG_HOME"])
config_file = os.path.join(config_home, "email2post.conf")
else:
config_home = os.path.expanduser("~")
config_file = os.path.join(config_home, ".email2post.conf")
a_parser = argparse.ArgumentParser()
a_parser.add_argument(
'-d', '--debug', action='store_true', dest='debug',
help="debug"
)
a_parser.add_argument(
'-c', '--config', dest='config_file',
)
a_parser.add_argument(
'-p', '--pnut', action='store_true', dest='pnut',
help="post to pnut.io"
)
a_parser.add_argument(
'-m', '--mastodon', action='store_true', dest='mstdn',
help="post to mastodon"
)
args = a_parser.parse_args()
if args.debug:
logging.basicConfig(level=logging.DEBUG)
if args.config_file:
config_file = args.config_file
config = configparser.ConfigParser()
config.read(config_file)
pnutpy.api.add_authorization_token(config['pnut']['token'])
mastodon = Mastodon(
client_id=config['mastodon']['client_id'],
client_secret=config['mastodon']['client_secret'],
access_token=config['mastodon']['access_token'],
api_base_url=config['mastodon']['url']
)
data = email.message_from_file(sys.stdin)
parse(data, args.pnut, args.mstdn)

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
pnutpy
Mastodon.py