2019-11-15 19:45:01 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
## If this script contains bugs, blame cmccabe.
|
|
|
|
|
|
|
|
import glob
|
|
|
|
import getpass
|
|
|
|
import os
|
|
|
|
import time
|
|
|
|
import sys
|
2019-11-18 12:22:31 +00:00
|
|
|
import subprocess
|
2019-11-15 19:45:01 +00:00
|
|
|
|
|
|
|
## TO DO:
|
|
|
|
## PARSE/USE IGNORE FILE
|
|
|
|
## VALIDATE INPUT FROM linkulator.data FILE
|
2019-11-17 12:36:50 +00:00
|
|
|
## "POST" COMMAND LINE ARG SHOULD TAKE AN OPTIONAL LINK ARGUMENT
|
|
|
|
## CAPTURE CTRL-C AND GRACEFULLY EXIT
|
2019-11-18 12:22:31 +00:00
|
|
|
## NEED TO VALIDATE THAT LYNX IS INSTALLED, AND DON'T OFFER OPEN-IN-BROWSER IF NOT
|
2019-11-15 19:45:01 +00:00
|
|
|
|
2019-11-17 15:56:33 +00:00
|
|
|
## FUTURE, TO DO:
|
|
|
|
## LINK/REPLIES TREE SHOULD BE A SINGLE DATA STRUCTURE
|
|
|
|
|
2019-11-15 19:45:01 +00:00
|
|
|
username = getpass.getuser()
|
|
|
|
|
|
|
|
help_text = "options: -h or --help for help, -p or --post to post a link, and no argument to browse links."
|
|
|
|
|
2019-11-16 12:21:31 +00:00
|
|
|
link_data = []
|
2019-11-17 12:36:50 +00:00
|
|
|
## username, datestamp, parent-id, category, link-url, link-title
|
2019-11-16 12:21:31 +00:00
|
|
|
categories = []
|
|
|
|
|
2019-11-17 12:36:50 +00:00
|
|
|
def build_menu():
|
2019-11-16 12:21:31 +00:00
|
|
|
## WHENEVER THIS FUNCTION IS CALLED, THE DATA IS REFRESHED FROM FILES. SINCE
|
|
|
|
## DISK IO IS PROBABLY THE HEAVIEST PART OF THIS SCRIPT, DON'T DO THIS OFTEN.
|
2019-11-15 19:45:01 +00:00
|
|
|
|
|
|
|
linkulator_files = glob.glob('/home/*/.linkulator/linkulator.data')
|
|
|
|
ignore_file = glob.glob('/home/' + username + '/.linkulator/ignore')
|
|
|
|
|
|
|
|
if len(linkulator_files) == 0:
|
2019-11-17 12:36:50 +00:00
|
|
|
print("It looks link there are no links yet. Run 'linkulator -p' to add one.")
|
2019-11-18 03:04:57 +00:00
|
|
|
exit()
|
2019-11-15 19:45:01 +00:00
|
|
|
|
|
|
|
else:
|
|
|
|
|
2019-11-16 12:21:31 +00:00
|
|
|
global link_data
|
2019-11-15 19:45:01 +00:00
|
|
|
linkulator_lines = []
|
2019-11-16 12:21:31 +00:00
|
|
|
for filename in linkulator_files:
|
|
|
|
with open(filename) as f:
|
|
|
|
file_owner = filename.split('/')[2]
|
2019-11-15 19:45:01 +00:00
|
|
|
for line in f:
|
2019-11-16 12:21:31 +00:00
|
|
|
line = line.rstrip('\n')
|
|
|
|
split_line = line.split('|')
|
|
|
|
split_line.insert(0,file_owner)
|
|
|
|
linkulator_lines.append(split_line) ## creating a list of lists
|
2019-11-18 03:04:57 +00:00
|
|
|
|
2019-11-17 01:49:06 +00:00
|
|
|
i=1
|
|
|
|
for idx, line in enumerate(linkulator_lines):
|
|
|
|
if line[2] == "": # CREATE/INSERT PARENT ID:
|
|
|
|
linkulator_lines[idx].insert(0, i)
|
|
|
|
i=i+1
|
|
|
|
else: ## NOT PARENT, SO NO PARENT ID
|
|
|
|
linkulator_lines[idx].insert(0,"")
|
2019-11-16 12:21:31 +00:00
|
|
|
link_data = linkulator_lines
|
|
|
|
|
|
|
|
global categories
|
|
|
|
for line in link_data:
|
2019-11-17 12:36:50 +00:00
|
|
|
if line[4] not in categories and line[4] != "":
|
2019-11-17 01:49:06 +00:00
|
|
|
categories.append(line[4])
|
2019-11-17 12:36:50 +00:00
|
|
|
|
2019-11-18 03:04:57 +00:00
|
|
|
|
2019-11-17 12:36:50 +00:00
|
|
|
def print_categories():
|
2019-11-16 12:21:31 +00:00
|
|
|
print("Current link post categories include: ")
|
|
|
|
print(categories)
|
|
|
|
view_category_contents()
|
|
|
|
|
2019-11-17 01:49:06 +00:00
|
|
|
|
2019-11-16 12:21:31 +00:00
|
|
|
def view_category_contents():
|
|
|
|
view_cat = ""
|
|
|
|
while view_cat not in categories:
|
2019-11-18 12:22:31 +00:00
|
|
|
view_cat = input("Type a category to view its posts or hit [Enter] to quit: ")
|
2019-11-17 20:13:01 +00:00
|
|
|
if view_cat == "":
|
2019-11-18 03:04:57 +00:00
|
|
|
graceful_exit()
|
2019-11-16 12:21:31 +00:00
|
|
|
if view_cat not in categories:
|
2019-11-18 03:04:57 +00:00
|
|
|
print("Sorry, that category does not exist. Try again, or hit [Enter] to quit.")
|
|
|
|
|
2019-11-16 12:21:31 +00:00
|
|
|
for line in link_data:
|
2019-11-17 01:49:06 +00:00
|
|
|
if line[4] == view_cat:
|
2019-11-15 19:45:01 +00:00
|
|
|
print(line)
|
2019-11-18 03:04:57 +00:00
|
|
|
|
2019-11-18 12:22:31 +00:00
|
|
|
pid = input("Enter a post ID to see its thread, \"m\" to return to the main menu, or hit [Enter] to quit: ")
|
2019-11-18 03:04:57 +00:00
|
|
|
if pid == "": ## HARMLESS BUT UNINTENDED
|
|
|
|
graceful_exit() ## ABILITY HERE IS THAT USERS
|
2019-11-18 12:22:31 +00:00
|
|
|
elif pid =="m" or pid == "M": ## CAN PUT ANY PID IN, NOT JUST
|
|
|
|
print_categories() ## FROM WITHIN THIS CATEGORY.
|
|
|
|
return()
|
|
|
|
else:
|
|
|
|
view_thread(pid)
|
2019-11-17 01:49:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
def view_thread(post_id):
|
2019-11-17 12:36:50 +00:00
|
|
|
|
|
|
|
parent_id = ""
|
2019-11-18 12:22:31 +00:00
|
|
|
url = ""
|
2019-11-17 12:36:50 +00:00
|
|
|
for line in link_data:
|
|
|
|
if str(line[0]) == post_id:
|
|
|
|
parent_id = line[1] + "+" + str(line[2])
|
|
|
|
parent_user = line[1]
|
|
|
|
parent_timestamp = line[2]
|
2019-11-18 12:22:31 +00:00
|
|
|
url = line[5]
|
2019-11-18 03:04:57 +00:00
|
|
|
|
2019-11-17 12:36:50 +00:00
|
|
|
if parent_id == "":
|
2019-11-18 03:04:57 +00:00
|
|
|
print("Sorry, thread found with that ID.")
|
|
|
|
return() ## THIS IS NOT A GOOD END POINT. SHOULD ASK USER TO RE-ENTER THEIR CHOICE.
|
2019-11-17 12:36:50 +00:00
|
|
|
|
|
|
|
for line in link_data:
|
|
|
|
if line[1] == parent_user and line[2] == parent_timestamp:
|
|
|
|
print("Parent post:")
|
|
|
|
print(line)
|
|
|
|
|
|
|
|
print("Replies:")
|
|
|
|
i = 0
|
|
|
|
for line in link_data:
|
|
|
|
if line[3] == parent_id:
|
|
|
|
print(line)
|
|
|
|
i = i+1
|
|
|
|
if i == 0:
|
|
|
|
print("(No replies yet. Be the first!)")
|
|
|
|
|
2019-11-18 12:22:31 +00:00
|
|
|
next_step = input("Type 'R' to reply, 'B' to view in Lynx, 'M' for main menu, or anything else to quit: ")
|
2019-11-17 12:36:50 +00:00
|
|
|
if next_step == "M" or next_step == "m":
|
|
|
|
print_categories()
|
2019-11-18 12:22:31 +00:00
|
|
|
elif next_step =="B" or next_step == "b":
|
|
|
|
view_link_in_browser(url, post_id)
|
2019-11-17 12:36:50 +00:00
|
|
|
elif next_step == "R" or next_step == "r":
|
|
|
|
reply(parent_user, parent_timestamp, post_id)
|
|
|
|
else:
|
2019-11-18 03:04:57 +00:00
|
|
|
graceful_exit()
|
2019-11-15 19:45:01 +00:00
|
|
|
|
|
|
|
|
2019-11-18 12:22:31 +00:00
|
|
|
def view_link_in_browser(url, post_id):
|
|
|
|
print("URL = " + url)
|
|
|
|
if url.startswith("gopher://") or url.startswith("https://") or url.startswith("http://"):
|
|
|
|
subprocess.call(['lynx', url])
|
|
|
|
else:
|
|
|
|
print("Sorry, that url doesn't start with gopher://, http:// or https://")
|
|
|
|
view_thread(post_id)
|
|
|
|
|
|
|
|
|
2019-11-15 19:45:01 +00:00
|
|
|
def post_link():
|
|
|
|
link_url = input("URL: ")
|
|
|
|
link_category = input("Category: ")
|
|
|
|
link_title = input("Title: ")
|
|
|
|
timestamp = str(time.time())
|
|
|
|
filename = '/home/' + username + '/.linkulator/linkulator.data'
|
|
|
|
if os.path.exists(filename):
|
|
|
|
append_write = 'a' # append if already exists
|
|
|
|
else:
|
|
|
|
append_write = 'w' # make a new file if not
|
|
|
|
with open(filename, append_write) as file:
|
2019-11-17 01:49:06 +00:00
|
|
|
file.write(timestamp + '||' + link_category + '|' + link_url + '|' + link_title + "\r")
|
2019-11-18 03:04:57 +00:00
|
|
|
print("Link added!")
|
|
|
|
graceful_exit()
|
2019-11-15 19:45:01 +00:00
|
|
|
|
|
|
|
|
2019-11-17 12:36:50 +00:00
|
|
|
def reply(owner, tstamp, post_id):
|
|
|
|
global username
|
|
|
|
|
|
|
|
comment = input("Enter your comment: ")
|
|
|
|
|
|
|
|
filename = '/home/' + username + '/.linkulator/linkulator.data'
|
|
|
|
if os.path.exists(filename):
|
|
|
|
append_write = 'a' # append if already exists
|
|
|
|
else:
|
|
|
|
append_write = 'w' # make a new file if not
|
|
|
|
with open(filename, append_write) as file:
|
|
|
|
file.write('|' + owner + "+" + tstamp + '|||' + comment + "\r")
|
|
|
|
|
|
|
|
x = input('Reply added. Hit [Enter] to return to thread.')
|
|
|
|
build_menu()
|
|
|
|
view_thread(post_id)
|
|
|
|
|
2019-11-16 12:21:31 +00:00
|
|
|
|
2019-11-18 03:04:57 +00:00
|
|
|
def graceful_exit():
|
|
|
|
print("Thank you for linkulating. Goodbye.")
|
|
|
|
exit()
|
|
|
|
|
2019-11-16 12:21:31 +00:00
|
|
|
|
2019-11-15 19:45:01 +00:00
|
|
|
def parse_command():
|
|
|
|
args = sys.argv[1:]
|
|
|
|
if not len(args):
|
2019-11-17 12:36:50 +00:00
|
|
|
print("----------")
|
2019-11-17 01:49:06 +00:00
|
|
|
print("LINKULATOR")
|
2019-11-17 12:36:50 +00:00
|
|
|
print("----------")
|
|
|
|
build_menu()
|
|
|
|
print_categories()
|
2019-11-15 19:45:01 +00:00
|
|
|
elif args[0] in ["-h", "--help", "help"]:
|
|
|
|
print(help_text)
|
|
|
|
elif args[0] in ["-p", "--post", "-p"]:
|
|
|
|
post_link()
|
|
|
|
else:
|
|
|
|
print("Unknown command: {}".format(args[0]))
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
parse_command()
|