urwid client kinda does stuff now lmao
parent
19af814a93
commit
ef5d1a2869
|
@ -190,6 +190,14 @@ class BBJ:
|
||||||
return response["data"]
|
return response["data"]
|
||||||
|
|
||||||
|
|
||||||
|
def user_is_registered(self, target_user):
|
||||||
|
"""
|
||||||
|
Returns a boolean true or false whether target_user
|
||||||
|
is a registered BBJ user.
|
||||||
|
"""
|
||||||
|
return self("user_is_registered", target_user=target_user)["data"]
|
||||||
|
|
||||||
|
|
||||||
def user_register(self, user_name, user_auth, hash_auth=True, set_as_user=True):
|
def user_register(self, user_name, user_auth, hash_auth=True, set_as_user=True):
|
||||||
"""
|
"""
|
||||||
Register user_name into the system with user_auth. Unless hash_auth
|
Register user_name into the system with user_auth. Unless hash_auth
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from time import sleep, localtime
|
from time import time, sleep, localtime
|
||||||
|
from random import choice, randrange
|
||||||
from string import punctuation
|
from string import punctuation
|
||||||
from subprocess import run
|
from subprocess import run
|
||||||
from random import choice
|
|
||||||
from network import BBJ
|
from network import BBJ
|
||||||
import urwid
|
import urwid
|
||||||
|
|
||||||
|
@ -36,20 +36,35 @@ colors = [
|
||||||
|
|
||||||
class App:
|
class App:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.mode = None
|
||||||
colors = [
|
colors = [
|
||||||
("bar", "light magenta", "default", "underline"),
|
("bar", "light magenta", "default"),
|
||||||
("button", "light red", "default")
|
("button", "light red", "default"),
|
||||||
|
("dim", "dark gray", "default"),
|
||||||
|
|
||||||
|
# map the bbj api color values for display
|
||||||
|
("0", "default", "default"),
|
||||||
|
("1", "light red", "default"),
|
||||||
|
("2", "yellow", "default"),
|
||||||
|
("3", "light green", "default"),
|
||||||
|
("4", "light blue", "default"),
|
||||||
|
("5", "light cyan", "default"),
|
||||||
|
("6", "light magenta", "default")
|
||||||
]
|
]
|
||||||
self.loop = urwid.MainLoop(urwid.Frame(
|
self.loop = urwid.MainLoop(urwid.Frame(
|
||||||
urwid.LineBox(ActionBox(urwid.SimpleFocusListWalker([]))),
|
urwid.LineBox(ActionBox(urwid.SimpleFocusListWalker([])),
|
||||||
), colors)
|
title="> > T I L D E T O W N < <",
|
||||||
|
tlcorner="@", tline="=", lline="|", rline="|",
|
||||||
|
bline="_", trcorner="@", brcorner="@", blcorner="@"
|
||||||
|
|
||||||
|
)), colors)
|
||||||
self.date_format = "{1}/{2}/{0}"
|
self.date_format = "{1}/{2}/{0}"
|
||||||
self.index()
|
self.index()
|
||||||
|
|
||||||
|
|
||||||
def set_header(self, text, *format_specs):
|
def set_header(self, text, *format_specs):
|
||||||
self.loop.widget.header = urwid.AttrMap(urwid.Text(
|
self.loop.widget.header = urwid.AttrMap(urwid.Text(
|
||||||
("%s@bbj | " % network.user_name)
|
("%s@bbj | " % (network.user_name or "anonymous"))
|
||||||
+ text.format(*format_specs)
|
+ text.format(*format_specs)
|
||||||
), "bar")
|
), "bar")
|
||||||
|
|
||||||
|
@ -61,30 +76,30 @@ class App:
|
||||||
self.loop.widget.footer = urwid.AttrMap(urwid.Text(text), "bar")
|
self.loop.widget.footer = urwid.AttrMap(urwid.Text(text), "bar")
|
||||||
|
|
||||||
|
|
||||||
def readable_delta(self, created, modified):
|
def readable_delta(self, modified):
|
||||||
delta = modified - created
|
delta = time() - modified
|
||||||
minutes = delta // 60
|
hours, remainder = divmod(delta, 3600)
|
||||||
if not minutes:
|
if hours > 48:
|
||||||
return "less than a minute ago"
|
return self.date_format.format(*localtime(modified))
|
||||||
elif minutes < 60:
|
elif hours > 1:
|
||||||
return "%d minutes ago" % minutes
|
|
||||||
hours = delta // 60
|
|
||||||
if hours == 1:
|
|
||||||
return "about an hour ago"
|
|
||||||
elif hours < 48:
|
|
||||||
return "%d hours ago" % hours
|
return "%d hours ago" % hours
|
||||||
return self.date_format.format(*localtime(modified))
|
elif hours == 1:
|
||||||
|
return "about an hour ago"
|
||||||
|
minutes, remainder = divmod(remainder, 60)
|
||||||
|
if minutes > 1:
|
||||||
|
return "%d minutes ago"
|
||||||
|
return "less than a minute ago"
|
||||||
|
|
||||||
|
|
||||||
def index(self):
|
def index(self):
|
||||||
|
self.mode = "index"
|
||||||
threads, usermap = network.thread_index()
|
threads, usermap = network.thread_index()
|
||||||
self.set_header("{} threads", len(threads))
|
self.set_header("{} threads", len(threads))
|
||||||
self.set_footer("Compose")
|
self.set_footer("Refresh", "Compose", "/Search", "?Help")
|
||||||
walker = self.loop.widget.body.base_widget.body
|
walker = self.loop.widget.body.base_widget.body
|
||||||
|
walker.clear()
|
||||||
for thread in threads:
|
for thread in threads:
|
||||||
button = urwid.Button("", self.thread_load, thread["thread_id"])
|
button = cute_button(">>", self.thread_load, thread["thread_id"])
|
||||||
super(urwid.Button, button).__init__(
|
|
||||||
urwid.SelectableIcon(">>"))
|
|
||||||
title = urwid.Text(thread["title"])
|
title = urwid.Text(thread["title"])
|
||||||
|
|
||||||
last_mod = thread["last_mod"]
|
last_mod = thread["last_mod"]
|
||||||
|
@ -92,31 +107,81 @@ class App:
|
||||||
infoline = "by ~{} @ {} | last active {}".format(
|
infoline = "by ~{} @ {} | last active {}".format(
|
||||||
usermap[thread["author"]]["user_name"],
|
usermap[thread["author"]]["user_name"],
|
||||||
self.date_format.format(*localtime(created)),
|
self.date_format.format(*localtime(created)),
|
||||||
self.readable_delta(created, last_mod)
|
self.readable_delta(last_mod)
|
||||||
)
|
)
|
||||||
|
|
||||||
walker.append(urwid.Columns([(3, urwid.AttrMap(button, "button")), title]))
|
[walker.append(element)
|
||||||
walker.append(urwid.Text(infoline))
|
for element in [
|
||||||
walker.append(urwid.Divider("-"))
|
urwid.Columns([(3, urwid.AttrMap(button, "button")), title]),
|
||||||
|
urwid.AttrMap(urwid.Text(infoline), "dim"),
|
||||||
|
urwid.AttrMap(urwid.Divider("-"), "dim")
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
def thread_load(self, button, thread_id):
|
def thread_load(self, button, thread_id):
|
||||||
|
self.mode = "thread"
|
||||||
thread, usermap = network.thread_load(thread_id)
|
thread, usermap = network.thread_load(thread_id)
|
||||||
walker = self.loop.widget.body.base_widget.body
|
walker = self.loop.widget.body.base_widget.body
|
||||||
walker.clear()
|
walker.clear()
|
||||||
self.set_header("~{}: {}",
|
self.set_header("~{}: {}",
|
||||||
usermap[thread["author"]]["user_name"], thread["title"])
|
usermap[thread["author"]]["user_name"], thread["title"])
|
||||||
for message in thread["messages"]:
|
for message in thread["messages"]:
|
||||||
pass
|
name = urwid.Text("~{}".format(usermap[message["author"]]["user_name"]))
|
||||||
|
info = "@ " + self.date_format.format(*localtime(message["created"]))
|
||||||
|
if message["edited"]:
|
||||||
|
info += " [edited]"
|
||||||
|
head = urwid.Columns([
|
||||||
|
(3, urwid.AttrMap(cute_button(">>"), "button")),
|
||||||
|
(len(name._text) + 1, urwid.AttrMap(name, str(usermap[message["author"]]["color"]))),
|
||||||
|
urwid.AttrMap(urwid.Text(info), "dim")
|
||||||
|
])
|
||||||
|
|
||||||
|
[walker.append(element)
|
||||||
|
for element in [
|
||||||
|
head, urwid.Divider(), urwid.Text(message["body"]),
|
||||||
|
urwid.Divider(), urwid.AttrMap(urwid.Divider("-"), "dim")
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ActionBox(urwid.ListBox):
|
class ActionBox(urwid.ListBox):
|
||||||
pass
|
def keypress(self, size, key):
|
||||||
|
super(ActionBox, self).keypress(size, key)
|
||||||
|
if key.lower() in ["j", "n"]:
|
||||||
|
self._keypress_down(size)
|
||||||
|
elif key.lower() in ["k", "p"]:
|
||||||
|
self._keypress_up(size)
|
||||||
|
elif key.lower() == "q":
|
||||||
|
if app.mode == "index":
|
||||||
|
app.loop.stop()
|
||||||
|
# run("clear", shell=True)
|
||||||
|
width, height = urwid.raw_display.Screen().get_cols_rows()
|
||||||
|
for x in range(height - 1):
|
||||||
|
line = str()
|
||||||
|
for x in range(width):
|
||||||
|
line += choice([" ", choice(punctuation)])
|
||||||
|
motherfucking_rainbows(line)
|
||||||
|
sleep(0.008)
|
||||||
|
exit()
|
||||||
|
else: app.index()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def cute_button(label, callback=None, data=None):
|
||||||
|
"""
|
||||||
|
Urwid's default buttons are shit, and they have ugly borders.
|
||||||
|
This function returns buttons that are a bit easier to love.
|
||||||
|
"""
|
||||||
|
button = urwid.Button("", callback, data)
|
||||||
|
super(urwid.Button, button).__init__(
|
||||||
|
urwid.SelectableIcon(label))
|
||||||
|
return button
|
||||||
|
|
||||||
|
|
||||||
def motherfucking_rainbows(string, inputmode=False, end="\n"):
|
def motherfucking_rainbows(string, inputmode=False, end="\n"):
|
||||||
"""
|
"""
|
||||||
I cANtT FeELLE MyYE FACECsEE ANYrrMOROeeee!!
|
I cANtT FeELLE MyYE FACECsEE ANYrrMOROeeee
|
||||||
"""
|
"""
|
||||||
for character in string:
|
for character in string:
|
||||||
print(choice(colors) + character, end="")
|
print(choice(colors) + character, end="")
|
||||||
|
@ -195,7 +260,7 @@ def log_in():
|
||||||
try:
|
try:
|
||||||
network.set_credentials(name, "")
|
network.set_credentials(name, "")
|
||||||
# make it easy for people who use an empty password =)
|
# make it easy for people who use an empty password =)
|
||||||
motherfucking_rainbows("~~logged in as {}~~".format(network.user_name))
|
motherfucking_rainbows("~~welcome back {}~~".format(network.user_name))
|
||||||
|
|
||||||
except ConnectionRefusedError:
|
except ConnectionRefusedError:
|
||||||
def login_loop(prompt, positive):
|
def login_loop(prompt, positive):
|
||||||
|
@ -206,7 +271,7 @@ def log_in():
|
||||||
login_loop("// R E J E C T E D //.", False)
|
login_loop("// R E J E C T E D //.", False)
|
||||||
|
|
||||||
login_loop("Enter your password", True)
|
login_loop("Enter your password", True)
|
||||||
motherfucking_rainbows("~~logged in as {}~~".format(network.user_name))
|
motherfucking_rainbows("~~welcome back {}~~".format(network.user_name))
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
motherfucking_rainbows("Nice to meet'cha, %s!" % name)
|
motherfucking_rainbows("Nice to meet'cha, %s!" % name)
|
||||||
|
@ -216,7 +281,12 @@ def log_in():
|
||||||
)
|
)
|
||||||
|
|
||||||
if response == "c":
|
if response == "c":
|
||||||
name = sane_value("user_name", "Pick a new name")
|
def nameloop(prompt, positive):
|
||||||
|
name = sane_value("user_name", prompt, positive)
|
||||||
|
if network.user_is_registered(name):
|
||||||
|
return nameloop("%s is already registered" % name, False)
|
||||||
|
return name
|
||||||
|
name = nameloop("Pick a new name", True)
|
||||||
|
|
||||||
def password_loop(prompt, positive=True):
|
def password_loop(prompt, positive=True):
|
||||||
response1 = paren_prompt(prompt, positive)
|
response1 = paren_prompt(prompt, positive)
|
||||||
|
@ -239,7 +309,7 @@ def main():
|
||||||
motherfucking_rainbows(obnoxious_logo)
|
motherfucking_rainbows(obnoxious_logo)
|
||||||
print(welcome)
|
print(welcome)
|
||||||
log_in()
|
log_in()
|
||||||
# sleep(1) # let that confirmation message shine
|
sleep(0.6) # let that confirmation message shine
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
global app
|
global app
|
||||||
|
|
|
@ -7,8 +7,9 @@ from markdown import markdown
|
||||||
from html import escape
|
from html import escape
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
#0, 1 2 3 4 5 6
|
||||||
colors = [
|
colors = [
|
||||||
"red", "green", "yellow", "blue", "magenta", "cyan"
|
"red", "yellow", "green", "blue", "cyan", "magenta"
|
||||||
]
|
]
|
||||||
|
|
||||||
markup = [
|
markup = [
|
||||||
|
|
Loading…
Reference in New Issue