o
    f�Øh%k  ã                	   @   s�   d dl Z d dlZd dlmZmZmZmZ d dlmZ d dl	m
Z
 ejejdd� e e¡ZG dd„ dƒZdd	ed
ee deeef fdd„ZdS )é    N)ÚListÚDictÚAnyÚOptional)ÚClient)Úcollect_paginated_apiz)%(asctime)s - %(levelname)s - %(message)s)ÚlevelÚformatc                	   @   s   e Zd Zdefdd„Zdedeeef fdd„Zd7d
eeee	f  de
dedefdd„Zdeeee	f  defdd„Zdeee	f defdd„Zdeee	f dedefdd„Zdeee	f defdd„Zd8deee	f dededefdd„Zdeee	f defdd„Zdeee	f defdd „Zdeee	f defd!d"„Zdeee	f defd#d$„Zdeee	f defd%d&„Zdeee	f defd'd(„Zdeee	f defd)d*„Zdeee	f defd+d,„Zdeee	f defd-d.„Zdeee	f defd/d0„Zdeee	f defd1d2„Zd3edefd4d5„Zd6S )9ÚNotionToMarkdownÚtokenc                 C   s   t |d�| _d S )N)Úauth)r   Úclient)Úselfr   © r   ú)/var/www/html/notion2html/notion_to_md.pyÚ__init__   s   zNotionToMarkdown.__init__Úpage_idÚreturnc              
   C   sœ  �z4| j j |¡}d}| di ¡}| ¡ D ]8\}}| d¡dkrM| d¡rMt|d ƒdkrM|d d  dd¡ ¡ }d | ¡ ¡}t	 
d|› d	|› �¡  nqt| j jjj|d
�}t	 
dt|ƒ› d�¡ |dkrÐ|rÐ|D ]d}	|	 d¡}
d}|
dkr‚|  |	d d ¡}n9|
dkr�|  |	d d ¡}n+|
dkrž|  |	d d ¡}n|
dkr»|  |	d d ¡}|r»t| ¡ ƒdk r»d|vr»|}|rÏ| ¡ rÏ| ¡ }t	 
d|› �¡  nqkt	 
d|› �¡ |  |¡}|�r1|dk�r1g }dd„ }g d¢}|D ]}||v �r||| ƒ}|�r| d|› d|› �¡ qñd|› �g}|�r%| d¡ | |¡ | d¡ d |¡}|› d|› �}||fW S  t�yM } zt	 dt|ƒ› �¡ ‚ d}~ww )a  
        Fetch all content from a Notion page and convert it to Markdown format.
        
        Args:
            page_id: The ID of the Notion page to export
            
        Returns:
            tuple[str, str]: A tuple containing (page_title, markdown_content)
        ÚUntitledÚ
propertiesÚtypeÚtitler   Ú
plain_textú zFound title from property 'z': ©Úblock_idz
Retrieved z blocks from pageNÚ	heading_1Ú	rich_textÚ	heading_2Ú	heading_3Ú	paragraphéd   Ú
z$Using first content block as title: zRetrieved page: c                 S   s°   |   d¡}|dkr|   dg ¡}|rdd„ |D ƒ}d |¡S dS |dkr2|   d¡}|r0|  dd¡S dS |d	krE|   d	¡}|rC|  d
d¡S dS |dkrV|   d¡}|rV|  d
d¡S dS )Nr   Úpeoplec                 S   s   g | ]}|  d d¡‘qS )ÚnameÚUnknown©Úget)Ú.0Úpersonr   r   r   Ú
<listcomp>[   s    zgNotionToMarkdown.get_page_content_as_markdown.<locals>.format_property_for_markdown.<locals>.<listcomp>z, ÚdateÚstartÚ Ústatusr$   Úselect)r'   Újoin)Ú	prop_dataÚ	prop_typer#   ÚnamesÚ	date_dataÚstatus_dataÚselect_datar   r   r   Úformat_property_for_markdownU   s,   

ñ
ö
û
zSNotionToMarkdown.get_page_content_as_markdown.<locals>.format_property_for_markdown)ÚApprovalzApproval DatezProtocol TypezDocument Statusú**z**: z# r-   zError retrieving page content: )r   ÚpagesÚretriever'   ÚitemsÚlenÚstripr0   ÚsplitÚloggerÚinfor   ÚblocksÚchildrenÚlistÚ_extract_rich_textÚ_convert_blocks_to_markdownÚappendÚextendÚ	ExceptionÚerrorÚstr)r   r   ÚpageÚ
page_titler   Ú	prop_nameÚ
prop_valueÚ	raw_titlerB   ÚblockÚ
block_typeÚtitle_from_contentÚtextÚmarkdown_contentÚmetadata_linesr7   Údesired_propertiesÚheader_partsÚheader_contentÚer   r   r   Úget_page_content_as_markdown   sz   
€
þ
€

€




€þz-NotionToMarkdown.get_page_content_as_markdownTr   rB   Úprocess_linked_pagesÚnesting_levelc                    s|  g }d}d}|D �]}|  d¡}|dur3|dv r|dks$|dkr3|dv r3| d¡ | d¡ | d¡ |dkrCd}| |  |¡¡ �np|d	krTd}| |  |d¡¡ �n_|d
kred}| |  |d¡¡ �nN|dkrvd}| |  |d¡¡ �n=|dkrÂ|dkr€d}d}	||v r‹| |¡nd}
|
dkr¨|
t|ƒd k r¨||
d  }|  d¡dkr¨d}	|	r¹|  |d d ¡}| |¡ nú| |  |¡¡ nñ|dkrÛ|dvrÌd}| |  |||¡¡ |d7 }nØ|dkrî|dkråd}| |  	|¡¡ nÅ|dkrýd}| |  
|¡¡ n¶|dk�rd}| |  |¡¡ n¦|dk�rd}| |  |¡¡ n–|dk�r-d}| |  |¡¡ n†|dk�r:d}| d¡ ny|dk�rJd}| |  |¡¡ ni|dk�rZd}| |  |¡¡ nY|dk�rjd}| |  |¡¡ nI|dk�rzd}| |  |¡¡ n9|d k�rŠd}| |  |¡¡ n)|d!k�r�q|d"k�r¨d}|�r§|  |¡}|�r§| |¡ nd}| d#|› d$�¡ |}|  d%d¡�r!zBt| jjjj|d& d'�}|  |||d ¡}| ¡ �rý|dk�rßd(‰ n
|dk�rçd(‰ nd)‰ d* ‡ fd+d,„| d*¡D ƒ¡}| |¡ W q t�y  } zt d-|d& › d.t |ƒ› �¡ W Y d}~qd}~ww qg }|D ]}| ¡ �s2|dk�r7| |¡ �q&d/ |¡S )0a˜  
        Convert a list of Notion blocks to Markdown format.
        
        Args:
            blocks: List of Notion block objects
            process_linked_pages: Whether to embed content from linked pages (prevents recursion)
            nesting_level: Current nesting level for numbering styles (0=top level)
            
        Returns:
            str: Markdown representation of the blocks
        é   Nr   )Úbulleted_list_itemÚto_doÚnumbered_list_itemr-   z&nbsp;r    r   r   é   r   é   r_   Féÿÿÿÿr   Tr   )ra   r`   ÚtoggleÚquoteÚcodeÚcalloutÚdividerú---ÚimageÚfileÚbookmarkÚembedÚtableÚ	table_rowÚlink_to_pagez<!-- Unsupported block type: z -->Úhas_childrenÚidr   z    z  r"   c                    s   g | ]
}|  ¡ rˆ | ‘qS r   )r>   )r(   Úline©Úindentr   r   r*     s    z@NotionToMarkdown._convert_blocks_to_markdown.<locals>.<listcomp>z"Error retrieving child blocks for z: z

)!r'   rG   Ú_convert_paragraphÚ_convert_headingÚindexr=   rE   Ú_convert_bulleted_list_itemÚ_convert_numbered_list_itemÚ_convert_todoÚ_convert_toggleÚ_convert_quoteÚ_convert_codeÚ_convert_calloutÚ_convert_imageÚ_convert_fileÚ_convert_bookmarkÚ_convert_embedÚ_convert_tableÚ_convert_link_to_pager   r   rB   rC   rD   rF   r>   r0   r?   rI   r@   ÚwarningrK   )r   rB   r\   r]   Úmarkdown_linesÚnumbered_list_counterÚlast_block_typerQ   rR   Únext_block_is_numberedÚcurrent_indexÚ
next_blockrT   Úlinked_contentÚchild_blocksÚchild_markdownÚindented_childrZ   Úresult_linesrt   r   ru   r   rF   ‰   sä   


















€
þ



€*€ÿë
€
z,NotionToMarkdown._convert_blocks_to_markdownÚrich_text_arrayc                 C   sº   |sdS g }|D ]O}|  dd¡}|  di ¡}|  d¡r!d|› d�}|  d¡r,d|› d�}|  d¡r7d	|› d	�}|  d
¡rBd|› d�}|  d¡rRd|› d|d › d�}| |¡ qd |¡S )zü
        Extract plain text from Notion rich text array and apply basic formatting.
        
        Args:
            rich_text_array: Array of rich text objects from Notion
            
        Returns:
            str: Formatted text string
        r-   r   ÚannotationsÚboldr9   ÚitalicÚ*Ústrikethroughz~~rg   ú`Úhrefú[ú](ú))r'   rG   r0   )r   r“   ÚresultÚtext_objÚcontentr”   r   r   r   rE      s$   






