diff --git a/Makefile b/Makefile index 4ba061e..d7e2d57 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,9 @@ install: - cp notes2web /usr/local/bin + cp notes2web.py /usr/local/bin + pip install -r requirement.txt mkdir -p /opt/notes2web cp -r templates /opt/notes2web cp styles.css /opt/notes2web uninstall: - rm -rf /usr/local/bin/notes2web/opt/notes2web + rm -rf /usr/local/bin/notes2web.py /opt/notes2web diff --git a/notes2web b/notes2web deleted file mode 100755 index 5fbba21..0000000 --- a/notes2web +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env bash - - -# set default config values, load user config, export config variables -name="" -output="web" -article_template="/opt/notes2web/templates/article.html" -textarticlehead_template="/opt/notes2web/templates/textarticlehead.html" -textarticlefoot_template="/opt/notes2web/templates/textarticlefoot.html" -listitem_template="/opt/notes2web/templates/listitem.html" -index_template="/opt/notes2web/templates/index.html" -stylesheet="/opt/notes2web/styles.css" - -for configpath in "$HOME/.notes2web.conf" "$HOME/.config/notes2web/config" ".notes2web.conf" -do - [[ -f "$configpath" ]] && source "$configpath" -done - -export name -export output -export article_template -export textarticlehead_template -export textarticlefoot_template -export listitem_template -export index_template -export stylesheet - - -[[ "$1" == "--help" ]] && echo "USAGE: $0 [NOTES_DIRECTORY_1 [NOTES_DIRECTORY_2 [...]]]" && exit 0 -[[ "$1" == "--clean" ]] && { - find -name ".2web" -exec rm {} \; - rm -rf "$output" - exit 0 -} - - -mkdir -p "$output" - - -function _renderarticle { - echo "rendering $1" - mkdir -p "$(dirname "$output/${1}.html")" - pandoc\ - --toc\ - --standalone\ - -t html\ - --template "$article_template"\ - -o "$output/${1}.html"\ - "$1"\ - --mathjax -} - - -function _rendertextarticle { - [[ "$(file -b "$1")" == "ASCII text" ]] || exit - echo "rendering text file $1" - mkdir -p "$(dirname "$output/${1}.html")" - sed -e "s#\\\$title\\\$#$1#" "$textarticlehead_template"\ - > "$output/${1}.html" - cat "$1" >> "$output/${1}.html" - cat "$textarticlefoot_template" >> "$output/${1}.html" -} - - -function _adddirtoindex { - dir="$(dirname "$1")" - echo "

$(basename "$dir") notes

" >> $output/index.md - find "$dir" -name '*.md' -exec bash -c "_addarticletoindex '{}'" \; - find "$dir" -not -path '**/.git/**' -not -name '*.md' -type f -exec bash -c "_addtextarticletoindex '{}'" \; -} - - -function _addtextarticletoindex { - [[ "$(file -b "$1")" == "ASCII text" ]] || exit - pandoc\ - -t html\ - -V "filepath=${1}.html"\ - -V "title=$1"\ - --template "$listitem_template"\ - "$1"\ - >> $output/index.md -} - - -function _addarticletoindex { - echo "adding $1 to list of notes" - pandoc\ - -t html\ - -V "filepath=${1}.html"\ - --template "$listitem_template"\ - "$1"\ - >> $output/index.md -} - - -export -f _renderarticle -export -f _rendertextarticle -export -f _adddirtoindex -export -f _addarticletoindex -export -f _addtextarticletoindex - - -#render each markdown file in every folder passed in args -for dir in "$@" -do - find "$dir" -name '*.md' -exec bash -c "_renderarticle '{}'" \; - find "$dir" -not -path '**/.git/**' -not -name '*.md' -type f -exec bash -c "_rendertextarticle '{}'" \; -done - - -# create an intermediate markdown file of links to each article -echo "---" > $output/index.md -[[ -z "$name" ]] && echo "title: notes" >> $output/index.md || echo "title: ${name}'s notes" >> $output/index.md -echo "---" >> $output/index.md - - -# mark folders to be included in notes2web's index -for file in "$@" -do - [[ ! -f "$file" ]] && echo "the presence of this files tells notes2web that it should be added to the notes2web index" > "$file/.2web" -done - - -# add articles to index and render -find -name '.2web' -exec bash -c "_adddirtoindex '{}'" \; - - -echo "copying styles.css to current directory" -cp "$stylesheet" "$output/styles.css" - - -echo "rendering index.md" -pandoc\ - -t html\ - --template "$index_template"\ - -o "$output/index.html"\ - "$output/index.md" diff --git a/notes2web.py b/notes2web.py new file mode 100755 index 0000000..a8a7764 --- /dev/null +++ b/notes2web.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 + + +from bs4 import BeautifulSoup as bs +import magic +import sys +import pathlib +import pypandoc +import shutil +import os +import re + +TEXT_ARTICLE_TEMPLATE_FOOT = None +TEXT_ARTICLE_TEMPLATE_HEAD = None +INDEX_TEMPLATE_FOOT = None +INDEX_TEMPLATE_HEAD = None + +def get_files(folder): + markdown = [] + plaintext = [] + other = [] + + for root, folders, files in os.walk(folder): + for filename in files: + name = os.path.join(root, filename) + if os.path.splitext(name)[1] == '.md': + markdown.append(name) + elif re.match(r'^text/', magic.from_file(name, mime=True)): + plaintext.append(name) + other.append(name) + else: + other.append(name) + + return markdown, plaintext, other + +def get_dirs(folder): + r = [] + + for root, folders, files in os.walk(folder): + [r.append(os.path.join(root, folder)) for folder in folders] + + return r + + +def get_args(): + """ Get command line arguments """ + + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('notes', type=pathlib.Path) + parser.add_argument('-o', '--output-dir', type=pathlib.Path, default='web') + parser.add_argument('-t', '--template', type=pathlib.Path, default=pathlib.Path('/opt/notes2web/templates/article.html')) + parser.add_argument('-H', '--template-text-head', type=pathlib.Path, default=pathlib.Path('/opt/notes2web/templates/textarticlehead.html')) + parser.add_argument('-f', '--template-text-foot', type=pathlib.Path, default=pathlib.Path('/opt/notes2web/templates/textarticlefoot.html')) + parser.add_argument('-i', '--template-index-head', type=pathlib.Path, default=pathlib.Path('/opt/notes2web/templates/indexhead.html')) + parser.add_argument('-I', '--template-index-foot', type=pathlib.Path, default=pathlib.Path('/opt/notes2web/templates/indexfoot.html')) + parser.add_argument('-s', '--stylesheet', type=pathlib.Path, default=pathlib.Path('/opt/notes2web/styles.css')) + return parser.parse_args() + + +def main(args): + """ Entry point for script """ + + with open(args.template_text_foot) as fp: + TEXT_ARTICLE_TEMPLATE_FOOT = fp.read() + + with open(args.template_text_head) as fp: + TEXT_ARTICLE_TEMPLATE_HEAD = fp.read() + + with open(args.template_index_foot) as fp: + INDEX_TEMPLATE_FOOT = fp.read() + + with open(args.template_index_head) as fp: + INDEX_TEMPLATE_HEAD = fp.read() + + if not os.path.exists(args.output_dir): + os.makedirs(args.output_dir, exist_ok=True) + + if os.path.isfile(args.output_dir): + print("Output directory ({output_dir}) cannot be a file.") + + + markdown_files, plaintext_files, other_files = get_files(args.notes) + + print(f"{markdown_files=}") + for filename in markdown_files: + html = pypandoc.convert_file(filename, 'html', extra_args=[f'--template={args.template}']) + output_filename = os.path.splitext(re.sub(f"^{args.notes.name}", args.output_dir.name, filename))[0] + '.html' + os.makedirs(os.path.dirname(output_filename), exist_ok=True) + + with open(output_filename, 'w+') as fp: + fp.write(html) + + print(f"{plaintext_files=}") + for filename in plaintext_files: + output_filename = re.sub(f"^{args.notes.name}", args.output_dir.name, filename) + '.html' + os.makedirs(os.path.dirname(output_filename), exist_ok=True) + title = os.path.basename(output_filename) + html = re.sub(r'\$title\$', title, TEXT_ARTICLE_TEMPLATE_HEAD) + html = re.sub(r'\$raw\$', os.path.basename(filename), html) + with open(filename) as fp: + html += fp.read() + html += TEXT_ARTICLE_TEMPLATE_FOOT + + with open(output_filename, 'w+') as fp: + fp.write(html) + + print(f"{other_files=}") + for filename in other_files: + output_filename = re.sub(f"^{args.notes.name}", args.output_dir.name, filename) + os.makedirs(os.path.dirname(output_filename), exist_ok=True) + shutil.copyfile(filename, output_filename) + + + dirs_to_index = [args.output_dir.name] + get_dirs(args.output_dir) + print(f"{dirs_to_index=}") + for directory in dirs_to_index: + paths = os.listdir(directory) + print(f"{paths=}") + + indexentries = [] + + for path in paths: + if path == 'index.html': + continue + + fullpath = os.path.join(directory, path) + print(fullpath) + if os.path.splitext(path)[1] == '.html': + with open(fullpath) as fp: + soup = bs(fp.read(), 'html.parser') + + try: + title = soup.find('title').get_text() + except AttributeError: + title = path + else: + title = path + + if title.strip() == '': + title = path + + indexentries.append({ + 'title': title, + 'path': path, + 'isdirectory': os.path.isdir(fullpath) + }) + + indexentries.sort(key=lambda entry: entry['title']) + indexentries.sort(key=lambda entry: entry['isdirectory'], reverse=True) + + html = re.sub(r'\$title\$', directory, INDEX_TEMPLATE_HEAD) + for entry in indexentries: + html += f"
{entry['title']}{'/' if entry['isdirectory'] else ''}
" + html += INDEX_TEMPLATE_FOOT + + with open(os.path.join(directory, 'index.html'), 'w+') as fp: + fp.write(html) + + shutil.copyfile(args.stylesheet, os.path.join(args.output_dir.name, 'styles.css')) + + return 0 + + +if __name__ == '__main__': + try: + sys.exit(main(get_args())) + except KeyboardInterrupt: + sys.exit(0) diff --git a/readme.md b/readme.md index 0b15af7..84c0175 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,7 @@ View your notes as a static html site. ## Usage ``` -$ notes2web NOTES_DIRECTORY_1 [NOTES_DIRECTORY_2 [...]] +$ notes2web.py NOTES_DIRECTORY_1 [NOTES_DIRECTORY_2 [...]] ``` The command will generate a website in the `$output` directory (`./web` by default). @@ -28,6 +28,8 @@ Then you just have to point a webserver at `$output`. ## Config +NOT CURRENTLY IMPLEMENTED + `notes2web` looks for a config file called `.notes2web.conf` in your current directory and your home directory. Default config values: diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9056194 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +beautifulsoup4==4.9.3 +pypandoc==1.5 +soupsieve==2.2.1 diff --git a/templates/indexfoot.html b/templates/indexfoot.html new file mode 100644 index 0000000..3de525c --- /dev/null +++ b/templates/indexfoot.html @@ -0,0 +1,2 @@ +

page generated by notes2web

+ diff --git a/templates/indexhead.html b/templates/indexhead.html new file mode 100644 index 0000000..6f5b02e --- /dev/null +++ b/templates/indexhead.html @@ -0,0 +1,11 @@ + + + + + +$title$ + + + +

$title$

+
../
diff --git a/templates/textarticlehead.html b/templates/textarticlehead.html index a2f7ed9..8c69998 100644 --- a/templates/textarticlehead.html +++ b/templates/textarticlehead.html @@ -10,6 +10,7 @@

$title$

This file was not rendered by notes2web because it is a plaintext file, not a markdown file. + You access the raw file here. Below is an unformatted representation of the file: