Compare commits

..

5 Commits
0.0.7 ... main

Author SHA1 Message Date
digitalstudium 1bd46b2105 Add mimify_html 2024-01-20 15:07:43 +03:00
Digital Studium 98912ac09b Fix observer' screen 2023-10-14 18:46:50 +03:00
Digital Studium d29570739b Sorting by date 2023-10-14 13:53:51 +03:00
Digital Studium 2c30a3bb30 Add minifiers 2023-07-28 20:35:34 +03:00
Digital Studium 024ba1f56a Fix readme 2023-07-23 22:52:34 +03:00
4 changed files with 75 additions and 59 deletions

View File

@ -8,7 +8,7 @@ Example website: https://git.digitalstudium.com/digitalstudium/digitalstudium.co
## Installation (Linux): ## Installation (Linux):
``` ```
curl https://git.digitalstudium.com/attachments/ea3e7e10-198b-4ae7-823d-2a6168c8d82c -o franca && chmod +x franca && sudo mv franca /usr/local/bin curl https://git.digitalstudium.com/attachments/ceaf659d-f161-4ca4-86f9-172993b35e7e -o franca && chmod +x franca && sudo mv franca /usr/local/bin
``` ```
## Usage: ## Usage:
Development: Development:

2
common

@ -1 +1 @@
Subproject commit faba107ed11c0ffb1965710e602cab9a1342baf0 Subproject commit f551c17705ea4be7369423f5d829264911588523

91
franca.py Normal file → Executable file
View File

