mirror of https://git.envs.net/envs/ttbp.git
fix packaging
This commit is contained in:
parent
446c70306b
commit
4e2cdd9973
|
@ -1,5 +1,3 @@
|
|||
include ttbp/config/defaults/*.txt
|
||||
include ttbp/config/defaults/style.css
|
||||
include ttbp/config/defaults/header.txt
|
||||
include ttbp/config/defaults/footer.txt
|
||||
include ttbp/config/banner-beta.txt
|
||||
|
||||
include doc/manual.html
|
||||
|
|
110
README.html
110
README.html
|
@ -51,8 +51,8 @@ by creating files with any date you want.)</em></p>
|
|||
<li>you can use <a href="https://daringfireball.net/projects/markdown/syntax">markdown</a></li>
|
||||
<li>you can use html</li>
|
||||
<li>you can also put things between <code><!-- comments --></code> to have them show up
|
||||
in the feed but not render in a browser (but people can still read
|
||||
them with view-source)</li>
|
||||
in the feed but not render in a browser (but people can still read
|
||||
them with view-source)</li>
|
||||
</ul>
|
||||
<h3>reading other feels</h3>
|
||||
<p>the <code>browse global feels</code> feature shows the ten most recent entries that anyone
|
||||
|
@ -68,6 +68,20 @@ world-viewable way! please be respectful about having access to other people's
|
|||
feels, and do not copy/repeat any information without getting their explicit
|
||||
permission. envs.net operates on a high level of mutual trust, and <code>ttbp</code> is
|
||||
designed to give individuals control over their content.</p>
|
||||
|
||||
<h3>subscribing to users</h3>
|
||||
|
||||
<p>the <code>visit your subscriptions</code> feature lets you view recent entries from a list
|
||||
of users you've subscribed to, as well as manage your subscription list. your
|
||||
list is saved to <code>~/.ttbp/config/subs</code>, which gets automatically updated when
|
||||
you add or remove subscriptions from ttbp.</p>
|
||||
|
||||
<p>your subscription list is private; this means no one other than you can see who
|
||||
you're following. subscription view only shows the 50 most recent entries from
|
||||
your subscribe list; if you want to see more entries from an individual, you
|
||||
can navigate to their entries in `check out your neighbors from the main
|
||||
menu.</p>
|
||||
|
||||
<h3>privacy</h3>
|
||||
<p>when you start your ttbp, you have the option of publishing or not publishing
|
||||
your blog.</p>
|
||||
|
@ -79,8 +93,8 @@ entries through the ttbp interface, or by directly accessing your
|
|||
directory.</p>
|
||||
<p>if you opt to publish, the program creates a directory <code>~/.ttbp/www</code> where it
|
||||
stores all html files it generates, and symlinks this from your <code>~/public_html</code>
|
||||
with your chosen blog directory. your blog will also be listed on the <a href="https://envs.net/ttbp">main ttbp
|
||||
page</a>.</p>
|
||||
with your chosen blog directory. </p>
|
||||
|
||||
<p>you can also opt to publish to gopher, and the program will automatically
|
||||
generate a gophermap of your feels.</p>
|
||||
<p>you can set publishing status on individual entries, or bury individual feels;
|
||||
|
@ -91,46 +105,46 @@ these are all actions you can perform manually from the command line, but doing
|
|||
them from within the program can help keep your files properly linked up.</p>
|
||||
<ul>
|
||||
<li><strong>read over feels</strong>--a list of all your entries, which you can open and
|
||||
read like any other feel</li>
|
||||
read like any other feel</li>
|
||||
<li><strong>modify feels publishing</strong>--this lets you toggle privacy on individual
|
||||
posts. entries marked <code>(nopub)</code> will not get written to html or gopher,
|
||||
and toggling them from this menu will immediately publish or unpublish
|
||||
that entry (if you're not publishing your posts at all, these settings
|
||||
won't matter, since your feels will never show up outside of envs.net)</li>
|
||||
posts. entries marked <code>(nopub)</code> will not get written to html or gopher,
|
||||
and toggling them from this menu will immediately publish or unpublish
|
||||
that entry (if you're not publishing your posts at all, these settings
|
||||
won't matter, since your feels will never show up outside of tilde.team)</li>
|
||||
<li><strong>backup your feels</strong>--makes a .tar.gz of all your entries, saving one
|
||||
copy to <code>~/.ttbp/backups/</code> with the current date, and a second copy to
|
||||
your home directory for safekeeping.</li>
|
||||
copy to <code>~/.ttbp/backups/</code> with the current date, and a second copy to
|
||||
your home directory for safekeeping.</li>
|
||||
<li><strong>import a feels backup</strong>--unpacks a backup file into your current feels
|
||||
list. this tool checks the <code>~/.ttbp/backups</code> directory for archives, and
|
||||
expects a file created by the above backup utility. if it detects any file
|
||||
collisions, it will preserve your current live copy and leave the backup
|
||||
verison in a temp directory, and notify you that this happened. also, any
|
||||
entries that were previously marked as <code>(nopub)</code> will retain their nopub
|
||||
status.</li>
|
||||
list. this tool checks the <code>~/.ttbp/backups</code> directory for archives, and
|
||||
expects a file created by the above backup utility. if it detects any file
|
||||
collisions, it will preserve your current live copy and leave the backup
|
||||
verison in a temp directory, and notify you that this happened. also, any
|
||||
entries that were previously marked as <code>(nopub)</code> will retain their nopub
|
||||
status.</li>
|
||||
<li><strong>bury some feels</strong>--hides individual feels from viewing; entries are
|
||||
moved to <code>~/.ttbp/buried</code> (and marked with a unique timestamp to prevent
|
||||
file collision) with permissions set to 600, meaning no one except you
|
||||
will be able to open that file. these entries are also hidden from your
|
||||
own view from <code>read over feels</code>, and you'll have to open the files from
|
||||
the command line if you want to see them. this is intended to be a
|
||||
permament action, so you'll be asked to type the entry date once to load
|
||||
the feel, then shown a preview of that feel, and then type the date again
|
||||
to confirm burying.</li>
|
||||
moved to <code>~/.ttbp/buried</code> (and marked with a unique timestamp to prevent
|
||||
file collision) with permissions set to 600, meaning no one except you
|
||||
will be able to open that file. these entries are also hidden from your
|
||||
own view from <code>read over feels</code>, and you'll have to open the files from
|
||||
the command line if you want to see them. this is intended to be a
|
||||
permament action, so you'll be asked to type the entry date once to load
|
||||
the feel, then shown a preview of that feel, and then type the date again
|
||||
to confirm burying.</li>
|
||||
<li><strong>delete feels by day</strong>--<em>permanently removes individual entries</em>,
|
||||
including deleting published html/gopher files if needed. this action is
|
||||
not recoverable, unless you have a backup to restore; you'll be asked to
|
||||
type the entry date once to load the feel, then shown a preview of that
|
||||
feel, and then type the date again to confirm deletion.</li>
|
||||
including deleting published html/gopher files if needed. this action is
|
||||
not recoverable, unless you have a backup to restore; you'll be asked to
|
||||
type the entry date once to load the feel, then shown a preview of that
|
||||
feel, and then type the date again to confirm deletion.</li>
|
||||
<li><strong>purge all feels</strong>--<em>permanently removes all feels</em>, including deleting
|
||||
all published html/gopher files if needed. this action is not recoverable,
|
||||
unless you have a backup to restore. you'll be asked to type a
|
||||
one-time-use purge code to confirm this action.</li>
|
||||
all published html/gopher files if needed. this action is not recoverable,
|
||||
unless you have a backup to restore. you'll be asked to type a
|
||||
one-time-use purge code to confirm this action.</li>
|
||||
<li><strong>wipe feels account</strong>--<em>permanently removes all data associated with
|
||||
feels</em>, including deleting any published hmtl/gopher files and removing
|
||||
your <code>~/.ttbp</code> directory. any backups that you have in <code>~/.ttbp/backups</code>
|
||||
will also be deleted with this action (which is why the backup function
|
||||
makes a second copy for safekeeping in your home directory). you will no
|
||||
longer show up in any lists as a user.</li>
|
||||
feels</em>, including deleting any published hmtl/gopher files and removing
|
||||
your <code>~/.ttbp</code> directory. any backups that you have in <code>~/.ttbp/backups</code>
|
||||
will also be deleted with this action (which is why the backup function
|
||||
makes a second copy for safekeeping in your home directory). you will no
|
||||
longer show up in any lists as a user.</li>
|
||||
</ul>
|
||||
<h3>settings</h3>
|
||||
<p>the settings menu lets you change specific options for handling your feels and
|
||||
|
@ -139,11 +153,11 @@ using the interface.</p>
|
|||
<li><strong>editor</strong>--set your text editor</li>
|
||||
<li><strong>gopher</strong>--opt in or out of automatically posting to gopher</li>
|
||||
<li><strong>post as nopub</strong>--set whether posts default to being published or not
|
||||
published (if you're not publishing your feels, this doesn't matter)</li>
|
||||
published (if you're not publishing your feels, this doesn't matter)</li>
|
||||
<li><strong>publish dir</strong>--set the directory under you <code>public_html</code> where feels will be
|
||||
published (if you're not publishing your feels, this defaults to <code>None</code>)</li>
|
||||
published (if you're not publishing your feels, this defaults to <code>None</code>)</li>
|
||||
<li><strong>publishing</strong>--opt in or out of automatically publishing entries to a
|
||||
world-readable html page</li>
|
||||
world-readable html page</li>
|
||||
<li><strong>rainbows</strong>--opt in or out of having multicolored menu text</li>
|
||||
</ul>
|
||||
<h3>changing your page layout</h3>
|
||||
|
@ -154,19 +168,21 @@ your ~/.ttbp directory entirely. <strong>you might want to back up your
|
|||
~/.ttbp/entries directory before you do this.</strong></p>
|
||||
<ul>
|
||||
<li>to modify your stylesheet, edit your ~/.ttbp/config/style.css</li>
|
||||
<li>to modify the page header, edit your ~/.ttbp/config/header.txt</li>
|
||||
<li>to modify the page header, edit your ~/.ttbp/config/header.txt
|
||||
<ul>
|
||||
<li>there's a place marked off in the default header where you can safely put
|
||||
custom HTML elements!</li>
|
||||
custom HTML elements!</li>
|
||||
</ul></li>
|
||||
<li>to modify the page footer, edit your ~/.ttbp/config/footer.txt</li>
|
||||
</ul>
|
||||
<h3>general tips/troubleshooting</h3>
|
||||
<ul>
|
||||
<li>if the date looks like it's ahead or behind, it's because you haven't set
|
||||
your local timezone yet. here are some
|
||||
<a href="http://www.cyberciti.biz/faq/linux-unix-set-tz-environment-variable/">timezone setting instructions</a></li>
|
||||
your local timezone yet. here are some
|
||||
<a href="http://www.cyberciti.biz/faq/linux-unix-set-tz-environment-variable/">timezone setting instructions</a></li>
|
||||
<li>the feels burying tool will effectively clear your post for the day; you can
|
||||
use this feature to start a fresh entry on a particular day by burying the
|
||||
current day's feels and then editing a new file</li>
|
||||
use this feature to start a fresh entry on a particular day by burying the
|
||||
current day's feels and then editing a new file</li>
|
||||
</ul>
|
||||
<h3>future features</h3>
|
||||
<p>these are a few ideas being kicked around, or under active development:</p>
|
||||
|
@ -200,4 +216,4 @@ or open a github issue and i'll get back to you as soon as i can.</p>
|
|||
<li>~vilmibm, packaging help and gopher support</li>
|
||||
<li>~sanqui, the bug swatter</li>
|
||||
<li>~sinacutie, for css updates</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
|
13
README.md
13
README.md
|
@ -93,6 +93,19 @@ feels, and do not copy/repeat any information without getting their explicit
|
|||
permission. envs.net operates on a high level of mutual trust, and `ttbp` is
|
||||
designed to give individuals control over their content.
|
||||
|
||||
### subscribing to users
|
||||
|
||||
the `visit your subscriptions` feature lets you view recent entries from a list
|
||||
of users you've subscribed to, as well as manage your subscription list. your
|
||||
list is saved to `~/.ttbp/config/subs`, which gets automatically updated when
|
||||
you add or remove subscriptions from ttbp.
|
||||
|
||||
your subscription list is private; this means no one other than you can see who
|
||||
you're following. subscription view only shows the 50 most recent entries from
|
||||
your subscribe list; if you want to see more entries from an individual, you
|
||||
can navigate to their entries in `check out your neighbors from the main
|
||||
menu.
|
||||
|
||||
### privacy
|
||||
|
||||
when you start your ttbp, you have the option of publishing or not publishing
|
||||
|
|
40
setup.py
40
setup.py
|
@ -1,24 +1,32 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="ttbp",
|
||||
version="0.12.2",
|
||||
description="command line social blogging tool used on tilde.town",
|
||||
url="https://github.com/modgethanc/ttbp",
|
||||
author="~endorphant",
|
||||
author_email="endorphant@tilde.town",
|
||||
license="MIT",
|
||||
name='ttbp',
|
||||
version='0.12.2',
|
||||
description='command line social blogging tool used on tilde.team',
|
||||
url='https://github.com/envs-net/ttbp',
|
||||
author='~endorphant',
|
||||
author_email='endorphant@tilde.town',
|
||||
license='MIT',
|
||||
classifiers=[
|
||||
"Topic :: Artistic Software",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
'Topic :: Artistic Software',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
],
|
||||
keywords="blog",
|
||||
packages=["ttbp", "ttbp/config"],
|
||||
install_requires=["inflect==0.2.5", "mistune==0.8.1", "colorama==0.3.9", "six"],
|
||||
include_package_data=True,
|
||||
entry_points={
|
||||
"console_scripts": ["feels = ttbp.ttbp:main", "ttbp = ttbp.ttbp:main"]
|
||||
keywords='blog',
|
||||
packages=setuptools.find_packages(),
|
||||
install_requires = [
|
||||
'inflect==0.2.5',
|
||||
'mistune==0.8.1',
|
||||
'colorama==0.3.9',
|
||||
'six'
|
||||
],
|
||||
include_package_data = True,
|
||||
entry_points = {
|
||||
'console_scripts': [
|
||||
'feels = ttbp.ttbp:main',
|
||||
'ttbp = ttbp.ttbp:main',
|
||||
]
|
||||
},
|
||||
)
|
||||
|
|
|
@ -3,7 +3,7 @@ import os
|
|||
import random
|
||||
|
||||
DEFAULT_LANG = {
|
||||
"greet": [
|
||||
"greet":[
|
||||
"hi",
|
||||
"hey",
|
||||
"howdy",
|
||||
|
@ -12,55 +12,58 @@ DEFAULT_LANG = {
|
|||
"good day",
|
||||
"good evening",
|
||||
"welcome back",
|
||||
"nice to see you",
|
||||
"nice to see you"
|
||||
],
|
||||
"bye": [
|
||||
"bye":[
|
||||
"see you later, space cowboy",
|
||||
"bye, teammate",
|
||||
"until next time, friend",
|
||||
"come back whenever",
|
||||
"come back whenever"
|
||||
],
|
||||
"friend": ["friend", "pal", "buddy", "teammate"],
|
||||
"months": {
|
||||
"01": "january",
|
||||
"02": "february",
|
||||
"03": "march",
|
||||
"04": "april",
|
||||
"05": "may",
|
||||
"06": "june",
|
||||
"07": "july",
|
||||
"08": "august",
|
||||
"09": "september",
|
||||
"10": "october",
|
||||
"11": "november",
|
||||
"12": "december",
|
||||
},
|
||||
"friend":[
|
||||
"friend",
|
||||
"pal",
|
||||
"buddy",
|
||||
"teammate"
|
||||
],
|
||||
"months":{
|
||||
"01":"january",
|
||||
"02":"february",
|
||||
"03":"march",
|
||||
"04":"april",
|
||||
"05":"may",
|
||||
"06":"june",
|
||||
"07":"july",
|
||||
"08":"august",
|
||||
"09":"september",
|
||||
"10":"october",
|
||||
"11":"november",
|
||||
"12":"december"
|
||||
}
|
||||
}
|
||||
|
||||
if os.path.exists("/home/endorphant/lib/python/chatterlib.json"):
|
||||
with open("/home/endorphant/lib/python/chatterlib.json", "r") as f:
|
||||
with open("/home/endorphant/lib/python/chatterlib.json", 'r') as f:
|
||||
LANG = json.load(f)
|
||||
else:
|
||||
LANG = DEFAULT_LANG
|
||||
|
||||
|
||||
def say(keyword):
|
||||
"""
|
||||
'''
|
||||
takes a keyword and randomly returns from language dictionary to match that keyword
|
||||
|
||||
returns None if keyword doesn't exist
|
||||
|
||||
TODO: validate keyword?
|
||||
"""
|
||||
'''
|
||||
|
||||
return random.choice(LANG.get(keyword))
|
||||
|
||||
|
||||
def month(num):
|
||||
"""
|
||||
'''
|
||||
takes a MM and returns lovercase full name of that month
|
||||
|
||||
TODO: validate num?
|
||||
"""
|
||||
'''
|
||||
|
||||
return LANG["months"].get(num)
|
||||
|
|
|
@ -3,20 +3,20 @@ import os
|
|||
import sys
|
||||
import time
|
||||
|
||||
from .. import util
|
||||
import ttbp.util
|
||||
|
||||
## System config
|
||||
|
||||
# We refer to some package files (ie .css stuff), so we save a reference to the
|
||||
# path.
|
||||
INSTALL_PATH = os.path.dirname(sys.modules["ttbp"].__file__)
|
||||
INSTALL_PATH = os.path.dirname(sys.modules['ttbp'].__file__)
|
||||
|
||||
# We use this to store any persisted, global state.
|
||||
VAR = "/var/global/ttbp"
|
||||
VAR_WWW = os.path.join(VAR, "www")
|
||||
VAR = '/var/global/ttbp'
|
||||
VAR_WWW = os.path.join(VAR, 'www')
|
||||
|
||||
if not os.path.isdir("/var/global"):
|
||||
raise Exception("bad system state: /var/global does not exist.")
|
||||
if not os.path.isdir('/var/global'):
|
||||
raise Exception('bad system state: /var/global does not exist.')
|
||||
|
||||
if not os.path.isdir(VAR):
|
||||
os.mkdir(VAR)
|
||||
|
@ -24,7 +24,7 @@ if not os.path.isdir(VAR):
|
|||
if not os.path.isdir(VAR_WWW):
|
||||
os.mkdir(VAR_WWW)
|
||||
|
||||
LIVE = "https://envs.net/~"
|
||||
LIVE = 'https://envs.net/~'
|
||||
FEEDBOX = "sudoers@envs.net"
|
||||
USERFILE = os.path.join(VAR, "users.txt")
|
||||
GRAFF_DIR = os.path.join(VAR, "graffiti")
|
||||
|
@ -36,7 +36,7 @@ if not os.path.isdir(GRAFF_DIR):
|
|||
|
||||
## Defaults
|
||||
|
||||
DEFAULT_HEADER = """
|
||||
DEFAULT_HEADER = '''
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<html>
|
||||
<head>
|
||||
|
@ -58,9 +58,9 @@ DEFAULT_HEADER = """
|
|||
</div>
|
||||
|
||||
<div id="tlogs">
|
||||
""".lstrip()
|
||||
'''.lstrip()
|
||||
|
||||
DEFAULT_FOOTER = """
|
||||
DEFAULT_FOOTER = '''
|
||||
</div>
|
||||
<!-- Button DarkLight-->
|
||||
<div class="button_darklight">
|
||||
|
@ -75,32 +75,32 @@ DEFAULT_FOOTER = """
|
|||
|
||||
</body>
|
||||
</html>
|
||||
""".lstrip()
|
||||
'''.lstrip()
|
||||
|
||||
with open(os.path.join(INSTALL_PATH, "config", "defaults", "style.css")) as f:
|
||||
with open(os.path.join(INSTALL_PATH, 'config', 'defaults', 'style.css')) as f:
|
||||
DEFAULT_STYLE = f.read()
|
||||
|
||||
|
||||
## User config
|
||||
|
||||
USER = os.path.basename(os.path.expanduser("~"))
|
||||
USER_HOME = os.path.expanduser("~")
|
||||
PATH = os.path.join(USER_HOME, ".ttbp")
|
||||
PUBLIC = os.path.join(USER_HOME, "public_html")
|
||||
WWW = os.path.join(PATH, "www")
|
||||
GOPHER_ENTRIES = os.path.join(PATH, "gopher")
|
||||
GOPHER_PATH = os.path.join(USER_HOME, "public_gopher", "feels")
|
||||
USER_CONFIG = os.path.join(PATH, "config")
|
||||
TTBPRC = os.path.join(USER_CONFIG, "ttbprc")
|
||||
MAIN_FEELS = os.path.join(PATH, "entries")
|
||||
BURIED_FEELS = os.path.join(PATH, "buried")
|
||||
NOPUB = os.path.join(USER_CONFIG, "nopub")
|
||||
BACKUPS = os.path.join(PATH, "backups")
|
||||
SUBS = os.path.join(USER_CONFIG, "subs")
|
||||
USER = os.path.basename(os.path.expanduser('~'))
|
||||
USER_HOME = os.path.expanduser('~')
|
||||
PATH = os.path.join(USER_HOME, '.ttbp')
|
||||
PUBLIC = os.path.join(USER_HOME, 'public_html')
|
||||
WWW = os.path.join(PATH, 'www')
|
||||
GOPHER_ENTRIES = os.path.join(PATH, 'gopher')
|
||||
GOPHER_PATH = os.path.join(USER_HOME, 'public_gopher', 'feels')
|
||||
USER_CONFIG = os.path.join(PATH, 'config')
|
||||
TTBPRC = os.path.join(USER_CONFIG, 'ttbprc')
|
||||
MAIN_FEELS = os.path.join(PATH, 'entries')
|
||||
BURIED_FEELS = os.path.join(PATH, 'buried')
|
||||
NOPUB = os.path.join(USER_CONFIG, 'nopub')
|
||||
BACKUPS = os.path.join(PATH, 'backups')
|
||||
SUBS = os.path.join(USER_CONFIG, 'subs')
|
||||
|
||||
## UI
|
||||
|
||||
BANNER = """
|
||||
BANNER = '''
|
||||
___________________________________________________________
|
||||
| |
|
||||
| ____ ____ ____ _ ____ ____ _ _ ____ _ _ _ ____ |
|
||||
|
@ -109,9 +109,9 @@ ___________________________________________________________
|
|||
| <gan jue; to feel> ver 0.12.2 |
|
||||
| envs.net edition |
|
||||
|__________________________________________________________|
|
||||
""".lstrip()
|
||||
'''.lstrip()
|
||||
# ~ u n s t a b l e e x p e r i m e n t a l b r a n c h ~
|
||||
# '''.lstrip()
|
||||
#'''.lstrip()
|
||||
|
||||
## page texts
|
||||
|
||||
|
@ -140,7 +140,7 @@ other contributors:
|
|||
~sinacutie, for css updates
|
||||
|
||||
if you have ideas for ttbp, you are welcome to contact me to discuss them;
|
||||
please send me tildemail or open an issue. i am not a very experienced
|
||||
please send me mail or open a github issue. i am not a very experienced
|
||||
developer, and ttbp is one of my first public-facing projects, so i appreciate
|
||||
your patience while i learn how to be a better developer!
|
||||
|
||||
|
@ -160,14 +160,12 @@ these.
|
|||
press <enter> to begin recording your feels in your chosen text
|
||||
editor.
|
||||
|
||||
""".format(
|
||||
today=time.strftime("%d %B %Y")
|
||||
)
|
||||
""".format(today=time.strftime("%d %B %Y"))
|
||||
|
||||
bury_feels_prompt = """\
|
||||
burying a feel removes it from view, including your own. buried feels are
|
||||
stashed in a private directory at:
|
||||
|
||||
|
||||
{buried_dir}
|
||||
|
||||
you can visit your feels there from the command line, but no one else can view
|
||||
|
@ -178,9 +176,7 @@ command line to view your buried feels)
|
|||
|
||||
which day's feels do you want to bury?
|
||||
|
||||
YYYYMMDD (or 'q' to cancel)> """.format(
|
||||
buried_dir=BURIED_FEELS
|
||||
)
|
||||
YYYYMMDD (or 'q' to cancel)> """.format(buried_dir=BURIED_FEELS)
|
||||
|
||||
account_wipe_prompt = """\
|
||||
warning! ! ! this action is irreversible!!!
|
||||
|
@ -214,34 +210,34 @@ figure it out!
|
|||
## update announcements
|
||||
|
||||
UPDATES = {
|
||||
"0.9.0": """
|
||||
"0.9.0": """
|
||||
ver. 0.9.0 features:
|
||||
* browsing other people's feels from neighbor view
|
||||
* documentation browser""",
|
||||
"0.9.1": """
|
||||
"0.9.1": """
|
||||
ver 0.9.1 features:
|
||||
* graffiti wall """,
|
||||
"0.9.2": """
|
||||
"0.9.2": """
|
||||
ver 0.9.2 features:
|
||||
* paginated entry view
|
||||
* improved entry listing performance so it should
|
||||
be less sluggish (for now)
|
||||
* expanded menu for viewing your own feels (further features to be implemented) """,
|
||||
"0.9.3": """
|
||||
"0.9.3": """
|
||||
version 0.9.3 features:
|
||||
* ttbp is now packaged, making it easier to contribute to.
|
||||
* things should otherwise be the same!
|
||||
* check out https://github.com/modgethanc/ttbp if you'd like to contribute.
|
||||
* takes advantage of new /var/global """,
|
||||
"0.10.1": """
|
||||
"0.10.1": """
|
||||
~[version 0.10.1 features]~
|
||||
* thanks to help from ~vilmibm, ttbp now supports publishing to gopher!
|
||||
* if you enable gopher publishing, feels will automatically publish to
|
||||
gopher://tilde.town/1/~{user}/feels
|
||||
gopher://tilde.team/1/~{user}/feels
|
||||
* if you don't know what gopher is, it's fine to opt-out; ask around on
|
||||
irc if you'd like to learn more!
|
||||
* the settings menu has been reworked to be less clunky""",
|
||||
"0.11.0": """
|
||||
"0.11.0": """
|
||||
~[version 0.11.0 update]~
|
||||
|
||||
* rainbow menus are now an option! please message ~endorphant (with
|
||||
|
@ -264,14 +260,14 @@ version 0.9.3 features:
|
|||
* ~login created centralfeels, which is an opt-in collection of
|
||||
html-published feels; create a blank file called '.centralfeels' in
|
||||
your home directory if you'd like to be included!""",
|
||||
"0.11.1": """
|
||||
"0.11.1": """
|
||||
~[version 0.11.1 update]~
|
||||
|
||||
* a quick patch to correct a directory listing error, nothing too
|
||||
exciting
|
||||
* general PSA: feel free to use the github repo for bugs/feature requests:
|
||||
https://github.com/modgethanc/ttbp/issues""",
|
||||
"0.11.2": """
|
||||
"0.11.2": """
|
||||
~[version 0.11.2 update]~
|
||||
|
||||
* added a new option to allow setting entries to default to either public or
|
||||
|
@ -279,7 +275,7 @@ version 0.9.3 features:
|
|||
already publishing to html/gopher, but is available either way!
|
||||
|
||||
you can find this option under 'settings' as 'post as nopub'.""",
|
||||
"0.11.3": """
|
||||
"0.11.3": """
|
||||
~[version 0.11.3 update]~
|
||||
|
||||
* thanks to ~sinacutie, you can now set custom css for the permalink text
|
||||
|
@ -287,7 +283,7 @@ version 0.9.3 features:
|
|||
your current css file, and shouldn't change the appearance of your page.
|
||||
|
||||
if you're not using custom css, don't worry about this!""",
|
||||
"0.12.0": """
|
||||
"0.12.0": """
|
||||
~[version 0.12.0 update]~
|
||||
|
||||
a lot of new stuff this time! from the main menu, option (1) is now called
|
||||
|
@ -320,11 +316,11 @@ version 0.9.3 features:
|
|||
and wants to kick some spare change my way; this is a labor of love, and i'm
|
||||
happy to work on it regardless :)
|
||||
""",
|
||||
"0.12.1": """
|
||||
"0.12.1":"""
|
||||
~[version 0.12.1 update]~
|
||||
|
||||
new feature: "visit your subscriptions"
|
||||
* view recent entries from a list of townies you've subscribed to
|
||||
* view recent entries from a list of teammates you've subscribed to
|
||||
* subscription list is private; no one else can see who you're following
|
||||
* add/remove users from the subscription menu
|
||||
|
||||
|
@ -337,7 +333,7 @@ version 0.9.3 features:
|
|||
|
||||
keep feelin' together <3
|
||||
""",
|
||||
"0.12.2": """
|
||||
"0.12.2":"""
|
||||
~[version 0.12.2 update]~
|
||||
|
||||
bug fix: ~epicmorphism helped out with fixing the pagination bug! now, when
|
||||
|
@ -350,5 +346,5 @@ version 0.9.3 features:
|
|||
|
||||
feel on!
|
||||
~endo
|
||||
""",
|
||||
"""
|
||||
}
|
||||
|
|
291
ttbp/core.py
291
ttbp/core.py
|
@ -1,11 +1,13 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
'''
|
||||
ttbp: tilde town blogging platform
|
||||
(also known as the feels engine)
|
||||
a console-based blogging program developed for tilde.town
|
||||
copyright (c) 2016 ~endorphant (endorphant@tilde.town)
|
||||
|
||||
forked for envs.net by ~creme (creme@envs.net)
|
||||
|
||||
core.py:
|
||||
this is a core handler for some ttbp standalone/output functions
|
||||
|
||||
|
@ -30,7 +32,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
the complete codebase is available at:
|
||||
https://github.com/modgethanc/ttbp
|
||||
"""
|
||||
and
|
||||
https://github.com/envs-net/ttbp
|
||||
'''
|
||||
|
||||
import os
|
||||
import time
|
||||
|
@ -39,10 +43,7 @@ import re
|
|||
import mistune
|
||||
import json
|
||||
|
||||
from . import chatter
|
||||
from . import config
|
||||
from . import gopher
|
||||
from . import util
|
||||
from ttbp import config, chatter, gopher, util
|
||||
|
||||
FEED = os.path.join("/var", "global", "ttbp", "public_html", "index.html")
|
||||
SETTINGS = {}
|
||||
|
@ -52,11 +53,10 @@ FOOTER = ""
|
|||
FILES = []
|
||||
NOPUBS = []
|
||||
|
||||
|
||||
def load(ttbprc={}):
|
||||
"""
|
||||
'''
|
||||
get all them globals set up!!
|
||||
"""
|
||||
'''
|
||||
|
||||
global HEADER
|
||||
global FOOTER
|
||||
|
@ -69,17 +69,15 @@ def load(ttbprc={}):
|
|||
load_nopubs()
|
||||
load_files()
|
||||
|
||||
|
||||
def reload_ttbprc(ttbprc={}):
|
||||
"""
|
||||
'''
|
||||
reloads new ttbprc into current session
|
||||
"""
|
||||
'''
|
||||
|
||||
global SETTINGS
|
||||
|
||||
SETTINGS = ttbprc
|
||||
|
||||
|
||||
def get_files(feelsdir=config.MAIN_FEELS):
|
||||
"""Returns a list of user's feels in the given directory (defaults to main
|
||||
feels dir)"""
|
||||
|
@ -98,15 +96,14 @@ def get_files(feelsdir=config.MAIN_FEELS):
|
|||
|
||||
return files
|
||||
|
||||
|
||||
def load_files(feelsdir=config.MAIN_FEELS):
|
||||
"""
|
||||
'''
|
||||
file loader
|
||||
|
||||
* reads user's nopub file
|
||||
* calls get_files() to load all files for given directory
|
||||
* re-renders main html file and/or gopher if needed
|
||||
"""
|
||||
'''
|
||||
|
||||
global FILES
|
||||
|
||||
|
@ -115,9 +112,8 @@ def load_files(feelsdir=config.MAIN_FEELS):
|
|||
|
||||
if publishing():
|
||||
write_html("index.html")
|
||||
if SETTINGS.get("gopher"):
|
||||
gopher.publish_gopher("feels", FILES)
|
||||
|
||||
if SETTINGS.get('gopher'):
|
||||
gopher.publish_gopher('feels', FILES)
|
||||
|
||||
def load_nopubs():
|
||||
"""Load a list of the user's nopub entries.
|
||||
|
@ -134,26 +130,20 @@ def load_nopubs():
|
|||
|
||||
return len(NOPUBS)
|
||||
|
||||
|
||||
## html outputting
|
||||
|
||||
|
||||
def write_html(outurl="default.html"):
|
||||
"""
|
||||
'''
|
||||
main page renderer
|
||||
|
||||
* takes everything currently in FILES and writes a single non-paginated html
|
||||
file
|
||||
* calls write_page() on each file to make permalinks
|
||||
"""
|
||||
'''
|
||||
|
||||
outfile = open(os.path.join(config.WWW, outurl), "w")
|
||||
|
||||
outfile.write(
|
||||
"<!--generated by the envs.net blogging platform on "
|
||||
+ time.strftime("%d %B %y")
|
||||
+ "\nhttps://envs.net/ttbp/-->\n\n"
|
||||
)
|
||||
outfile.write("<!--generated by the envs.net blogging platform on "+time.strftime("%d %B %y")+"\nhttp://envs.net/ttbp/-->\n\n")
|
||||
|
||||
for line in HEADER:
|
||||
outfile.write(line)
|
||||
|
@ -172,29 +162,20 @@ def write_html(outurl="default.html"):
|
|||
|
||||
outfile.close()
|
||||
|
||||
return os.path.join(
|
||||
config.LIVE + config.USER,
|
||||
os.path.basename(os.path.realpath(config.WWW)),
|
||||
outurl,
|
||||
)
|
||||
|
||||
return os.path.join(config.LIVE+config.USER,os.path.basename(os.path.realpath(config.WWW)),outurl)
|
||||
|
||||
def write_page(filename):
|
||||
"""
|
||||
'''
|
||||
permalink generator
|
||||
|
||||
* makes a page out of a single entry for permalinking, using filename/date as
|
||||
url
|
||||
"""
|
||||
'''
|
||||
|
||||
outurl = os.path.join(config.WWW, "".join(util.parse_date(filename)) + ".html")
|
||||
outurl = os.path.join(config.WWW, "".join(util.parse_date(filename))+".html")
|
||||
outfile = open(outurl, "w")
|
||||
|
||||
outfile.write(
|
||||
"<!--generated by the envs.net blogging platform on "
|
||||
+ time.strftime("%d %B %y")
|
||||
+ "\nhttps://envs.net/ttbp/-->\n\n"
|
||||
)
|
||||
outfile.write("<!--generated by the envs.net blogging platform on "+time.strftime("%d %B %y")+"\nhttp://envs.net/ttbp/-->\n\n")
|
||||
|
||||
for line in HEADER:
|
||||
outfile.write(line)
|
||||
|
@ -213,32 +194,21 @@ def write_page(filename):
|
|||
|
||||
return outurl
|
||||
|
||||
|
||||
def write_entry(filename):
|
||||
"""
|
||||
'''
|
||||
entry text generator
|
||||
|
||||
* dump given file into entry format by parsing file as markdown
|
||||
* return as list of strings
|
||||
"""
|
||||
'''
|
||||
|
||||
date = util.parse_date(filename)
|
||||
|
||||
entry = [
|
||||
'\t\t<p><a name="' + date[0] + date[1] + date[2] + '"></a><br /><br /></p>\n',
|
||||
'\t\t<div class="entry">\n',
|
||||
'\t\t\t<h5><a href="#'
|
||||
+ date[0]
|
||||
+ date[1]
|
||||
+ date[2]
|
||||
+ '">'
|
||||
+ date[2]
|
||||
+ "</a> "
|
||||
+ chatter.month(date[1])
|
||||
+ " "
|
||||
+ date[0]
|
||||
+ "</h5>\n"
|
||||
# "\t\t\t<P>"
|
||||
"\t\t<p><a name=\""+date[0]+date[1]+date[2]+"\"></a><br /><br /></p>\n",
|
||||
"\t\t<div class=\"entry\">\n",
|
||||
"\t\t\t<h5><a href=\"#"+date[0]+date[1]+date[2]+"\">"+date[2]+"</a> "+chatter.month(date[1])+" "+date[0]+"</h5>\n"
|
||||
#"\t\t\t<P>"
|
||||
]
|
||||
|
||||
raw = []
|
||||
|
@ -248,41 +218,33 @@ def write_entry(filename):
|
|||
raw.append(line)
|
||||
rawfile.close()
|
||||
|
||||
entry.append(
|
||||
"\t\t\t" + mistune.markdown("".join(raw), escape=False, hard_wrap=False)
|
||||
)
|
||||
entry.append("\t\t\t"+mistune.markdown("".join(raw), escape=False, hard_wrap=False))
|
||||
|
||||
# for line in raw:
|
||||
# entry.append(line+"\t\t\t")
|
||||
# if line == "\n":
|
||||
# entry.append("</p>\n\t\t\t<p>")
|
||||
#for line in raw:
|
||||
#entry.append(line+"\t\t\t")
|
||||
#if line == "\n":
|
||||
# entry.append("</p>\n\t\t\t<p>")
|
||||
|
||||
# entry.append("</p>\n")
|
||||
entry.append(
|
||||
'\t\t\t<p class="permalink"><a href="'
|
||||
+ "".join(date)
|
||||
+ '.html">permalink</a></p>\n'
|
||||
)
|
||||
#entry.append("</p>\n")
|
||||
entry.append("\t\t\t<p class=\"permalink\"><a href=\""+"".join(date)+".html\">permalink</a></p>\n")
|
||||
entry.append("\n\t\t</div>\n")
|
||||
|
||||
return entry
|
||||
|
||||
|
||||
def write_global_feed(blogList):
|
||||
"""
|
||||
'''
|
||||
main ttbp index printer
|
||||
|
||||
* sources README.md for documentation
|
||||
* takes incoming list of formatted blog links for all publishing blogs and
|
||||
prints to blog feed
|
||||
"""
|
||||
'''
|
||||
|
||||
try:
|
||||
try:
|
||||
outfile = open(FEED, "w")
|
||||
|
||||
## header
|
||||
outfile.write(
|
||||
"""\
|
||||
outfile.write("""\
|
||||
<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2//EN\">
|
||||
<html>
|
||||
<head>
|
||||
|
@ -308,39 +270,25 @@ def write_global_feed(blogList):
|
|||
)
|
||||
|
||||
## docs
|
||||
outfile.write(
|
||||
"""\
|
||||
<div class="docs">"""
|
||||
)
|
||||
outfile.write(
|
||||
mistune.markdown(
|
||||
open(os.path.join(config.INSTALL_PATH, "..", "README.md"), "r").read()
|
||||
)
|
||||
)
|
||||
outfile.write(
|
||||
"""\
|
||||
</div>"""
|
||||
)
|
||||
outfile.write("""\
|
||||
<div class="docs">""")
|
||||
outfile.write(mistune.markdown(open(os.path.join(config.INSTALL_PATH, "..", "README.md"), "r").read()))
|
||||
outfile.write("""\
|
||||
</div>""")
|
||||
|
||||
## feed
|
||||
outfile.write(
|
||||
"""\
|
||||
outfile.write("""\
|
||||
<p> </p>
|
||||
<div class=\"feed\">
|
||||
<h3>live feels-sharing:</h3>
|
||||
<ul>"""
|
||||
)
|
||||
<ul>""")
|
||||
for blog in blogList:
|
||||
outfile.write(
|
||||
"""
|
||||
<li>"""
|
||||
+ blog
|
||||
+ """</li>\
|
||||
"""
|
||||
)
|
||||
outfile.write("""
|
||||
<li>"""+blog+"""</li>\
|
||||
""")
|
||||
|
||||
## footer
|
||||
outfile.write(
|
||||
"""
|
||||
outfile.write("""
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Button DarkLight-->
|
||||
|
@ -356,20 +304,17 @@ def write_global_feed(blogList):
|
|||
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
outfile.close()
|
||||
# subprocess.call(['chmod', 'a+w', FEED])
|
||||
#subprocess.call(['chmod', 'a+w', FEED])
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
## misc helpers
|
||||
|
||||
|
||||
def meta(entries=FILES):
|
||||
"""
|
||||
def meta(entries = FILES):
|
||||
'''
|
||||
metadata generator
|
||||
|
||||
* takes a list of filenames and returns a 2d list:
|
||||
|
@ -381,58 +326,50 @@ def meta(entries=FILES):
|
|||
[5] author
|
||||
|
||||
* sorted in reverse date order by [4]
|
||||
"""
|
||||
'''
|
||||
|
||||
meta = []
|
||||
|
||||
for filename in entries:
|
||||
mtime = os.path.getmtime(filename)
|
||||
try:
|
||||
wc = int(
|
||||
subprocess.check_output(
|
||||
["wc", "-w", filename], stderr=subprocess.STDOUT
|
||||
).split()[0]
|
||||
)
|
||||
except subprocess.CalledProcessError:
|
||||
wc = "???"
|
||||
timestamp = time.strftime("%Y-%m-%d at %H:%M", time.localtime(mtime))
|
||||
date = "-".join(util.parse_date(filename))
|
||||
author = os.path.split(
|
||||
os.path.split(os.path.split(os.path.split(filename)[0])[0])[0]
|
||||
)[1]
|
||||
mtime = os.path.getmtime(filename)
|
||||
try:
|
||||
wc = int(subprocess.check_output(["wc","-w",filename], stderr=subprocess.STDOUT).split()[0])
|
||||
except subprocess.CalledProcessError:
|
||||
wc = "???"
|
||||
timestamp = time.strftime("%Y-%m-%d at %H:%M", time.localtime(mtime))
|
||||
date = "-".join(util.parse_date(filename))
|
||||
author = os.path.split(os.path.split(os.path.split(os.path.split(filename)[0])[0])[0])[1]
|
||||
|
||||
meta.append([filename, mtime, wc, timestamp, date, author])
|
||||
meta.append([filename, mtime, wc, timestamp, date, author])
|
||||
|
||||
# meta.sort(key = lambda filename:filename[4])
|
||||
# meta.reverse()
|
||||
#meta.sort(key = lambda filename:filename[4])
|
||||
#meta.reverse()
|
||||
|
||||
return meta
|
||||
|
||||
|
||||
def valid(filename):
|
||||
"""
|
||||
'''
|
||||
filename validator
|
||||
|
||||
* check if the filename is YYYYMMDD.txt
|
||||
"""
|
||||
'''
|
||||
|
||||
filesplit = os.path.splitext(os.path.basename(filename))
|
||||
|
||||
if filesplit[1] != ".txt":
|
||||
return False
|
||||
|
||||
pattern = "^((19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|1\d|2\d|3[01])$"
|
||||
pattern = '^((19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|1\d|2\d|3[01])$'
|
||||
|
||||
if not re.match(pattern, filesplit[0]):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def find_ttbps():
|
||||
"""
|
||||
'''
|
||||
returns a list of users with a ttbp by checking for a valid ttbprc
|
||||
"""
|
||||
'''
|
||||
|
||||
users = []
|
||||
|
||||
|
@ -442,11 +379,10 @@ def find_ttbps():
|
|||
|
||||
return users
|
||||
|
||||
|
||||
def publishing(username=config.USER):
|
||||
"""
|
||||
'''
|
||||
checks .ttbprc for whether or not user opted for www publishing
|
||||
"""
|
||||
'''
|
||||
|
||||
ttbprc = {}
|
||||
|
||||
|
@ -454,17 +390,14 @@ def publishing(username=config.USER):
|
|||
ttbprc = SETTINGS
|
||||
|
||||
else:
|
||||
ttbprc = json.load(
|
||||
open(os.path.join("/home", username, ".ttbp", "config", "ttbprc"))
|
||||
)
|
||||
ttbprc = json.load(open(os.path.join("/home", username, ".ttbp", "config", "ttbprc")))
|
||||
|
||||
return ttbprc.get("publishing")
|
||||
|
||||
|
||||
def www_neighbors():
|
||||
"""
|
||||
'''
|
||||
takes a list of users with publiishing turned on and prepares it for www output
|
||||
"""
|
||||
'''
|
||||
|
||||
userList = []
|
||||
|
||||
|
@ -472,13 +405,11 @@ def www_neighbors():
|
|||
if not publishing(user):
|
||||
continue
|
||||
|
||||
userRC = json.load(
|
||||
open(os.path.join("/home", user, ".ttbp", "config", "ttbprc"))
|
||||
)
|
||||
userRC = json.load(open(os.path.join("/home", user, ".ttbp", "config", "ttbprc")))
|
||||
|
||||
url = ""
|
||||
if userRC["publish dir"]:
|
||||
url = config.LIVE + user + "/" + userRC["publish dir"]
|
||||
url = config.LIVE+user+"/"+userRC["publish dir"]
|
||||
|
||||
lastfile = ""
|
||||
try:
|
||||
|
@ -492,21 +423,15 @@ def www_neighbors():
|
|||
|
||||
if lastfile:
|
||||
last = os.path.getctime(lastfile)
|
||||
timestamp = (
|
||||
time.strftime("%Y-%m-%d at %H:%M", time.localtime(last))
|
||||
+ " (utc"
|
||||
+ time.strftime("%z")[0]
|
||||
+ time.strftime("%z")[2]
|
||||
+ ")"
|
||||
)
|
||||
timestamp = time.strftime("%Y-%m-%d at %H:%M", time.localtime(last)) + " (utc"+time.strftime("%z")[0]+time.strftime("%z")[2]+")"
|
||||
else:
|
||||
timestamp = ""
|
||||
last = 0
|
||||
|
||||
userList.append(['<a href="' + url + '">~' + user + "</a> " + timestamp, last])
|
||||
userList.append(["<a href=\""+url+"\">~"+user+"</a> "+timestamp, last])
|
||||
|
||||
# sort user by most recent entry
|
||||
userList.sort(key=lambda userdata: userdata[1])
|
||||
userList.sort(key = lambda userdata:userdata[1])
|
||||
userList.reverse()
|
||||
sortedUsers = []
|
||||
for user in userList:
|
||||
|
@ -514,15 +439,13 @@ def www_neighbors():
|
|||
|
||||
write_global_feed(sortedUsers)
|
||||
|
||||
|
||||
def nopub(filename):
|
||||
"""
|
||||
'''
|
||||
checks to see if given filename is in user's NOPUB
|
||||
"""
|
||||
'''
|
||||
|
||||
return os.path.basename(filename) in NOPUBS
|
||||
|
||||
|
||||
def toggle_nopub(filename):
|
||||
"""toggles pub/nopub status for the given filename
|
||||
|
||||
|
@ -540,52 +463,38 @@ def toggle_nopub(filename):
|
|||
NOPUBS.append(filename)
|
||||
unpublish_feel(filename)
|
||||
|
||||
nopub_file = open(config.NOPUB, "w")
|
||||
nopub_file.write(
|
||||
"""\
|
||||
nopub_file = open(config.NOPUB, 'w')
|
||||
nopub_file.write("""\
|
||||
# files that don't get published html/gopher. this file is
|
||||
# generated by ttbp; editing it directly may result in unexpected
|
||||
# behavior. if you have problems, back up this file, delete it, and
|
||||
# rebuild it from ttbp.\n"""
|
||||
)
|
||||
# rebuild it from ttbp.\n""")
|
||||
for entry in NOPUBS:
|
||||
nopub_file.write(entry + "\n")
|
||||
nopub_file.write(entry+"\n")
|
||||
nopub_file.close()
|
||||
|
||||
load_files()
|
||||
|
||||
return action
|
||||
|
||||
|
||||
def bury_feel(filename):
|
||||
"""buries given filename; this removes the feel from any publicly-readable
|
||||
location, and moves the textfile to user's private feels directory.
|
||||
|
||||
|
||||
timestring will be added to the filename to disambiguate and prevent
|
||||
filename collisions.
|
||||
|
||||
|
||||
creates buried feels dir if it doesn't exist.
|
||||
|
||||
|
||||
regenerates feels list and republishes."""
|
||||
|
||||
if not os.path.exists(config.BURIED_FEELS):
|
||||
os.mkdir(config.BURIED_FEELS)
|
||||
subprocess.call(["chmod", "700", config.BURIED_FEELS])
|
||||
|
||||
buryname = (
|
||||
os.path.splitext(os.path.basename(filename))[0]
|
||||
+ "-"
|
||||
+ str(int(time.time()))
|
||||
+ ".txt"
|
||||
)
|
||||
buryname = os.path.splitext(os.path.basename(filename))[0]+"-"+str(int(time.time()))+".txt"
|
||||
|
||||
subprocess.call(
|
||||
[
|
||||
"mv",
|
||||
os.path.join(config.MAIN_FEELS, filename),
|
||||
os.path.join(config.BURIED_FEELS, buryname),
|
||||
]
|
||||
)
|
||||
subprocess.call(["mv", os.path.join(config.MAIN_FEELS, filename), os.path.join(config.BURIED_FEELS, buryname)])
|
||||
subprocess.call(["chmod", "600", os.path.join(config.BURIED_FEELS, buryname)])
|
||||
|
||||
if publishing():
|
||||
|
@ -595,7 +504,6 @@ def bury_feel(filename):
|
|||
|
||||
return os.path.join(config.BURIED_FEELS, buryname)
|
||||
|
||||
|
||||
def delete_feel(filename):
|
||||
"""deletes given filename; removes the feel from publicly-readable
|
||||
locations, then deletes the original file."""
|
||||
|
@ -606,21 +514,18 @@ def delete_feel(filename):
|
|||
unpublish_feel(filename)
|
||||
load_files(config.MAIN_FEELS)
|
||||
|
||||
|
||||
def unpublish_feel(filename):
|
||||
"""takes given filename and removes it from public_html and gopher_html, if
|
||||
those locations exists. afterwards, regenerate index files appropriately."""
|
||||
|
||||
live_html = os.path.join(
|
||||
config.WWW, os.path.splitext(os.path.basename(filename))[0] + ".html"
|
||||
)
|
||||
live_html = os.path.join(config.WWW,
|
||||
os.path.splitext(os.path.basename(filename))[0]+".html")
|
||||
if os.path.exists(live_html):
|
||||
subprocess.call(["rm", live_html])
|
||||
live_gopher = os.path.join(config.GOPHER_PATH, filename)
|
||||
if os.path.exists(live_gopher):
|
||||
subprocess.call(["rm", live_gopher])
|
||||
|
||||
|
||||
def process_backup(filename):
|
||||
"""takes given filename and unpacks it into a temp directory, then returns a
|
||||
list of filenames with collisions filtered out.
|
||||
|
@ -651,7 +556,6 @@ def process_backup(filename):
|
|||
imported.sort()
|
||||
return imported
|
||||
|
||||
|
||||
def import_feels(backups):
|
||||
"""takes a list of filepaths and copies those to current main feels.
|
||||
|
||||
|
@ -665,11 +569,10 @@ def import_feels(backups):
|
|||
#############
|
||||
#############
|
||||
|
||||
|
||||
def test():
|
||||
load()
|
||||
|
||||
metaTest = meta()
|
||||
|
||||
for x in metaTest:
|
||||
print(x)
|
||||
print(x)
|
||||
|
|
|
@ -6,10 +6,7 @@ import os
|
|||
import time
|
||||
import subprocess
|
||||
|
||||
from . import util
|
||||
from . import config
|
||||
|
||||
# from .core import parse_date
|
||||
from ttbp import util, config
|
||||
|
||||
GOPHER_PROMPT = """
|
||||
|
||||
|
@ -42,7 +39,7 @@ GOPHERMAP_HEADER = """
|
|||
|
||||
this file is automatically generated by ttbp.
|
||||
|
||||
0(about ttbp)\t/~endorphant/ttbp.txt\ttilde.town\t70
|
||||
0(about ttbp)\t/ttbp.txt\tenvs.net\t70
|
||||
1(back to user's home)\t/~{user}
|
||||
|
||||
entries:
|
||||
|
@ -53,39 +50,32 @@ entries:
|
|||
def select_gopher():
|
||||
return util.input_yn(GOPHER_PROMPT)
|
||||
|
||||
|
||||
def publish_gopher(gopher_path, entry_filenames):
|
||||
"""This function (re)generates a user's list of feels posts in their gopher
|
||||
directory and their gophermap."""
|
||||
entry_filenames = entry_filenames[
|
||||
:
|
||||
] # force a copy since this might be shared state in core.py
|
||||
ttbp_gopher = os.path.join(os.path.expanduser("~/public_gopher"), gopher_path)
|
||||
entry_filenames = entry_filenames[:] # force a copy since this might be shared state in core.py
|
||||
ttbp_gopher = os.path.join(
|
||||
os.path.expanduser('~/public_gopher'),
|
||||
gopher_path)
|
||||
|
||||
if not os.path.isdir(ttbp_gopher):
|
||||
print(
|
||||
"\n\tERROR: something is wrong. your gopher directory is missing. re-enable gopher publishing from the settings menu to fix this up!"
|
||||
)
|
||||
print('\n\tERROR: something is wrong. your gopher directory is missing. re-enable gopher publishing from the settings menu to fix this up!')
|
||||
return
|
||||
|
||||
with open(os.path.join(ttbp_gopher, "gophermap"), "w") as gophermap:
|
||||
gophermap.write(GOPHERMAP_HEADER.format(user=getpass.getuser()))
|
||||
with open(os.path.join(ttbp_gopher, 'gophermap'), 'w') as gophermap:
|
||||
gophermap.write(GOPHERMAP_HEADER.format(
|
||||
user=getpass.getuser()))
|
||||
for entry_filename in entry_filenames:
|
||||
filename = os.path.basename(entry_filename)
|
||||
|
||||
gopher_entry_symlink = os.path.join(
|
||||
ttbp_gopher, os.path.basename(entry_filename)
|
||||
)
|
||||
gopher_entry_symlink = os.path.join(ttbp_gopher, os.path.basename(entry_filename))
|
||||
if not os.path.exists(gopher_entry_symlink):
|
||||
subprocess.call(["ln", "-s", entry_filename, gopher_entry_symlink])
|
||||
|
||||
label = "-".join(util.parse_date(entry_filename))
|
||||
gophermap.write(
|
||||
"0{file_label}\t{filename}\n".format(
|
||||
file_label=label, filename=filename
|
||||
)
|
||||
)
|
||||
|
||||
gophermap.write('0{file_label}\t{filename}\n'.format(
|
||||
file_label=label,
|
||||
filename=filename))
|
||||
|
||||
def setup_gopher(gopher_path):
|
||||
"""Given a path relative to ~/public_gopher, this function:
|
||||
|
@ -96,7 +86,7 @@ def setup_gopher(gopher_path):
|
|||
It doesn't create a gophermap as that is left to the publish_gopher
|
||||
function.
|
||||
"""
|
||||
public_gopher = os.path.expanduser("~/public_gopher")
|
||||
public_gopher = os.path.expanduser('~/public_gopher')
|
||||
|
||||
if not os.path.isdir(public_gopher):
|
||||
"""
|
||||
|
@ -108,9 +98,7 @@ def setup_gopher(gopher_path):
|
|||
ttbp_gopher = os.path.join(public_gopher, gopher_path)
|
||||
|
||||
if os.path.isdir(ttbp_gopher):
|
||||
print(
|
||||
"\n\tERROR: gopher path is already set up. quitting so we don't overwrite anything."
|
||||
)
|
||||
print("\n\tERROR: gopher path is already set up. quitting so we don't overwrite anything.")
|
||||
return
|
||||
|
||||
gopher_entries = os.path.join(os.path.expanduser("~/.ttbp"), "gopher")
|
||||
|
@ -119,7 +107,6 @@ def setup_gopher(gopher_path):
|
|||
|
||||
subprocess.call(["ln", "-s", gopher_entries, ttbp_gopher])
|
||||
|
||||
|
||||
def unpublish():
|
||||
"""blanks all gopher things and recreates the directories."""
|
||||
|
||||
|
|
1114
ttbp/ttbp.py
1114
ttbp/ttbp.py
File diff suppressed because it is too large
Load Diff
|
@ -3,4 +3,4 @@
|
|||
import core
|
||||
|
||||
core.load()
|
||||
print("\n blog updated at " + core.write("index.html") + "\n")
|
||||
print("\n blog updated at "+core.write("index.html")+"\n")
|
||||
|
|
90
ttbp/util.py
90
ttbp/util.py
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
'''
|
||||
util.py: frequently used terminal and text processing utilities
|
||||
copyright (c) 2016 ~endorphant (endorphant@tilde.town)
|
||||
|
||||
|
@ -22,7 +22,7 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
'''
|
||||
import random
|
||||
import time
|
||||
from six.moves import input
|
||||
|
@ -32,29 +32,20 @@ import colorama
|
|||
import inflect
|
||||
|
||||
## misc globals
|
||||
BACKS = ["back", "b", "q", "<q>"]
|
||||
NAVS = ["u", "d"]
|
||||
BACKS = ['back', 'b', 'q', '<q>']
|
||||
NAVS = ['u', 'd']
|
||||
|
||||
## color stuff
|
||||
colorama.init()
|
||||
textcolors = [
|
||||
colorama.Fore.RED,
|
||||
colorama.Fore.GREEN,
|
||||
colorama.Fore.YELLOW,
|
||||
colorama.Fore.BLUE,
|
||||
colorama.Fore.MAGENTA,
|
||||
colorama.Fore.WHITE,
|
||||
colorama.Fore.CYAN,
|
||||
]
|
||||
textcolors = [ colorama.Fore.RED, colorama.Fore.GREEN, colorama.Fore.YELLOW, colorama.Fore.BLUE, colorama.Fore.MAGENTA, colorama.Fore.WHITE, colorama.Fore.CYAN]
|
||||
lastcolor = colorama.Fore.RESET
|
||||
|
||||
p = inflect.engine()
|
||||
|
||||
|
||||
def set_rainbow():
|
||||
"""
|
||||
'''
|
||||
prints a random terminal color code
|
||||
"""
|
||||
'''
|
||||
|
||||
global lastcolor
|
||||
|
||||
|
@ -66,19 +57,17 @@ def set_rainbow():
|
|||
|
||||
print(color)
|
||||
|
||||
|
||||
def reset_color():
|
||||
"""
|
||||
'''
|
||||
prints terminal color code reset
|
||||
"""
|
||||
'''
|
||||
|
||||
print(colorama.Fore.RESET)
|
||||
|
||||
|
||||
def attach_rainbow():
|
||||
"""
|
||||
'''
|
||||
returns a random terminal color code, presumably to be 'attached' to a string
|
||||
"""
|
||||
'''
|
||||
|
||||
global lastcolor
|
||||
|
||||
|
@ -89,27 +78,24 @@ def attach_rainbow():
|
|||
lastcolor = color
|
||||
return color
|
||||
|
||||
|
||||
def attach_reset():
|
||||
"""
|
||||
'''
|
||||
returns terminal color code reset, presumably to be 'attached' to a string
|
||||
"""
|
||||
'''
|
||||
|
||||
return colorama.Style.RESET_ALL
|
||||
|
||||
|
||||
def hilight(text):
|
||||
"""
|
||||
'''
|
||||
takes a string and highlights it on return
|
||||
"""
|
||||
|
||||
return colorama.Style.BRIGHT + text + colorama.Style.NORMAL
|
||||
'''
|
||||
|
||||
return colorama.Style.BRIGHT+text+colorama.Style.NORMAL
|
||||
|
||||
def rainbow(txt):
|
||||
"""
|
||||
'''
|
||||
Takes a string and makes every letter a different color.
|
||||
"""
|
||||
'''
|
||||
|
||||
rainbow = ""
|
||||
for letter in txt:
|
||||
|
@ -119,15 +105,14 @@ def rainbow(txt):
|
|||
|
||||
return rainbow
|
||||
|
||||
|
||||
def pretty_time(time):
|
||||
"""
|
||||
'''
|
||||
human-friendly time formatter
|
||||
|
||||
takes an integer number of seconds and returns a phrase that describes it,
|
||||
using the largest possible figure, rounded down (ie, time=604 returns '10
|
||||
minutes', not '10 minutes, 4 seconds' or '604 seconds')
|
||||
"""
|
||||
'''
|
||||
|
||||
m, s = divmod(time, 60)
|
||||
if m > 0:
|
||||
|
@ -151,28 +136,26 @@ def pretty_time(time):
|
|||
else:
|
||||
return p.no("second", s)
|
||||
|
||||
|
||||
def genID(digits=5):
|
||||
"""
|
||||
'''
|
||||
returns a string-friendly string of digits, which can start with 0
|
||||
"""
|
||||
'''
|
||||
|
||||
id = ""
|
||||
x = 0
|
||||
x = 0
|
||||
while x < digits:
|
||||
id += str(random.randint(0, 9))
|
||||
id += str(random.randint(0,9))
|
||||
x += 1
|
||||
|
||||
return id
|
||||
|
||||
|
||||
def print_menu(menu, rainbow=False):
|
||||
"""
|
||||
'''
|
||||
A pretty menu handler that takes an incoming lists of
|
||||
options and prints them nicely.
|
||||
|
||||
Set rainbow=True for colorized menus.
|
||||
"""
|
||||
'''
|
||||
|
||||
i = 0
|
||||
for x in menu:
|
||||
|
@ -182,24 +165,23 @@ def print_menu(menu, rainbow=False):
|
|||
line.append("\t[ ")
|
||||
if i < 10:
|
||||
line.append(" ")
|
||||
line.append(str(i) + " ] " + x)
|
||||
line.append(str(i)+" ] "+x)
|
||||
line.append(attach_reset())
|
||||
print("".join(line))
|
||||
i += 1
|
||||
|
||||
|
||||
def list_select(options, prompt):
|
||||
"""
|
||||
'''
|
||||
Given a list and query prompt, returns either False as an
|
||||
eject flag, or an integer index of the list Catches cancel
|
||||
option from list defined by BACKS; otherwise, retries on
|
||||
ValueError or IndexError.
|
||||
"""
|
||||
'''
|
||||
|
||||
ans = ""
|
||||
invalid = True
|
||||
|
||||
choice = input("\n" + prompt)
|
||||
choice = input("\n"+prompt)
|
||||
|
||||
if choice in BACKS:
|
||||
return False
|
||||
|
@ -219,14 +201,13 @@ def list_select(options, prompt):
|
|||
|
||||
return ans
|
||||
|
||||
|
||||
def input_yn(query):
|
||||
"""
|
||||
'''
|
||||
Given a query, returns boolean True or False by processing y/n input
|
||||
"""
|
||||
'''
|
||||
|
||||
try:
|
||||
ans = input(query + " [y/n] ")
|
||||
ans = input(query+" [y/n] ")
|
||||
except KeyboardInterrupt:
|
||||
input_yn(query)
|
||||
|
||||
|
@ -235,9 +216,8 @@ def input_yn(query):
|
|||
|
||||
return ans == "y"
|
||||
|
||||
|
||||
def parse_date(file):
|
||||
"""
|
||||
'''
|
||||
parses date out of pre-validated filename
|
||||
|
||||
* assumes a filename of YYYYMMDD.txt
|
||||
|
@ -245,7 +225,7 @@ def parse_date(file):
|
|||
[0] 'YYYY'
|
||||
[1] 'MM'
|
||||
[2] 'DD'
|
||||
"""
|
||||
'''
|
||||
|
||||
rawdate = os.path.splitext(os.path.basename(file))[0]
|
||||
|
||||
|
|
Loading…
Reference in New Issue