Files
pelican-obsidian/pelican/plugins/obsidian/obsidian.py
T
tanner 7ee02b03d1 Include "/" in empty paths
When articles were in the base directory, the string replacement:
`str(full_path).replace(str(base_path) + '/'`
would not match, causing the whole absolute path to be included which
would break the link.

This should now work if the article is in the base directory or in any
subfolder.
2022-04-22 15:34:27 -06:00

133 lines
3.9 KiB
Python

from pathlib import Path
from itertools import chain
import os
import re
from pelican import signals
from pelican.readers import MarkdownReader
from pelican.utils import pelican_open
from markdown import Markdown
ARTICLE_PATHS = {}
FILE_PATHS = {}
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 ]]
![[ a file.jpg ]]
![[file.jpg]]
"""
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):
"""
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):
def link_replacement(match):
filename, linkname = get_file_and_linkname(match)
path = ARTICLE_PATHS.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
def file_replacement(match):
filename, linkname = get_file_and_linkname(match)
path = FILE_PATHS.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 ARTICLE_PATHS
global FILE_PATHS
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)
path = str(full_path).replace(str(base_path), '') + '/'
ARTICLE_PATHS[filename] = path
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)
path = str(full_path).replace(str(base_path), '') + '/'
FILE_PATHS[filename_w_ext] = path
def modify_reader(article_generator):
populate_files_and_articles(article_generator)
article_generator.readers.readers['md'] = ObsidianMarkdownReader(article_generator.settings)
def modify_metadata(article_generator, metadata):
"""
Modify the tags so we can define the tags as we are used to in obsidian.
"""
for tag in metadata.get('tags', []):
if '#' in tag.name:
tag.name = tag.name.replace('#', '')
def register():
signals.article_generator_context.connect(modify_metadata)
signals.article_generator_init.connect(modify_reader)