This commit is contained in:
GitHub Merge Button 2012-04-17 12:18:48 -07:00
commit 47e5c8a2c6
2 changed files with 41 additions and 3 deletions

View file

@ -136,6 +136,12 @@ Can do:
Why not create a beautiful [timeline](http://timeline.verite.co/) of your journal? Why not create a beautiful [timeline](http://timeline.verite.co/) of your journal?
### Markdown export
jrnl -markdown
Markdown is a simple markup language that is human readable and can be used to be rendered to other formats (html, pdf). This README for example is formatted in markdown and github makes it look nice.
### Encryption ### Encryption
Should you ever want to decrypt your journal manually, you can do so with any program that supports the AES algorithm. The key used for encryption is the SHA-256-hash of your password, and the IV (initialisation vector) is stored in the first 16 bytes of the encrypted file. So, to decrypt a journal file in python, run Should you ever want to decrypt your journal manually, you can do so with any program that supports the AES algorithm. The key used for encryption is the SHA-256-hash of your password, and the IV (initialisation vector) is stored in the first 16 bytes of the encrypted file. So, to decrypt a journal file in python, run

38
jrnl.py
View file

@ -17,7 +17,6 @@ from Crypto.Cipher import AES
from Crypto.Random import random, atfork from Crypto.Random import random, atfork
import hashlib import hashlib
import getpass import getpass
import mimetypes
default_config = { default_config = {
'journal': os.path.expanduser("~/journal.txt"), 'journal': os.path.expanduser("~/journal.txt"),
@ -67,6 +66,21 @@ class Entry:
'time': self.date.strftime("%H:%M") 'time': self.date.strftime("%H:%M")
} }
def to_md(self):
date_str = self.date.strftime(self.journal.config['timeformat'])
body_wrapper = "\n\n" if self.body.strip() else ""
body = body_wrapper + self.body.strip()
space = "\n"
md_head = "###"
return "%(md)s %(date)s, %(title)s %(body)s %(space)s" % {
'md': md_head,
'date': date_str,
'title': self.title,
'body': body,
'space': space
}
class Journal: class Journal:
def __init__(self, config, **kwargs): def __init__(self, config, **kwargs):
config.update(kwargs) config.update(kwargs)
@ -169,6 +183,22 @@ class Journal:
"""Returns a JSON representation of the Journal.""" """Returns a JSON representation of the Journal."""
return json.dumps([e.to_dict() for e in self.entries], indent=2) return json.dumps([e.to_dict() for e in self.entries], indent=2)
def to_md(self):
"""Returns a markdown representation of the Journal"""
out = []
year, month = -1, -1
for e in self.entries:
if not e.date.year == year:
year = e.date.year
out.append(str(year))
out.append("=" * len(str(year)) + "\n")
if not e.date.month == month:
month = e.date.month
out.append(e.date.strftime("%B"))
out.append('-' * len(e.date.strftime("%B")) + "\n")
out.append(e.to_md())
return "\n".join(out)
def __repr__(self): def __repr__(self):
return "<Journal with %d entries>" % len(self.entries) return "<Journal with %d entries>" % len(self.entries)
@ -203,7 +233,6 @@ class Journal:
search_tags = set([tag.lower() for tag in tags]) search_tags = set([tag.lower() for tag in tags])
end_date = self.parse_date(end_date) end_date = self.parse_date(end_date)
start_date = self.parse_date(start_date) start_date = self.parse_date(start_date)
print start_date, end_date
# If strict mode is on, all tags have to be present in entry # If strict mode is on, all tags have to be present in entry
tagged = search_tags.issubset if strict else search_tags.intersection tagged = search_tags.issubset if strict else search_tags.intersection
result = [ result = [
@ -307,11 +336,12 @@ if __name__ == "__main__":
reading.add_argument('-and', dest='strict', action="store_true", help='Filter by tags using AND (default: OR)') reading.add_argument('-and', dest='strict', action="store_true", help='Filter by tags using AND (default: OR)')
reading.add_argument('-n', dest='limit', default=None, metavar="N", help='Shows the last n entries matching the filter', nargs="?", type=int) reading.add_argument('-n', dest='limit', default=None, metavar="N", help='Shows the last n entries matching the filter', nargs="?", type=int)
reading.add_argument('-json', dest='json', action="store_true", help='Returns a JSON-encoded version of the Journal') reading.add_argument('-json', dest='json', action="store_true", help='Returns a JSON-encoded version of the Journal')
reading.add_argument('-markdown', dest='markdown', action="store_true", help='Returns a Markdown-formated version of the Journal')
args = parser.parse_args() args = parser.parse_args()
# Guess mode # Guess mode
compose = True compose = True
if args.start_date or args.end_date or args.limit or args.json or args.strict: if args.start_date or args.end_date or args.limit or args.json or args.strict or args.markdown:
# Any sign of displaying stuff? # Any sign of displaying stuff?
compose = False compose = False
elif not args.date and args.text and all(word[0] in config['tagsymbols'] for word in args.text): elif not args.date and args.text and all(word[0] in config['tagsymbols'] for word in args.text):
@ -349,5 +379,7 @@ if __name__ == "__main__":
journal.limit(args.limit) journal.limit(args.limit)
if args.json: if args.json:
print(journal.to_json()) print(journal.to_json())
elif args.markdown:
print(journal.to_md())
else: else:
print(journal) print(journal)