#!/usr/bin/env python3 """ ================================= | | This file is part of | | staticoso | | Just a simple Static Site Generator | | | | Licensed under the AGPLv3 license | | Copyright (C) 2022, OctoSpacc | | ================================= """ import argparse import os import shutil from ast import literal_eval from datetime import datetime from pathlib import Path try: from Modules.ActivityPub import * ActivityPub = True except: print("[E] Can't load the ActivityPub module. Its use is disabled. Make sure the 'requests' library is installed.") ActivityPub = False from Modules.Config import * from Modules.Gemini import * from Modules.Markdown import * from Modules.Site import * from Modules.Sitemap import * from Modules.Utils import * def ResetPublic(): for i in ('public', 'public.gmi'): try: shutil.rmtree(i) except FileNotFoundError: pass def DelTmp(): for Ext in FileExtensions['Tmp']: for File in Path('public').rglob(f"*.{Ext}"): os.remove(File) for Dir in ('public', 'public.gmi'): for File in Path(Dir).rglob('*.tmp'): os.remove(File) def SetSorting(Sorting): Default = { 'Pages':'Standard', 'Posts':'Inverse'} for i in Default: if i not in Sorting: Sorting.update({i:Default[i]}) return Sorting def GetConfMenu(Entries, MarkdownExts): if Entries: Menu, Max = [], 0 for i in Entries: if int(i) > Max: Max = int(i) Menu = [None] * (Max+1) for i in Entries: e = Entries[i] if not ((e.startswith('<') or e.startswith('[') or e.startswith('- ')) and (e.endswith('>') or e.endswith(')') or e.endswith('}'))): if not e.lower().endswith(FileExtensions['HTML']): e += '.html' Menu[int(i)] = e return Menu def Main(Args, FeedEntries): HavePages, HavePosts = False, False SiteConf = LoadConfFile('Site.ini') SiteName = Args.SiteName if Args.SiteName else ReadConf(SiteConf, 'Site', 'Name') if ReadConf(SiteConf, 'Site', 'Name') else '' BlogName = Args.BlogName if Args.BlogName else ReadConf(SiteConf, 'Site', 'BlogName') if ReadConf(SiteConf, 'Site', 'BlogName') else '' SiteTagline = Args.SiteTagline if Args.SiteTagline else ReadConf(SiteConf, 'Site', 'Tagline') if ReadConf(SiteConf, 'Site', 'Tagline') else '' SiteTemplate = Args.SiteTemplate if Args.SiteTemplate else ReadConf(SiteConf, 'Site', 'Template') if ReadConf(SiteConf, 'Site', 'Template') else 'Default.html' SiteDomain = Args.SiteDomain.rstrip('/') if Args.SiteDomain else ReadConf(SiteConf, 'Site', 'Domain').rstrip('/') if ReadConf(SiteConf, 'Site', 'Domain') else '' SiteRoot = Args.SiteRoot if Args.SiteRoot else ReadConf(SiteConf, 'Site', 'Root') if ReadConf(SiteConf, 'Site', 'Root') else '/' SiteLang = Args.SiteLang if Args.SiteLang else ReadConf(SiteConf, 'Site', 'Lang') if ReadConf(SiteConf, 'Site', 'Lang') else 'en' Locale = LoadLocale(SiteLang) MastodonURL = Args.MastodonURL if Args.MastodonURL else ReadConf(SiteConf, 'Mastodon', 'URL') if ReadConf(SiteConf, 'Mastodon', 'URL') else '' MastodonToken = Args.MastodonToken if Args.MastodonToken else ReadConf(SiteConf, 'Mastodon', 'Token') if ReadConf(SiteConf, 'Mastodon', 'Token') else '' DynamicParts = literal_eval(Args.DynamicParts) if Args.DynamicParts else EvalOpt(ReadConf(SiteConf, 'Site', 'DynamicParts')) if ReadConf(SiteConf, 'Site', 'DynamicParts') else {} MarkdownExts = literal_eval(Args.MarkdownExts) if Args.MarkdownExts else EvalOpt(ReadConf(SiteConf, 'Markdown', 'Exts')) if ReadConf(SiteConf, 'Markdown', 'Exts') else MarkdownExtsDefault ActivityPubTypeFilter = Args.ActivityPubTypeFilter if Args.ActivityPubTypeFilter else ReadConf(SiteConf, 'ActivityPub', 'TypeFilter') if ReadConf(SiteConf, 'ActivityPub', 'TypeFilter') else 'Post' FeedCategoryFilter = Args.FeedCategoryFilter if Args.FeedCategoryFilter else 'Blog' Minify = StringBoolChoose(False, Args.Minify, ReadConf(SiteConf, 'Site', 'Minify')) NoScripts = StringBoolChoose(False, Args.NoScripts, ReadConf(SiteConf, 'Site', 'NoScripts')) ImgAltAndTitle = StringBoolChoose(True, Args.ImgAltAndTitle, ReadConf(SiteConf, 'Site', 'ImgAltAndTitle')) AutoCategories = StringBoolChoose(False, Args.AutoCategories, ReadConf(SiteConf, 'Site', 'AutoCategories')) GemtextOut = StringBoolChoose(False, Args.GemtextOut, ReadConf(SiteConf, 'Site', 'GemtextOut')) SitemapOut = StringBoolChoose(True, Args.SitemapOut, ReadConf(SiteConf, 'Site', 'SitemapOut')) FeedEntries = int(FeedEntries) if (FeedEntries or FeedEntries == 0) and FeedEntries != 'Default' else int(ReadConf(SiteConf, 'Site', 'FeedEntries')) if ReadConf(SiteConf, 'Site', 'FeedEntries') else 10 Sorting = literal_eval(Args.Sorting) if Args.Sorting else EvalOpt(ReadConf(SiteConf, 'Site', 'Sorting')) if ReadConf(SiteConf, 'Site', 'Sorting') else {} MenuEntries = ReadConf(SiteConf, 'Menu') if MenuEntries: ConfMenu = GetConfMenu(MenuEntries, MarkdownExts) else: ConfMenu = [] ResetPublic() if os.path.isdir('Pages'): HavePages = True shutil.copytree('Pages', 'public') if GemtextOut: shutil.copytree('Pages', 'public.gmi', ignore=IgnoreFiles) if os.path.isdir('Posts'): HavePosts = True shutil.copytree('Posts', 'public/Posts') if GemtextOut: shutil.copytree('Posts', 'public.gmi/Posts', ignore=IgnoreFiles) if not HavePages and not HavePosts: print("[E] No Pages or posts found. Nothing to do, exiting!") exit(1) print("[I] Generating HTML") Pages = MakeSite( TemplatesText=LoadFromDir('Templates', ['*.htm', '*.html']), StaticPartsText=LoadFromDir('StaticParts', ['*.htm', '*.html']), DynamicParts=DynamicParts, DynamicPartsText=LoadFromDir('DynamicParts', ['*.htm', '*.html']), ConfMenu=ConfMenu, GlobalMacros=ReadConf(SiteConf, 'Macros'), SiteName=SiteName, BlogName=BlogName, SiteTagline=SiteTagline, SiteTemplate=SiteTemplate, SiteDomain=SiteDomain, SiteRoot=SiteRoot, FolderRoots=literal_eval(Args.FolderRoots) if Args.FolderRoots else {}, SiteLang=SiteLang, Locale=Locale, Minify=Minify, NoScripts=NoScripts, ImgAltAndTitle=ImgAltAndTitle, Sorting=SetSorting(Sorting), MarkdownExts=MarkdownExts, AutoCategories=AutoCategories) if FeedEntries != 0: print("[I] Generating Feeds") for FeedType in (True, False): MakeFeed( CategoryFilter=FeedCategoryFilter, Pages=Pages, SiteName=SiteName, SiteTagline=SiteTagline, SiteDomain=SiteDomain, MaxEntries=FeedEntries, Lang=SiteLang, FullSite=FeedType, Minify=Minify) if SitemapOut: print("[I] Generating Sitemap") MakeSitemap(Pages, SiteDomain) if ActivityPub and MastodonURL and MastodonToken and SiteDomain: print("[I] Mastodon Stuff") MastodonPosts = MastodonShare( InstanceURL=MastodonURL, Token=MastodonToken, Pages=Pages, SiteDomain=SiteDomain, SiteLang=SiteLang, Locale=Locale, TypeFilter=ActivityPubTypeFilter, CategoryFilter=FeedCategoryFilter, HoursLimit=Args.ActivityPubHoursLimit if Args.ActivityPubHoursLimit else 168) else: MastodonPosts = [] for File, Content, Titles, Meta, ContentHTML, SlimHTML, Description, Image in Pages: File = 'public/{}.html'.format(StripExt(File)) Content = ReadFile(File) Post = '' for p in MastodonPosts: if p['Link'] == SiteDomain + '/' + File[len('public/'):]: Post = '

