2022-05-16 20:12:06 +02:00
#!/usr/bin/env python3
2022-05-17 22:58:51 +02:00
""" ================================= |
2022-06-26 00:06:34 +02:00
| This file is part of |
| staticoso |
2022-05-17 22:58:51 +02:00
| Just a simple Static Site Generator |
2022-05-21 20:03:27 +02:00
| |
| Licensed under the AGPLv3 license |
2022-06-26 00:06:34 +02:00
| Copyright ( C ) 2022 , OctoSpacc |
2022-05-17 22:58:51 +02:00
| == == == == == == == == == == == == == == == == = """
2022-05-17 18:16:39 +02:00
2022-05-24 00:22:32 +02:00
import argparse
2022-05-16 20:12:06 +02:00
import os
import shutil
2022-06-07 13:42:32 +02:00
from ast import literal_eval
2022-06-24 20:00:38 +02:00
from datetime import datetime
2022-06-29 20:09:13 +02:00
from pathlib import Path
# Our local Markdown patches conflict if the module is installed on the system, so first try to import from system
try :
from markdown import markdown
except ModuleNotFoundError :
from Libs . markdown import markdown
2022-06-24 00:30:50 +02:00
from Libs import htmlmin
2022-06-23 20:42:43 +02:00
from Libs . bs4 import BeautifulSoup
2022-07-02 22:09:09 +02:00
try :
from Modules . ActivityPub import *
ActivityPub = True
except :
ActivityPub = False
2022-06-29 00:17:52 +02:00
from Modules . Gemini import *
2022-06-29 20:09:13 +02:00
from Modules . Pug import *
2022-06-26 00:06:34 +02:00
from Modules . Utils import *
2022-05-16 20:12:06 +02:00
2022-06-20 16:16:41 +02:00
Extensions = {
' Pages ' : ( ' md ' , ' pug ' ) }
2022-05-16 20:12:06 +02:00
def ResetPublic ( ) :
2022-06-29 00:17:52 +02:00
for i in ( ' public ' , ' public.gmi ' ) :
try :
shutil . rmtree ( i )
except FileNotFoundError :
pass
2022-05-16 20:12:06 +02:00
2022-06-20 23:16:31 +02:00
def GetLevels ( Path , AsNum = False , Add = 0 , Sub = 0 ) :
n = Path . count ( ' / ' ) + Add - Sub
2022-06-20 10:55:45 +02:00
return n if AsNum else ' ../ ' * n
2022-06-20 18:47:31 +02:00
def DashifyTitle ( Title , Done = [ ] ) :
2022-06-20 23:16:31 +02:00
return UndupeStr ( DashifyStr ( Title ) , Done , ' - ' )
2022-06-20 18:47:31 +02:00
2022-05-30 20:10:43 +02:00
def GetTitle ( Meta , Titles , Prefer = ' MetaTitle ' ) :
2022-06-23 18:41:52 +02:00
if Prefer == ' BodyTitle ' :
2022-06-10 19:41:54 +02:00
Title = Titles [ 0 ] . lstrip ( ' # ' ) if Titles else Meta [ ' Title ' ] if Meta [ ' Title ' ] else ' Untitled '
2022-05-30 20:10:43 +02:00
elif Prefer == ' MetaTitle ' :
2022-06-10 19:41:54 +02:00
Title = Meta [ ' Title ' ] if Meta [ ' Title ' ] else Titles [ 0 ] . lstrip ( ' # ' ) if Titles else ' Untitled '
2022-05-30 20:10:43 +02:00
elif Prefer == ' HTMLTitle ' :
2022-06-10 19:41:54 +02:00
Title = Meta [ ' HTMLTitle ' ] if Meta [ ' HTMLTitle ' ] else Meta [ ' Title ' ] if Meta [ ' Title ' ] else Titles [ 0 ] . lstrip ( ' # ' ) if Titles else ' Untitled '
if Meta [ ' Type ' ] == ' Post ' :
# TODO: This hardcodes my blog name, bad, will fix asap
2022-06-15 12:01:59 +02:00
Title + = ' - blogoctt '
2022-06-10 19:41:54 +02:00
return Title
2022-05-30 20:10:43 +02:00
2022-06-23 18:41:52 +02:00
def GetDescription ( Meta , BodyDescription , Prefer = ' MetaDescription ' ) :
if Prefer == ' BodyDescription ' :
Description = BodyDescription if BodyDescription else Meta [ ' Description ' ] if Meta [ ' Description ' ] else ' '
2022-06-15 12:01:59 +02:00
elif Prefer == ' MetaDescription ' :
2022-06-23 18:41:52 +02:00
Description = Meta [ ' Description ' ] if Meta [ ' Description ' ] else BodyDescription if BodyDescription else ' '
2022-06-15 12:01:59 +02:00
return Description
2022-06-23 18:41:52 +02:00
def GetImage ( Meta , BodyImage , Prefer = ' MetaImage ' ) :
if Prefer == ' BodyImage ' :
Image = BodyImage if BodyImage else Meta [ ' Image ' ] if Meta [ ' Image ' ] else ' '
elif Prefer == ' MetaImage ' :
Image = Meta [ ' Image ' ] if Meta [ ' Image ' ] else BodyImage if BodyImage else ' '
return Image
2022-06-20 18:47:31 +02:00
def MakeLinkableTitle ( Line , Title , DashTitle , Type ) :
2022-06-14 13:51:23 +02:00
if Type == ' md ' :
Index = Title . split ( ' ' ) [ 0 ] . count ( ' # ' )
return ' <h {} id= " {} " > {} </h {} > ' . format ( Index , DashTitle , Title [ Index + 1 : ] , Index )
elif Type == ' pug ' :
2022-06-14 14:05:20 +02:00
NewLine = ' '
2022-06-14 13:51:23 +02:00
Index = Line . find ( ' h ' )
NewLine + = Line [ : Index ]
NewLine + = " {} (id= ' {} ' ) " . format ( Line [ Index : Index + 2 ] , DashTitle )
NewLine + = Line [ Index + 2 : ]
return NewLine
2022-05-17 22:58:51 +02:00
2022-06-20 16:16:41 +02:00
def MakeListTitle ( File , Meta , Titles , Prefer , SiteRoot , PathPrefix = ' ' ) :
2022-06-03 23:38:47 +02:00
Title = GetTitle ( Meta , Titles , Prefer )
2022-06-19 16:22:33 +02:00
Link = False if Meta [ ' Index ' ] == ' Unlinked ' else True
if Link :
2022-06-03 23:38:47 +02:00
Title = ' [ {} ]( {} ) ' . format (
Title ,
2022-06-20 16:16:41 +02:00
' {} {} .html ' . format ( PathPrefix , StripExt ( File ) ) )
2022-06-19 16:22:33 +02:00
if Meta [ ' Type ' ] == ' Post ' and Meta [ ' CreatedOn ' ] :
Title = ' [ {} ] {} ' . format (
Meta [ ' CreatedOn ' ] ,
Title )
2022-06-03 23:38:47 +02:00
return Title
2022-05-16 20:12:06 +02:00
def FormatTitles ( Titles ) :
2022-06-20 18:47:31 +02:00
# TODO: Somehow titles written in Pug can end up here and don't work, they should be handled
MDTitles , DashyTitles = ' ' , [ ]
2022-05-16 21:16:36 +02:00
for t in Titles :
2022-05-17 22:58:51 +02:00
n = t . split ( ' ' ) [ 0 ] . count ( ' # ' )
2022-05-22 23:19:02 +02:00
Heading = ' - ' * n
2022-05-21 13:04:05 +02:00
Title = t . lstrip ( ' # ' )
2022-06-20 18:47:31 +02:00
DashyTitle = DashifyTitle ( Title , DashyTitles )
DashyTitles + = [ DashyTitle ]
Title = ' [ {} ](# {} ) ' . format ( Title , DashyTitle )
2022-05-22 23:19:02 +02:00
MDTitles + = Heading + Title + ' \n '
2022-06-29 20:09:13 +02:00
return markdown ( MDTitles )
2022-05-27 11:11:33 +02:00
def LoadFromDir ( Dir , Rglob ) :
2022-05-16 20:12:06 +02:00
Contents = { }
2022-05-27 11:11:33 +02:00
for File in Path ( Dir ) . rglob ( Rglob ) :
2022-05-16 20:12:06 +02:00
File = str ( File ) [ len ( Dir ) + 1 : ]
Contents . update ( { File : ReadFile ( ' {} / {} ' . format ( Dir , File ) ) } )
return Contents
2022-06-14 13:51:23 +02:00
def PreProcessor ( Path , SiteRoot ) :
File = ReadFile ( Path )
2022-06-20 18:47:31 +02:00
Content , Titles , DashyTitles , Meta = ' ' , [ ] , [ ] , {
2022-05-16 20:12:06 +02:00
' Template ' : ' Standard.html ' ,
2022-05-21 13:04:05 +02:00
' Style ' : ' ' ,
2022-06-23 16:05:02 +02:00
' Type ' : ' ' ,
2022-05-23 22:36:50 +02:00
' Index ' : ' True ' ,
2022-05-24 20:24:12 +02:00
' Title ' : ' ' ,
2022-05-30 20:10:43 +02:00
' HTMLTitle ' : ' ' ,
2022-06-15 12:01:59 +02:00
' Description ' : ' ' ,
' Image ' : ' ' ,
2022-06-18 23:40:01 +02:00
' Categories ' : [ ] ,
2022-06-03 23:38:47 +02:00
' CreatedOn ' : ' ' ,
' EditedOn ' : ' ' ,
2022-05-24 20:24:12 +02:00
' Order ' : None }
2022-05-16 20:12:06 +02:00
for l in File . splitlines ( ) :
ls = l . lstrip ( )
2022-05-30 20:10:43 +02:00
if ls . startswith ( ' // ' ) :
2022-06-01 00:08:49 +02:00
lss = ls [ 3 : ]
2022-06-15 12:01:59 +02:00
for Item in ( ' Template ' , ' Type ' , ' Index ' , ' Title ' , ' HTMLTitle ' , ' Description ' , ' Image ' , ' CreatedOn ' , ' EditedOn ' ) :
2022-06-01 00:08:49 +02:00
ItemText = ' {} : ' . format ( Item )
if lss . startswith ( ItemText ) :
Meta [ Item ] = lss [ len ( ItemText ) : ]
2022-06-18 23:40:01 +02:00
if lss . startswith ( ' Categories: ' ) :
for i in lss [ len ( ' Categories: ' ) : ] . split ( ' ' ) :
Meta [ ' Categories ' ] + = [ i ]
elif lss . startswith ( ' Background: ' ) :
Meta [ ' Style ' ] + = " #MainBox { Background: " + lss [ len ( ' Background: ' ) : ] + " ;} "
2022-06-01 00:08:49 +02:00
elif lss . startswith ( ' Style: ' ) :
2022-06-18 23:40:01 +02:00
Meta [ ' Style ' ] + = lss [ len ( ' Style: ' ) : ] + ' '
2022-06-01 00:08:49 +02:00
elif lss . startswith ( ' Order: ' ) :
2022-06-18 23:40:01 +02:00
Meta [ ' Order ' ] = int ( lss [ len ( ' Order: ' ) : ] )
2022-06-14 13:51:23 +02:00
else :
if Path . endswith ( ' .md ' ) :
if ls . startswith ( ' # ' ) :
2022-06-20 18:47:31 +02:00
DashTitle = DashifyTitle ( l . lstrip ( ' # ' ) , DashyTitles )
DashyTitles + = [ DashTitle ]
2022-06-14 13:51:23 +02:00
Titles + = [ l ]
2022-06-20 18:47:31 +02:00
Content + = MakeLinkableTitle ( l , ls , DashTitle , ' md ' ) + ' \n '
2022-06-14 13:51:23 +02:00
else :
2022-05-24 20:24:12 +02:00
Content + = l + ' \n '
2022-06-14 13:51:23 +02:00
elif Path . endswith ( ' .pug ' ) :
if ls . startswith ( ( ' h1 ' , ' h2 ' , ' h3 ' , ' h4 ' , ' h5 ' , ' h6 ' ) ) :
if ls [ 2 : ] . startswith ( ( " (class= ' NoTitle " , ' (class= " NoTitle ' ) ) :
Content + = l + ' \n '
else :
Title = ' # ' * int ( ls [ 1 ] ) + str ( ls [ 3 : ] )
2022-06-20 18:47:31 +02:00
DashTitle = DashifyTitle ( Title . lstrip ( ' # ' ) , DashyTitles )
DashyTitles + = [ DashTitle ]
2022-06-14 13:51:23 +02:00
Titles + = [ Title ]
2022-06-20 18:47:31 +02:00
# TODO: We should handle headers that for any reason already have parenthesis
2022-06-14 13:51:23 +02:00
if ls [ 2 : ] == ' ( ' :
Content + = l + ' \n '
else :
2022-06-20 18:47:31 +02:00
Content + = MakeLinkableTitle ( l , Title , DashTitle , ' pug ' ) + ' \n '
2022-05-24 20:24:12 +02:00
else :
2022-06-14 13:51:23 +02:00
Content + = l + ' \n '
2022-05-16 20:12:06 +02:00
return Content , Titles , Meta
2022-06-20 23:16:31 +02:00
def MakeContentHeader ( Meta , Locale , Categories = ' ' ) :
2022-06-10 19:41:54 +02:00
Header = ' '
if Meta [ ' Type ' ] == ' Post ' :
2022-06-20 18:47:31 +02:00
for i in [ ' CreatedOn ' , ' EditedOn ' ] :
if Meta [ i ] :
2022-06-20 23:16:31 +02:00
Header + = ' {} {} \n ' . format ( Locale [ i ] , Meta [ i ] )
if Categories :
Header + = ' {} : {} \n ' . format ( Locale [ ' Categories ' ] , Categories )
2022-06-29 20:09:13 +02:00
return markdown ( Header )
2022-06-10 19:41:54 +02:00
2022-06-20 23:16:31 +02:00
def MakeCategoryLine ( Meta , Reserved ) :
Categories = ' '
if Meta [ ' Categories ' ] :
for i in Meta [ ' Categories ' ] :
Categories + = ' [ {} ]( {} {} .html) ' . format ( i , GetLevels ( Reserved [ ' Categories ' ] ) + Reserved [ ' Categories ' ] , i )
return Categories
2022-07-01 17:29:37 +02:00
def PatchHTML ( HTML , PartsText , ContextParts , ContextPartsText , HTMLPagesList , PagePath , Content , Titles , Meta , SiteRoot , FolderRoots , Categories , Locale , Reserved ) :
2022-05-16 20:12:06 +02:00
HTMLTitles = FormatTitles ( Titles )
2022-06-24 00:30:50 +02:00
BodyDescription , BodyImage = ' ' , ' '
2022-06-23 20:42:43 +02:00
Parse = BeautifulSoup ( Content , ' html.parser ' )
if not BodyDescription and Parse . p :
BodyDescription = Parse . p . get_text ( ) [ : 150 ] . replace ( ' \n ' , ' ' ) . replace ( ' " ' , " ' " ) + ' ... '
if not BodyImage and Parse . img and Parse . img [ ' src ' ] :
BodyImage = Parse . img [ ' src ' ]
2022-06-24 21:22:37 +02:00
Title = GetTitle ( Meta , Titles , ' MetaTitle ' )
Description = GetDescription ( Meta , BodyDescription , ' MetaDescription ' )
Image = GetImage ( Meta , BodyImage , ' MetaImage ' )
2022-07-01 17:29:37 +02:00
for Line in HTML . splitlines ( ) :
2022-06-07 13:42:32 +02:00
Line = Line . lstrip ( ) . rstrip ( )
if Line . startswith ( ' [HTML:ContextPart: ' ) and Line . endswith ( ' ] ' ) :
Path = Line [ len ( ' [HTML:ContextPart: ' ) : - 1 ]
Section = Path . split ( ' / ' ) [ - 1 ]
if Section in ContextParts :
Part = ContextParts [ Section ]
Text = ' '
if type ( Part ) == list :
for i in Part :
Text + = ContextPartsText [ ' {} / {} ' . format ( Path , i ) ] + ' \n '
elif type ( Part ) == str :
Text = ContextPartsText [ ' {} / {} ' . format ( Path , Part ) ]
else :
Text = ' '
2022-07-01 17:29:37 +02:00
HTML = HTML . replace ( ' [HTML:ContextPart: {} ] ' . format ( Path ) , Text )
2022-06-07 13:42:32 +02:00
for i in PartsText :
2022-07-01 17:29:37 +02:00
HTML = HTML . replace ( ' [HTML:Part: {} ] ' . format ( i ) , PartsText [ i ] )
HTML = HTML . replace ( ' [HTML:Page:LeftBox] ' , HTMLPagesList )
HTML = HTML . replace ( ' [HTML:Page:RightBox] ' , HTMLTitles )
HTML = HTML . replace ( ' [HTML:Page:Title] ' , Title )
HTML = HTML . replace ( ' [HTML:Page:Description] ' , Description )
HTML = HTML . replace ( ' [HTML:Page:Image] ' , Image )
HTML = HTML . replace ( ' [HTML:Page:Path] ' , PagePath )
HTML = HTML . replace ( ' [HTML:Page:Style] ' , Meta [ ' Style ' ] )
HTML = HTML . replace ( ' [HTML:Page:Content] ' , Content )
HTML = HTML . replace ( ' [HTML:Page:ContentHeader] ' , MakeContentHeader ( Meta , Locale , MakeCategoryLine ( Meta , Reserved ) ) )
HTML = HTML . replace ( ' [HTML:Site:AbsoluteRoot] ' , SiteRoot )
HTML = HTML . replace ( ' [HTML:Site:RelativeRoot] ' , GetLevels ( PagePath ) )
2022-06-19 23:07:23 +02:00
for i in FolderRoots :
2022-07-01 17:29:37 +02:00
HTML = HTML . replace ( ' [HTML:Folder: {} :AbsoluteRoot] ' . format ( i ) , FolderRoots [ i ] )
2022-06-19 16:22:33 +02:00
for i in Categories :
2022-07-01 17:29:37 +02:00
HTML = HTML . replace ( ' <span>[HTML:Category: {} ]</span> ' . format ( i ) , Categories [ i ] )
2022-06-24 21:22:37 +02:00
2022-06-29 20:09:13 +02:00
# TODO: Clean this doubling?
2022-07-01 17:29:37 +02:00
ContentHTML = Content
ContentHTML = ContentHTML . replace ( ' [HTML:Site:AbsoluteRoot] ' , SiteRoot )
ContentHTML = ContentHTML . replace ( ' [HTML:Site:RelativeRoot] ' , GetLevels ( PagePath ) )
2022-06-24 21:22:37 +02:00
for i in FolderRoots :
2022-07-01 17:29:37 +02:00
ContentHTML = ContentHTML . replace ( ' [HTML:Folder: {} :AbsoluteRoot] ' . format ( i ) , FolderRoots [ i ] )
2022-06-29 20:09:13 +02:00
for i in Categories :
2022-07-01 17:29:37 +02:00
ContentHTML = ContentHTML . replace ( ' <span>[HTML:Category: {} ]</span> ' . format ( i ) , Categories [ i ] )
SlimHTML = HTMLPagesList + ContentHTML
2022-06-24 21:22:37 +02:00
2022-07-01 17:29:37 +02:00
return HTML , ContentHTML , SlimHTML , Description , Image
2022-05-16 20:12:06 +02:00
2022-05-24 20:24:12 +02:00
def OrderPages ( Old ) :
New = [ ]
2022-06-23 17:20:06 +02:00
NoOrder = [ ]
2022-05-24 20:24:12 +02:00
Max = 0
for i , e in enumerate ( Old ) :
2022-06-23 17:20:06 +02:00
Curr = e [ 3 ] [ ' Order ' ]
if Curr :
if Curr > Max :
Max = Curr
else :
NoOrder + = [ e ]
2022-05-24 20:24:12 +02:00
for i in range ( Max + 1 ) :
New + = [ [ ] ]
for i , e in enumerate ( Old ) :
2022-06-23 17:20:06 +02:00
Curr = e [ 3 ] [ ' Order ' ]
if Curr :
New [ Curr ] = e
2022-05-24 20:24:12 +02:00
while [ ] in New :
New . remove ( [ ] )
2022-06-23 17:20:06 +02:00
return New + NoOrder
2022-05-24 20:24:12 +02:00
2022-06-26 00:06:34 +02:00
def CanIndex ( Index , For ) :
if Index in ( ' False ' , ' None ' ) :
return False
elif Index in ( ' True ' , ' All ' , ' Unlinked ' ) :
return True
else :
return True if Index == For else False
def GetHTMLPagesList ( Pages , SiteRoot , PathPrefix , Type = ' Page ' , Category = None , For = ' Menu ' ) :
2022-06-20 16:16:41 +02:00
List , ToPop , LastParent = ' ' , [ ] , [ ]
2022-06-01 00:08:49 +02:00
IndexPages = Pages . copy ( )
for e in IndexPages :
2022-06-23 17:20:06 +02:00
if e [ 3 ] [ ' Index ' ] == ' False ' or e [ 3 ] [ ' Index ' ] == ' None ' :
2022-06-10 19:41:54 +02:00
IndexPages . remove ( e )
2022-06-03 23:38:47 +02:00
for i , e in enumerate ( IndexPages ) :
2022-06-23 17:20:06 +02:00
if e [ 3 ] [ ' Type ' ] != Type :
2022-06-10 19:41:54 +02:00
ToPop + = [ i ]
2022-06-20 16:16:41 +02:00
ToPop = RevSort ( ToPop )
2022-06-10 19:41:54 +02:00
for i in ToPop :
IndexPages . pop ( i )
2022-06-03 23:38:47 +02:00
if Type == ' Page ' :
IndexPages = OrderPages ( IndexPages )
2022-06-23 17:20:06 +02:00
for File , Content , Titles , Meta in IndexPages :
2022-06-26 00:06:34 +02:00
if Meta [ ' Type ' ] == Type and CanIndex ( Meta [ ' Index ' ] , For ) and GetTitle ( Meta , Titles , Prefer = ' HTMLTitle ' ) != ' Untitled ' and ( not Category or Category in Meta [ ' Categories ' ] ) :
2022-05-23 22:36:50 +02:00
n = File . count ( ' / ' ) + 1
if n > 1 :
CurParent = File . split ( ' / ' ) [ : - 1 ]
for i , s in enumerate ( CurParent ) :
if LastParent != CurParent :
LastParent = CurParent
Levels = ' - ' * ( n - 1 + i )
2022-05-30 20:10:43 +02:00
if File [ : - 3 ] . endswith ( ' index. ' ) :
2022-06-20 16:16:41 +02:00
Title = MakeListTitle ( File , Meta , Titles , ' HTMLTitle ' , SiteRoot , PathPrefix )
2022-05-30 20:10:43 +02:00
else :
Title = CurParent [ n - 2 + i ]
2022-05-23 22:36:50 +02:00
List + = Levels + Title + ' \n '
2022-05-30 20:10:43 +02:00
if not ( n > 1 and File [ : - 3 ] . endswith ( ' index. ' ) ) :
Levels = ' - ' * n
2022-06-20 16:16:41 +02:00
Title = MakeListTitle ( File , Meta , Titles , ' HTMLTitle ' , SiteRoot , PathPrefix )
2022-05-30 20:10:43 +02:00
List + = Levels + Title + ' \n '
2022-06-29 20:09:13 +02:00
return markdown ( List )
2022-05-23 22:36:50 +02:00
2022-05-17 22:58:51 +02:00
def DelTmp ( ) :
2022-06-20 16:16:41 +02:00
for Ext in Extensions [ ' Pages ' ] :
for File in Path ( ' public ' ) . rglob ( ' *. {} ' . format ( Ext ) ) :
os . remove ( File )
2022-06-30 18:50:18 +02:00
for Dir in ( ' public ' , ' public.gmi ' ) :
for File in Path ( Dir ) . rglob ( ' *.tmp ' ) :
os . remove ( File )
2022-05-17 22:58:51 +02:00
2022-06-20 16:16:41 +02:00
def RevSort ( List ) :
List . sort ( )
List . reverse ( )
return List
def DoMinify ( HTML ) :
return htmlmin . minify (
input = HTML ,
remove_comments = True ,
remove_empty_space = True ,
remove_all_empty_space = False ,
reduce_empty_attributes = True ,
reduce_boolean_attributes = True ,
remove_optional_attribute_quotes = True ,
convert_charrefs = True ,
keep_pre = True )
2022-06-29 23:56:20 +02:00
def MakeSite ( TemplatesText , PartsText , ContextParts , ContextPartsText , SiteName , SiteTagline , SiteDomain , SiteRoot , FolderRoots , Reserved , Locale , Minify , Sorting , MarkdownExts ) :
2022-06-24 21:22:37 +02:00
PagesPaths , PostsPaths , Pages , MadePages , Categories = [ ] , [ ] , [ ] , [ ] , { }
2022-06-20 16:16:41 +02:00
for Ext in Extensions [ ' Pages ' ] :
for File in Path ( ' Pages ' ) . rglob ( ' *. {} ' . format ( Ext ) ) :
2022-06-23 16:05:02 +02:00
PagesPaths + = [ FileToStr ( File , ' Pages/ ' ) ]
for File in Path ( ' Posts ' ) . rglob ( ' *. {} ' . format ( Ext ) ) :
PostsPaths + = [ FileToStr ( File , ' Posts/ ' ) ]
2022-06-23 17:20:06 +02:00
if Sorting [ ' Pages ' ] == ' Standard ' :
PagesPaths . sort ( )
elif Sorting [ ' Pages ' ] == ' Inverse ' :
PagesPaths = RevSort ( PagesPaths )
if Sorting [ ' Posts ' ] == ' Standard ' :
PostsPaths . sort ( )
elif Sorting [ ' Posts ' ] == ' Inverse ' :
PostsPaths = RevSort ( PostsPaths )
2022-06-23 16:05:02 +02:00
for Type in [ ' Page ' , ' Post ' ] :
if Type == ' Page ' :
Files = PagesPaths
elif Type == ' Post ' :
Files = PostsPaths
for File in Files :
Content , Titles , Meta = PreProcessor ( ' {} s/ {} ' . format ( Type , File ) , SiteRoot )
2022-06-23 17:20:06 +02:00
if Type != ' Page ' :
File = Type + ' s/ ' + File
2022-06-23 16:05:02 +02:00
if not Meta [ ' Type ' ] :
Meta [ ' Type ' ] = Type
2022-06-23 17:20:06 +02:00
Pages + = [ [ File , Content , Titles , Meta ] ]
2022-06-23 16:05:02 +02:00
for Category in Meta [ ' Categories ' ] :
Categories . update ( { Category : ' ' } )
2022-06-14 14:05:20 +02:00
PugCompileList ( Pages )
2022-06-23 17:20:06 +02:00
2022-06-19 16:22:33 +02:00
for Category in Categories :
2022-06-20 16:16:41 +02:00
Categories [ Category ] = GetHTMLPagesList (
2022-06-26 00:06:34 +02:00
Pages = Pages ,
SiteRoot = SiteRoot ,
PathPrefix = GetLevels ( Reserved [ ' Categories ' ] ) , # This hardcodes paths, TODO make it somehow guess the path for every page containing the [HTML:Category] macro
Type = ' Page ' ,
Category = Category ,
For = ' Categories ' )
Categories [ Category ] + = GetHTMLPagesList (
2022-06-20 16:16:41 +02:00
Pages = Pages ,
SiteRoot = SiteRoot ,
2022-06-23 17:20:06 +02:00
PathPrefix = GetLevels ( Reserved [ ' Categories ' ] ) , # This hardcodes paths, TODO make it somehow guess the path for every page containing the [HTML:Category] macro
2022-06-20 16:16:41 +02:00
Type = ' Post ' ,
2022-06-26 00:06:34 +02:00
Category = Category ,
For = ' Categories ' )
2022-06-23 17:20:06 +02:00
for File , Content , Titles , Meta in Pages :
2022-06-20 16:16:41 +02:00
HTMLPagesList = GetHTMLPagesList (
Pages = Pages ,
SiteRoot = SiteRoot ,
PathPrefix = GetLevels ( File ) ,
2022-06-26 00:06:34 +02:00
Type = ' Page ' ,
For = ' Menu ' )
2022-06-15 12:01:59 +02:00
PagePath = ' public/ {} .html ' . format ( StripExt ( File ) )
2022-06-14 13:51:23 +02:00
if File . endswith ( ' .md ' ) :
2022-06-29 23:56:20 +02:00
Content = markdown ( Content , extensions = MarkdownExts )
2022-06-14 13:51:23 +02:00
elif File . endswith ( ' .pug ' ) :
2022-06-15 12:01:59 +02:00
Content = ReadFile ( PagePath )
2022-07-01 17:29:37 +02:00
HTML , ContentHTML , SlimHTML , Description , Image = PatchHTML (
HTML = TemplatesText [ Meta [ ' Template ' ] ] ,
2022-06-20 16:16:41 +02:00
PartsText = PartsText ,
ContextParts = ContextParts ,
ContextPartsText = ContextPartsText ,
HTMLPagesList = HTMLPagesList ,
PagePath = PagePath [ len ( ' public/ ' ) : ] ,
Content = Content ,
Titles = Titles ,
Meta = Meta ,
SiteRoot = SiteRoot ,
FolderRoots = FolderRoots ,
Categories = Categories ,
2022-06-20 23:16:31 +02:00
Locale = Locale ,
Reserved = Reserved )
2022-06-24 20:00:38 +02:00
if Minify not in ( ' False ' , ' None ' ) :
2022-06-20 16:16:41 +02:00
HTML = DoMinify ( HTML )
WriteFile ( PagePath , HTML )
2022-07-01 17:29:37 +02:00
MadePages + = [ [ File , Content , Titles , Meta , ContentHTML , SlimHTML , Description , Image ] ]
2022-05-16 20:12:06 +02:00
2022-06-24 21:22:37 +02:00
return MadePages
2022-06-24 20:00:38 +02:00
2022-06-20 23:16:31 +02:00
def SetReserved ( Reserved ) :
for i in [ ' Categories ' ] :
if i not in Reserved :
Reserved . update ( { i : i } )
for i in Reserved :
if not Reserved [ i ] . endswith ( ' / ' ) :
Reserved [ i ] = ' {} / ' . format ( Reserved [ i ] )
return Reserved
2022-06-23 17:20:06 +02:00
def SetSorting ( Sorting ) :
Default = {
' Pages ' : ' Standard ' ,
' Posts ' : ' Inverse ' }
for i in Default :
if i not in Sorting :
Sorting . update ( { i : Default [ i ] } )
return Sorting
2022-06-29 23:56:20 +02:00
def Main ( Args , FeedEntries ) :
2022-06-24 17:19:22 +02:00
SiteName = Args . SiteName if Args . SiteName else ' '
SiteTagline = Args . SiteTagline if Args . SiteTagline else ' '
2022-06-30 23:29:44 +02:00
SiteDomain = Args . SiteDomain . rstrip ( ' / ' ) if Args . SiteDomain else ' '
2022-06-24 17:19:22 +02:00
SiteLang = Args . SiteLang if Args . SiteLang else ' en '
2022-06-30 23:29:44 +02:00
Locale = LoadLocale ( SiteLang )
MastodonURL = Args . MastodonURL if Args . MastodonURL else ' '
MastodonToken = Args . MastodonToken if Args . MastodonToken else ' '
2022-06-24 17:19:22 +02:00
2022-05-16 20:12:06 +02:00
ResetPublic ( )
2022-06-23 16:05:02 +02:00
if os . path . isdir ( ' Pages ' ) :
shutil . copytree ( ' Pages ' , ' public ' )
2022-06-29 20:09:13 +02:00
if Args . GemtextOut :
shutil . copytree ( ' Pages ' , ' public.gmi ' , ignore = IgnoreFiles )
2022-06-23 16:05:02 +02:00
if os . path . isdir ( ' Posts ' ) :
shutil . copytree ( ' Posts ' , ' public/Posts ' )
2022-06-29 20:09:13 +02:00
if Args . GemtextOut :
shutil . copytree ( ' Posts ' , ' public.gmi/Posts ' , ignore = IgnoreFiles )
2022-06-24 17:19:22 +02:00
2022-07-01 16:39:54 +02:00
print ( " [I] Generating HTML " )
2022-06-24 20:00:38 +02:00
Pages = MakeSite (
2022-06-20 16:16:41 +02:00
TemplatesText = LoadFromDir ( ' Templates ' , ' *.html ' ) ,
PartsText = LoadFromDir ( ' Parts ' , ' *.html ' ) ,
ContextParts = literal_eval ( Args . ContextParts ) if Args . ContextParts else { } ,
ContextPartsText = LoadFromDir ( ' ContextParts ' , ' *.html ' ) ,
2022-06-24 17:19:22 +02:00
SiteName = SiteName ,
SiteTagline = SiteTagline ,
SiteDomain = SiteDomain ,
2022-06-20 16:16:41 +02:00
SiteRoot = Args . SiteRoot if Args . SiteRoot else ' / ' ,
FolderRoots = literal_eval ( Args . FolderRoots ) if Args . FolderRoots else { } ,
2022-06-20 23:16:31 +02:00
Reserved = SetReserved ( literal_eval ( Args . ReservedPaths ) if Args . ReservedPaths else { } ) ,
2022-06-30 23:29:44 +02:00
Locale = Locale ,
2022-06-23 17:20:06 +02:00
Minify = Args . Minify if Args . Minify else ' None ' ,
2022-06-29 23:56:20 +02:00
Sorting = SetSorting ( literal_eval ( Args . ContextParts ) if Args . ContextParts else { } ) ,
MarkdownExts = literal_eval ( Args . MarkdownExts ) if Args . MarkdownExts else [ ' attr_list ' ] )
2022-06-24 17:19:22 +02:00
if FeedEntries != 0 :
2022-07-01 16:39:54 +02:00
print ( " [I] Generating Feeds " )
2022-06-24 17:19:22 +02:00
MakeFeed (
2022-06-24 20:00:38 +02:00
Pages = Pages ,
2022-06-24 17:19:22 +02:00
SiteName = SiteName ,
SiteTagline = SiteTagline ,
SiteDomain = SiteDomain ,
MaxEntries = FeedEntries ,
Lang = SiteLang ,
2022-06-24 20:00:38 +02:00
Minify = True if Args . Minify and Args . Minify not in ( ' False ' , ' None ' ) else False )
2022-06-24 17:19:22 +02:00
2022-07-02 22:09:09 +02:00
if ActivityPub and MastodonURL and MastodonToken and SiteDomain :
2022-07-01 16:39:54 +02:00
print ( " [I] Mastodon Stuff " )
2022-07-01 14:00:25 +02:00
MastodonPosts = MastodonShare (
2022-06-30 23:29:44 +02:00
MastodonURL ,
MastodonToken ,
Pages ,
SiteDomain ,
SiteLang ,
Locale )
2022-07-01 14:00:25 +02:00
else :
MastodonPosts = [ ]
2022-07-01 17:29:37 +02:00
for File , Content , Titles , Meta , ContentHTML , SlimHTML , Description , Image in Pages :
2022-07-01 14:00:25 +02:00
File = ' public/ {} .html ' . format ( StripExt ( File ) )
Content = ReadFile ( File )
Post = ' '
for p in MastodonPosts :
if p [ ' Link ' ] == SiteDomain + ' / ' + File [ len ( ' public/ ' ) : ] :
Post = ' <br><h3> {StrComments} </h3><a href= " {URL} " rel= " noopener " target= " _blank " > {StrOpen} ↗️</a> ' . format (
StrComments = Locale [ ' Comments ' ] ,
StrOpen = Locale [ ' OpenInNewTab ' ] ,
URL = p [ ' Post ' ] )
break
Content = Content . replace ( ' [HTML:Comments] ' , Post )
WriteFile ( File , Content )
if Args . GemtextOut :
2022-07-01 16:39:54 +02:00
print ( " [I] Generating Gemtext " )
2022-07-01 17:29:37 +02:00
GemtextCompileList ( Pages , SiteName )
2022-06-29 00:17:52 +02:00
2022-06-23 17:20:06 +02:00
DelTmp ( )
2022-05-17 22:58:51 +02:00
os . system ( " cp -R Assets/* public/ " )
2022-07-01 16:39:54 +02:00
print ( " [I] Done! " )
2022-05-16 20:12:06 +02:00
if __name__ == ' __main__ ' :
2022-05-24 00:22:32 +02:00
Parser = argparse . ArgumentParser ( )
2022-06-20 23:16:31 +02:00
Parser . add_argument ( ' --Minify ' , type = str )
2022-06-23 17:20:06 +02:00
Parser . add_argument ( ' --Sorting ' , type = str )
2022-06-20 16:16:41 +02:00
Parser . add_argument ( ' --SiteLang ' , type = str )
2022-05-29 00:51:19 +02:00
Parser . add_argument ( ' --SiteRoot ' , type = str )
2022-06-24 17:19:22 +02:00
Parser . add_argument ( ' --SiteName ' , type = str )
Parser . add_argument ( ' --SiteDomain ' , type = str )
2022-06-29 23:56:20 +02:00
Parser . add_argument ( ' --GemtextOut ' , type = bool )
2022-06-24 17:19:22 +02:00
Parser . add_argument ( ' --SiteTagline ' , type = str )
Parser . add_argument ( ' --FeedEntries ' , type = int )
2022-06-19 23:07:23 +02:00
Parser . add_argument ( ' --FolderRoots ' , type = str )
2022-06-07 13:42:32 +02:00
Parser . add_argument ( ' --ContextParts ' , type = str )
2022-06-29 23:56:20 +02:00
Parser . add_argument ( ' --MarkdownExts ' , type = str )
2022-06-20 23:16:31 +02:00
Parser . add_argument ( ' --ReservedPaths ' , type = str )
2022-06-30 18:50:18 +02:00
Parser . add_argument ( ' --MastodonURL ' , type = str )
Parser . add_argument ( ' --MastodonToken ' , type = str )
2022-06-29 23:56:20 +02:00
Args = Parser . parse_args ( )
try :
import lxml
from Modules . Feed import *
FeedEntries = Args . FeedEntries if Args . FeedEntries else 10
except :
2022-07-01 16:39:54 +02:00
print ( " [E] Can ' t load the Atom/RSS feed libraries. Their generation is disabled. " )
2022-06-29 23:56:20 +02:00
FeedEntries = 0
2022-06-20 16:16:41 +02:00
Main (
2022-06-29 23:56:20 +02:00
Args = Args ,
FeedEntries = FeedEntries )