pelican-obsidian/pelican/plugins/obsidian/obsidian.py

133 lines
3.9 KiB
Python
Raw Normal View History

from pathlib import Path
from itertools import chain
import os
import re
2021-07-03 10:59:04 +00:00
from pelican import signals
from pelican.readers import MarkdownReader
from pelican.utils import pelican_open
2021-07-03 10:59:04 +00:00
from markdown import Markdown
2021-07-03 11:40:42 +00:00
ARTICLES = {}
FILES = {}
link = r'\[\[\s*(?P<filename>[\w+\s.]+)(\|\s*(?P<linkname>[\w\s]+))?\]\]'
file_re = re.compile(r'!' + link)
link_re = re.compile(link)
"""
# Test cases
[[my link]]
[[ my work ]]
[[ my work | is finished ]]
2021-07-03 10:59:04 +00:00
![[ a file.jpg ]]
![[file.jpg]]
"""
2021-07-03 10:59:04 +00:00
2021-07-03 18:41:06 +00:00
def get_file_and_linkname(match):
group = match.groupdict()
filename = group['filename'].strip()
linkname = group['linkname'] if group['linkname'] else filename
linkname = linkname.strip()
return filename, linkname
class ObsidianMarkdownReader(MarkdownReader):
2021-07-03 10:59:04 +00:00
"""
Change the format of various links to the accepted case of pelican.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def replace_obsidian_links(self, text):
2021-07-03 18:41:06 +00:00
def link_replacement(match):
filename, linkname = get_file_and_linkname(match)
2021-07-03 18:11:08 +00:00
path = ARTICLES.get(filename)
if path:
link_structure = '[{linkname}]({{filename}}/{path}/{filename}.md)'.format(
linkname=linkname, path=path, filename=filename
)
else:
link_structure = '{linkname}'.format(linkname=linkname)
return link_structure
2021-07-03 18:41:06 +00:00
def file_replacement(match):
filename, linkname = get_file_and_linkname(match)
path = FILES.get(filename)
if path:
link_structure = '![{linkname}]({{static}}/{path}/{filename})'.format(
linkname=linkname, path=path, filename=filename
)
else:
# don't show it at all since it will be broken
link_structure = ''
return link_structure
text = file_re.sub(file_replacement, text)
text = link_re.sub(link_replacement, text)
return text
def read(self, source_path):
"""Parse content and metadata of markdown files
It also changes the links to the acceptable format for pelican
"""
self._source_path = source_path
self._md = Markdown(**self.settings['MARKDOWN'])
with pelican_open(source_path) as text:
text = self.replace_obsidian_links(text)
content = self._md.convert(text)
if hasattr(self._md, 'Meta'):
metadata = self._parse_metadata(self._md.Meta)
else:
metadata = {}
return content, metadata
def populate_files_and_articles(article_generator):
global ARTICLES
global FILES
base_path = Path(article_generator.path)
articles = base_path.glob('**/*.md')
for article in articles:
full_path, filename_w_ext = os.path.split(article)
filename, ext = os.path.splitext(filename_w_ext)
full_path = str(full_path).replace(str(base_path) + '/', '')
ARTICLES[filename] = full_path
2021-07-03 18:41:06 +00:00
globs = [base_path.glob('**/*.{}'.format(ext)) for ext in ['png', 'jpg', 'svg', 'apkg', 'gif']]
files = chain(*globs)
for _file in files:
full_path, filename_w_ext = os.path.split(_file)
full_path = str(full_path).replace(str(base_path) + '/', '')
FILES[filename_w_ext] = full_path
def modify_reader(article_generator):
populate_files_and_articles(article_generator)
article_generator.readers.readers['md'] = ObsidianMarkdownReader(article_generator.settings)
2021-07-03 10:59:04 +00:00
2021-07-03 11:41:04 +00:00
def modify_metadata(article_generator, metadata):
2021-07-03 10:59:04 +00:00
"""
2021-07-03 11:41:04 +00:00
Modify the tags so we can define the tags as we are used to in obsidian.
2021-07-03 10:59:04 +00:00
"""
2021-07-03 18:11:08 +00:00
for tag in metadata.get('tags', []):
2021-07-03 11:41:04 +00:00
if '#' in tag.name:
tag.name = tag.name.replace('#', '')
2021-07-03 10:59:04 +00:00
def register():
signals.article_generator_context.connect(modify_metadata)
signals.article_generator_init.connect(modify_reader)