2019-08-24 12:14:46 +00:00
|
|
|
import re
|
2019-08-29 09:47:44 +00:00
|
|
|
import shutil
|
|
|
|
import subprocess
|
2019-08-24 12:14:46 +00:00
|
|
|
|
2020-04-15 12:01:23 +00:00
|
|
|
from datetime import datetime, timezone
|
2019-08-27 12:34:51 +00:00
|
|
|
|
2019-08-24 12:14:46 +00:00
|
|
|
HASHTAG_PATTERN = re.compile(r'(?<!\w)(#\w+)\b')
|
|
|
|
|
|
|
|
|
2019-08-27 12:34:51 +00:00
|
|
|
def parse_datetime(value):
|
|
|
|
"""Returns an aware datetime in local timezone"""
|
2019-09-04 06:36:12 +00:00
|
|
|
|
|
|
|
# In Python < 3.7, `%z` does not match `Z` offset
|
|
|
|
# https://docs.python.org/3.7/library/datetime.html#strftime-and-strptime-behavior
|
|
|
|
if value.endswith("Z"):
|
2020-04-15 12:01:23 +00:00
|
|
|
dttm = datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=timezone.utc)
|
2019-09-04 06:36:12 +00:00
|
|
|
else:
|
|
|
|
dttm = datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f%z")
|
|
|
|
|
|
|
|
return dttm.astimezone()
|
2019-08-28 13:32:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
def highlight_keys(text, high_attr, low_attr=""):
|
|
|
|
"""
|
|
|
|
Takes a string and adds high_attr attribute to parts in square brackets,
|
|
|
|
and optionally low_attr attribute to parts outside square brackets.
|
|
|
|
|
|
|
|
The result can be rendered using a urwid.Text widget.
|
|
|
|
|
|
|
|
For example:
|
|
|
|
|
|
|
|
>>> highlight_keys("[P]rint [V]iew", "blue")
|
|
|
|
>>> [('blue', 'P'), 'rint ', ('blue', 'V'), 'iew']
|
|
|
|
"""
|
|
|
|
def _gen():
|
|
|
|
highlighted = False
|
|
|
|
for part in re.split("\\[|\\]", text):
|
|
|
|
if part:
|
|
|
|
if highlighted:
|
|
|
|
yield (high_attr, part) if high_attr else part
|
|
|
|
else:
|
|
|
|
yield (low_attr, part) if low_attr else part
|
|
|
|
highlighted = not highlighted
|
|
|
|
return list(_gen())
|
|
|
|
|
|
|
|
|
|
|
|
def highlight_hashtags(line, attr="hashtag"):
|
|
|
|
return [
|
|
|
|
(attr, p) if p.startswith("#") else p
|
|
|
|
for p in re.split(HASHTAG_PATTERN, line)
|
|
|
|
]
|
2019-08-29 09:47:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
def show_media(paths):
|
|
|
|
"""
|
|
|
|
Attempt to open an image viewer to show given media files.
|
|
|
|
|
|
|
|
FIXME: This is not very thought out, but works for me.
|
|
|
|
Once settings are implemented, add an option for the user to configure their
|
|
|
|
prefered media viewer.
|
|
|
|
"""
|
|
|
|
viewer = None
|
|
|
|
potential_viewers = [
|
|
|
|
"feh",
|
|
|
|
"eog",
|
|
|
|
"display"
|
|
|
|
]
|
|
|
|
for v in potential_viewers:
|
|
|
|
viewer = shutil.which(v)
|
|
|
|
if viewer:
|
|
|
|
break
|
|
|
|
|
|
|
|
if not viewer:
|
|
|
|
raise Exception("Cannot find an image viewer")
|
|
|
|
|
|
|
|
subprocess.run([viewer] + paths)
|