z#NotionToMarkdown._extract_rich_textrQ   c                 C   s   |   |d d ¡S )z$Convert paragraph block to markdown.r    r   ©rE   )r   rQ   r   r   r   rw   B  s   z#NotionToMarkdown._convert_paragraphr   c                 C   s*   |   |d|› � d ¡}d| › d|› �S )z"Convert heading block to markdown.Úheading_r   ú#r   r¡   )r   rQ   r   Úheading_textr   r   r   rx   F  s   z!NotionToMarkdown._convert_headingc                 C   ó   |   |d d ¡}d|› �S )z'Convert bulleted list item to markdown.r_   r   ú- r¡   ©r   rQ   rT   r   r   r   rz   K  ó   
z,NotionToMarkdown._convert_bulleted_list_itemÚlist_numberc                 C   s    |   |d d ¡}|› d|› �S )zVConvert numbered list item to markdown with proper numbered lists for HTML conversion.ra   r   z. r¡   )r   rQ   r©   r]   rT   r   r   r   r{   P  s   z,NotionToMarkdown._convert_numbered_list_itemc                 C   s>   |   |d d ¡}|d  dd¡}|rdnd}d|› d|› �S )	z Convert to-do block to markdown.r`   r   ÚcheckedFz[x]z[ ]r¦   r   ©rE   r'   )r   rQ   rT   rª   Úcheckboxr   r   r   r|   Y  s   zNotionToMarkdown._convert_todoc                 C   s   |   |d d ¡}d|› d�S )z!Convert toggle block to markdown.re   r   z<details><summary>z</summary></details>r¡   r§   r   r   r   r}   `  s   z NotionToMarkdown._convert_togglec                 C   r¥   )z Convert quote block to markdown.rf   r   ú> r¡   r§   r   r   r   r~   e  r¨   zNotionToMarkdown._convert_quotec                 C   s4   |   |d d ¡}|d  dd¡}d|› d|› d�S )zConvert code block to markdown.rg   r   Úlanguager-   z```r"   z
```r«   )r   rQ   Ú	code_textr®   r   r   r   r   j  s   zNotionToMarkdown._convert_codec                 C   sP   |   |d d ¡}|d  di ¡}d}| d¡dkr | dd¡}d|› d|› �S )	z"Convert callout block to markdown.rh   r   Úiconr-   r   Úemojir­   r   r«   )r   rQ   rT   r°   Ú	icon_textr   r   r   r€   p  s   z!NotionToMarkdown._convert_calloutc                 C   sp   |d }|d dkr|d d }n|d dkr|d d }ndS |   | dg ¡¡}|r-|nd}d	|› d
|› d�S )z Convert image block to markdown.rk   r   ÚexternalÚurlrl   z'<!-- Image block (unsupported type) -->ÚcaptionÚImagez![rœ   r�   r«   )r   rQ   Ú
image_datar´   rµ   Úalt_textr   r   r   r�   y  s   zNotionToMarkdown._convert_imagec                 C   s^   |d }|d dkr|d d }n|d dkr|d d }ndS |  dd¡}d|› d	|› d
�S )zConvert file block to markdown.rl   r   r³   r´   z&<!-- File block (unsupported type) -->r$   ÚFiler›   rœ   r�   r&   )r   rQ   Ú	file_datar´   r$   r   r   r   r‚   ‡  s   zNotionToMarkdown._convert_filec                 C   s@   |d d }|   |d  dg ¡¡}|r|n|}d|› d|› d�S )z#Convert bookmark block to markdown.rm   r´   rµ   r›   rœ   r�   r«   )r   rQ   r´   rµ   Ú	link_textr   r   r   rƒ   ”  s   z"NotionToMarkdown._convert_bookmarkc                 C   s   |d d }d|› d�S )z Convert embed block to markdown.rn   r´   z[Embedded content](r�   r   )r   rQ   r´   r   r   r   r„   ›  s   zNotionToMarkdown._convert_embedc              
   C   sp  t  d|d › �¡ z�t| jjjj|d d�}|s!t  d¡ W dS t  dt|ƒ› d�¡ g }t	|ƒD ]]\}}|d d	kr�|d	 d
 }g }|D ]#}|  
|¡}	|	r`|	 dd¡}	ddl}
|
 dd|	¡}	| |	rf|	nd¡ qFd |¡}| d|› d�¡ |dkr�d dgt|ƒ ¡}| d|› d�¡ q2t  d¡ d |¡W S  ty· } zt  dt|ƒ› �¡ W Y d}~dS d}~ww )z Convert table block to markdown.zConverting table block: rs   r   zEmpty table foundz<!-- Empty table -->zFound z rows in tabler   rp   Úcellsr"   z<br>r   Nz
(<br>){2,}z<br><br>r   z | z| z |rj   z(Successfully converted table to markdownzError converting table: z<!-- Table conversion error -->)r@   rA   r   r   rB   rC   rD   r‡   r=   Ú	enumeraterE   ÚreplaceÚreÚsubrG   r0   rI   rK   )r   rQ   Ú
table_rowsÚmarkdown_rowsÚiÚrowr¼   Úcell_contentsÚcellrT   r¿   Úrow_textÚ	separatorrZ   r   r   r   r…      sF   
þ


€
€þzNotionToMarkdown._convert_tablec              
   C   s  zl|d }d}|d dkr|d }n|d dkr%t  d|d › �¡ W dS |s/t  d¡ W d	S t  d
|› �¡ t| jjjj|d�}|sNt  d|› �¡ W d	S | j|ddd�}| 	¡ rj|  
|¡}t  d|› �¡ |W S W d	S  ty‰ } zt  dt|ƒ› �¡ W Y d}~d	S d}~ww )zLConvert link_to_page block to markdown by embedding the linked page content.rq   Nr   r   Údatabase_idz1Database link encountered in link_to_page block: z-<!-- Linked database content not embedded -->z&No page_id found in link_to_page blockr-   z$Embedding content from linked page: r   z!No content found in linked page: Fr   )r\   r]   z0Successfully embedded content from linked page: z%Error converting link_to_page block: )r@   r‡   rA   r   r   rB   rC   rD   rF   r>   Ú_process_linked_contentrI   rK   )r   rQ   Úlink_to_page_datar   Úlinked_blocksÚlinked_markdownÚprocessed_markdownrZ   r   r   r   r†   Ô  s<   


þ
€þz&NotionToMarkdown._convert_link_to_pagerU   c                 C   sž   ddl }| d¡}g }|D ]<}| ¡ dkr| d¡ q| d|¡}|r@| d¡}| d¡}|d	 }	t|	ƒd
kr9d}	|	› d|› �}d| }
| |
¡ qd |¡S )a5  
        Process linked page content by wrapping in blockquote and demoting heading levels.
        
        Args:
            markdown_content: The raw markdown content from the linked page
            
        Returns:
            str: Processed markdown wrapped in blockquote with demoted headings
        r   Nr"   r-   ú>z^(#{1,6})\s+(.*)$r^   rb   r£   é   z######r   r­   )r¿   r?   r>   rG   ÚmatchÚgroupr=   r0   )r   rU   r¿   ÚlinesÚprocessed_linesrt   Úheading_matchÚcurrent_hashesr¤   Ú
new_hashesÚblockquote_liner   r   r   rÊ     s$   





z(NotionToMarkdown._process_linked_contentN)Tr   )r   )Ú__name__Ú
__module__Ú__qualname__rK   r   Útupler[   r   r   r   ÚboolÚintrF   rE   rw   rx   rz   r{   r|   r}   r~   r   r€   r�   r‚   rƒ   r„   r…   r†   rÊ   r   r   r   r   r
      s,    (z "$		4-r
   r   r   r   c                 C   s,   |st  d¡}|stdƒ‚t|ƒ}| | ¡S )a(  
    Export a Notion page to Markdown format.
    
    Args:
        page_id: The ID of the Notion page to export
        token: Notion API token (if not provided, will use NOTION_TOKEN env var)
        
    Returns:
        tuple[str, str]: A tuple containing (page_title, markdown_content)
    ÚNOTION_TOKENzGNotion token not provided and NOTION_TOKEN environment variable not set)ÚosÚgetenvÚ
ValueErrorr
   r[   )r   r   Ú	converterr   r   r   Úexport_notion_page_to_markdown*  s   

rä   )N)rà   ÚloggingÚtypingr   r   r   r   Únotion_clientr   Únotion_client.helpersr   ÚbasicConfigÚINFOÚ	getLoggerrÙ   r@   r
   rK   rÜ   rä   r   r   r   r   Ú<module>   s    
    (#