601 lines
23 KiB
Python
Executable File
601 lines
23 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
# gempost - experimental gemlog manager for tilde.team, written by ~desertmouse
|
|
|
|
from os import system as exec
|
|
from os import listdir, getlogin
|
|
from datetime import date
|
|
|
|
from sys import argv
|
|
|
|
from hashlib import sha1
|
|
from random import random
|
|
|
|
import curses
|
|
from math import ceil
|
|
|
|
# colored output functions
|
|
def prRed(skk): print("\033[91m {}\033[00m" .format(skk))
|
|
def prGreen(skk): print("\033[92m {}\033[00m" .format(skk))
|
|
def prYellow(skk): print("\033[93m {}\033[00m" .format(skk))
|
|
def prPurple(skk): print("\033[95m {}\033[00m" .format(skk))
|
|
|
|
# main variable declarations
|
|
default_post_page_header = """
|
|
# posts
|
|
"""
|
|
|
|
wdir = f"/home/{getlogin()}/public_gemini/" # working/main directory
|
|
postDir = wdir + "postdir/" # all post files along with the archive.gmi are stored here
|
|
indexFile = wdir + "postIndex" # the index is maintained in this file
|
|
editor = "nano --restricted -t"
|
|
|
|
def menuFunction(menu = [], headerLine = "Use the arrow keys or j,k to make a selection. Press 'c' to cancel.\n"):
|
|
"""An ncurses menu that integrates with both <manage> and <search> arguments."""
|
|
stdscr = curses.initscr() # initializing ncurses
|
|
curses.noecho()
|
|
curses.cbreak()
|
|
stdscr.keypad(True)
|
|
|
|
sy, sx = stdscr.getmaxyx() # getting terminal dimensions
|
|
pageLength = sy - 5 # no. of items I can show in a single page.
|
|
pages = ceil(len(menu)/pageLength) + 1 # calculating the no. of pages required
|
|
|
|
pageIndex = 1 # current page
|
|
imenu = [] # internal list that is modified to only contain items of a specific page
|
|
|
|
imenu = menu[((pageLength)*(pageIndex-1)):(pageLength*pageIndex)]
|
|
|
|
endOfPage = len(imenu) # separate variable is required for this because the last page might have lesser entries than {pageLength}
|
|
|
|
if (menu == []): # do nothing if list is empty
|
|
curses.endwin()
|
|
return None
|
|
|
|
highlight, highlight_prev = 0, 0 # variable that controls which entry is selected, variable that stores its previous value
|
|
while True:
|
|
sy, sx = stdscr.getmaxyx() # getting terminal dimensions again to adapt to window resize events while the menu is being displayed
|
|
stdscr.clear()
|
|
|
|
if (highlight >= endOfPage): # incrementing page number
|
|
if (pageIndex == pages - 1) or (pageIndex == 1):
|
|
highlight = highlight_prev
|
|
pass
|
|
else:
|
|
pageIndex += 1 # incrementing page index
|
|
imenu = [] # resetting imenu
|
|
try:
|
|
imenu = menu[((pageLength)*(pageIndex-1)):(pageLength*pageIndex)] # only {pageLength} no. of items
|
|
except IndexError:
|
|
try:
|
|
imenu = menu[((pageLength)*(pageIndex-1)):]
|
|
except IndexError:
|
|
pass
|
|
endOfPage = len(imenu)
|
|
highlight = 0
|
|
|
|
if (highlight < 0): # decrementing page number
|
|
if (pageIndex == 1):
|
|
highlight = highlight_prev
|
|
pass
|
|
else:
|
|
pageIndex -= 1
|
|
imenu = []
|
|
try:
|
|
imenu = menu[((pageLength)*(pageIndex-1)):(pageLength*pageIndex)]
|
|
except IndexError:
|
|
pass
|
|
endOfPage = len(imenu)
|
|
highlight = endOfPage - 1
|
|
|
|
stdscr.addstr(headerLine)
|
|
|
|
for sno in range(len(imenu)):
|
|
if (sno == highlight):
|
|
entry = str(((pageLength)*(pageIndex-1)) + (sno+1)) + " - " + imenu[sno] # the menu entry
|
|
|
|
"""
|
|
TODO:
|
|
- exit displaying an error if terminal too small
|
|
"""
|
|
|
|
stdscr.addstr(f"\n{entry}{' '*(sx - len(entry) - 1)}", curses.A_STANDOUT)
|
|
else:
|
|
stdscr.addstr(f"\n{((pageLength)*(pageIndex-1)) + (sno+1)} - {imenu[sno]}")
|
|
sno += 1
|
|
|
|
stdscr.addstr(f"\n\npage {pageIndex} / {pages - 1}\n") # a line on the bottom showing page number
|
|
stdscr.refresh()
|
|
|
|
c = stdscr.getch()
|
|
|
|
if (c == curses.KEY_DOWN or c == ord('j')):
|
|
highlight_prev = highlight
|
|
highlight += 1
|
|
|
|
elif (c == curses.KEY_UP or c == ord('k')):
|
|
highlight_prev = highlight
|
|
highlight -= 1
|
|
|
|
elif (c == curses.KEY_ENTER or c == 10 or c == 13):
|
|
break
|
|
|
|
elif (c == ord('c') or c == ord('q')):
|
|
highlight = None
|
|
break
|
|
|
|
curses.endwin()
|
|
if (highlight != None):
|
|
return (pageLength * (pageIndex-1)) + highlight
|
|
else:
|
|
return highlight
|
|
|
|
def checkInit():
|
|
""" Checks if the public_gemini/ directory has been initialized for use with gempost or is missing some files. """
|
|
contents = listdir(wdir)
|
|
valid_contents = ["postIndex","trash","postdir"]
|
|
validity = 0
|
|
missing = []
|
|
for i in contents:
|
|
if i in valid_contents:
|
|
validity += 1
|
|
|
|
if (validity != len(valid_contents)):
|
|
if (validity == 0):
|
|
prRed(f'\n Your "public_gemini/" directory has not been initialized yet. Use "gempost qs" to read the quickstart.')
|
|
else:
|
|
prRed(f'\n Your "public_gemini/" directory is missing some required files and directories / has not been properly initialized.\n\n The following files/directories are required: {valid_contents}\n Validity score: {validity}/{len(valid_contents)}')
|
|
exit()
|
|
|
|
def rebuildReferences(filename = None, title = None, callingFrom = "default"):
|
|
""" reads {wdir}postIndex and rebuilds the {wdir}posts.gmi and {postDir}archive.gmi files """
|
|
customized = False
|
|
allposts = [] # storing all indexFile entries inside a list
|
|
|
|
with open(f"{indexFile}",'r') as i:
|
|
allposts = i.readlines()
|
|
if (len(allposts) == 0): # if postIndex is empty, there is nothing to to
|
|
# reset posts.gmi and delete archive.gmi
|
|
# ie, customize the function
|
|
customized = True
|
|
|
|
headerText = []
|
|
try:
|
|
with open(f"{wdir}postPageHeader.gmi",'r') as h: # the file postPageHeader.gmi should be defined by the user in {wdir}. It should contain the user's custom post page header
|
|
headerText = h.readlines()
|
|
except FileNotFoundError: # If user hasn't created that file, a default line "# posts" is added to posts.gmi
|
|
headerText.append(default_post_page_header)
|
|
|
|
if (customized == True): # if postIndex was empty, then do not do more than this. Just remove archive.gmi after this
|
|
exec(f"rm {postDir}archive.gmi") # delete archive.gmi
|
|
with open(f"{wdir}posts.gmi",'w') as po: # writing the header into posts.gmi
|
|
po.writelines(headerText)
|
|
return 0
|
|
|
|
headerText.append("\n## Latest\n")
|
|
if (callingFrom == "delete"): # the function's callingFrom switch is to perform special operations based on where it is invoked from
|
|
headerText.append(f"{allposts[-1]}")
|
|
else:
|
|
headerText.append(f"=> postdir/{filename}.gmi {title}\n")
|
|
|
|
headerText.append("\n## Recent\n") # adding the five most recent posts to posts.gmi
|
|
try:
|
|
counter = 0
|
|
for i in allposts[::-1]:
|
|
if (counter == 5):
|
|
break
|
|
headerText.append(i)
|
|
counter += 1
|
|
except IndexError:
|
|
pass
|
|
|
|
allposts = [] # storing all indexFile entries inside a list
|
|
with open(f"{indexFile}",'r') as i:
|
|
allposts = i.readlines()
|
|
|
|
headerText.append("\n## Older\n") # for older entries, refer to another file, archive.gmi, which is basically a reversed copy of {indexFile} to show the most recent posts on top
|
|
|
|
archiveLines = [] # archive.gmi needs just ./filenames instead of postdir/filenames
|
|
for i in allposts[::-1]: # storing a modified file list with just the filenames as links
|
|
archiveLines.append(f"=> ./{i[11:]}")
|
|
with open(f"{postDir}archive.gmi","w") as ar: # creating all posts list
|
|
ar.writelines(archiveLines)
|
|
|
|
headerText.append(f"=> postdir/archive.gmi Older Posts")
|
|
|
|
with open(f"{wdir}posts.gmi",'w') as po: # finally writing into posts.gmi to "bring it all together"
|
|
po.writelines(headerText)
|
|
|
|
|
|
def newpost(title, existing_content = None, filename = None):
|
|
modified = False
|
|
""" Write and submit a new post """
|
|
if (existing_content == None or existing_content == []):
|
|
pass
|
|
else:
|
|
modified = True # modify the function if doing this for existing file
|
|
|
|
if (filename == None):
|
|
filename = sha1(str(f"{title}{random()}").encode("utf-8")).hexdigest() # generating a unique filename
|
|
|
|
if (title[-1] == '\n'): # remove the \n at end of title if its there
|
|
title = title[:-1]
|
|
if (filename[-1] == '\n'): # remove the \n at end of filename if its there
|
|
filename = filename[:-1]
|
|
|
|
exec(f"touch {wdir + filename}.gmi") # creating empty file
|
|
|
|
che = input("\nAdd an ASCII Art header to your post? (define it in blogpostHeader.gmi): (y/[n]) ")
|
|
if (che == 'y' or che == 'Y'):
|
|
try:
|
|
with open(f"{wdir}blogpostHeader.gmi") as a: # checking if header for each post has been defined
|
|
postHeader = a.readlines()
|
|
with open(f"{wdir + filename}.gmi",'w') as f:
|
|
f.writelines(postHeader)
|
|
except FileNotFoundError:
|
|
postHeader = [""]
|
|
else:
|
|
postHeader = [""]
|
|
|
|
if modified: # add content to file using the existing_content list instead of opening editor
|
|
if (che != 'y' or che == 'Y'):
|
|
with open(f"{wdir+filename}.gmi", 'w') as o:
|
|
o.writelines(postHeader + existing_content)
|
|
else:
|
|
with open(f"{wdir+filename}.gmi", 'w') as o:
|
|
o.writelines(existing_content)
|
|
else:
|
|
temp = "# " + title
|
|
exec(f'echo "{temp}" | cat >> {wdir + filename}.gmi') # adding title to empty file
|
|
|
|
exec(f"{editor} {wdir+filename}.gmi") # opening editor
|
|
|
|
ch = input("\nWould you like to review before posting? (c to cancel) (y/[n]): ")
|
|
|
|
if (ch == 'y' or ch == 'Y'):
|
|
exec(f"less {wdir+filename}.gmi") # opening the file in editor for review
|
|
exec(f"mv {wdir+filename}.gmi {postDir+filename}.gmi") # moving file to postdir
|
|
elif (ch == 'c'):
|
|
exec(f"mv {wdir+filename}.gmi {wdir}trash/")
|
|
print("\nCancelled.")
|
|
return None
|
|
else:
|
|
exec(f"mv {wdir+filename}.gmi {postDir+filename}.gmi") # moving file to postdir without review
|
|
|
|
# updating postIndex
|
|
exec(f'echo "=> postdir/{filename}.gmi {title}" | cat >> {indexFile}')
|
|
|
|
# updating posts.gmi, preserving the user's custom header - rbfn begin
|
|
rebuildReferences(filename, title)
|
|
|
|
# changing file permissions
|
|
exec(f"chmod 745 {wdir}posts.gmi")
|
|
exec(f"chmod 745 {wdir}postdir && chmod 745 {wdir}postdir/*")
|
|
|
|
prGreen("\n Your post is live!") # yay?
|
|
|
|
def manage(direct = ""):
|
|
""" Posts management function. If direct is given a string filename, then that filename is selected directly. """
|
|
if (direct == ""):
|
|
with open(f"{indexFile}",'r') as i: # storing all indexFile entries inside a list
|
|
allposts = i.readlines()
|
|
|
|
postsList = []
|
|
|
|
for i in allposts: # creating a list containing titles corresponding to filenames
|
|
postsList.append(i[11:].split(".gmi ", 1))
|
|
|
|
for i in postsList: # removing the \n characters
|
|
if i[1][-1] == '\n':
|
|
i[1] == i[1][:-1]
|
|
if i[0][-1] == '\n':
|
|
i[0] = i[0][:-1]
|
|
|
|
menuItems = []
|
|
for i in postsList: # formatting it into a string list for the ncurses menu function
|
|
menuItems.append(f"{i[0]} | {i[1][:-1]}")
|
|
|
|
which = menuFunction(menuItems)
|
|
|
|
if (which == None): # menuFunction returns None if the list supplied to it is empty
|
|
if (menuItems == []):
|
|
print("You don't have any posts yet.")
|
|
print("\nCancelled.")
|
|
return 0
|
|
|
|
"""
|
|
TODO:
|
|
- remove the following number input based interface with pressing keys for delete, edit and cancel
|
|
"""
|
|
|
|
print(f"\nYou have selected:\n\nTITLE: {postsList[which][1][:-1]}\nFILENAME: {postsList[which][0]}.gmi")
|
|
|
|
try:
|
|
mode = int(input("\nSELECT MODE:\n1 - EDIT\n2 - DELETE\n3 - CANCEL\n-> ")) # what does the user want to do with the selection?
|
|
except ValueError:
|
|
print("\nCancelled.")
|
|
return 0
|
|
|
|
if (mode == 1): # if mode is EDIT, open editor with the post file
|
|
if (direct == ""):
|
|
print(f'\nEditing "{postsList[which][1][:-1]}" ...')
|
|
exec(f"{editor} {postDir}{postsList[which][0]}.gmi")
|
|
else:
|
|
print(f'\nEditing {direct}.gmi')
|
|
exec(f"{editor} {postDir}{direct}.gmi")
|
|
prGreen("\n Post updated.")
|
|
elif (mode == 2): # for DELETE mode, first delete post file, delete its reference from {wdir}postIndex, and rebuild the {wdir}posts.gmi and {postDir}archive.gmi files
|
|
if (direct == ""):
|
|
exec(f"mv {postDir}{postsList[which][0]}.gmi {wdir}trash/")
|
|
exec(f"sed -i '/{postsList[which][0]}.gmi/d' {indexFile}")
|
|
else:
|
|
exec(f"mv {postDir}{direct}.gmi {wdir}trash/")
|
|
exec(f"sed -i '/{direct}.gmi/d' {indexFile}")
|
|
rebuildReferences(None, None, "delete")
|
|
print(f"\nfile moved to trash")
|
|
print(f"postIndex updated")
|
|
print("rebuilt posts.gmi, archive.gmi")
|
|
prGreen("All done.")
|
|
|
|
elif (mode == 3):
|
|
print("\nCancelled.")
|
|
else:
|
|
pass
|
|
|
|
# information strings
|
|
helpText = """
|
|
gempost (v0.6) - *experimental* gemlog manager for tilde.team
|
|
|
|
Available arguments:
|
|
post - create a new post
|
|
Usage:
|
|
post (without arguments) Write a blog post from scratch
|
|
post [path to file] Post from .gmi file, first line will be used as heading
|
|
|
|
manage - edit or delete your posts
|
|
|
|
search [search term] - Search your post titles for a search term and manage just those posts
|
|
|
|
purge - premanently delete the files in trash/
|
|
init - set up your public_gemini/ directory for gempost
|
|
reset - delete all posts and re-initialize public_gemini/
|
|
|
|
help - display this help text
|
|
desc - a brief description of how the program works
|
|
|
|
\033[93mqs - Quick Start for new users\033[00m
|
|
|
|
Source at:
|
|
https://tildegit.org/desertmouse/gempost
|
|
"""
|
|
|
|
quickStart = """
|
|
Basically, gempost manages a "posts.gmi" file and maintains it in a clean format
|
|
such that it shows your latest post, your five most recent posts, along with
|
|
an archive of all your posts, arranged from newest to oldest.
|
|
|
|
Doing all this manually would be *very* tedious.
|
|
|
|
If you are an existing user, please back up your public_gemini/ directory and then
|
|
proceed with the given steps.
|
|
|
|
Quickstart:
|
|
STEP 1
|
|
With only your index.gmi file in public_gemini/ , run the following to set everyting up:
|
|
|
|
gempost init
|
|
|
|
STEP 2
|
|
Skip this if you chose to initialize an index.gmi during gempost init.
|
|
|
|
gempost doesn't touch your index.gmi file, so you will have to manually add a link to "posts.gmi"
|
|
|
|
To do that, just add the following line to your index.gmi file:
|
|
=> ./posts.gmi Posts
|
|
|
|
CONGRATULATIONS!
|
|
You are ready to use gempost. Please just use "gempost help" from now on to only get a list of commands.
|
|
|
|
You may run "gempost desc" to get to know a bit more about how gempost works, along with two optional features:
|
|
- postPageHeader.gmi , and
|
|
- blogpostHeader.gmi
|
|
"""
|
|
|
|
description = """
|
|
Directory Structure:
|
|
gempost expects the following structure of your ~/public_gemini/ directory:
|
|
|
|
public_gemini/
|
|
├── index.gmi
|
|
├── postdir/
|
|
├── postIndex
|
|
├── postPageHeader.gmi (optional)
|
|
├── blogpostHeader.gmi (optional)
|
|
├── posts.gmi
|
|
└── trash/
|
|
|
|
2 directories, 5 files
|
|
|
|
- "postdir/" is where all your gemlog posts are stored.
|
|
- "postIndex" is the file that gempost uses to maintain an index of your posts.
|
|
|
|
- "postPageHeader.gmi" should contain a text banner that will show on your Posts page.
|
|
- "blogpostHeader.gmi" contains a text banner that will show on top of each of your posts.
|
|
|
|
- "posts.gmi" is where the program will maintain links to:
|
|
- your latest post
|
|
- your 5 most recent posts
|
|
- a link to "archive.gmi" that contains a list of all your posts
|
|
|
|
- "trash/" is the directory where gempost keeps your deleted posts. use "gempost purge" to delete its contents.
|
|
|
|
Source at:
|
|
https://tildegit.org/desertmouse/gempost
|
|
"""
|
|
|
|
# Process command-line arguments
|
|
try:
|
|
arg = argv[1]
|
|
except IndexError:
|
|
print(helpText) # print the help text if no arguments passed
|
|
exit()
|
|
|
|
if (arg == "help" or arg == "-h" or arg == "--help"): # help text listing all available arguments
|
|
print(helpText)
|
|
|
|
elif (arg == "desc"): # description of how the program uses different files and dierctories
|
|
print(description)
|
|
|
|
elif (arg == "qs"):
|
|
print(quickStart) # a simple 2-step quick start for new users
|
|
|
|
elif (arg == "post"):
|
|
checkInit()
|
|
|
|
title = ""
|
|
while True: # inputting post title from user
|
|
title = input("\nPOST TITLE: ")
|
|
if (title[-1] == '\n'): # removing the \n that creeps in because of input()
|
|
title = title[:-1]
|
|
|
|
if (len(title) == 0):
|
|
prRed("Post title cannot be empty.")
|
|
else:
|
|
break
|
|
|
|
fname = None
|
|
existing_files = listdir(f"{postDir}")
|
|
while True: # inputting custom filename from user, or not. if empty, simply set fname to None, which makes newpost() know to generate filename using the sha1 hash
|
|
fname = input("\nFILENAME: (without .gmi extension) (no spaces. leave empty to generate random) ")
|
|
|
|
try:
|
|
if (fname[-1] == '\n'): # removing the \n that creeps in because of input()
|
|
fname = fname[:-1]
|
|
except IndexError:
|
|
fname = ''
|
|
|
|
if ".gmi" in fname:
|
|
prYellow("The filename should not contain .gmi extension because it is automatically added.\n Correcting and continuing...")
|
|
fname = fname[:-4]
|
|
|
|
if ' ' in fname:
|
|
prRed("The filename cannot contain spaces.")
|
|
elif (fname == ''):
|
|
fname = None
|
|
break
|
|
elif f"{fname}.gmi" in existing_files:
|
|
prRed("A file with this name already exists.")
|
|
else:
|
|
break
|
|
|
|
if (len(argv) >= 3): # checking if more than 1 arg (except python) to see if source file has been supplied
|
|
filePath = argv[2] # storing that file's path in a var
|
|
print(f"\nUsing file {filePath}") # tell the user that the program is using a source file
|
|
exiting_content = [] # stores content of the file
|
|
|
|
try:
|
|
with open(filePath, 'r') as f: # populating file content list
|
|
existing_content = f.readlines()
|
|
|
|
newpost(title, existing_content, fname)
|
|
|
|
except FileNotFoundError:
|
|
prRed("Invalid file path / file does not exist.")
|
|
|
|
else: # the normal flow of new post
|
|
print("\nAn editor will be launched for you to write your blog post.")
|
|
print("The process will continue after you exit the editor (Ctrl+X).")
|
|
cont = input("Press enter to continue.")
|
|
newpost(title, None, fname)
|
|
|
|
elif (arg == "manage"):
|
|
checkInit()
|
|
manage()
|
|
|
|
elif (arg == "search"):
|
|
checkInit()
|
|
|
|
if (len(argv) >= 3): # getting search term from args
|
|
t = argv[2]
|
|
if (t == ''): # if empty search term given, skip looping to search all posts and just open the normal manage mode
|
|
manage()
|
|
exit()
|
|
else:
|
|
prYellow("No search term specified.")
|
|
exit()
|
|
|
|
allposts = [] # storing all indexFile entries inside a list
|
|
with open(f"{indexFile}",'r') as i:
|
|
allposts = i.readlines()
|
|
|
|
tempList = []
|
|
for i in allposts: # creating a temporary list having titles corresponding to filenames
|
|
tempList.append(i[11:].split(".gmi ", 1))
|
|
|
|
postsList = [] # adding items that contain the search term from the temporary list to postsList
|
|
for i in tempList:
|
|
if t in i[1]:
|
|
postsList.append(i)
|
|
|
|
menuItems = []
|
|
for i in postsList: # formatting it into a string list for the ncurses menu function
|
|
menuItems.append(f"{i[0]} | {i[1][:-1]}")
|
|
|
|
which = menuFunction(menuItems, f"Search listing for '{t}':\n")
|
|
|
|
if (which == None): # menuFunction returns None if the list supplied to it is empty
|
|
print("\nNo items found.")
|
|
exit()
|
|
else:
|
|
print(f"\nYou have selected:\n\nTITLE: {postsList[which][1][:-1]}\nFILENAME: {postsList[which][0]}.gmi")
|
|
|
|
c = input("\nOpen manager? (y/[n]) ")
|
|
if (c == 'y' or c == 'Y'):
|
|
manage(f"{postsList[which][0]}")
|
|
|
|
elif (arg == "purge"): # permanently delete trashed posts
|
|
checkInit()
|
|
if (len(listdir(f"{wdir}trash/")) == 0):
|
|
prYellow("Trash is already empty.")
|
|
else:
|
|
prRed("This will permanently delete your trashed posts.")
|
|
cc = input("Confirm (y/[n]): ")
|
|
if (cc == 'y' or cc == 'Y'):
|
|
exec(f"rm {wdir}trash/*")
|
|
print("\nTrash cleared.")
|
|
else:
|
|
print("\nCancelled.")
|
|
|
|
elif (arg == "init"): # initialize public_gemini/ for use with gempost
|
|
if (len(listdir(f"{wdir}")) <= 1):
|
|
exec(f"touch {wdir}postIndex && mkdir {wdir}postdir/ {wdir}trash/ && chmod 745 {wdir}* && chmod 700 {wdir}trash/")
|
|
ch = input("\nAlso create index.gmi ? (y/[n]) ")
|
|
if (ch == 'y' or ch == 'Y'):
|
|
index_init = [f"# {getlogin()}'s page\n", "\nThis is your homepage. You can customize it however you want by editing this file.\n", "\nJust remember keeping around the link below to point your visitors to your posts!\n", "\n=> ./posts.gmi Posts"]
|
|
exec(f"touch {wdir}index.gmi")
|
|
with open(f"{wdir}index.gmi", 'w') as i:
|
|
i.writelines(index_init)
|
|
prGreen('Done. Use "gempost help" to view available arguments.')
|
|
else:
|
|
prRed('Only your "index.gmi" should be there in public_gemini/')
|
|
|
|
elif (arg == "reset"): # delete all posts and re-initialize public_gemini/ for use with gempost
|
|
prRed("Warning: This will delete all your posts.")
|
|
if (input('Type "yes, I understand" to continue: ') == "yes, I understand"):
|
|
exec(f"rm -rf {wdir}postdir/ {wdir}trash/ && rm -f {wdir}posts.gmi {indexFile}")
|
|
exec(f"touch {wdir}postIndex && mkdir {wdir}postdir/ {wdir}trash/ && chmod 745 {wdir}* && chmod 700 {wdir}trash/")
|
|
ch = input("Also create index.gmi ? (y/[n]) ")
|
|
if (ch == 'y' or ch == 'Y'):
|
|
index_init = [f"# {getlogin()}'s page\n", "\nThis is your homepage. You can customize it however you want by editing this file.\n", "\nJust remember keeping around the link below to point your visitors to your posts!\n", "\n=> ./posts.gmi Posts"]
|
|
exec(f"touch {wdir}index.gmi")
|
|
with open(f"{wdir}index.gmi", 'w') as i:
|
|
i.writelines(index_init)
|
|
prYellow("public_gemini/ has been re-initialized successfully.")
|
|
else:
|
|
print("\nCancelled.")
|
|
|
|
else:
|
|
print(f"Unknown argument '{arg}'")
|
|
|
|
|