#!/usr/bin/python3 # -*- coding: utf-8 -*- """ Updates a mastodon account based on a CSV file containing status Status are defined using - date - time - any number of fields usable in jinja2 templates as variables whose name is the column name """ import codecs import csv from datetime import datetime, timezone import io import operator import os from os.path import isfile, isdir, dirname, join, realpath import sys # Templates import jinja2 # Toot from toot.console import main # Command line Arguments from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("-f", "--csv-file", type=str, default="status.csv", help="Which file to use for future status") parser.add_argument("-a", "--account", type=str, default="default", help="Which name for your bot (if multiple)") parser.add_argument("-p", "--lastseen-path", type=str, default="/var/cache/newTopics", help="Which path to use for storing ") parser.add_argument("-pt", "--template-file", type=str, default="template.jinja", help="Which template file to use ") args = parser.parse_args() def sort_csv(csv_filename): """Read and return CSV data sorted by first two fields """ data = [] global headers with open(csv_filename, 'rb') as f: for row in csv.reader(codecs.iterdecode(f, 'utf-8'), delimiter=';'): if( row[0] == "Date"): headers = row else: data.append( row ) data = sorted(data, key = operator.itemgetter(0,1)) return data def recordUpdate(): """ Helper for updating lastseen """ handle = open(last_updated_file, 'w') handle.write(str(last_updated_at.strftime('%Y-%m-%d %H:%M:%S.%f%z'))) handle.close() # Variables headers = [] date_now = datetime.now(timezone.utc) # Now() account = args.account # The tag file lastseen path lastseen_path = args.lastseen_path # The tag file lastseen path csv_file = args.csv_file # The status file template_file = args.template_file # The status file last_updated_at = date_now # The last time we updated the status last_updated_file = join(lastseen_path, "{}.lastseen".format(account)) # lastseen file templateLoader = jinja2.FileSystemLoader(searchpath="./") templateEnv = jinja2.Environment(loader=templateLoader) # Exit if lastseen path doesn't exist if( not isdir( lastseen_path) ): print( "Critical error: please create directory {}".format( lastseen_path) ) os._exit(2) # Touch last seen file if not exists if( isfile( last_updated_file ) ): wrapper = open(last_updated_file, 'r',encoding="utf-8") try: record = next(wrapper) except IOError as e: print("Couldn't open or write to file (%s)." % e) last_updated_at = datetime.strptime(record.rstrip(), '%Y-%m-%d %H:%M:%S.%f%z') print( last_updated_at ) else: try: recordUpdate() except IOError as e: print("Couldn't open or write to file (%s)." % e) # Read CSV file statusList = sort_csv(csv_file) # Walk through records until a date is strictly superior to previous action and inferior to now for status in statusList: status_date = datetime.strptime("{} {}-+0000".format(status[0],status[1]), '%Y-%m-%d %H:%M:%S-%z') status_date.replace(tzinfo=timezone.utc) # Debug print( "status:{} last_updated_at:{} now:{}".format(status_date, last_updated_at, date_now) ) # Status should be published if( status_date > last_updated_at and status_date < date_now ): template = templateEnv.get_template(template_file) template_vars = dict(zip(headers, status)) outputText = template.render( template_vars ) # Toot sim_args = [sys.argv[0], 'post' ] if ( account ) : sim_args.extend( ( '-u', account )) sim_args.append( outputText ) sys.argv = sim_args main() last_updated_at = date_now # recordUpdate() os._exit(1) os._exit(0)