ttbp/bin/ttbp.py

507 lines
15 KiB
Python
Raw Normal View History

2016-04-30 03:17:06 +00:00
#!/usr/bin/python
import os
2016-05-01 17:44:49 +00:00
import random
import tempfile
import subprocess
import time
2016-05-01 22:43:12 +00:00
import json
2016-05-01 17:44:49 +00:00
2016-05-01 23:34:20 +00:00
import core
2016-05-01 00:19:00 +00:00
import chatter
2016-05-03 17:14:53 +00:00
import inflect
import util
2016-04-30 03:17:06 +00:00
2016-05-01 22:26:26 +00:00
## system globals
2016-05-01 00:19:00 +00:00
SOURCE = os.path.join("/home", "endorphant", "projects", "ttbp", "bin")
2016-05-01 22:26:26 +00:00
LIVE = "http://tilde.town/~"
FEEDBACK = os.path.join("/home", "endorphant", "ttbp-mail")
2016-05-01 23:34:20 +00:00
USERFILE = os.path.join("/home", "endorphant", "projects", "ttbp", "users.txt")
2016-05-03 17:14:53 +00:00
p = inflect.engine()
2016-05-01 22:26:26 +00:00
## user globals
2016-05-01 00:19:00 +00:00
USER = os.path.basename(os.path.expanduser("~"))
PATH = os.path.join("/home", USER, ".ttbp")
PUBLIC = os.path.join("/home", USER, "public_html")
2016-05-01 00:19:00 +00:00
WWW = os.path.join(PATH, "www")
2016-04-30 03:48:01 +00:00
CONFIG = os.path.join(PATH, "config")
2016-05-01 22:43:12 +00:00
TTBPRC = os.path.join(CONFIG, "ttbprc")
2016-05-01 00:19:00 +00:00
DATA = os.path.join(PATH, "entries")
2016-05-01 22:26:26 +00:00
SETTINGS = {
"editor": "none",
"publish dir": False
2016-05-01 22:26:26 +00:00
}
2016-04-30 03:17:06 +00:00
2016-05-01 22:26:26 +00:00
## ui globals
2016-05-01 18:10:04 +00:00
BANNER = open(os.path.join(SOURCE, "config", "banner.txt")).read()
2016-05-01 17:44:49 +00:00
SPACER = "\n\n\n"
2016-05-01 18:10:04 +00:00
INVALID = "please pick a number from the list of options!\n\n"
DUST = "sorry about the dust, but this part is still under construction. check back later!\n\n"
QUITS = ['exit', 'quit', 'q', 'x']
BACKS = ['back', 'b', 'q']
EJECT = "eject button fired! going home now."
2016-05-01 18:10:04 +00:00
2016-05-01 22:26:26 +00:00
## ref
EDITORS = ["vim", "vi", "emacs", "pico", "nano"]
SUBJECTS = ["help request", "bug report", "feature suggestion", "general comment"]
2016-05-01 22:26:26 +00:00
2016-05-01 18:10:04 +00:00
##
def redraw(leftover=""):
os.system("clear")
print(BANNER)
print(SPACER)
if leftover:
print("> "+leftover+"\n")
2016-04-30 03:17:06 +00:00
def start():
2016-05-01 18:10:04 +00:00
redraw()
2016-05-01 17:44:49 +00:00
#print(chatter.say("greet")+", "+chatter.say("friend"))
#print("(remember, you can always press ctrl-c to come home)\n")
2016-05-01 23:34:20 +00:00
print("if you don't want to be here at any point, press <ctrl-d> and it'll all go away.\njust keep in mind that you might lose anything you've started here.\n")
2016-04-30 03:17:06 +00:00
try:
print(check_init())
except EOFError:
print(stop())
return
redraw()
while 1:
try:
print(main_menu())
except EOFError:
print(stop())
break
except KeyboardInterrupt:
redraw(EJECT)
else:
break
2016-04-30 03:34:43 +00:00
def stop():
return "\n\n\t"+chatter.say("bye")+"\n\n"
2016-04-30 03:34:43 +00:00
def check_init():
2016-05-01 22:43:12 +00:00
global SETTINGS
2016-05-01 23:34:20 +00:00
print("\n\n")
2016-04-30 03:34:43 +00:00
if os.path.exists(os.path.join(os.path.expanduser("~"),".ttbp")):
2016-05-01 23:34:20 +00:00
print(chatter.say("greet")+", "+USER+".")
2016-05-01 22:43:12 +00:00
while not os.path.isfile(TTBPRC):
setup_handler()
try:
SETTINGS = json.load(open(TTBPRC))
except ValueError:
setup_handler()
2016-05-03 17:46:54 +00:00
raw_input("\n\npress <enter> to explore your feels.\n\n")
2016-05-01 23:34:20 +00:00
core.load()
2016-05-01 17:44:49 +00:00
return ""
2016-04-30 03:34:43 +00:00
else:
return init()
def init():
2016-05-01 23:34:20 +00:00
try:
raw_input("i don't recognize you, stranger. let's make friends.\n\npress <enter> to begin, or <ctrl-c> to get out of here. \n\n")
except KeyboardInterrupt:
print("\n\nthanks for checking in! i'll always be here.\n\n")
quit()
2016-05-01 23:34:20 +00:00
users = open(USERFILE, 'a')
users.write(USER+"\n")
users.close()
subprocess.call(["mkdir", PATH])
subprocess.call(["mkdir", CONFIG])
subprocess.call(["mkdir", DATA])
#subprocess.call(["cp", os.path.join(SOURCE, "config", "defaults", "header.txt"), CONFIG])
header = gen_header()
headerfile = open(os.path.join(CONFIG, "header.txt"), 'w')
for line in header:
headerfile.write(line)
headerfile.close()
2016-05-01 23:34:20 +00:00
subprocess.call(["cp", os.path.join(SOURCE, "config", "defaults", "footer.txt"), CONFIG])
setup()
subprocess.call(["cp", os.path.join(SOURCE, "config", "defaults", "style.css"), WWW])
2016-05-01 23:34:20 +00:00
core.load()
raw_input("\nyou're all good to go, "+chatter.say("friend")+"! hit <enter> to continue.\n\n")
2016-05-01 17:44:49 +00:00
return ""
def gen_header():
header = []
header.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2//EN\">")
2016-05-02 03:44:01 +00:00
header.append("\n<html>")
header.append("\n\t<head>")
header.append("\n\t\t<title>~"+USER+" on TTBP</title>")
header.append("\n\t\t<link rel=\"stylesheet\" href=\"style.css\" />")
header.append("\n\t</head>")
header.append("\n\t<body>")
header.append("\n\t\t<div id=\"meta\">")
2016-05-03 17:14:53 +00:00
header.append("\n\t\t\t<h1><a href=\"index.html#\">~"+USER+"</a>@<a href=\"/~endorphant/ttbp\">TTBP</a></h1>")
2016-05-02 03:44:01 +00:00
header.append("\n\t\t</div>\n")
header.append("\n\t\t<!---put your custom html here-->\n\n\n\n")
header.append("\n\t\t<!---don't put anything after this line-->\n")
header.append("\n\t\t<div id=\"tlogs\">\n")
return header
2016-05-01 22:43:12 +00:00
def setup_handler():
print("\nyour ttbp configuration doesn't look right. let's make you a fresh copy.\n\n")
try:
setup()
except KeyboardInterrupt:
print("\n\nsorry, trying again.\n\n")
setup()
2016-05-01 22:26:26 +00:00
def setup():
global SETTINGS
# editor selection
print_menu(EDITORS)
choice = raw_input("\npick your favorite text editor: ")
while choice not in ['0', '1', '2', '3', '4']:
choice = raw_input("\nplease pick a number from the list: ")
SETTINGS["editor"] = EDITORS[int(choice)]
redraw("text editor set to: "+SETTINGS["editor"])
2016-05-01 22:26:26 +00:00
# publish directory selection
if SETTINGS["publish dir"]:
print("\tcurrent publish dir:\t"+os.path.join(PUBLIC, SETTINGS["publish dir"])+"\n\n")
choice = raw_input("\nwhere do you want your blog published? (leave blank to use default \"blog\") ")
2016-05-01 22:26:26 +00:00
if not choice:
choice = "blog"
publishing = os.path.join(PUBLIC, choice)
2016-05-01 22:26:26 +00:00
while os.path.exists(publishing):
second = raw_input("\n"+publishing+" already exists!\nif you're sure you want to use it, hit <enter> to confirm. otherwise, pick another location: ")
if second == "":
break
choice = second
publishing = os.path.join(PUBLIC, choice)
2016-05-01 22:26:26 +00:00
SETTINGS["publish dir"] = choice
2016-05-01 22:26:26 +00:00
# set up publish directory
if not os.path.exists(publishing):
subprocess.call(["mkdir", publishing])
subprocess.call(["touch", os.path.join(publishing, "index.html")])
index = open(os.path.join(publishing, "index.html"), "w")
index.write("<h1>ttbp blog placeholder</h1>")
index.close()
2016-05-01 23:34:20 +00:00
if os.path.exists(WWW):
subprocess.call(["rm", WWW])
2016-05-01 22:26:26 +00:00
subprocess.call(["ln", "-s", publishing, WWW])
print("\n\tpublishing to "+LIVE+USER+"/"+SETTINGS["publish dir"]+"/\n\n")
2016-05-01 22:26:26 +00:00
2016-05-01 22:43:12 +00:00
# save settings
ttbprc = open(TTBPRC, "w")
ttbprc.write(json.dumps(SETTINGS, sort_keys=True, indent=2, separators=(',',':')))
ttbprc.close()
2016-05-01 22:26:26 +00:00
return SETTINGS
2016-05-01 17:44:49 +00:00
## menus
def print_menu(menu):
i = 0
for x in menu:
line = []
line.append("\t[ ")
if i < 10:
line.append(" ")
line.append(str(i)+" ] "+x)
print("".join(line))
i += 1
2016-04-30 03:34:43 +00:00
2016-04-30 03:17:06 +00:00
def main_menu():
2016-05-01 18:10:04 +00:00
#os.system("clear")
#print(BANNER)
#redraw()
2016-05-01 22:26:26 +00:00
menuOptions = [
2016-05-03 17:46:54 +00:00
"record your feels",
"review your feels",
2016-05-03 17:46:54 +00:00
"check out your neighbors",
"browse global feels",
2016-05-03 17:46:54 +00:00
"change your settings",
"send some feedback",
"(wip) see credits"]
2016-05-01 18:10:04 +00:00
#print(SPACER)
#print("you're at ttbp home. remember, you can always press <ctrl-c> to come back here.\n\n")
print("you're at ttbp home.\n\n")
2016-05-01 17:44:49 +00:00
print_menu(menuOptions)
#print("how are you feeling today? ")
#try:
# choice = raw_input("\ntell me about your feels (or 'quit' to exit): ")
#except KeyboardInterrupt:
# redraw(EJECT)
# return main_menu()
2016-05-01 22:26:26 +00:00
try:
choice = raw_input("\ntell me about your feels (or 'quit' to exit): ")
2016-05-01 22:26:26 +00:00
except KeyboardInterrupt:
redraw(EJECT)
2016-05-01 22:26:26 +00:00
return main_menu()
2016-05-01 17:44:49 +00:00
if choice == '0':
2016-05-01 23:34:20 +00:00
redraw()
today = time.strftime("%Y%m%d")
write_entry(os.path.join(DATA, today+".txt"))
2016-05-01 17:44:49 +00:00
elif choice == '1':
redraw("here are your recorded feels, listed by date:\n\n")
view_own()
elif choice == '2':
users = find_ttbps()
redraw("the following "+p.no("user", len(users))+" "+p.plural("is", len(users))+" recording feels on ttbp:\n\n")
view_neighbors(users)
elif choice == '3':
redraw("now viewing most recent entries\n\n")
view_feed()
elif choice == '4':
pretty_settings = "\n\ttext editor:\t" +SETTINGS["editor"]
pretty_settings += "\n\tpublish dir:\t" +os.path.join(PUBLIC, SETTINGS["publish dir"])
redraw("now changing your settings. press <ctrl-c> if you didn't mean to do this.\n\ncurrent settings "+pretty_settings+"\n")
2016-05-05 00:10:33 +00:00
try:
setup()
except KeyboardInterrupt():
redraw(EJECT)
raw_input("\nyou're all good to go, "+chatter.say("friend")+"! hit <enter> to continue.\n\n")
redraw()
elif choice == '5':
2016-05-01 18:10:04 +00:00
redraw()
feedback_menu()
elif choice == '6':
redraw()
show_credits()
elif choice in QUITS:
2016-05-01 17:44:49 +00:00
return stop()
else:
2016-05-01 18:10:04 +00:00
redraw(INVALID)
2016-05-01 17:44:49 +00:00
return main_menu()
2016-04-30 03:17:06 +00:00
###
2016-05-01 17:44:49 +00:00
def feedback_menu():
2016-05-01 18:10:04 +00:00
print("you're about to send mail to ~endorphant about ttbp\n\n")
2016-04-30 03:17:06 +00:00
2016-05-01 22:26:26 +00:00
print_menu(SUBJECTS)
2016-05-01 17:44:49 +00:00
choice = raw_input("\npick a category for your feedback: ")
2016-04-30 03:17:06 +00:00
2016-05-01 17:44:49 +00:00
cat = ""
2016-05-03 17:14:53 +00:00
if choice in ['0', '1', '2', '3']:
2016-05-01 22:26:26 +00:00
cat = SUBJECTS[int(choice)]
raw_input("\ncomposing a "+cat+" to ~endorphant.\n\npress <enter> to open an external text editor. mail will be sent once you save and quit.\n")
2016-05-01 18:10:04 +00:00
redraw(send_feedback(cat))
return
2016-05-01 17:44:49 +00:00
else:
2016-05-01 18:10:04 +00:00
redraw(INVALID)
2016-05-01 17:44:49 +00:00
return feedback_menu()
def view_neighbors(users):
userList = []
for user in users:
userRC = json.load(open(os.path.join("/home", user, ".ttbp", "config", "ttbprc")))
url = LIVE+user+"/"+userRC["publish dir"]
2016-05-03 17:14:53 +00:00
count = 0
lastfile = ""
files = os.listdir(os.path.join("/home", user, ".ttbp", "entries"))
files.sort()
for filename in files:
2016-05-03 17:14:53 +00:00
if os.path.splitext(filename)[1] == ".txt" and len(os.path.splitext(filename)[0]) == 8:
count += 1
lastfile = os.path.join("/home", user, ".ttbp", "entries", filename)
ago = "never"
if lastfile:
last = os.path.getctime(lastfile)
since = time.time()-last
ago = util.pretty_time(int(since)) + " ago"
else:
last = 0
pad = ""
2016-05-03 17:46:54 +00:00
if len(user) < 8:
pad = "\t"
2016-05-03 17:14:53 +00:00
user = "~"+user
if len(user) < 8:
user += "\t"
userList.append(["\t"+user+"\t"+url+pad+"\t("+ago+")", last])
# sort user by most recent entry
userList.sort(key = lambda userdata:userdata[1])
userList.reverse()
sortedUsers = []
for user in userList:
sortedUsers.append(user[0])
print_menu(sortedUsers)
raw_input("\n\npress <enter> to go back home.\n\n")
redraw()
return
2016-05-03 17:14:53 +00:00
def view_own():
filenames = []
for entry in os.listdir(DATA):
filenames.append(os.path.join(DATA, entry))
metas = core.meta(filenames)
2016-05-03 17:14:53 +00:00
entries = []
for entry in metas:
entries.append(""+entry[4]+" ("+p.no("word", entry[2])+") ")
2016-05-03 17:14:53 +00:00
return view_entries(metas, entries, "here are your recorded feels, listed by date: \n\n")
def show_credits():
print("ttbp was written by ~endorphant in python. the codebase is\npublicly available on github at https://github.com/modgethanc/ttbp\n\nif you have ideas for ttbp, you are welcome to fork the repo and \nwork on it. i'm only a baby dev, so i apologize for any \nhorrendously ugly coding habits i have.\n\nthanks to everyone who reads, listens, writes, and feels.")
raw_input("\n\npress <enter> to go back home.\n\n")
redraw()
return
## handlers
def write_entry(entry=os.path.join(DATA, "test.txt")):
entered = raw_input("\nfeels will be recorded for today, "+time.strftime("%d %B %Y")+".\n\nif you've already started recording feels for this day, you \ncan pick up where you left off.\n\npress <enter> to begin recording your feels.\n\n")
if entered:
entryFile = open(entry, "a")
entryFile.write("\n"+entered+"\n")
entryFile.close()
subprocess.call([SETTINGS["editor"], entry])
core.load_files()
core.write("index.html")
redraw("posted to "+LIVE+USER+"/"+SETTINGS["publish dir"]+"/index.html\n\nthanks for sharing your feels!")
return
def send_feedback(subject="none", mailbox=os.path.join(FEEDBACK, USER+"-"+time.strftime("%Y%m%d-%H%M")+".msg")):
mail = ""
temp = tempfile.NamedTemporaryFile()
subprocess.call([SETTINGS["editor"], temp.name])
mail = open(temp.name, 'r').read()
outfile = open(mailbox, 'w')
outfile.write("from:\t\t~"+USER+"\n")
outfile.write("subject:\t"+subject+"\n")
outfile.write("date:\t"+time.strftime("%d %B %y")+"\n")
outfile.write(mail)
outfile.close()
return "mail sent. thanks for writing! i'll try to respond to you soon."
def view_entries(metas, entries, prompt):
2016-05-04 15:00:28 +00:00
print_menu(entries)
choice = list_select(entries, "pick an entry from the list, or type 'back' to go home: ")
if choice is not False:
redraw("now reading ~"+metas[choice][5]+"'s feels on "+metas[choice][4]+"\n> press <q> to return to feels list.\n\n")
show_entry(metas[choice][0])
redraw(prompt)
return view_entries(metas, entries, prompt)
else:
redraw()
return
def show_entry(filename):
subprocess.call(["less", filename])
return
def view_feed():
feedList = []
for townie in find_ttbps():
entryDir = os.path.join("/home", townie, ".ttbp", "entries")
filenames = os.listdir(entryDir)
for entry in filenames:
2016-05-05 00:22:14 +00:00
### REALLY MAKE A REAL FILENAME VALIDATOR
fileSplit = os.path.splitext(entry)
if len(fileSplit[0]) == 8 and fileSplit[1] == ".txt":
feedList.append(os.path.join(entryDir, entry))
metas = core.meta(feedList)
metas.sort(key = lambda entry:entry[3])
metas.reverse()
2016-05-05 00:22:14 +00:00
entries = []
for entry in metas[0:10]:
pad = ""
if len(entry[5]) < 8:
pad = "\t"
2016-05-05 00:07:42 +00:00
entries.append("~"+entry[5]+pad+"\ton "+entry[3]+" ("+p.no("word", entry[2])+") ")
#print_menu(entries)
view_entries(metas, entries, "most recent ten entries: \n\n")
2016-05-04 15:00:28 +00:00
2016-05-03 17:14:53 +00:00
redraw()
2016-05-03 17:14:53 +00:00
return
2016-04-30 03:48:01 +00:00
#####
def find_ttbps():
# looks for users with a valid ttbp config and returns a list of them
users = []
for townie in os.listdir("/home"):
if os.path.exists(os.path.join("/home", townie, ".ttbp", "config", "ttbprc")):
users.append(townie)
return users
def list_select(options, prompt):
# runs the prompt for the list until a valid index is imputted
ans = ""
invalid = True
while invalid:
#try:
# choice = raw_input("\n\n"+prompt)
#except KeyboardInterrupt:
# redraw()
# main_menu()
choice = raw_input("\n\n"+prompt)
if choice in BACKS:
return False
try:
ans = int(choice)
except ValueError:
return list_select(options, prompt)
invalid = False
if ans >= len(options):
return list_select(options, prompt)
return ans
#####
2016-04-30 03:48:01 +00:00
start()