diff --git a/obsidianhtml/MarkdownPage.py b/obsidianhtml/MarkdownPage.py
index c26da55f..e1142d2f 100644
--- a/obsidianhtml/MarkdownPage.py
+++ b/obsidianhtml/MarkdownPage.py
@@ -33,9 +33,8 @@ def __init__(self, src_path, src_folder_path, file_tree):
self.codelines = []
# Load contents of entrypoint and strip frontmatter yaml.
- page = frontmatter.load(str(src_path))
- self.page = page.content
- self.yaml = page
+ with open(src_path, encoding="utf-8") as f:
+ self.metadata, self.page = frontmatter.parse(f.read())
def SetDestinationPath(self, dst_folder_path, entrypoint_src_path):
"""Set destination path of the converted file. Both full and relative paths are set."""
@@ -64,6 +63,23 @@ def RestoreCodeSections(self):
for i, value in enumerate(self.codelines):
self.page = self.page.replace(f'%%%codeline-placeholder-{i}%%%', f"`{value}`")
+ def AddToTagtree(self, tagtree, url=''):
+ if 'tags' not in self.metadata:
+ return
+
+ if url == '':
+ url = str(self.dst_path)
+
+ for tag in self.metadata['tags']:
+ ctagtree = tagtree
+ for n, subtag in enumerate(tag.split('/')):
+ if subtag not in ctagtree['subtags'].keys():
+ ctagtree['subtags'][subtag] = {'notes': [], 'subtags': {}}
+ ctagtree = ctagtree['subtags'][subtag]
+
+ if n == (len(tag.split('/')) - 1):
+ ctagtree['notes'].append(url)
+
def ConvertObsidianPageToMarkdownPage(self, dst_folder_path, entrypoint_path, include_depth=0):
"""Full subroutine converting the Obsidian Code to proper markdown. Linked files are copied over to the destination folder."""
# -- Load contents
diff --git a/obsidianhtml/PicknickBasket.py b/obsidianhtml/PicknickBasket.py
new file mode 100644
index 00000000..93f8fde1
--- /dev/null
+++ b/obsidianhtml/PicknickBasket.py
@@ -0,0 +1,11 @@
+class PicknickBasket:
+ files = None
+ tagtree = None
+ config = None
+ paths = None
+ html_template = None
+
+ def __init__(self, config, paths):
+ self.config = config
+ self.tagtree = {'notes': [], 'subtags': {}}
+ self.paths = paths
\ No newline at end of file
diff --git a/obsidianhtml/__init__.py b/obsidianhtml/__init__.py
index 4df54f55..515f83e3 100644
--- a/obsidianhtml/__init__.py
+++ b/obsidianhtml/__init__.py
@@ -6,18 +6,25 @@
import markdown # convert markdown to html
import yaml
import urllib.parse # convert link characters like %
+import frontmatter
+
from .MarkdownPage import MarkdownPage
from .MarkdownLink import MarkdownLink
from .lib import DuplicateFileNameInRoot, GetObsidianFilePath, image_suffixes
+from .PicknickBasket import PicknickBasket
# Open source files in the package
import importlib.resources as pkg_resources
-from . import src # relative-import the *package* containing the templates
+from . import src
# python run.py 'C:\Users\Installer\OneDrive\Obsidian\Notes' "C:\Users\Installer\OneDrive\Obsidian\Notes\Devfruits Notes.md" "output/md" "output/html" "Devfruits/Notes"
-def recurseObisidianToMarkdown(page_path_str, paths, files, conf):
+def recurseObisidianToMarkdown(page_path_str, pb):
+ paths = pb.paths
+ files = pb.files
+ conf = pb.config
+
# Convert path string to Path and do a double check
page_path = Path(page_path_str).resolve()
if page_path.exists() == False:
@@ -28,6 +35,9 @@ def recurseObisidianToMarkdown(page_path_str, paths, files, conf):
md = MarkdownPage(page_path, paths['obsidian_folder'], files)
md.ConvertObsidianPageToMarkdownPage(paths['md_folder'], paths['obsidian_entrypoint'])
+ # Add yaml frontmatter back in
+ md.page = (frontmatter.dumps(frontmatter.Post("", **md.metadata))) + '\n' + md.page
+
# -- Save file
# Create folder if necessary
md.dst_path.parent.mkdir(parents=True, exist_ok=True)
@@ -49,10 +59,14 @@ def recurseObisidianToMarkdown(page_path_str, paths, files, conf):
# Convert the note that is linked to
if conf['toggles']['verbose_printout']:
print(f"converting {files[link_path]['fullpath']} (parent {page_path})")
- recurseObisidianToMarkdown(files[link_path]['fullpath'], paths, files, conf)
+ recurseObisidianToMarkdown(files[link_path]['fullpath'], pb)
-def ConvertMarkdownPageToHtmlPage(page_path_str, paths, files, html_template, conf):
+def ConvertMarkdownPageToHtmlPage(page_path_str, pb):
page_path = Path(page_path_str).resolve()
+ paths = pb.paths
+ files = pb.files
+ html_template = pb.html_template
+ conf = pb.config
if page_path.exists() == False:
return
@@ -171,6 +185,8 @@ def ConvertMarkdownPageToHtmlPage(page_path_str, paths, files, html_template, co
md.dst_path.parent.mkdir(parents=True, exist_ok=True)
html_dst_path_posix = md.dst_path.as_posix()[:-3] + '.html'
+ md.AddToTagtree(pb.tagtree, md.dst_path.relative_to(paths['html_output_folder']).as_posix()[:-3] + '.html')
+
# Write html
with open(html_dst_path_posix, 'w', encoding="utf-8") as f:
f.write(html)
@@ -195,7 +211,38 @@ def ConvertMarkdownPageToHtmlPage(page_path_str, paths, files, html_template, co
if conf['toggles']['verbose_printout']:
print("html: converting ", files[link_path]['fullpath'], " (parent ", md.src_path, ")")
- ConvertMarkdownPageToHtmlPage(files[link_path]['fullpath'], paths, files, html_template, conf)
+ ConvertMarkdownPageToHtmlPage(files[link_path]['fullpath'], pb)
+
+def recurseTagList(tagtree, tagpath, pb):
+ html_url_prefix = pb.config['html_url_prefix']
+ tag_dst_path = pb.paths['html_output_folder'].joinpath(f'{tagpath}index.html').resolve()
+ tag_dst_path_posix = tag_dst_path.as_posix()
+ rel_dst_path_as_posix = tag_dst_path.relative_to(pb.paths['html_output_folder']).as_posix()
+
+ # Compile markdown
+ md = ''
+ if len(tagtree['subtags'].keys()) > 0:
+ md += '# Subtags\n'
+ for key in tagtree['subtags'].keys():
+ rel_key_path_as_posix = recurseTagList(tagtree['subtags'][key], tagpath + key + '/', pb)
+ md += f'- [{key}](/{rel_key_path_as_posix})' + '\n'
+
+ if len(tagtree['notes']) > 0:
+ md = '\n# Notes\n'
+ for note in tagtree['notes']:
+ md += f'- [{note.replace(".html", "")}]({html_url_prefix}/{note})\n'
+
+ # Compile html
+ html_body = markdown.markdown(md, extensions=['extra', 'codehilite', 'toc'])
+ html_body = html_body.replace('', '')
+ html = pb.html_template.replace('{content}', html_body).replace('{title}', pb.config['site_name']).replace('{html_url_prefix}', pb.config['html_url_prefix'])
+
+ # Write file
+ tag_dst_path.parent.mkdir(parents=True, exist_ok=True)
+ with open(tag_dst_path_posix, 'w', encoding="utf-8") as f:
+ f.write(html)
+
+ return rel_dst_path_as_posix
def main():
# Config
@@ -276,6 +323,8 @@ def main():
paths['md_folder'].mkdir(parents=True, exist_ok=True)
paths['html_output_folder'].mkdir(parents=True, exist_ok=True)
+ # Make "global" object that we can pass so functions
+ pb = PicknickBasket(conf, paths)
# Convert Obsidian to markdown
# ------------------------------------------
@@ -290,10 +339,12 @@ def main():
files[path.name] = {'fullpath': str(path), 'processed': False}
+ pb.files = files
+
# Start conversion with entrypoint.
# Note: this will mean that any note not (indirectly) linked by the entrypoint will not be included in the output!
print(f'> COMPILING MARKDOWN FROM OBSIDIAN CODE ({str(paths["obsidian_entrypoint"])})')
- recurseObisidianToMarkdown(str(paths['obsidian_entrypoint']), paths, files, conf)
+ recurseObisidianToMarkdown(str(paths['obsidian_entrypoint']), pb)
# Convert Markdown to Html
@@ -321,8 +372,14 @@ def main():
rel_path_posix = path.relative_to(paths['md_folder']).as_posix()
files[rel_path_posix] = {'fullpath': str(path.resolve()), 'processed': False}
+ pb.files = files
+ pb.html_template = html_template
+
# Start conversion from the entrypoint
- ConvertMarkdownPageToHtmlPage(str(paths['md_entrypoint']), paths, files, html_template, conf)
+ ConvertMarkdownPageToHtmlPage(str(paths['md_entrypoint']), pb)
+
+ # Create tag page
+ recurseTagList(pb.tagtree, 'tags/', pb)
# Add Extra stuff to the output directories
# ------------------------------------------
diff --git a/pypi_readme.md b/pypi_readme.md
index 0ddc7a54..e02aad12 100644
--- a/pypi_readme.md
+++ b/pypi_readme.md
@@ -15,6 +15,7 @@ To convert your notes, you need to point to your notes folder, and to one note t
Only notes that are found by following links recursively, starting with the entrypoint, will be converted!
**Changelog**:
-0.0.4: Added the option to use a custom html template, and to export the packaged template.
-0.0.3: Updated readme file to work with pypi.
-0.0.2: Updated readme file to work with pypi.
\ No newline at end of file
+- 0.0.5: Tag list added.
+- 0.0.4: Added the option to use a custom html template, and to export the packaged template.
+- 0.0.3: Updated readme file to work with pypi.
+- 0.0.2: Updated readme file to work with pypi.
\ No newline at end of file
diff --git a/readme.md b/readme.md
index 45ebd21e..e7e357a3 100644
--- a/readme.md
+++ b/readme.md
@@ -82,7 +82,7 @@ This will make sure future runs of obsidianhtml will use your custom template (p
# Features
## Not supported
-- Tags (you can use them in Obsidian, but they are ignored in the conversion)
+- Inline tags (you can use them in Obsidian, but they are ignored in the conversion). Frontmatter tags are converted to a tag list, see below.
- Possibly a lot more
## Conversion of Obsidian type links
@@ -115,6 +115,10 @@ When using the format `![[Name of note]]`, the contents of the note will be incl
This package also supports partial inclusions. You can use this by writing `![[Name of note#Chapter Name]]`. In this case, only that chapter and its contents until the next chapter of the same depth is included. See also [Example Website#partial-code-inclusion](https://obsidian-html.github.io/#!partial-code-inclusion).
+## Frontmatter Tag list
+Inline tags are excluded, but those listed in the yaml frontmatter are compiled into a list.
+When running your website, go to `/tags` to view the tag list. [Example](https://obsidian-html.github.io/tags/).
+
## Basic Templating
All generated html code will be wrapped by the html code in `src/template.html`. This template points to `src/main.css`.
Change this code *in the `/src` folder* to have the changes persist across runs of the code (output will be overwritten).
diff --git a/setup.cfg b/setup.cfg
index 5306104d..7cd33226 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = obsidianhtml
-version = 0.0.4
+version = 0.0.5
summary = Converts Obsidian notes into proper markdown and HTML
long_description = file: pypi_readme.md
home-page = https://github.com/obsidian-html/obsidian-html