@ -1,17 +1,17 @@
#!/usr/bin/env python3
import csv import csv
import os import os
import shutil import shutil
from pathlib import Path from pathlib import Path
from watchdog.observers import Observer from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler from watchdog.events import PatternMatchingEventHandler
from jinja2 import Environment, FileSystemLoader, select_autoescape from jinja2 import Environment, FileSystemLoader, select_autoescape
import yaml import yaml
import frontmatter import frontmatter
import markdown2 import markdown2
import fire import fire
from PIL import Image import minify_html
from common.functions import * from common.functions import *
@ -21,7 +21,8 @@ def load_translations(file_path, _dict):
reader = csv.DictReader(f, delimiter='|') # reader = csv.DictReader(f, delimiter='|') #
for row in reader: # проходим по строкам csv, каждая из которых является словарём for row in reader: # проходим по строкам csv, каждая из которых является словарём
_dict[row['id']] = row # добавляем ключ - значение ключа id, значение - словарь row _dict[row['id']] = row # добавляем ключ - значение ключа id, значение - словарь row
del row['id'] # удаляем ключ по названием "id" из словаря row, так как его значение уже является ключом в словаре _dict del row[
'id'] # удаляем ключ по названием "id" из словаря row, так как его значение уже является ключом в словаре _dict
# Функции, доступные в теме # Функции, доступные в теме
@ -29,22 +30,31 @@ def translate(id, language):
global translations global translations
return translations[id][language] return translations[id][language]
translations = {} # здесь будут переводы от темы и от сайта translations = {} # здесь будут переводы от темы и от сайта
config = yaml.safe_load(read_file('config.yaml')) # Чиатем конфиг сайта config = yaml.safe_load(read_file('config.yaml')) # Читаем конфиг сайта
running = False # нужно для проверки running = False # нужно для проверки
# класс для watchdog.
# При обнаружении изменений в папках content и themes/{config['theme']}, перегенерировать папку public # класс для watchdog
class Develop(FileSystemEventHandler): # Во время разработки, при обнаружении изменений в папках content и themes/{config['theme']},
# перегенерировать папку public
class Develop(PatternMatchingEventHandler):
def __init__(self):
PatternMatchingEventHandler.__init__(self, patterns=['*.md', '*.css'],
ignore_directories=True, case_sensitive=False)
def on_modified(self, event): def on_modified(self, event):
print(f'event type: {event.event_type} path : {event.src_path}') print(f'event type: {event.event_type} path : {event.src_path}')
crater() franca()
def on_created(self, event): def on_created(self, event):
print(f'event type: {event.event_type} path : {event.src_path}') print(f'event type: {event.event_type} path : {event.src_path}')
crater() franca()
def on_deleted(self, event): def on_deleted(self, event):
print(f'event type: {event.event_type} path : {event.src_path}') print(f'event type: {event.event_type} path : {event.src_path}')
crater() franca()
# Функция для запуска разработки # Функция для запуска разработки
@ -65,10 +75,10 @@ def develop(prod):
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
# Функция для генерации сайта # Функция для генерации сайта
def crater(prod=False): def franca(prod=False):
# if prod is False, then redefine config.base_url if not prod:
if prod is False:
config['base_url'] = "http://127.0.0.1:8000" config['base_url'] = "http://127.0.0.1:8000"
# Load theme's jinja templates # Load theme's jinja templates
templates = Environment(loader=FileSystemLoader( templates = Environment(loader=FileSystemLoader(
@ -103,20 +113,20 @@ def crater(prod=False):
"content", "public").rstrip(".md") "content", "public").rstrip(".md")
os.makedirs(post_path, exist_ok=True) os.makedirs(post_path, exist_ok=True)
content = markdown2.markdown(post_data.content, extras=['fenced-code-blocks']) content = markdown2.markdown(post_data.content, extras=['fenced-code-blocks'])
description = content.partition('<!--more-->')[0] description = content.partition('<!--more-->')[0]
content = "{% import 'shortcodes.j2' as shortcodes %}" + content content = "{% import 'shortcodes.j2' as shortcodes %}" + content
url = post_path.replace(f"public/{language}", "") url = post_path.replace(f"public/{language}", "")
section = "/" if len(url.split('/')) == 2 else url.split('/')[1] section = "/" if len(url.split('/')) == 2 else url.split('/')[1]
date = post_data['date']
posts[language].setdefault(date, {})
posts[language][date].setdefault(section, {})
posts[language].setdefault(section, {}) posts[language][date][section][url] = {
posts[language][section][url] = {
'title': post_data['title'], 'title': post_data['title'],
'description': description, 'description': description,
'date': post_data['date'], 'date': date,
'content': templates.from_string(content).render() 'content': templates.from_string(content).render()
} }
@ -124,42 +134,42 @@ def crater(prod=False):
if image: if image:
os.makedirs(os.path.dirname(f'public{image}'), exist_ok=True) os.makedirs(os.path.dirname(f'public{image}'), exist_ok=True)
filename = image.split('/')[-1].split('.')[0] filename = image.split('/')[-1].split('.')[0]
extension = image.split('/')[-1].split('.')[1]
image = Image.open(f'assets{image}')
image.thumbnail((600, 600)) create_thumbnail(f'assets{image}', f'public/images/{filename}_600.jpg', 600)
image.save(f'public/images/{filename}_600.{extension}', optimize=True) posts[language][date][section][url]['image'] = f'/images/{filename}_600.jpg'
posts[language][section][url]['image'] = f'/images/{filename}_600.{extension}'
image.thumbnail((400, 400)) create_thumbnail(f'assets{image}', f'public/images/{filename}_400.jpg', 400)
image.save(f'public/images/{filename}_400.{extension}', optimize=True) posts[language][date][section][url]['thumbnail'] = f'/images/{filename}_400.jpg'
posts[language][section][url]['thumbnail'] = f'/images/{filename}_400.{extension}'
posts[language] = dict(sorted(posts[language].items(), reverse=True))
for section, urls in posts[language].items(): for date, sections in posts[language].items():
for section, urls in sections.items():
if section != "/": if section != "/":
html = base.render(config=config, section=section, html = base.render(config=config, section=section,
language=language, posts=posts) language=language, posts=posts)
write_file(f"public/{language}/{section}/index.html", html) write_file(f"public/{language}/{section}/index.html", minify_html.minify(html, minify_js=True))
for url, post in urls.items(): for url, post in urls.items():
html = base.render(config=config, post=post, html = base.render(config=config, post=post,
language=language, url=url, posts=posts) language=language, url=url, posts=posts)
write_file(f"public/{language}{url}/index.html", html) write_file(f"public/{language}{url}/index.html", minify_html.minify(html, minify_js=True))
html = base.render(config=config, posts=posts, html = base.render(config=config, posts=posts,
language=language, home=True) language=language, home=True)
write_file(f"public/{language}/index.html", html) write_file(f"public/{language}/index.html", minify_html.minify(html, minify_js=True))
# copy images/css/js from theme # copy images/css/js from theme
shutil.copytree(f"themes/{config['theme']}/static/images", 'public/images', dirs_exist_ok=True) shutil.copytree(f"themes/{config['theme']}/static/images", 'public/images', dirs_exist_ok=True)
copy_file(f"themes/{config['theme']}/static/css/style.css", 'public/css/') css = read_file(f"themes/{config['theme']}/static/css/style.css")
minify_css('public/css/style.css', css)
if 'css_includes' in config: if 'css_includes' in config:
for include in config['css_includes']: for include in config['css_includes']:
copy_file(f"themes/{config['theme']}/static/css/{include}", 'public/css/') css = read_file(f"themes/{config['theme']}/static/css/{include}")
minify_css(f'public/css/{include}', css)
if 'js_includes' in config: if 'js_includes' in config:
for include in config['js_includes']: for include in config['js_includes']:
copy_file(f"themes/{config['theme']}/static/js/{include}", 'public/js/') copy_file(f"themes/{config['theme']}/static/js/{include}", 'public/js/')
@ -173,15 +183,20 @@ def crater(prod=False):
# Write main index.html # Write main index.html
html = index.render(config=config) html = index.render(config=config)
write_file('public/index.html', html) write_file('public/index.html', minify_html.minify(html, minify_js=True))
# Write robots.txt # Write robots.txt
robots_content = "User-agent: *\nDisallow: /" robots_content = "User-agent: *"
if config.get('search_engines', None) == "allow": if not config.get('search_engines', None) == "allow":
robots_content = robots_content.rstrip("/") robots_content += "\nDisallow: /"
write_file('public/robots.txt', robots_content) write_file('public/robots.txt', robots_content)
global running
if not running:
if 'pagefind' in config:
os.system("npx pagefind --source public") # build search index
develop(prod) develop(prod)
if __name__ == '__main__': if __name__ == '__main__':
fire.Fire(crater) fire.Fire(franca)

View File

@ -3,6 +3,7 @@ fire==0.5.0
Jinja2==3.1.2 Jinja2==3.1.2
markdown2==2.4.9 markdown2==2.4.9
MarkupSafe==2.1.3 MarkupSafe==2.1.3
minify_html==0.15.0
Pillow==10.0.0 Pillow==10.0.0
Pygments==2.15.1 Pygments==2.15.1
pyinstaller==5.13.0 pyinstaller==5.13.0