In [7]:
import re

re_newlines = re.compile(r'\r\n|\r')

def linebreaks(value):
    """Convert newlines into <p> and <br>s."""
    value = re_newlines.sub('\n', str(value))
    
    paragraphs = re.split('\n{2,}', str(value))
    
    paragraphs = ['<p>{}</p>'.format(p.replace('\n', '<br>')) for p in paragraphs]
    
    return '\n\n'.join(paragraphs)

In [14]:
from pathlib import Path

import bleach
import markdown
import toml

class PathDoesNotExist(Exception):
    pass

    
class HEntry:
    
    name = None
    summary = None
    content = None
    
    published = None
    updated = None
    
    photo = None
    author = None
    category = []
    location = None
    syndication = []
    in_reply_to = None
    rsvp = None
    link_of = None
    repost_of = None

    def __init__(self, path):
        self.path = Path(path)
        
        if not self.path.is_dir():
            raise PathDoesNotExist(self.path)
        
        self.load_meta()
        self.load_files()
    
    def __repr__(self):
        return 'HEntry({})'.format(self.path)

    def __str__(self):
        if self.name:
            return '{}'.format(self.name)
        elif self.summary:
            return '{}'.format(self.summary)
        else:
            return '{}'.format(self.path)
    
    def load_meta(self):
        meta_file = next(self.path.glob('_meta.toml'))
        
        with meta_file.open() as fobj:
            meta = toml.loads(fobj.read())
        
        for key, value in meta.items():
            setattr(self, key, value)
    
    def load_files(self):
        files = self.path.glob('[!_meta]*')
        
        for file in files:
            key = file.stem

            with file.open() as fobj:
                value = fobj.read()
            
            if file.suffix == '.txt':
                setattr(self, key,
                    bleach.linkify(linebreaks(value)))
                
            elif file.suffix in ['.md', '.markdown', '.mdown']:
                setattr(self, key, markdown.markdown(value))
                
            elif file.suffix == '.html':
                setattr(self, key, value)
    
    def list_media(self):
        media_files = self.path.glob('media/**/*')
        return media_files
    
    def get_media(self, file_name):
        return self.path / 'media' / file_name

entry = HEntry('/Users/myles/WebSites/mylesbraithwaite.com-content/posts/2018/064/01')

entry.__dict__


Out[14]:
{'bookmark_of': 'https://medium.com/we-distribute/hiveway-io-shamelessly-rips-off-of-mastodon-and-slaps-a-blockchain-on-top-for-some-reason-57b7aba3e84f',
 'content': '<blockquote>\n<p>The problem here regards the nature of how Mastodon is being forked. Unfortunately for Hiveway, they give the impression of trying to actively avoid affiliation with Mastodon, going as far as <a href="https://github.com/hiveway/hiveway" title="Hiveway.io GitHub Repository">setting up a separate code repository</a> and overwriting commits that had been attributed to the original people who did the work. For Open Source contributors, this kind of thing comes across as distasteful.</p>\n</blockquote>',
 'name': 'Hiveway.io forks Mastodon and slaps a blockchain on top, for some reason',
 'path': PosixPath('/Users/myles/WebSites/mylesbraithwaite.com-content/posts/2018/064/01'),
 'published': datetime.datetime(2018, 3, 5, 8, 5, tzinfo=<toml.TomlTz object at 0x103aeb5f8>),
 'syndication': ['https://twitter.com/mylesb/statuses/970646376555208706'],
 'type': 'bookmark'}

In [22]:
class HEntries:
    
    def __init__(self, path):
        self.path = Path(path)
    
    def query(self, query, reverse=True):
        posts = [HEntry(x.parents[0]) for x in self.path.glob('posts/{}/_meta.*'.format(query))]
        posts.sort(key=lambda x: x.published, reverse=reverse)
        return posts
    
    def all(self, reverse=True):
        return self.query('**', reverse=reverse)

    def get(self, slug):
        return HEntry(self.path / 'posts' / slug)
    
    def by_year(self, year, reverse=True):
        return self.query('{}/**'.format(year), reverse=reverse)

    def by_day(self, year, day, reverse=True)
        return self.query('{0}/{1}/**'.format(year, day), reverse=reverse)
        
h = HEntries('/Users/myles/WebSites/mylesbraithwaite.com-content')

h


Out[22]:
<__main__.HEntries at 0x103b06940>

In [23]:
for p in h.all():
    print(p)


First Pull Request to the Pandas Project
/Users/myles/WebSites/mylesbraithwaite.com-content/posts/2018/069/01
/Users/myles/WebSites/mylesbraithwaite.com-content/posts/2018/068/01
The Broccoli Tree
/Users/myles/WebSites/mylesbraithwaite.com-content/posts/2018/065/01
Hiveway.io forks Mastodon and slaps a blockchain on top, for some reason
/Users/myles/WebSites/mylesbraithwaite.com-content/posts/2018/062/01
Not Moving to Portland

In [24]:
h.get('2018/069/01')


Out[24]:
HEntry(/Users/myles/WebSites/mylesbraithwaite.com-content/posts/2018/069/01)

In [ ]: