Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I updated the notion exporter to modified my newer notion2md exporter #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
__pychache__/
.vscode/
3 changes: 0 additions & 3 deletions .vscode/settings.json

This file was deleted.

74 changes: 74 additions & 0 deletions build_site.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import streamlit as st
import base64
import shutil
from zipfile import ZipFile
from pathlib import Path
import notion
import os
from notion.client import NotionClient
import requests
import sys
from exporter import PageBlockExporter

def export_cli(token_v2,url):
if not(os.path.isdir(directory)):
os.makedirs(os.path.join(directory))

client=NotionClient(token_v2=token_v2)
url=url

exporter = PageBlockExporter(url,client)
exporter.create_main_folder(directory)
exporter.create_file()
export(exporter)

def export(exporter):
"""Recursively export page block with its sub pages

Args:
exporter(PageBlockExporter()): export page block
"""
exporter.page2md(tapped = 0)
try:
exporter.write_file()
except:
st.markdown(f"Error exporting {exporter.title}.md!")
for sub_exporter in exporter.sub_exporters:
export(sub_exporter)

def zipdir(path, ziph):
# ziph is zipfile handle
for root, dirs, files in os.walk(path):
for file in files:
ziph.write(os.path.join(root, file))

# main proc starts here
st.title("Notion Markdown Exporter")
st.markdown("This Web app is developed by [Shuyi Wang](https://twitter.com/wshuyi) based on [Eunchan Cho(@echo724)\'s notion2md](https://github.com/echo724/notion2md)")
st.markdown("The coressponding [Github Page of this app is here](https://github.com/wshuyi/demo-notion-markdown-exporter).")


token_v2 = st.text_input("Your Notion token_v2:")
url = st.text_input("The Link or ID you want to export:")

running = False

directory='./notion_output/'

if token_v2 and url and not running:
if st.button("export"):
running = True

if Path(directory).exists():
shutil.rmtree(Path(directory))
export_cli(token_v2, url)
with ZipFile('exported.zip', 'w') as myzip:
zipdir(directory, myzip)
with open('exported.zip', "rb") as f:
bytes = f.read()
b64 = base64.b64encode(bytes).decode()
href = f'<a href="data:file/zip;base64,{b64}" download=\'exported.zip\'>\
Click to download\
</a>'
st.markdown(href, unsafe_allow_html=True)
running = False
254 changes: 254 additions & 0 deletions exporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
import os
import requests
from datetime import datetime

class PageBlockExporter:
def __init__(self,url,client):
self.client = client
self.page = self.client.get_block(url)
self.title = self.page.title
self.file_name = self.page.title
self.md = ""
self.image_dir=""
self.download_dir=""
self.sub_exporters = []

def create_main_folder(self,directory):
"""create folder with file name

Args:
directory(Stirng): set empty by default.
"""
self.dir = directory + self.title +'/'

if not(os.path.isdir(self.dir)):
os.makedirs(os.path.join(self.dir))

def create_folder(self,directory):
"""create folder with directory

Args:
directory(Stirng): set empty by default.
"""
self.dir = directory

if not(os.path.isdir(self.dir)):
os.makedirs(os.path.join(self.dir))

def create_sub_folder(self):
"""create sub folder with current file name

Args:
directory(Stirng): set empty by default.
"""
self.sub_dir = self.dir + 'subpage/'
if not(os.path.isdir(self.sub_dir)):
os.makedirs(os.path.join(self.sub_dir))

def create_file(self):
"""create md file that md will be stored

Returns:
self.file(String): path of file
"""
file_path = os.path.join(self.dir ,self.file_name + '.md')
self.file = open(file_path,'w')
return file_path

def write_file(self):
"""save markdown output in the file
"""
self.file.write(self.md)
self.file.close()

def create_image_foler(self):
"""create image output directory
"""
self.image_dir = os.path.join(self.dir,'image/')
if not(os.path.isdir(self.image_dir)):
os.makedirs(os.path.join(self.image_dir))

def image_export(self,url,count):
"""make image file based on url and count.

Args:
url(Stirng): url of image
count(int): the number of image in the page

Returns:
image_path(String): image_path for the link in markdown
"""
if self.image_dir is "":
self.create_image_foler()

