Last active
May 19, 2017 21:07
-
-
Save FlyMyPG/41b273afe525541c2bc7334d9384b134 to your computer and use it in GitHub Desktop.
Read all toots you've written (excluding Boosts).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
ReadMyToots.py - Download the toots you wrote, in chronological order. | |
Author: BobC - https://mastodon.hasameli.com/@BobC | |
License: "CC BY-NC-SA 4.0" https://creativecommons.org/licenses/by-nc-sa/4.0/ | |
Usage: python ReadMyToots.py [UserName InstanceName LoginEmail Password]+ | |
Parameters: UserName - Your handle on this instance (no '@') | |
InstanceName - The instance address (no 'http://') | |
LoginEmail - Yup | |
Password - Yup | |
Parameters must form complete sets. Multiple sets are supported. | |
WARNING: No parameter validation is done. Blood & guts fly everywhere. | |
Output: Status and progress messages go to stdout. | |
Toots go to file: "[User_Name]@[InstanceName].txt" | |
Dependencies: Be sure you have Mastodon.py installed: | |
pip install mastodon.py | |
This ***SHOULD*** work on ALL major Python 3.x platforms (Win, Lin, Mac). | |
""" | |
DEBUG = False # Set to True for so much fun! | |
import sys | |
if __name__ != "__main__": | |
print("This program is NOT a library and must NOT be imported!", file=sys.stderr) | |
sys.exit() | |
# And now we will continue with our regularly scheduled program... | |
import os | |
import re | |
import textwrap | |
import pathlib as pl | |
import html | |
from mastodon import Mastodon | |
if DEBUG is True: | |
import code ####DEBUG | |
import pprint ####DEBUG | |
## Local functions: | |
if DEBUG is True: | |
def pdict(dct, indent=1, spaces=3): | |
""" Print a dict that may contain other dicts """ | |
tabs = ' '*spaces*indent | |
for key, val in dct.items(): | |
if not isinstance(val, dict): | |
try: | |
print("%s%s = "%(tabs, key), val) | |
except: | |
print("%s%s = [unprintable]"%(tabs, key)) | |
else: | |
print("%s%s = {dict}"%(tabs, key)) | |
pdict(val, indent=indent+1) | |
return | |
def witext(string, indent=1, width=80, spaces=3): | |
""" Return a wrapped and indented string """ | |
tabs = ' '*spaces*indent | |
wide = width - len(tabs) | |
lines = string.split("\n") # Paragraphs and line breaks | |
lists = (textwrap.wrap(line, wide, initial_indent=tabs, subsequent_indent=tabs) | |
for line in lines) | |
body = "\n".join("\n".join(lst) for lst in lists) | |
return body | |
def striphtml(data): | |
""" Remove or replace HTML tags and replace symbols """ | |
data = html.unescape(data) # Replace symbols | |
data = re.sub(r'<[/ ]*br[/ ]*>', '\n', data) # Preserve line breaks | |
data = re.sub(r'</*p>', '\n', data) # Preserve paragraphs | |
data = re.sub(r'<[^<]+?>', '', data) # Strip all other tags | |
return data | |
## Main code: | |
if DEBUG is True: | |
p = pprint.PrettyPrinter().pprint ####DEBUG | |
appName = os.path.splitext(os.path.basename(__file__))[0] | |
appArgNames = "UserName InstanceName LoginEmail Password" | |
appArgs = len(appArgNames.split()) | |
args = sys.argv[1:] # Parameters follow program name | |
numArgs = len(args) | |
numAcct = 0 | |
if numArgs > 0 and numArgs % appArgs == 0: # Allow only complete parameter sets | |
numAcct = int(numArgs / appArgs) | |
# Read parameters as sets | |
parameterSets = [args[(x*appArgs):(x+1)*appArgs] for x in range(numAcct)] | |
numAcct = len(parameterSets) | |
print("Read %d set(s) of user parameters.\n"%(numAcct)) | |
else: | |
print("Error: Argument[s] missing.") | |
print("Usage: %s %s ..."%(appName, appArgNames)) | |
sys.exit() | |
# Repeat for each account | |
for pset in parameterSets: | |
# Simplify parameter access | |
me, instance, email, password = pset | |
#TODO: How about some parameter validation? | |
outFile = "%s@%s.txt"%(me, instance) | |
# Prep filenames for persistent credentials | |
cliCred = "%s_%s_clientcred.txt"%(appName, instance) | |
usrCred = "%s_%s_usercred.txt"%(appName, me) | |
# Register app - only once! | |
url = "https://%s"%(instance) | |
if pl.Path(cliCred).is_file(): | |
print("Using persistent client credentials.") | |
else: | |
print("Obtaining client credentials (persistent not present).") | |
Mastodon.create_app(appName, api_base_url=url, to_file=cliCred) | |
# Create mastodon client | |
mastodon = Mastodon(api_base_url=url, client_id=cliCred) | |
# User login - either every time, or use persisted | |
if pl.Path(usrCred).is_file(): # Use persistent | |
print("Using persistent user credentials.") | |
numAcct = 1 | |
else: # Create fresh | |
print("Obtaining user credentials (persistent not present).") | |
# Login | |
mastodon.log_in(username=email, password=password, to_file=usrCred) | |
numAcct = 1 | |
# Create actual instance | |
mastodon = Mastodon(api_base_url=url, client_id=cliCred, access_token=usrCred) | |
# Get integer user ID | |
user_id = mastodon.account_search(me)[0]['id'] | |
print("user_id for %s = %s"%(me, user_id)) | |
# Collect all toots for user | |
print("\nGathering toots for @%s@%s "%(me, instance), end='') | |
sys.stdout.flush() | |
toots = [] | |
t = mastodon.account_statuses(user_id) | |
while len(t) > 0: | |
print('.', end='') | |
sys.stdout.flush() | |
toots += t | |
t = mastodon.account_statuses(user_id, max_id=t[-1]['id']) | |
print() | |
print("Processing %d toots, id %d to %d\n"%( | |
len(toots), toots[-1]['id'], toots[0]['id'])) | |
with open(outFile, 'w') as f: | |
for toot in reversed(toots): # Process from oldest to newest | |
# Gather toots by me that aren't boosts | |
if toot['reblog'] is None: | |
print("\n%s\n"%(toot['created_at']), | |
witext(striphtml(toot['content'])), file=f) | |
print("Toots written to: %s\n"%(outFile)) | |
if DEBUG is True: | |
# Go interactive only when stdout not redirected ####DEBUG | |
if os.fstat(0) == os.fstat(1): ####DEBUG | |
print("\nEntering Interactive Mode: ^Z or ^D when done.") ####DEBUG | |
code.interact(local=dict(globals(), **locals())) ####DEBUG | |
print("Exiting!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment