Giter VIP home page Giter VIP logo

devidw / obsidian-to-hugo Goto Github PK

View Code? Open in Web Editor NEW
275.0 1.0 21.0 1.12 MB

Process Obsidian notes to publish them with Hugo. Supports transformation of Obsidian wiki links into Hugo shortcodes for internal linking.

Home Page: https://obsidian-to-hugo.wolf.gdn

License: MIT License

Python 69.98% Dockerfile 0.23% Makefile 3.31% TypeScript 2.29% Astro 24.19%
obsidian-md obsidian obsidianmd obsidian-notes obsidian-publish hugo hugo-helper processing replacement replace-text

obsidian-to-hugo's Introduction


Obsidian Vault to Hugo Content

Lightweight, extensible, zero-dependency CLI written in Python to help us publish obsidian notes with hugo.

It only takes two arguments: The obsidian vault directory (--obsidian-vault-dir) and the hugo content directory (--hugo-content-dir).

python -m obsidian_to_hugo --obsidian-vault-dir=<path> --hugo-content-dir=<path>

It takes care of the following steps:

  • Clears hugo content directory (directory will be deleted and recreated)
  • Copies obsidian vault contents into hugo content directory (.obsidian gets removed immediately after copying)
  • Replaces obsidian wiki links ([[wikilink]]) with hugo shortcode links ([wikilink]({{< ref "wikilink" >}}))
  • Replaces obsidian marks (==important==) with HTML marks (<mark>important</mark>)
  • Want to do more? You can write and register custom filters to dynamically include/exclude content from processing and processors to do whatever you want with the file contents.

Replacement examples

Obsidian Hugo
[[/some/wiki/link]] [/some/wiki/link]({{< ref "/some/wiki/link" >}})
[[/some/wiki/link|Some text]] [Some text]({{< ref "/some/wiki/link" >}})
[[/some/wiki/link/_index]] [/some/wiki/link/]({{< ref "/some/wiki/link/" >}})
[[/some/wiki/link#Some Heading|Some Heading Link]] [Some Heading Link]({{< ref "/some/wiki/link#some-heading" >}})
==foo bar=== <mark>foo bar</mark>

Note For now, there is no way to escape obsidian wiki links. Every link will be replaced with a hugo link. The only way to get around this is changing the wiki link to don't match the exact sytax, for example by adding an invisible space (Obsidian will highlight the invisible character as a red dot). However, this still is really really not best practice, so if anyone wants to implement real escaping, please do so.

Installation

pip install obsidian-to-hugo

Usage

usage: __main__.py [-h] [--version] [--hugo-content-dir HUGO_CONTENT_DIR]
                   [--obsidian-vault-dir OBSIDIAN_VAULT_DIR]

options:
  -h, --help            show this help message and exit
  --version, -v         Show the version and exit.
  --hugo-content-dir HUGO_CONTENT_DIR
                        Directory of your Hugo content directory, the obsidian notes
                        should be processed into.
  --obsidian-vault-dir OBSIDIAN_VAULT_DIR
                        Directory of the Obsidian vault, the notes should be processed
                        from.

Python API

from obsidian_to_hugo import ObsidianToHugo

obsidian_to_hugo = ObsidianToHugo(
    obsidian_vault_dir="path/to/obsidian/vault",
    hugo_content_dir="path/to/hugo/content",
)

obsidian_to_hugo.run()

Filters

You can pass an optional filters argument to the ObsidianToHugo constructor. This argument should be a list of functions.

The function will be invoked for each file from the obsidian vault that is copied into the hugo content directory.

Inside the function, you have access to the file path and the file contents.

When the function returns False, the file will be skipped and not copied into the hugo content directory.

from obsidian_to_hugo import ObsidianToHugo

def filter_file(file_contents: str, file_path: str) -> bool:
    # do something with the file path and contents
    if your_condition:
        return True # copy file
    else:
        return False # skip file

obsidian_to_hugo = ObsidianToHugo(
    obsidian_vault_dir="path/to/obsidian/vault",
    hugo_content_dir="path/to/hugo/content",
    filters=[filter_file],
)

obsidian_to_hugo.run()

Processors

You can pass an optional processors argument to the ObsidianToHugo constructor. This argument should be a list of functions.

The function will be invoked for each file from the obsidian vault that is copied into the hugo content directory. It will be passed the file contents as string, and should return the processed version of the file contents.

Custom processors are invoked after the default processing of the file contents.

from obsidian_to_hugo import ObsidianToHugo

def process_file(file_contents: str) -> str:
    # do something with the file contents
    return file_contents

obsidian_to_hugo = ObsidianToHugo(
    obsidian_vault_dir="path/to/obsidian/vault",
    hugo_content_dir="path/to/hugo/content",
    processors=[process_file],
)

obsidian_to_hugo.run()

obsidian-to-hugo's People

Contributors

anakojm avatar dependabot[bot] avatar devidw avatar frederikb96 avatar green-leader avatar portevent avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

obsidian-to-hugo's Issues

Links to headings not converted correctly if containing spaces or upper case letters

If you have a space or upper case letters in your headings in Obsidian and have an internal link pointing to this heading, it will exactly look like the heading (containing spaces and upper case letters).

Obsidian:

# My Heading containing upper case letters and spaces

# H2

Link to heading 1:

[[#My Heading containing upper case letters and spaces]]

However, in hugo the heading ids are generated as all lower case ids and spaces are replaced by a minus, as described in the documentation.

So in hugo it should look like this:

# My Heading containing upper case letters and spaces

# H2

Link to heading 1:

[#My Heading containing upper case letters and spaces]({{< ref "#my-heading-containing-upper-case-letters-and-spaces" >}})

Though, with your code, the links to the headings, stay the same. Btw: this is only necessary for links to headings, since links to pages are automatically adjusted by hugo, such that spaces are replaced by a minus and upper case letters converted to lower case.

I forked your project and provided a fix for this problem and will create a pull request, you can look into, if you feel like :)

mark support

Hi, what do you think of adding support for converting markdown ==marks== so they are displayed correctly in html as :<mark>marks</mark>.
I already added support in my fork so I can open a PR if you want

Codeblocks should not be parsed

Obsidian-to-hugo wrongly convert the following:

```python
if foo==bar and foo==baz:
    L = [[12,42],[13,90]]
```

to

```python
if foo<mark>bar and foo</mark>baz:
    L = [12,42],[13,90]({{< ref "12,42],[13,90" >}})
```

Codeblocks should instead be skipped to prevent such false positives (I have no idea how to implement this).

TypeError: 'type' object is not subscriptable

I did a pip install in a WSL container.

Trying to import the module from a Python 3 REPL results in:

$ python3
Python 3.8.10 (default, Nov 14 2022, 12:59:47)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from obsidian_to_hugo import ObsidianToHugo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/me/.local/lib/python3.8/site-packages/obsidian_to_hugo/__init__.py", line 1, in <module>
    from .obsidian_to_hugo import ObsidianToHugo
  File "/home/me/.local/lib/python3.8/site-packages/obsidian_to_hugo/obsidian_to_hugo.py", line 8, in <module>
    from .wiki_links_processor import replace_wiki_links
  File "/home/me/.local/lib/python3.8/site-packages/obsidian_to_hugo/wiki_links_processor.py", line 12, in <module>
    def get_wiki_links(text: str) -> list[WikiLink]:
TypeError: 'type' object is not subscriptable
>>>

Hugo fails to build site if page has a link

Thank you for sharing your code.

I installed via pip3 , then uninstalled and installed development version via make after cloning the repo. Encountered the same issue with both.

Created two pages in the Obsidian vault:

index.md

This is a [[test]]

test.md

Only a test.

After running python3 -m obsidian_to_hugo ..., I see these two files created in the Hugo content folder:

index.md

This is a [test]({{< ref "test" >}})

test.md

Only a test.

When I run hugo, I get the following error:

hugo server -D --disableFastRender
Start building sites … 
hugo v0.104.3+extended darwin/arm64 BuildDate=unknown
ERROR 2022/10/09 02:14:41 [en] REF_NOT_FOUND: Ref "test": "/---/content/index.md:1:18": page not found
Error: Error building site: logged 1 error(s)

I have no idea what I'm doing wrong as I'm new to Obsidian, Hugo and this script.

I have tried "PaperMod" and "etch" themes, no difference.

Any help is appreciated :)

Export only flagged files

Hello,
Is there a way of exporting only certain files. For example flagged with "export: true" in frontmatter?
Moreover, links to files that are not exported should also be omitted.
For example, I have three files, and only two of them are exported.

I like.md

---
export: true
---

I like:
- [[I like motorcycles]]
- [[I like cars]]

I like motorcycles.md

---
export: true
---
I like Honda Africa twin

I like cars.md

The result would be

I like.md

I like:
- [I like motorcycles]({{< ref "I like motorcycles" >}})
- I like cars

I like motorcycles.md

I like Honda Africa twin

processors seem not to be ideal as they do they just transform the content of files not filter the list of files.

Issue with processor Use in Obsidian-to-Hugo Conversion

Hello, I'm facing challenges understanding the usage of processor. I have a list of tuples named error_description in my Obsidian double-links, which I'd like to keep unaltered during the Obsidian-to-Hugo conversion. I am attempting to use processors to replace [[error_description]] with (error_description) during this process.

However, I've noticed that the code seems to go directly to the else block, printing Debug: No match for [[error_description]]). I confirmed that [[error_description]] does indeed exist in the original text. Below is the snippet of code in question:

def process_file(file_contents: str) -> str:
    processed_contents = file_contents
    print(f"Debug: error_descriptions = {error_descriptions}")
    for error_description in error_descriptions:
        search_str = f'[[error_description]])'
        print(f"Debug: Looking for {search_str}")
        if search_str in processed_contents:
            print(f"Debug: Replacing {search_str}")
            processed_contents = processed_contents.replace(search_str, f'({error_description})')
        else:
            print(f"Debug: No match for {search_str}")
    print(f"Debug: Final file contents: {processed_contents[:100]}")  # Output the first 100 chars after modification

# Build and Run ObsidianToHugo
obsidian_to_hugo = ObsidianToHugo(
    obsidian_vault_dir=obsidian_vault_dir_path,
    hugo_content_dir=hugo_content_dir_path,
    processors=[process_file],
)
obsidian_to_hugo.run()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.