image_path = self.image_dir + 'img_{0}.png'.format(count)
r = requests.get(url, allow_redirects=True)
open(image_path,'wb').write(r.content)
return image_path

def create_download_foler(self):
"""create download output directory
"""
self.download_dir = os.path.join(self.dir,'download/')
if not(os.path.isdir(self.download_dir)):
os.makedirs(os.path.join(self.download_dir))

def downlaod_file(self,url,file_name):
"""download a file in the page.

Args:
url(Stirng): url of the downlaod file
file_name(String): name of the file

Returns:
None
"""
if self.download_dir is "":
self.create_download_foler()

download_path = self.download_dir + file_name
r = requests.get(url, allow_redirects=True)
open(download_path,'wb').write(r.content)

def block2md(self,block):
try:
btype = block.type
except:
print(block)
return
if btype != "numbered_list":
numbered_list_index = 0
try:
bt = block.title
except:
pass
if btype == 'header':
return "# " + bt
if btype == "sub_header":
return "## " +bt
if btype == "sub_sub_header":
return "### " +bt
if btype == 'page':
self.create_sub_folder()
sub_url = block.get_browseable_url()
exporter = PageBlockExporter(sub_url,self.client)
exporter.create_folder(self.sub_dir)
sub_page_path = exporter.create_file()
try:
if "https:" in block.icon:
icon = "!"+link_format("",block.icon)
else:
icon = block.icon
except:
icon = ""
self.sub_exporters.append(exporter)
return icon + link_format(exporter.file_name,sub_page_path)
if btype == 'text':
if bt == "":
return
return bt +" "
if btype == 'bookmark':
return link_format(bt,block.link)
if btype == "video" or btype == "file" or btype =="audio" or btype =="pdf" or btype == "gist":
return link_format(block.source,block.source)
if btype == "bulleted_list" or btype == "toggle":
return '- '+bt
if btype == "numbered_list":
numbered_list_index += 1
return str(numbered_list_index)+'. ' + bt
if btype == "image":
img_count += 1
img_path = self.image_export(block.source,img_count)
return "!"+link_format(img_path,img_path)
if btype == "code":
return "``` "+block.language.lower()+"\n"+block.title+"\n```"
if btype == "equation":
return "$$"+block.latex+"$$"
if btype == "divider":
return "---"
if btype == "to_do":
if block.checked:
return "- [x] "+ bt
else:
return "- [ ]" + bt
if btype == "quote":
return "> "+bt
if btype == "column" or btype =="column_list":
return
if btype == "file":
self.downlaod_file(block.source,block.title)
print("\n[Download]'{0}' is saved in 'download' folder".format(block.title))
if btype == "collection_view":
collection = block.collection
return self.make_table(collection)
if block.children and btype != 'page':
tapped += 1
self.page2md(tapped,page=block)

def page2md(self,tapped,page=None):
"""change notion's block to markdown string
"""
if tapped == 0:
img_count = 0
numbered_list_index = 0
else:
self.md += '\n'
for i in range(tapped):
self.md += '\t'
if page is None:
page = self.page
count = 0
for block in page.children:
if block != page.children[0]:
self.md +="\n\n"
try:
self.md += self.block2md(block)
except:
self.md += ""

def make_table(self,collection):
columns = []
row_blocks=collection.get_rows()
for proptitle in row_blocks[0].schema:
prop = proptitle['name']
if prop == "Name":
columns.insert(0,prop)
else:
columns.append(prop)
table = []
table.append(columns)
for row in row_blocks:
row_content = []
for column in columns:
if column == "Name" and row.get("content") is not None:
content = self.block2md(row)
else:
content = row.get_property(column)
if str(type(content))=="<class 'list'>":
content = ', '.join(content)
if str(type(content)) == "<class 'datetime.datetime'>":
content = content.strftime('%b %d, %Y')
if column =="Name":
row_content.insert(0,content)
else:
row_content.append(content)
table.append(row_content)
return table_to_markdown(table)

def link_format(name,url):
"""make markdown link format string
"""
return "["+name+"]"+"("+url+")"

def table_to_markdown(table):
md = ""
md += join_with_vertical(table[0])
md += "\n---|---|---\n"
for row in table[1:]:
if row != table[1]:
md += '\n'
md += join_with_vertical(row)
return md

def join_with_vertical(list):
return " | ".join(list)
Loading