{StrComments}

{StrOpen} ↗️'.format( StrComments=Locale['Comments'], StrOpen=Locale['OpenInNewTab'], URL=p['Post']) break Content = Content.replace('[staticoso:Comments]', Post) WriteFile(File, Content) if GemtextOut: print("[I] Generating Gemtext") GemtextCompileList( Pages, Header=Args.GemtextHeader if Args.GemtextHeader else f"# {SiteName}\n\n" if SiteName else '') print("[I] Cleaning Temporary Files") DelTmp() print("[I] Copying Assets") os.system("cp -R Assets/* public/") print("[I] Done!") if __name__ == '__main__': Parser = argparse.ArgumentParser() Parser.add_argument('--Sorting', type=str) Parser.add_argument('--SiteLang', type=str) Parser.add_argument('--SiteRoot', type=str) Parser.add_argument('--SiteName', type=str) Parser.add_argument('--BlogName', type=str) Parser.add_argument('--SiteTemplate', type=str) Parser.add_argument('--SiteDomain', type=str) Parser.add_argument('--Minify', type=str) Parser.add_argument('--NoScripts', type=str) Parser.add_argument('--ImgAltAndTitle', type=str) Parser.add_argument('--GemtextOut', type=str) Parser.add_argument('--GemtextHeader', type=str) Parser.add_argument('--SiteTagline', type=str) Parser.add_argument('--SitemapOut', type=str) Parser.add_argument('--FeedEntries', type=str) Parser.add_argument('--FolderRoots', type=str) Parser.add_argument('--DynamicParts', type=str) Parser.add_argument('--MarkdownExts', type=str) Parser.add_argument('--MastodonURL', type=str) Parser.add_argument('--MastodonToken', type=str) Parser.add_argument('--FeedCategoryFilter', type=str) Parser.add_argument('--ActivityPubTypeFilter', type=str) Parser.add_argument('--ActivityPubHoursLimit', type=int) Parser.add_argument('--AutoCategories', type=str) Args = Parser.parse_args() try: import lxml from Modules.Feed import * FeedEntries = Args.FeedEntries if Args.FeedEntries else 'Default' except: print("[E] Can't load the XML libraries. XML Feeds Generation is Disabled. Make sure the 'lxml' library is installed.") FeedEntries = 0 Main( Args=Args, FeedEntries=FeedEntries)