Release 0.9.0

arguments "all", "again", "newer" with wip/publish. Invert item in RSS (newest...

See merge request echolib/tyto-litterateur!3
This commit is contained in:
Adrien Bourmault 2023-04-14 12:24:17 +00:00
commit 4aba6ee8d3
35 changed files with 7621 additions and 2530 deletions

View File

@ -1,16 +1,10 @@
# Changelog # Changelog
Tyto - Littérateur Tyto - Littérateur
- Repository: https://git.a-lec.org/echolib/tyto - Repository: https://git.a-lec.org/echolib/tyto-litterateur
- Issues: https://git.a-lec.org/echolib/tyto/-/issues - Issues: https://git.a-lec.org/echolib/tyto-litterateur/-/issues
- Changelog: https://git.a-lec.org/echolib/tyto/-/blob/main/CHANGELOG.md - Changelog: https://git.a-lec.org/echolib/tyto-litterateur/-/blob/master/CHANGELOG.md
- License: https://git.a-lec.org/echolib/tyto/-/blob/main/LICENSE - License: https://git.a-lec.org/echolib/tyto-litterateur/-/blob/master/LICENSE
Tyto - Litterateur is a Libre project to create and manage multiple
websites from articles' files. Tyto uses its own syntax to convert
your articles in HTML5 static pages. Tyto works on a GNU/Linux system
and needs minimal dependancies.
- python3 rsync nano gawk curl
## [0.9.0] First Commit version (pre-final)
## [0.9.0]
- Last testings before final

View File

@ -1,21 +0,0 @@
# Installation manuelle
Si vous utilisez Debian, il est plus que recommandé de procéder à
l'installation par le paquet .deb
## Préparer les dossiers
````
sudo mkdir -p /var/lib/tyto /etc/tyto /var/log/tyto
sudo touch /usr/local/bin/tyto
sudo chown -R USER:GROUP /var/lib/tyto /etc/tyto /var/log/tyto
sudo chown USER:GROUP /usr/local/bin/tyto
sudo chmod +x /usr/local/bin/tyto
git clone https://git.a-lec.org/echolib/tyto
rsync -a folders'repo/ to /folders/
# Créer votre dossier pour le serveur web
# On utilise en général /var/www/
# Celui-ci sera à renseigner lors de la création d'un domaine dans Tyto
sudo mkdir -p /var/www/
````

32
Makefile Normal file
View File

@ -0,0 +1,32 @@
#!/bin/bash
# file: Makefile
# By neox
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
default: debian/tyto.deb
### MAKE DEB
.INTERMEDIATE: debian/debian-binary debian/control.tar.gz debian/data.tar.gz
.PHONY: clean
debian/tyto.deb: debian/debian-binary debian/control.tar.gz debian/data.tar.gz
ar -r debian/tyto.deb debian/debian-binary debian/control.tar.gz debian/data.tar.gz
debian/data.tar.gz:
cd src && tar czvf ../debian/data.tar.gz usr var
debian/control.tar.gz:
tar czvf debian/control.tar.gz debian/control #preinst postinst prerm postrm
debian/debian-binary:
echo 2.0 > debian/debian-binary
clean:
-rm debian/*.tar.gz
-rm debian/debian-binary
-rm debian/*.deb

238
README.md
View File

@ -1,5 +1,243 @@
# Tyto # Tyto
Pour obtenir de l'aide, taper juste la commande tyto
## Répertoire de code du projet Tyto ## Répertoire de code du projet Tyto
TODO
## Comment définir les métas
```
# Obligatoires uniques
# Ces marqueurs se configurent sur UNE ligne
title: Titre
about: Infos de l'article
author: Auteur
tags: mot-clé-1,mot 2,
date: YYYY-MM-DD (AAAA-MM-JJ)
# L'image doit être configurée avec le même Nom
# dans les marqueurs multiples
# Utilise l'image précisée comme "avatar" dans les réseaux sociaux
snpic: Nom
# Optionnels multiples
# Ces marqueurs se configurent sur 3 lignes
link: Nom du lien
URL
Texte Alternatif
image: Nom
URI
Texte Alternatif
file: Nom du lien
URL
Texte Alternatif
raw: Nom
URI
Texte Alternatif
abbr: abbrev
Définition de abbrev
ABBR (forme à afficher dans l'artile (optionnel))
# Séparateur d'au moins 5 "-" pour définir la fin
# des métadonnées d'entête de l'article
----------
```
## Comment écrire un article
### Écrire des titres
```
# Les titres HTML vont de 1 à 6.
# Utiliser #N, où N est entre 1 et 6.
# Si du contenu existe entre les titres, une <div> est ajoutée
# Astuce: on commence en général par #2 dans l'article
# Source
#1 Titre 1
Contenu 1
#2 Titre 2
#3 Titre 3
contenu 2
#4 Titre 4
# HTML
<h1 class="title_1">Titre 1</h1>
<div class="content_title">
Contenu 1
</div>
<h2 class="title_2">Titre 2</h2>
<h3 class="title_3">Titre 3</h3>
<div class="content_title">
contenu 2
</div>
<h4 class="title_4">Titre 4</h4>
```
### Paragraphes
```
(( CSS
Un paragraphe
))
```
### Code Brut
```
{{ CSS
def hello_world():
print("Hello")
}}
```
### Listes ul/ol
```
-( CSS
= Liste ul
== Sous-liste ul
=== Sous-sous-liste ul
++++ Sous-sous-sous-liste ol
+++ Sous-sous-liste ol
-)
```
### Ancres
```
# Source de l'ancre cible. "id" est son identité
-> id
# HTML
<a href="id2"></a>
# Source de l'ancre d'appel
# Définir l'identité cible et le texte du lien
((
>_id:Retourner au point d'ancre id_<
))
# HTML
<a class="anchor" href="#id">Retourner au point d'ancre id</a>
```
### Retour à la ligne HTML
```
# Source
|
# HTML
<br />
```
### Lien vers URL
```
Voir ce _Nom du lien # Ouverture même fenêtre
Voir ce _Nom du lien+ # ouverture nouvelle fenêtre
```
### Lien vers fichier
```
Voir ce __Nom du lien # Ouverture même fenêtre
Voir ce __Nom du lien+ # ouverture nouvelle fenêtre
```
Note:
Vous pouvez avoir un Nom identique pour les marqueur `file:` et `link:`
### Gras, Strong, italique...
```
*_très gras_* # <strong>
+_gras léger_+ # <b>
/_en italique_/ # <em>
[_en italique_] # <i>
~_texte barré_~ # <del>
:_Citation rapide_: # <cite>
%_Classe personnalisée_% >>> <span class="custom">
._Souligné_. # <u>
{_Code_} # <code>
# Montrer comment écrire du code dans Tyto:
# Bypass avec \ devant {_ et _}
{_\{_Comme ça\_}_}
```
### Abréviations
```
# abbrev sera remplacé par "ABBR" dans la page si défini en entête
# sinon, abbrev sera conservé
# - Toujours écrire dans l'article :
# - entre parenthèses ET majuscules les "(ABBREV)"
Avec cette (ABBREV).
# HTML: <abbr title="Définition de abbrev">ABBR</abbr>
```
### Images
```
# Chaque image doit être placée en début de ligne
# Placer dans un paragraphe pour chacune ou après "|",
# sinon, affichage les une à côté des autres
# ! Si pas d'unité pour w= et h= : défaut "px"
_image:Nom
_image:Nom c=CSS
_image:Nom c=css w=1080
_image:Nom w=640em h=480em
_image:Nom t=+ # Rend l'image interne cliquable
_image:Nom t=https://...# Donne un lien web à l'image
_image:Nom c=CSS t=https://... w=320px h=240 # 240px
```
### Code brut depuis un fichier
```
_raw:Nom
```
### Citations
Possibilité dans toute citation d'utiliser les marqueurs
optionnels `_xxx:`. Pour la date, utilisez le FORMAT INTERNATIONAL
```
# Source: citation complète
[[ CSS_TEST
_cite: echolib
_date: 2022-12-28
_lang: fr
_link: https://tyto.echolib.re
_book: Référence
((
Pfff, vraiment !
))
]]
# HTML
<figure class="CSS_TEST">
<blockquote class="CSS_TEST" lang="fr" cite="https://tyto.echolib.re" title="echolib - Reference (2022-12-28)">
<time datetime="2022-12-28">
<p class="tyto">
Pfff, vraiment !
</p>
</time>
</blockquote>
<figcaption class="CSS_TEST">
<a class="figc" href="https://tyto.echolib.re">echolib - Reference (2022-12-28)</a>
</figcaption>
</figure>
````
```
# Source: citation basique
[[
Une citation simple, et sans paragraphe
]]
# HTML
<blockquote class="tyto">
Une citation simple, et sans paragraphe
</blockquote>
```

10
debian/control vendored Normal file
View File

@ -0,0 +1,10 @@
Package: tyto
Version: 0.9.0
Section: custom
Priority: optional
Architecture: all
Essential: no
Depends: nano,python3
Installed-Size: `du -ks .|cut -f 1`
Maintainer: echolib <echolib@a-lec.org>
Description: Tyto - Litterateur is a libre project to create and manage multiple websites from articles files. Tyto uses its own syntax to convert your articles in HTML5 pages. Tyto works on a GNU/Linux system and needs minimal dependencies.

91
src/usr/bin/tyto Executable file
View File

@ -0,0 +1,91 @@
#!/usr/bin/env python3
# Version: 0.9.0
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Main binary to execute
# File: /usr/bin/tyto
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# scripts files:
# app lines:
# app comments:
# app functions:
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import sys
sys.path.insert(0, '/var/lib/tyto/program')
#====================#
# MAIN #
# Treat Arguments #
#--------------------#-------------------------------------------------
import logs
if not __name__ == "__main__":
logs.out("14", '', True)
# Check arguments
import args
action = args.set_action()
target = args.set_target()
# Check domain
import dom, status
status.domain()
# Command start argument
import check, form, html, new, publish, show, wip, infos
actions = {
'check' : check.manage,
'help' : infos.tyto,
'edit' : show.manage,
'edit-about' : show.manage,
'edit-db' : show.manage,
'edit-wip' : show.manage,
'edit-www' : show.manage,
'new' : new.manage,
'publish' : publish.manage_publish,
'show' : show.manage,
'show-about' : show.manage,
'show-db' : show.manage,
'show-wip' : show.manage,
'show-www' : show.manage,
'status' : status.check,
'template' : publish.manage_publish,
'wip' : wip.manage,
}
# Start action
# Argument's Check done in args.py
#---------------------------------
actions[action](target)

View File

@ -1,99 +0,0 @@
#!/usr/bin/env python3
# Version: 0.9.0
# Name: Tyto - Littérateur
# Type: Executable
# Description: Multiple Static Websites generator and manager
# file: tyto
# Folder: /usr/local/bin/
# By echolib (XMPP: im@echolib.re)
# Repo: https://git.a-lec.org/echolib/tyto.git
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#------------
# funny stats
#------------
# scripts files:
# app lines:
# app comments:
# app functions:
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
'''
All scripts are in /var/lib/tyto/program/
Directories that must be writeable by Tyto
- /var/lib/tyto/db/
- /var/log/tyto/
- /[LOCAL Server]/ (registred per domain)
'''
#**********************************************************************
# Import needed libs and tyto's libs
import sys
sys.path.insert(0, '/var/lib/tyto/program')
import check, wip, domain, log
#=======#
# Tools #
#=======#--------------------------------------------------------------
#=======================================#
# Check argument from main command line #
# # total arguments #
#---------------------------------------#
def tyto_args(ta):
global file_post, Opt
Domain = False
Opt = ''
Target = ''
# Start process accoring to first argument action
Actions = { 'check' : check.manage_check,
'wip' : wip.manage_wip,
'domain' : domain.manage_domain,
'log' : log.manage_log
}
# Dict for Options
Options = {
'-R' : "Remove", 'remove' : "Remove",
'-n' : "New", 'new' : "New",
'-e' : "Edit", 'edit' : "Edit",
'-F' : "Force", 'force' : "Force"
}
# Set Opt from other arguments options
# Set Target for article or new domain name
if sys.argv[1] == 'domain': Domain = True
for i in range(2, ta):
if sys.argv[i].endswith('.tyto'):
Target = sys.argv[i]
if Target[0] == '/':
Target = Target[1:len(Target)]
else:
try:
Opt = Options[sys.argv[i]]
except:
if Domain:
Target = sys.argv[i]
else:
print(':( Invalid option "%s"'%sys.argv[i])
sys.exit(0)
try:
Actions[sys.argv[1]](Target, Opt)
except KeyError:
print(':( Invalid action "%s"'%sys.argv[1])
#====================#
# MAIN #
# Treat Arguments #
#--------------------#-------------------------------------------------
tyto_args(len(sys.argv))

View File

@ -0,0 +1,16 @@
# Changelog
Tyto - Littérateur
- Repository: https://git.a-lec.org/echolib/tyto
- Issues: https://git.a-lec.org/echolib/tyto/-/issues
- Changelog: https://git.a-lec.org/echolib/tyto/-/blob/main/CHANGELOG.md
- License: https://git.a-lec.org/echolib/tyto/-/blob/main/LICENSE
Tyto - Litterateur is a Libre project to create and manage multiple
websites from articles' files. Tyto uses its own syntax to convert
your articles in HTML5 static pages. Tyto works on a GNU/Linux system
and needs minimal dependancies.
- python3 rsync nano gawk curl
## [0.9.0] First Commit version (pre-final)

View File

@ -0,0 +1,167 @@
# Tyto
## Répertoire de code du projet Tyto
## Comment définir les métas
```
# Obligatoires uniques
title: Titre
about: Infos de l'article
author: Autheur
tags: mots-clé-1,mots-clé-2
date: YYYY-MM-DD (AAAA-MM-JJ)
# Optionnels myltiples
link: Nom du lien
URL
Texte Alternatif
image: Nom
URI
Texte Alternatif
file: Nom du lien
URL
Texte Alternatif
brut: Nom
URI
Texte Alternatif
abbr: NOM (en majuscule)
Définition du NOM
nom (forme à afficher dans l'artile (optionnel))
# Séparateur d'au moins 5 "-" pour définir la fin
# des métadonnées d'entête de l'article
----------
```
## Comment écrire un article
### Titre h1 à h6
```
#1 Titre 1
((
Un paragraphe
))
#2 Titre 2
```
### Paragraphes
```
(( CSS
Un paragraphe
))
```
### Code Brut
```
{{ CSS
def hello_world():
print("Hello")
}}
```
### Listes ul/ol
```
-( CSS
= Liste ul
== Sous-liste ul
=== Sous-sous-liste ul
++++ Sous-sous-sous-liste ol
+++ Sous-sous-liste ol
-)
```
### Citations
```
[[ CSS
_cite: autheur
_lang: langue
_link: lien
_year: année ou date YYYY-MM-DD
_book: référence
((
Citation placée dans un paragraphe
))
]]
[[ CSS
Citation simple sans référence
]]
```
### Ancres
```
-> id
((
un long paragraphe
))
((
>_id:Retourner au point d'ancre_<
))
```
### Retour à la ligne HTML
```
| # <br />
```
### Lien vers URL
```
Voir ce _Nom du lien # Ouverture même fenêtre
Voir ce _Nom du lien+ # ouverture nouvelle fenêtre
```
### Lien vers fichier
```
Voir ce __Nom du lien # Ouverture même fenêtre
Voir ce __Nom du lien+ # ouverture nouvelle fenêtre
```
Note:
Vous pouvez avoir un NAME identique pour file: et link:
### Gras, Strong, italique...
```
*_très gras_* # <strong>
+_gras léger_+ # <b>
/_en italique_/ # <em>
[_en italique_] # <i>
~_texte barré_~ # <del>
{_Code_} # <code>
:_Citation rapide_: # <cite>
%_Classe personnalisée_% >>> <span class="custom">
._Souligné_. # <u>
```
### Abréviations
```
# ! NOM sera remplacé par "nom" dans la page si défini en entête
# sinon, NOM sera conservé
# Toujours écrire en majuscule les ABBR dans l'article brut
# <abbr title="Définition du NOM">nom</abbr>
Avec ce NOM.
```
### Images
```
# Chaque image doit être placée en début de ligne
# Placer dans un paragraphe pour chaque ou après "|",
# sinon, affichage les une à côté des autres
# ! Si pas d'unité pour w= et h= : défaut "px"
_image:Nom
_image:Nom c=CSS
_image:Nom c=css w=1080
_image:Nom w=640em h=480em
_image:Nom t=+ # Rend l'image interne cliquable
_image:Nom t=https://...# Donne un lien à l'image
_image:Nom c=CSS t=https://... w=320px h=240
```
### Code Brut depuis un fichier
```
_brut:NOM
```

View File

@ -0,0 +1,184 @@
/*
* All class / ID used by Tyto - Littérateur in a page
* DOMAIN MUST be changed by domain css set in configuration
*/
/*
* Header
*/
header#header_page {
}
div#site_logo {
}
a#site_logo_link {
}
img#site_logo_image {
}
div#site_infos {
}
a#site_link {
}
h1#site_title {
}
p#site_about {
}
/*
* navbar
*/
nav#site_menu {
}
ul#site_menu_items {
}
li.site_menu_item {
}
a.site_menu_link {
}
/*
* article
*/
article#article_main {
}
h1#main_title {
}
h2.title_2 {
}
h3.title_3 {
}
h4.title_4 {
}
h5.title_5 {
}
h6.title_6 {
}
/* Between every <h2-6> IF CONTENTS */
div.contents {
}
/* Default if not set in post */
p.DOMAIN {
}
br.DOMAIN {
}
a.link {
}
a.anchor_link {
}
abbr.DOMAIN {
}
img.DOMAIN_image {
}
code.icode {
}
ul.DOMAIN {
}
li.DOMAIN
strong.strong {
}
b.bold {
}
em.em{
}
i.italic {
}
del.del {
}
u.underline {
}
cite.cite {
}
span.custom {
}
/* Block_code */
code.DOMAIN {
}
pre.bcode {
}
p.bcode {
}
/* section for author and date */
section#article_infos {
}
span#article_author {
}
span#article_pub {
}
span#article_code {
}
a#article_code_link {
}
/*
* sidebar
*/
aside#sidebar {
}
h1#sidebar_title {
}
ul#sidebar_list {
}
li.sidebar_item {
}
a.sidebar_item_link {
}
h2.sidebar_item_title {
}
p.sidebar_item_about {
}
/*
* footer
*/
footer#footer_page {
}
/* Block*/
div#footer_infos {
}
h1#footer_site_title {
}
p#footer_about {
}
/* Block */
div#footer_references {
}
ul.footer_items {
}
li.footer_item {
}
a.footer_item_link {
}
/* Block */
div#footer_credits {
}
p.footer_copyright {
}
p.footer_generator {
}

View File

@ -0,0 +1,138 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Manage arguments from command line
# File: /var/lib/tyto/program/args.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os, sys
import infos
# Arguments from command line
# tyto [action] [target]
#----------------------------
actions = \
(
'check',
'edit',
'edit-about',
'edit-db',
'edit-wip',
'edit-www',
'help',
'new',
'show',
'show-about',
'show-db',
'show-wip',
'show-www',
'status',
'wip',
'publish'
)
pass_actions = (
'new'
)
# Actions that needs to check for article's database
pass_db = \
(
'check',
'edit',
'edit-db',
'edit-wip',
'edit-www',
'publish',
'show',
'show-about',
'show-db',
'show-wip',
'show-www',
'status',
'wip',
)
pass_targets = \
(
'added',
'again',
'updated',
'domain',
'footer',
'metas',
'navbar',
'sidebar',
'stats',
'template'
)
pass_status = \
(
'domain',
)
multi_chk = ('added', 'again', 'updated')
action = ''
target = ''
noaction = False
# action
#-------
try: action = sys.argv[1]
except: noaction = True
# With no argument, show help
if noaction:
infos.tyto(target)
sys.exit(0)
# Unused argument [action]
act_err = False
if not action in actions:
act_err = True
# target
#-------
try: target = sys.argv[2]
except: target = ''
# Set action and target for binary
def set_action():
return(action)
def set_target():
return(target)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Load article's database and check validity
# File: /var/lib/tyto/program/db.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os
import args, logs, dom, form, tyto, check, publish
remove = exists = post = corrupt = file_wip = file_www = False
chk_again = chk_updated = False
wip_again = wip_added = wip_updated = False
www_again = www_added = www_updated = False
if dom.hole:
logs.out("13", '', True)
# target needs db (file).
# action like show, wip, edit-db
# not domain, all, again...
if args.target \
and args.action in args.pass_db \
and not args.target in args.pass_targets:
# Domain must be valid
if not dom.exists: logs.out("10", '', True)
uri_file = '%s%s'%(dom.articles_d, args.target)
uri_id = tyto.get_filesum(uri_file, False)
# Set DB file
config = '%s%s.config'%(dom.articles_db_d, uri_id)
if tyto.exists(config):
exists = True
try:
exec(open(config).read())
except:
exists = False
else:
exists = False
# Article file exists
if tyto.exists(uri_file):
post = True
hash_post = tyto.get_filesum(uri_file, True)
else:
remove = True
# Check if database config is valid (contains values)
if exists:
values = \
(
'post_id',
'post_src',
'post_wip',
'post_www',
'direc_src',
'short_src',
'short_srv',
'sub_uri',
'http_wip',
'http_www',
'date_chk',
'hash_chk',
'date_wip',
'hash_wip',
'date_www',
'hash_www',
'title',
'about',
'author',
'meta_tags',
'date',
'snpic',
'uris',
'uniq_anchors',
'uniq_abbrs',
'uniq_links',
'uniq_images',
'uniq_files',
'uniq_raws',
'comments',
'tags',
'words',
'titles',
'paragraphs',
'links',
'images',
'anchors',
'abbrs',
'strongs',
'bolds',
'emphasis',
'italics',
'dels',
'underlines',
'cites',
'customs',
'icodes',
'bcodes',
'quotes',
'lists',
'files',
'raws',
'codes',
)
# Set exist for wip and www files
for value in values:
try:
eval(str(value))
except:
remove = True
corrupt = True
break
# Remove DB if unused source article or corrupted DB
if remove and exists:
os.remove(config)
exists = False
logs.out("23", config, False)
old_chk = old_wip = old_www = False
no_chk = no_wip = no_www = False
sync_srvs = False
# Set Statuses for chk, wip, www
if exists:
# File exists on servers
if tyto.exists(post_wip): file_wip = True
if tyto.exists(post_www): file_www = True
# Statuses not set in Db
if not hash_chk: no_chk = True
if not hash_wip: no_wip = True
if not hash_www: no_www = True
# Source article has changed
if hash_post != hash_chk: old_chk = chk_updated = True
if hash_chk: chk_again = True
# WIP article is old
if not old_chk:
if hash_wip and hash_chk != hash_wip: old_wip = wip_updated = True
if no_wip: wip_added = True
if hash_wip: wip_again = True
if not file_wip:
old_wip = wip_updated = True
wip_added = True
wip_again = True
# WWW article is old
if not old_wip:
if hash_www and hash_www != hash_wip: old_www = www_updated = True
if hash_www: www_again = True
if no_www: www_added = True
if not file_www:
old_www = www_updated = True
www_added = True
www_again = True
# Article is updated on both servers
if hash_chk == hash_wip == hash_www: sync_srvs = True

View File

@ -0,0 +1,276 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Load domain database and check validity
# File: /var/lib/tyto/program/dom.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os, sys, importlib, langs
import args
lib = 'tyto_domain'
exists = incomplete = active = ready = shortname = corrupt = False
local_user = articles_db_d = False
hole = False
# Set current directory
try:
user_dir
except:
try:
user_dir = os.getcwd() + "/"
except:
hole = True
# Settings for domain, check if db is not corrupted
dom_values = \
(
'directory',
'database',
'local_user',
'lang_sys',
'lang_logs',
'articles_db_d',
'articles_d',
'files_d',
'images_d',
'modules_d',
'navbar_f',
'sidebar_f',
'metas_f',
'footer_f',
'footer_about_f',
'shortname',
'www_url',
'wip_url',
'srv_root',
'srv_domain',
'srv_wip',
'srv_wip_tpl_d',
'srv_wip_images_d',
'srv_wip_files_d',
'srv_www',
'srv_www_tpl_d',
'srv_www_images_d',
'srv_www_files_d',
'wip_css_f',
'wip_logo_f',
'wip_navbar_f',
'wip_sidebar_f',
'wip_metas_f',
'wip_footer_f',
'wip_stats_f',
'www_css_f',
'www_navbar_f',
'www_sidebar_f',
'www_metas_f',
'www_footer_f',
'www_stats_f',
'www_logo_f',
'www_rss_f',
'logo',
'styles',
'rss',
'rss_items',
'title',
'date',
'about',
'lang_site',
'mail',
'tags',
'license',
'license_url',
'legal_url',
'terms_url',
'css',
'sep',
'article_code',
'relme',
'sidebar_title',
'sidebar_items',
'activated'
)
create_files = \
(
'navbar_f',
'sidebar_f',
'metas_f',
'footer_f',
'footer_about_f'
)
wip_html_mods = ()
err_val = (()) # Make a list from values error
file_unu = (()) # Make a list for files to check
file_mod = (()) # male a list for modules files to create
dir_new = (()) # Make a list for directories created
dir_unu = (()) # Not created, unused
if not hole:
home_dir = os.path.expanduser('~')
# Set configuration domain directory
root_dir = user_dir
if '/articles' in user_dir:
root_dir = user_dir.rsplit('/articles')[0] + "/"
# Set configuration domain file
config = '%styto_domain.py'%root_dir
shortname = config
# Set exists if configuration file
if os.path.exists(config):
exists = True
try:
exec(open(config).read())
try:
os.path.exists(articles_d)
if '/articles' in user_dir:
user_uri_dir = user_dir.rsplit(articles_d)[1]
else:
user_uri_dir = ''
os.chdir(articles_d)
except: corrupt = True
except:
corrupt = True
if not args.target in args.pass_targets:
if args.target.startswith("articles/"):
args.target = args.target.rsplit("articles/")[1]
args.target = user_uri_dir + args.target
# For logs: show uri if not shortname known
try: shortname
except: pass
try: active = activated
except: pass
if not corrupt:
for value in dom_values:
try:
eval(str(value))
value_set = True
except:
err_val = err_val + ((value),)
value_set = False
incomplete = True
active = False
if value.endswith('_d'):
if value_set:
if not os.path.exists(eval(str(value))):
try:
os.makedirs(eval(str(value)), exist_ok=True)
dir_new = dir_new + ((eval(str(value))),)
except:
dir_unu = dir_unu + ((eval(str(value))),)
elif value.endswith('_f'):
if value_set:
if not os.path.exists(eval(str(value))):
if value in create_files:
file_mod = file_mod + ((value),)
else:
file_unu = file_unu + ((eval(str(value))),)
#==============================================#
# When an active and complete domain is needed #
#----------------------------------------------#
if exists and not incomplete and not corrupt:
wip_html_mods = \
(
eval(str('wip_navbar_f')),
eval(str('wip_sidebar_f')),
eval(str('wip_metas_f')),
eval(str('wip_footer_f'))
)
if active:
ready = True
metas = (
eval(str('metas_f')),
eval(str('wip_metas_f')),
eval(str('www_metas_f'))
)
navbars = (
eval(str('navbar_f')),
eval(str('wip_navbar_f')),
eval(str('www_navbar_f'))
)
sidebars = (
eval(str('sidebar_f')),
eval(str('wip_sidebar_f')),
eval(str('www_sidebar_f'))
)
footers = (
eval(str('footer_f')),
eval(str('wip_footer_f')),
eval(str('www_footer_f')),
eval(str('footer_about_f'))
)
templates = (
eval(str('wip_logo_f')),
eval(str('wip_css_f')),
eval(str('wip_navbar_f')),
eval(str('wip_sidebar_f')),
eval(str('wip_metas_f')),
eval(str('wip_footer_f')),
eval(str('wip_stats_f')),
eval(str('www_logo_f')),
eval(str('www_css_f')),
eval(str('www_navbar_f')),
eval(str('www_sidebar_f')),
eval(str('www_metas_f')),
eval(str('www_footer_f')),
eval(str('www_stats_f')),
eval(str('www_rss_f')),
)
modules = {
"metas" : metas,
"navbar" : navbars,
"sidebar" : sidebars,
"footer" : footers,
"template": templates,
}
#====================================#
# Check if domain is ready and ready #
#------------------------------------#
def valid():
if incomplete: sys.exit(41)
elif not active: sys.exit(42)

View File

@ -1,540 +0,0 @@
#!/usr/bin/env python3
# Name: Tyto - Littérateur
# Type: Global functions for domain
# Description: Add new domain, check domain dir...
# file: domain.py
# Folder: /var/lib/tyto/scripts/
# By echolib (XMPP: im@echolib.re)
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
#======#
# MAIN #
#======#
import sys, os, subprocess, datetime
import check, log
# In Tyto DB dir
tyto_db = '/var/lib/tyto/db/'
tyto_domains = '%sdomains.conf'%tyto_db
# In Tyto log dir
tyto_logs_dir = '/var/log/tyto/'
tyto_logs = '%styto.log'%tyto_logs_dir
# Current dir
curr_dir = domain_articles = domain_logs = os.getcwd()
# set domain configuration file from current directory
conf_domain = '%s/tyto_domain.conf'%curr_dir
# Activation domain
domain_active = domain_conf = False
# Set needed directories
# Create Tyto logs
if not os.path.exists(tyto_logs):
file = open(tyto_logs, "w")
file.write('')
file.close()
msg_log = 'Log > Create logs file for Tyto in %s\n'%tyto_logs
log.append_f(tyto_logs,msg_log,0)
# Get database domains
# If not exists, create the file conf
# Will receive all domain registred
try:
exec(open(tyto_domains).read())
except:
domains_file = open(tyto_domains, 'w')
domains_file.write("# Tyto's file with all activated domains\n")
domains_file.close()
domains_db = open(tyto_domains,'r').read()
# Get user domain configuration file #
# If exists, set to True, and exec
try: # os.path.exists(conf_domain):
exec(open(conf_domain).read())
datas_domain = open(conf_domain, "r").read()
if domain_active:
print(':) Activated domain: "%s"'%domain_name)
else:
print(':/ Not activated domain in',conf_domain)
except:
print(':( Unused domain file:', conf_domain)
#=======#
# Tools #
#=======#--------------------------------------------------------------
#============================#
# Append new value to a file #
#----------------------------#
def append_f(f,line_val):
file = open(f, "a")
file.write('%s\n'%line_val)
#======================================#
# Just a generic exit #
# out defines message, not exit status #
# for process form: "
# - rename temp domain conf to legacy #
#--------------------------------------#
def exiting(process,out,msg):
msgs = [
'\n:) All done !',
'\n:/ Maybe next time...',
'%s'%msg
]
if process == 'form':
os.rename(temp_domain, conf_domain)
print(msgs[out])
sys.exit(0)
#==========================#
# Manage Argument 'domain' #
#==========================#-------------------------------------------
def manage_domain(Domain, Opt):
if not Opt:
try:
# No option: get domain and print it
print('\n',datas_domain)
except:
sys.exit(0)
elif Opt == 'New':
try:
# Domain NAME is defined in CLI
set_domain = Domain
except:
set_domain = ''
add_domain(set_domain)
elif Opt == 'Edit' or '-E':
if domain_conf:
print(':> Editing',domain_conf)
old_conf_ID = check.get_filesum(domain_conf, True)
edit_domain = subprocess.run(['/usr/bin/nano',
'--linenumbers',
domain_conf])
# Compare before and after domain conf file
new_conf_ID = check.get_filesum(domain_conf,True)
if not old_conf_ID == new_conf_ID:
exiting('root',2,':) Updated domain configuration file.')
else:
exiting('root',2,':) Unchanged domain configuration file.')
else:
sys.exit(0)
#===================================#
# Main fonction to add a new domain #
# Check first, if it already exists #
# Domain not activated: #
# - Show registred values in form #
#-----------------------------------#----------------------------------
def add_domain(set_domain):
# Exit if a domain already exists
if domain_active:
sys.exit(0)
global temp_domain
temp_domain = '%s/tyto_domain.tmp'%curr_dir
print('\n'
' ┌──────────────────────────────────────────────┐\n'
' │ Configure a new domain for current directory │\n'
' │ Answer Y = yes. Default value = (default) │\n'
' │ Empty Answer cancel process, except for │\n'
' │ - "Optional"\n'
' │ - "(default) value │\n'
' ├──────────────────────────────────────────────┘'
)
# Create new temp conf file
# Used to prepare values, leaving legacy conf file
file = open(temp_domain, "w")
file.write('# Tyto Configuration Domain\n')
file.close()
# Domain is or not given in CLI.
# Start form
if set_domain:
domain_input_confirn(set_domain)
domain_form()
else:
domain_input()
domain_form()
# End of form.
# Show resume's domain configuration from temp conf file
print('\n'
' ┌─────────────────────────────┐\n'
' │ Please check domain datas...│\n'
' ├─────────────────────────────┘'
)
with open(temp_domain, "r") as file:
post_temp = file.read()
for line in post_temp.split('\n'):
print('%s'%line)
# Ask to confirm to write activation domain
print(' ├─────────────────────────────')
confirm = input(' └ Activate domain configuration ? ')
if confirm in ['y', 'Y']:
create_domain()
else:
exiting('form',1,'')
#==============================#
# If domain name is set in CLI #
# Confirm process #
#------------------------------#
def domain_input_confirn(set_domain):
global domain_name
confirm = input(' ├ Add Domain (%s) here ? '%set_domain)
if confirm in ['y', 'Y']:
# Check if domain already registred
isdomain = set_domain.replace('.','_')
if isdomain in domains_db:
dom_folder = globals().get(isdomain,False)
if dom_folder and not dom_folder == curr_dir:
exiting('root',2,'\n:/ Domain exists in %s'%dom_folder)
domain_name = set_domain
else:
exiting('root',1,'')
#=====================#
# Add new domain_name #
#---------------------#
def domain_input():
global domain_name
set_domain = input(' ├ Enter Domain Name: ')
if not set_domain:
exiting('root',1,'')
else:
domain_name = set_domain
#====================#
# Domain FORM #
# domain_name is set #
# Configure domain #
#--------------------#
def domain_form():
# First settings to put in temp_domain config file
domain_db = '%s/%s/articles/'%(tyto_db,domain_name)
domain_logs = '%s%s/'%(tyto_logs_dir,domain_name)
domain_articles = '%s/articles/'%curr_dir
domain_images = '%simages/'%domain_articles
domain_files = '%sfiles/'%domain_articles
# Add settings from domain name before starting form
append_f(temp_domain,'domain_name = "%s"'%domain_name)
append_f(temp_domain,'domain_conf = "%s"'%conf_domain)
append_f(temp_domain,'domain_db = "%s"'%domain_db)
append_f(temp_domain,'domain_logs = "%s"'%domain_logs)
append_f(temp_domain,'\n# Article directories')
append_f(temp_domain,'domain_dir = "%s"'%curr_dir)
append_f(temp_domain,'domain_articles = "%s"'%domain_articles)
append_f(temp_domain,'domain_files = "%s"'%domain_files)
append_f(temp_domain,'domain_images = "%s"'%domain_images)
# ----------------------- #
# Starting Form #
# Some values are defaut #
# Values can be registred #
# from legacy conf file #
# ----------------------- #
# Local server Directory
# ----------------------
global srv
try:
srv
except:
srv = '/var/www'
set_srv = input(' ├ Local server directory (%s) ? '%srv)
if not set_srv and not srv:
exiting('form',1,'')
if set_srv and set_srv[-1] == '/':
srv = set_srv[:-1]
if not os.path.exists(srv):
exiting('form',2,'\n:( Unsed directory "%s"'%srv)
# Settings for server
srv_domain = '%s/%s/'%(srv,domain_name)
srv_wip = '%s/%s/wip/'%(srv,domain_name)
srv_wip_files = '%s/%s/wip/files/'%(srv,domain_name)
srv_wip_images = '%s/%s/wip/images/'%(srv,domain_name)
srv_wip_template = '%s/%s/wip/template/'%(srv,domain_name)
srv_www = '%s/%s/www/'%(srv,domain_name)
srv_www_files = '%s/%s/www/files/'%(srv,domain_name)
srv_www_images = '%s/%s/www/images/'%(srv,domain_name)
srv_www_template = '%s/%s/www/template/'%(srv,domain_name)
# Write settings to temp_omain
append_f(temp_domain,'\n# Server directories')
append_f(temp_domain,'srv = "%s"'%srv)
append_f(temp_domain,'srv_domain = "%s"'%srv_domain)
append_f(temp_domain,'srv_wip = "%s"'%srv_wip)
append_f(temp_domain,'srv_wip_files = "%s"'%srv_wip_files)
append_f(temp_domain,'srv_wip_images = "%s"'%srv_wip_images)
append_f(temp_domain,'srv_wip_template = "%s"'%srv_wip_template)
append_f(temp_domain,'srv_www = "%s"'%srv_www)
append_f(temp_domain,'srv_www_files = "%s"'%srv_www_files)
append_f(temp_domain,'srv_www_images = "%s"'%srv_www_images)
append_f(temp_domain,'srv_www_template = "%s"'%srv_www_template)
# Domain Title for website
# ------------------------
global domain_title
try:
domain_title
show_title = domain_title[:14] + '...'
except:
domain_title = show_title = ''
set_title = input(' ├ Domain Title (%s) ? '%show_title)
if not set_title and not domain_title:
exiting('form',1,'')
if set_title:
domain_title = set_title
if '"' in domain_title:
domain_title = domain_title.replace('"','\\"')
append_f(temp_domain,'\n# Domain datas for web pages')
append_f(temp_domain,'domain_title = "%s"'%domain_title)
# Separator Pages Titles (default '-')
# ------------------------------------
global sep_titles
try:
sep_titles
except:
sep_titles = '-'
set_sep = input(' ├ Website pages separator (%s) ? '%sep_titles)
if set_sep:
if len(set_sep) > 2:
exiting('form',2,'\n:( Seperator is 2 characters max')
sep_titles = set_sep
append_f(temp_domain,'sep_titles = "%s"'%sep_titles)
# Domain description
# ------------------
global domain_about
try:
domain_about
show_about = domain_about[:14] + '...'
except:
domain_about = show_about = ''
set_about = input(' ├ Domain description (%s) ? '%show_about)
if not set_about and not domain_about:
exiting('form',1,'')
if set_about:
domain_about = set_about
if '"' in domain_about:
domain_about = domain_about.replace('"','\\"')
append_f(temp_domain,'domain_about = "%s"'%domain_about)
# Lang for HTML Pages
# -------------------
global domain_lang
try:
domain_lang
except:
# Get default system language (2/3 chars for HTML)
import locale
domain_lang = locale.getdefaultlocale()[0].split('_')[0]
set_lang = input(' ├ Website HTML lang (%s) ? '%domain_lang)
if set_lang:
if len(set_lang) > 3:
exiting('form',2,'\n:( HTML Lang is 3 characters max')
domain_lang = set_lang
append_f(temp_domain,'domain_lang = "%s"'%domain_lang)
# Domain CSS (prefix class). alphanum only
# ----------------------------------------
global domain_css
try:
domain_css
except:
domain_css = 'tyto'
set_css = input(' ├ Generic CSS class (%s) ? '%domain_css)
if set_css:
domain_css = set_css
if not domain_css.isalnum():
css_alnum = ''.join(c for c in domain_css if c.isalnum())
domain_css = css_alnum
append_f(temp_domain,'domain_css = "%s"'%domain_css)
# Domain mail
# -----------
global domain_mail
try:
domain_mail
show_mail = domain_mail[:14] + '...'
except:
domain_mail = show_mail = ''
set_mail = input(' ├ Contact admin mail (%s) ? '%show_mail)
if not set_mail and not domain_mail:
exiting('form',1,'')
if set_mail:
if not '@' and not '.' in set_mail:
exiting('form',2,'\n:( Invalid mail format (x@x.x)')
domain_mail = set_mail
elif not domain_mail:
exiting('form',2,'\n:( Mail is required.')
append_f(temp_domain,'domain_mail = "%s"'%domain_mail)
# Domain Tags
# -----------
global domain_tags
try:
domain_tags
show_tags = domain_tags[:14] + '...'
except:
domain_tags = show_tags = ''
set_tags = input(' ├ Domain Tags [x,y] (%s) ? '%show_tags)
if not set_tags and not domain_tags:
exiting('form',1,'')
if set_tags:
domain_tags = set_tags
append_f(temp_domain,'domain_tags = "%s"'%domain_tags)
# Webpages Copyright
# ------------------
global domain_license
try:
domain_license
show_license = domain_license[:14] + '...'
except:
domain_license = show_license = 'CC BY-NC-SA'
set_license = input(' ├ Website copyright (%s) ? '%show_license)
if set_license:
domain_license = set_license
if '"' in domain_license:
domain_license = domain_license.replace('"','\\"')
append_f(temp_domain,'domain_license = "%s"'%domain_license)
# Sidebar Title
# -------------
global sidebar_title
try:
sidebar_title
show_st = sidebar_title[:14] + '...'
except:
if 'fr' in domain_lang:
sidebar_title = show_st = "À l'affiche !"
else:
sidebar_title = show_st = "Featured !"
set_st = input(' ├ Sidebar title (%s) ? '%show_st)
if set_st:
sidebar_title = set_st
if '"' in sidebar_title:
sidebar_title = sidebar_title.replace('"','\\"')
# Sidbar items number. Default: 12
# -------------------
global sidebar_items
try:
sidebar_items
except:
sidebar_items = 8
set_si = input(' ├ Sidebar max items [1-16] (%s) ? '%sidebar_items)
if set_si and set_si.isdigit():
if set_si in range(1,16):
exiting('form',2,'\n:( Items number: 1-16')
sidebar_items = set_si
# Domain LOGO (optional)
# ----------------------
global domain_logo
try:
domain_logo
show_logo = domain_logo[:14] + '...'
except:
domain_logo = show_logo = ''
set_logo = input(' ├ Optional. Logo filename (%s) ? '%show_logo)
if set_logo:
domain_logo = set_logo
append_f(temp_domain,'domain_logo = "%s"'%domain_logo)
# External URL profile (optional)
# -------------------------------
global domain_exturl
try:
domain_exturl
show_e= domain_exturl[:14] + '...'
except:
domain_exturl = show_e = ''
set_e = input(' └ Optionnal. URL to a social network (%s) ? '%show_e)
if set_e:
domain_exturl = set_e
append_f(temp_domain,'domain_exturl = "%s"'%domain_exturl)
# Adding sidebar conf
sidebar_dir = '%s/articles/sidebar/'%curr_dir
sidebar_load = '%styto.sidebar'%sidebar_dir
append_f(temp_domain,'\n# Sidebar')
append_f(temp_domain,'domain_sdb_dir = "%s"'%sidebar_dir)
append_f(temp_domain,'domain_sdb_load = "%s"'%sidebar_load)
append_f(temp_domain,'domain_sdb_title = "%s"'%sidebar_title)
append_f(temp_domain,'domain_sdb_items = "%s"'%sidebar_items)
#==========================#
# If confirm activation #
# Add value to domain conf #
# Create all directories #
#--------------------------#
def create_domain():
# Add activation var to temp domain conf
append_f(temp_domain,'\n# Domain activation')
append_f(temp_domain,'domain_active = True')
# Add var domain_name to tyto_domains file, if not exists
domain_var = domain_name.replace('.','_')
if not domain_var in domains_db:
append_f(tyto_domains,'%s = "%s"'%(domain_var,curr_dir))
# Create all directories for this domain
check.create_domain_dirs('all')
# Will rename temp_domain conf to legacy domain conf file
exiting('form',2,'\n:) Activated domain: "%s"'%domain_name)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,536 @@
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Create HTML page
# File: /var/lib/tyto/program/html.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os, sys, importlib
import logs, db, dom, tyto, form, langs
# Publish option can be
pub_opts = ('www', 'pub')
# Not a line if it starts with...(for sidebar, navbar)
nolines = ('#', '/')
#==========================#
# Load article DB #
# Start HTML page sections #
#--------------------------#
def set_page(target, article_bottom):
create_metas_page() # Include metas tags
create_main_page(target, article_bottom) # Create main page
#============================================#
# Set metas_page to be included in main page #
#--------------------------------------------#
def create_metas_page():
global metas_page
# Settings for metas
#-------------------
metas_page = ''
scale = 'width=device-width, initial-scale=1.0'
all_tags = dom.tags + ',' + db.meta_tags
css_ref = 'href="%stemplate/%s"'%(db.sub_uri, dom.styles)
rss_ref = 'type="application/rss+xml" ' + \
'href="%s%s" title="RSS 2.0. %s %s %s"'%(
db.sub_uri, dom.rss,
dom.title, dom.sep, dom.shortname
)
icon_file = 'favicon.png'
icon_ref = 'type="image/png" href="%stemplate/%s"'%(
db.sub_uri, icon_file
)
relme = '' # External URL in metas (if exists in config domain)
if dom.relme:
relme = '\n <link rel="me" type="text/html" href="%s">'%(
dom.relme
)
# Create author and date publish section infos
create_html_time_meta('wip')
# Set all raw HTML metas
#-----------------------
global metas
metas = \
'<!--# include virtual="/template/metas.html"-->\n' + \
' <meta name="viewport" content="%s" />\n'%scale + \
' <meta name=”url” content=”%s” />\n'%dom.www_url + \
' <meta name="language" content="%s" />\n'%dom.lang_site + \
' <meta name="reply-to" content="%s" />\n'%dom.mail + \
' <meta name="copyright" content="%s" />\n'%dom.license + \
' <meta name="generator" content="%s" />\n'%tyto.Tyto + \
' <meta name="title" content="%s" />\n'%db.title + \
' <meta name="author" content="%s" />\n'%db.author + \
' <meta name="description" content="%s" />\n'%db.about + \
' <meta name="keywords" content="%s" />\n'%all_tags + \
'%s'%meta_pub + \
' <link rel="canonical" href="%s" />\n'%db.http_www + \
' <link rel="alternate" %s />\n'%(rss_ref) + \
' <link rel="stylesheet" %s />\n'%css_ref + \
' <link rel="shortcut icon" %s />\n'%icon_ref + \
' <!-- Open Graph data -->\n' + \
' <meta property="og:site_name" content="%s" />\n'%dom.title + \
' <meta property="og:title" content="%s" />\n'%db.title + \
' <meta property="og:type" content="article" />\n' + \
' <meta property="og:url" content="%s" />\n'%db.http_www + \
' <meta property="og:description" content="%s" />\n'%db.about + \
' <meta property="og:image" content="%s" />\n'%db.snpic + \
'%s'%relme + \
' <title>%s %s %s</title>'%(db.title, dom.sep, dom.title)
#=======================================#
# Set main page, with all HTML sections #
#---------------------------------------#
def create_main_page(target, article_bottom):
global main_page, post_html_code
# Create link for website's logo
#-------------------------------
logo_html = \
'<a href="/"\n' + \
'%stitle="%s %s logo: %s"\n'%(11 * " ",
langs.site.home, dom.sep, dom.title
) + \
'%sid="site_logo_link">\n'%(11 * " ") + \
'%s<img src="%stemplate/%s"\n'%(
10 * " ", db.sub_uri, dom.logo
) + \
'%salt="logo: %s"\n'%(15 * " ", dom.title) + \
'%sid="site_logo_image" />\n'%(15 * " ") + \
'%s</a>'%(8 * " ")
post_html_code = ''
if dom.article_code:
post_html_code = \
' <span id="article_code"> \n' + \
' <a id="article_code_link"\n' + \
' href="./%s"\n'%os.path.basename(db.short_src) + \
' title="%s [%s]">{%s}</a></span> \n'%(
langs.site.tyto_psrc, db.title,
langs.site.source_code
)
#-----------------------#
# Create main HTML Page #
#-----------------------#
main_page = \
'<!Doctype html>\n' + \
'<html lang="%s">\n'%dom.lang_site + \
' <head>\n' + \
'%s\n'%metas + \
' </head>\n\n' + \
' <body>\n' + \
' <header id="header_page">\n' + \
' <div id="site_logo">\n' + \
' %s\n'%logo_html + \
' </div>\n' + \
' <div id="site_infos">\n' + \
' <a href="/"\n' + \
' title="%s"\n'%(langs.site.home) + \
' id="site_link">\n' + \
' <h1 id="site_title">%s</h1>\n'%dom.title + \
' </a>\n' + \
' <p id="site_about">%s</p>\n'%dom.about + \
' </div>\n' + \
' </header>\n' + \
'<!--# include virtual="/template/navbar.html"-->\n' + \
'\n' + \
' <article id="article_main">\n' + \
' <h1 id="main_title"\n' + \
' title="[%s] %s %s %s %s">%s</h1>\n'%(
db.title, langs.site.w_written, db.date,
langs.site.by, db.author,
db.title,
) + \
'%s\n'%article_bottom + \
' <section id="article_infos">\n' + \
' <p>\n' + \
' <span id="article_author"\n' + \
' title="%s %s [%s]">%s</span>, %s\n'%(
db.author, langs.site.author_of, db.title,
db.author, langs.site.le
) + \
'%s\n'%time_html_pub + \
'%s'%post_html_code + \
' </p>\n' + \
' </section>\n' + \
' </article>\n' + \
'\n' + \
'<!--# include virtual="/template/sidebar.html"-->\n' + \
'<!--# include virtual="/template/footer.html"-->\n' + \
' </body>\n' + \
'</html>'
#============================================#
# Create HTML line for article infos section #
# when wip, and publish #
#--------------------------------------------#
def create_html_time_meta(process):
# Need to reload the DB to get last time updated
importlib.reload(db)
global time_html_pub, meta_pub, date_raw
if process == 'wip':
try:
date_raw = db.date_wip # <time datetime= / meta search_date
date_pub = db.date_wip.rsplit(' ')[0]
time_pub = db.date_wip.rsplit(' ')[1]
except:
logs.out("23", '"date_wip = ?" > %s'%db.uri_file, True)
elif process == 'publish':
try:
date_raw = db.date_www # <time datetime=
date_pub = db.date_www.rsplit(' ')[0]
time_pub = db.date_www.rsplit(' ')[1]
except:
logs.out("23", '"date_www = ?" > %s'%db.uri_file, True)
if dom.lang_site == 'fr':
date_new = date_pub.rsplit('-')
date_pub = date_new[2] + '/' + date_new[1] + '/' + date_new[0]
# in <article> > section info : line with new date
time_html_pub = \
'<!--Tyto_Published-->\n' + \
' <time datetime="%s">\n'%date_raw + \
' <span id="article_pub"\n' + \
' title="[%s] %s %s (%s)">%s</span>\n'%(
db.title, langs.site.w_published, date_pub, time_pub,
date_pub
) + \
' </time>\n' + \
'<!--/Tyto_Published-->'
# meta search_date=
meta_pub = \
'<!--Tyto_Meta--> <meta name="search_date" content="%s" />\n'%(
date_raw.rsplit(' ')[0]
)
#=================================================#
# Create metas.html from _configs/tyto.metas.html #
# Opiton 'pub' force create (when publish) #
#-------------------------------------------------#
def create_user_metas(option):
dom.valid()
if option == 'wip': target = dom.wip_metas_f
elif option in pub_opts: target = dom.www_metas_f
if option == 'www' and tyto.exists(target):
form.asking('%s. %s%s '%(
langs.site.metas, langs.site.form_rep, langs.site.q
), True)
print('\n%s'%langs.site.metas_inf)
# Create wip metas.html file according to option
#-----------------------------------------------
try: user_file = open(dom.metas_f, 'r').read()
except: logs.out("1", dom.metas_f, True)
user_metas = ''
tab = 4 * ' '
metas_used = ('<meta ', '<link ')
for line in user_file.rsplit('\n'):
if line.startswith(metas_used):
if user_metas: user_metas = "%s\n%s%s"%(user_metas, tab, line)
else: user_metas = '%s%s'%(tab, line)
tyto.set_file(target, 'New', user_metas)
#==============================================#
# Create HTML sidebar from file tyto.navbar #
# If no index file in src directory: pass # #
# Create empty file in template/ if not exists #
#----------------------------------------------#
def create_navbar(option):
dom.valid()
if not tyto.exists(dom.navbar_f):
logs.out("1", dom.navbar_f, True)
if option == 'wip': target = dom.wip_navbar_f
elif option in pub_opts: target = dom.www_navbar_f
if option == 'www' and tyto.exists(target):
form.asking('%s. %s(%s)%s '%(
langs.site.navbar, langs.site.form_rep,
option, langs.site.q
), True)
print('\n%s'%langs.site.navbar_inf)
# navbar has items
navbar_items = False
# Set first HTML line
menu_html = \
'%s<nav id="site_menu">\n'%(4 * ' ') + \
'%s<ul id="site_menu_items">'%(6 * ' ')
navbar_lines = open(dom.navbar_f, 'r').read()
for line in navbar_lines.rsplit('\n'):
if not line or line.startswith(nolines): continue
# Get HTML title if defined (commented after)
if '#' in line:
direc = line.rsplit('#')[0].rstrip()
title = '%stitle="%s"\n'%(15 * ' ', line.rsplit('#')[1].lstrip())
else:
direc = line
title = ''
# Check if directory exists in articles/
dir_uri = os.path.join(dom.articles_d, direc)
if not os.path.isdir(dir_uri):
logs.out("24", '%s/'%dir_uri, False)
continue
# Check if an index.[ext] exists (src, wip, www)
no_wip_index = False
no_www_index = False
src_index = ''
wip_index = '%s%s/index.html'%(dom.srv_wip, direc)
www_index = '%s%s/index.html'%(dom.srv_www, direc)
# Source index article must exist
src_index = [ \
filename \
for filename in os.listdir(dir_uri) \
if filename.startswith("index.") \
and os.path.isfile \
]
if not src_index:
src_index = '%s%s/index.tyto'%(dom.articles_d, direc)
logs.out('26', '> %s'%(src_index), False)
continue
# index.html server files must exist (or 404 error)
if option == 'wip':
if not tyto.exists(wip_index):
logs.out('26', '> %s'%(wip_index), False)
no_wip_index = True
continue
elif option in pub_opts:
if not tyto.exists(www_index):
logs.out('26', '> %s'%(www_index), False)
no_www_index = True
continue
# Add link to HTML structure
navbar_items = True
menu_item = \
'\n%s<li class="site_menu_item">\n'%(8 * ' ') + \
'%s<a class="site_menu_link"\n'%(10 * ' ') + \
'%s'%title + \
'%shref="/%s/">%s</a>\n'%(
15 * ' ', direc, direc
) + \
'%s</li>'%(8 * ' ')
menu_html = '%s%s'%(menu_html, menu_item)
# Nothing to do
if not navbar_items:
if not tyto.exists(target):
tyto.set_file(target, 'New', '')
logs.out('28', '%s'%langs.log.navbar, False)
return
# Create ending HTML file
else:
menu_html = '\n%s\n%s</ul>\n%s</nav>\n'%(menu_html, 8 * ' ', 6 * ' ')
tyto.set_file(target, 'New', menu_html)
#==============================================#
# Create HTML sidebar from file tyto.sidebar #
# Create empty file in template/ if not exists #
#----------------------------------------------#
def create_sidebar(option):
dom.valid()
if not tyto.exists(dom.sidebar_f):
logs.out("1", dom.sidebar_f, True)
if int(dom.sidebar_items) > 16: db.sidebar_items = 6
if option == 'wip': target = dom.wip_sidebar_f
elif option in pub_opts: target = dom.www_sidebar_f
if option == 'www' and tyto.exists(target):
form.asking('%s. %s%s '%(
langs.site.sidebar, langs.site.form_rep, langs.site.q
), True)
print('\n%s'%langs.site.sidebar_inf)
sidebar_items = False
# Set HTML sidebar
sidebar_list = ''
sidebar_html = \
'<aside id="sidebar">\n' + \
' <h1 id="sidebar_title">%s</h1>\n' + \
' <ul id="sidebar_list">\n' + \
'%s' + \
' </ul>\n' + \
'</aside>'
sidebar_title = dom.sidebar_title
sidebar_lines = open(dom.sidebar_f, 'r').read()
counter = 0
for line in sidebar_lines.rsplit('\n'):
if not line or line.startswith(nolines):
continue
if line.startswith(':'):
sidebar_title = line.rsplit(':')[1].lstrip()
continue
f_uri = '%s%s'%(dom.articles_d, line)
if not tyto.exists(f_uri):
logs.out("24", f_uri, False)
continue
# Get Hash from uri to get db file
hash_uri = tyto.get_filesum(f_uri, False)
db_uri = '%s%s.config'%(dom.articles_db_d, hash_uri)
if not tyto.exists(db_uri):
logs.out('25', line, False)
continue
# Load article"s database
exec(open(db_uri).read(),globals())
# Check wip status and if article exists in server
if option == 'wip':
if hash_wip != hash_chk:
logs.out("30", line, False)
continue
if not tyto.exists(post_wip):
logs.out("24", post_wip, False)
continue
elif option in pub_opts:
if hash_www != hash_chk:
logs.out("30", line, False)
continue
if not tyto.exists(post_www):
logs.out("24", post_www, False)
continue
# Add item if not max
sidebar_items = True
counter += 1
if counter > dom.sidebar_items: break
# Show item to add
logs.out("35", '"%s" > %s'%(title, line), False)
# Create HTML list for this article
link_title = '%s [%s]'%(title, author)
sidebar_list = sidebar_list + \
' <li class="sidebar_item">\n' + \
' <a class="sidebar_item_link"\n' + \
' href="/%s">\n'%short_srv + \
' <h2 class="sidebar_item_title">%s</h2>\n'%title + \
' <p class="sidebar_item_about"\n' + \
' title="%s">\n'%link_title + \
' %s [%s] - %s\n'%(date, author, about) + \
' </p>\n' + \
' </a>\n' + \
' </li>\n'
# Nothing to do
if not sidebar_items:
if not tyto.exists(target):
tyto.set_file(target, 'New', '')
logs.out('28', '%s'%langs.log.sidebar, False)
return
else:
# Create HTML complete sidebar
sidebar_temp = sidebar_html%(sidebar_title, sidebar_list)
# Indent HTML code
sidebar_content = ''
for line in sidebar_temp.rsplit('\n'):
sidebar_content = sidebar_content + '%s%s\n'%(4 * ' ', line)
tyto.set_file(target, True, sidebar_content)
#===================================================#
# Create footer.html from _configs/tyto.footer.html #
#----------------------------------------------=====#
def create_user_footer(option):
dom.valid()
if option == 'wip': target = dom.wip_footer_f
elif option in pub_opts: target = dom.www_footer_f
if option == 'www' and tyto.exists(target):
form.asking('%s. %s%s '%(
langs.site.footer, langs.site.form_rep, langs.site.q
), True)
print('\n%s'%langs.site.footer_inf)
try: footer_f = open(dom.footer_f, 'r').read()
except: logs.out("1", dom.footer_f, True)
footer = ''
tab = 4 * ' '
for line in footer_f.rsplit('\n'):
if not line or line.startswith('#'): continue
if footer: footer = "%s\n%s%s"%(footer, tab, line)
else: footer = '%s%s'%(tab, line)
tyto.set_file(target, 'New', footer)

View File

@ -0,0 +1,101 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Show helps and informations
# File: /var/lib/tyto/program/infos.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os, importlib
import langs
importlib.reload(langs)
# Set colors
CS = '\033[0;0m'
CR = '\033[1;31m'
CY = '\033[1;33m'
CG = '\033[1;32m'
def tyto(target):
noinfos = False
# Show Version
tytobin = open('/usr/bin/tyto').read()
for line in tytobin.rsplit('\n'):
if line.startswith('# Version:'):
print(line)
break
# Show domains list
try:
has_domains = True
user = os.environ.get('USER')
user_dir = os.path.expanduser('~')
db_domains = '%s/.local/tyto'%user_dir
except:
has_domains = False
if not os.path.exists(db_domains):
has_domains = False
print('! No directory > %s/'%db_domains)
if has_domains:
list_domains = (())
for folder in os.listdir(db_domains):
domain_local_uri = '%s/%s'%(db_domains, folder)
if os.path.isdir(domain_local_uri):
domain_conf = '%s/domain_config.bkp'%domain_local_uri
if os.path.exists(domain_conf):
try:
exec(open(domain_conf).read(),globals())
except:
continue
if os.path.exists(directory):
dir_domain = '%s%s%s'%(CG, directory, CS)
else:
dir_domain = '%s%s%s'%(CR, directory, CS)
list_domains = \
(('%s > %s > %s'%(folder, dir_domain, www_url)),)
if list_domains:
print('# %s %ss %s'%(
langs.site.reg_domains,
langs.site.fo,
user
)
)
for domain in list_domains:
print(' - %s'%domain)
# Show arguments help
print(langs.site.args_helps)

View File

@ -0,0 +1,72 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Load translations file for logs and forms/sites
# File: /var/lib/tyto/program/langs.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import locale, sys, os, importlib
import dom
# Import translation directory
trans_dir = '/var/lib/tyto/translations'
sys.path.insert(0, trans_dir)
# Get default system language
# or set "en" (english) if no translation file
try:
lang_sys = locale.getdefaultlocale()[0].split('_')[0]
os.path.exists('%s/logs_%s.py'%(trans_dir, lang_sys))
except:
lang_sys = 'en'
# Set language logs from configuration domain
# or set default english if not known
try:
dom.exists
lang_logs = dom.lang_logs
os.path.exists('%s/logs_%s.py'%(trans_dir, lang_logs))
log = importlib.import_module('logs_%s'%lang_logse, package=None)
except:
log = importlib.import_module('logs_%s'%lang_sys, package=None)
# Set language site/form from configuration domain
# or set default english if not known
try:
dom.exists
lang_site = dom.lang_site
os.path.exists('%s/site_%s.py'%(trans_dir, lang_site))
site = importlib.import_module('site_%s'%lang_site, package=None)
except:
site = importlib.import_module('site_%s'%lang_sys, package=None)

View File

@ -1,81 +0,0 @@
#!/usr/bin/env python3
# Name: Tyto - Littérateur
# Type: Global functions for logs
# Description: Print data to specific log file
# file: log.py
# Folder: /var/lib/tyto/scripts/
# By echolib (XMPP: im@echolib.re)
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import check, domain
#=======================#
# Manage Argument 'log' #
# Read, remove log file #
#-----------------------#
def manage_log(file_post, Opt):
import os, sys
if file_post:
# No domain set, but ask for article : exit
if not domain.domain_conf:
sys.exit(1)
# Get complete URI for post
post_uri = '%s%s'%(domain.domain_articles, file_post)
# Get ID from URI
post_ID = check.get_filesum(post_uri,False)
# Set log file for article
post_logs = '%s%s.log'%(domain.domain_logs,post_ID)
else:
post_logs = domain.tyto_logs
if os.path.exists(post_logs):
if Opt == 'Remove' :
os.remove(post_logs)
msg_log = 'Log > Removed file: %s'%post_logs
if file_post:
append_f(domain.tyto_logs,msg_log,0)
else:
print(':) %s'%msg_log)
else:
file = open(post_logs,'r').read()
print(file)
else:
print(':| Unsed file yet: %s'%post_logs)
#==============================#
# Set and return date and time #
# (especially for logs) #
#------------------------------#
def nowdate():
import datetime
now = datetime.datetime.now()
return(now.strftime('%Y-%m-%d %H:%M:%S'))
#==================================#
# Append line to specific log file #
#----------------------------------#
def append_f(f,line,n):
smiley = [':)',':(\033[1;31m','\033[1;33m:|']
now = nowdate()
# Open file to append line
file = open(f, "a")
file.write('%s %s\n'%(now,line))
file.close()
if not line.endswith('\n'):
print('%s %s\033[0;0m'%(smiley[n],line))

View File

@ -0,0 +1,118 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Show logs messages, exit with nbr
# File: /var/lib/tyto/program/logs.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os, sys
import langs
# Set colors
CS = '\033[0;0m'
CR = '\033[1;31m'
CY = '\033[1;33m'
CG = '\033[1;32m'
# Exit from program with message #
#--------------------------------#
def out(nbr, value, out):
logs = {
'1' : '%s%s%s > %s'%(CR, langs.log.unused_r, CS, value),
'2' : '%s%s%s > %s'%(CR, langs.log.data_inc, CS, value),
'3' : '%s%s%s %s'%(CR, langs.log.data_inv, CS, value),
'4' : '%sUnable to create file%s: %s'%(CR, CS, value),
'5' : '%s%s%s > "%s"'%(CR, langs.log.no_arg, CS, value),
'6' : '%s%s%s > %s'%(CR, langs.log.sep_inv, CS, value),
'7' : '%s%s%s > %s'%(CR, langs.log.post_inv, CS, value),
'8' : '%s%s%s %s'%(CR, langs.log.mark_np, CS, value),
'9' : '%s%s%s > %s'%(CR, langs.log.post_chg, CS, value),
'10' : '%s%s%s'%(CR, langs.log.dom_no, CS),
'11' : '%s%s%s > %s'%(CR, langs.log.err_arg, CS, value),
'12' : '%s%s%s > %s'%(CR, langs.log.post_inc, CS, value),
'13' : '%s%s%s'%(CR, langs.log.no_fidi, CS),
'14' : '%sMismatch%s program start'%(CR, CS),
'15' : '%s%s%s %s'%(CR, langs.log.anch_nu, CS, value),
'16' : '%s%s%s "%s = ?"'%(CR, langs.log.unused_c, CS, value),
'17' : '%s%s%s "%s ?"'%(CR, langs.log.unused_v, CS, value),
'18' : '%s%s%s > %s'%(CR, langs.log.unused_p, CS, value),
'19' : '%s%s%s %s'%(CG, langs.log.was_wip, CS, value),
'20' : '%s%s%s %s'%(CG, langs.log.was_chk, CS, value),
'21' : '%s%s%s > %s'%(CG, langs.log.post_val, CS, value),
'22' : '%s%s%s %s'%(CY, langs.log.symb_np, CS, value),
'23' : '%s%s%s > %s'%(CY, langs.log.db_inv, CS, value),
'24' : '%s%s%s > %s'%(CY, langs.log.unused_r, CS, value),
'25' : '%s%s%s > %s'%(CY, langs.log.nycheck, CS, value),
'26' : '%s%s%s %s'%(CY, langs.log.nyfile, CS, value),
'27' : '%s%s%s %s'%(CY, langs.log.snpic_d, CS, value),
'28' : '%s (%s)'%(langs.log.ntd, value),
'29' : '%sEmpty configuration%s %s'%(CY, CS, value),
'30' : '%s%s%s > %s'%(CY, langs.log.nywip, CS, value),
'31' : '%s%s%s'%(CR, langs.log.nomods, CS),
'32' : ' ╞══ %s%s%s > %s'%(CG, langs.log.file_c, CS, value),
'33' : ' ╞══ %s%s%s > %s'%(CG, langs.log.dir_c, CS, value),
'34' : ' ╞══ %s%s%s > %s'%(CG, langs.log.file_n, CS, value),
'35' : ' ╞═ %s%s%s %s'%(CG, langs.log.add, CS, value),
'36' : '%s %s'%(langs.log.file_e, value),
'37' : '%s %s'%(langs.log.dir_e, value),
'38' : '%s%s%s "%s ?"'%(CR, langs.log.unused_t, CS, value),
'39' : '%s%s%s > %s'%(CR, langs.log.dom_cor, CS, value),
'40' : '%s%s%s > %s'%(CY, langs.log.dom_ina, CS, value),
'41' : '%s%s%s > %s'%(CR, langs.log.dom_inc, CS, value),
'42' : '%s%s%s > %s'%(CG, langs.log.dom_act, CS, value),
'43' : '%s%s%s'%(CY, langs.log.dom_no, CS),
'44' : '%s%s%s "tyto check %s"'%(CY, langs.log.check_m, CS, value),
'45' : '%s%s %s%s > %s'%(CY, langs.log.meta_t, langs.log.no_up, CS, value),
'46' : '%s%s %s%s > %s'%(CY, langs.log.time_t, langs.log.no_up, CS, value),
'51' : '%s%s%s > %s'%(CY, langs.log.data_inc, CS, value),
'60' : '\n%s'%langs.log.status_r,
'61' : '%s%s%s > %s'%(CG, langs.log.file_e, CS, value),
'71' : ' ╞═ %s%s%s > %s'%(CY, langs.log.post_nwi, CS, value),
'72' : ' ╞═ %s%s%s > %s'%(CG, langs.log.post_wip, CS, value),
'73' : ' ╞═ %s%s%s > %s'%(CY, langs.log.st_wip_n, CS, value),
'74' : ' ╞═ %s%s%s > %s'%(CY, langs.log.st_wip_o, CS, value),
'81' : ' ╞═ %s%s%s > %s'%(CY, langs.log.post_nww, CS, value),
'82' : ' ╞═ %s%s%s > %s'%(CG, langs.log.post_www, CS, value),
'83' : ' ╞═ %s%s%s > %s'%(CY, langs.log.st_www_n, CS, value),
'84' : ' ╞═ %s%s%s > %s'%(CY, langs.log.st_www_o, CS, value),
'85' : ' ╞═ %s%s%s > %s'%(CY, langs.log.was_pub, CS, value),
'94' : ' ╞═ %s%s%s > %s'%(CY, langs.log.st_chk_o, CS, value),
'255' : '%s'%langs.log.laterout
}
msg = logs[nbr]
print(msg)
out_0 = (21, 28)
if int(nbr) in out_0: nbr = 0
if out: sys.exit(int(nbr))

View File

@ -0,0 +1,62 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Create something new (domain, sidebar...)
# File: /var/lib/tyto/program/new.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import sys
import args, dom, logs, form, html
#===============================================#
# manage argument new for #
# - domain: target becomes 3rd command argument #
#-----------------------------------------------#
def manage(target):
# Generic option, except for domain
option = 'new'
if target == "domain":
try: option = sys.argv[3]
except: option = ''
if target in args.pass_targets:
actions = {
'domain' : form.manage,
'sidebar' : form.create_sidebar,
'navbar' : form.create_navbar,
'metas' : form.create_metas,
'footer' : form.create_footer
}
actions[target](option)
else:
logs.out("11", '"%s" with "%s"'%(target, option), True)

View File

@ -0,0 +1,263 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Publish on www server
# File: /var/lib/tyto/program/publish.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os, sys, shutil, importlib
from pathlib import Path
import logs, args, dom, db, wip, html, tyto, form, stats, rss, langs
#==============================#
# Manage action, get post db #
# check if publish can be done #
#------------------------------#
def manage_publish(target):
dom.valid()
# Target is footer, sidebar, navbar, metas
# template: create/copy template/ files
# all: publish all wip article
#-----------------------------------------
if target in args.pass_targets:
do = {
'updated' : publish_all,
'again' : publish_all,
'added' : publish_all,
'sidebar' : html.create_sidebar,
'navbar' : html.create_navbar,
'metas' : html.create_user_metas,
'footer' : html.create_user_footer,
'template' : publish_template,
'stats' : stats.manage
}
do[target]('www')
return
# Database must exists...
if not target: logs.out("5", '', True)
if not db.post: logs.out("1", db.uri_file, True)
if not db.exists: logs.out("25", db.uri_file, True)
# Publish in www server an article
check_to_publish('one')
# Article already published
if db.file_www:
logs.out("85", '%s > %s'%(db.date_chk, db.uri_file), False)
answer = form.asking('%s%s '%(
langs.site.publish_a, langs.site.q
), True)
# Publish
publish_article()
# Create new ATOM/RSS file
rss.create_feed()
#============================================#
# Option 'all' to publish again, based on DB #
#--------------------------------------------#
def publish_all(option):
tyto.show_multi_message('www', dom.srv_www)
form.asking('%s%s '%(langs.site.proceed, langs.site.q), True)
# Sort by newer articles (created by last check)
db_articles = sorted(Path(dom.articles_db_d).iterdir(),
key=os.path.getmtime
)
# Load domain configuration DB
option = args.target
found = False
for post_db in db_articles:
if not str(post_db).endswith('.config'): continue
# Load DB
exec(open(post_db).read(),globals())
args.target = short_src
importlib.reload(db)
if option == "again" and not db.www_again: continue
elif option == "added" and not db.www_added: continue
elif option == "updated" and not db.www_updated: continue
check_to_publish('all')
if err_pub:
continue
found = True
publish_article()
if not found:
logs.out("28", 'publish %s'%option, True)
# If found: create new ATOM/RSS file
rss.create_feed()
#==============================#
# Check if it can be published #
#------------------------------#
def check_to_publish(process):
global err_pub
err_pub = False
print('\n ├ [%s] > %s'%(db.title, db.post_src))
# Article was not checked or changed
if db.no_chk:
logs.out("25", db.uri_file, False)
err_pub = 25
elif db.old_chk:
logs.out("9", db.uri_file, False)
err_pub = 9
# Article must exists in wip server
if db.no_wip or db.old_wip:
logs.out("30", db.uri_file, False)
err_pub = 30
elif not db.file_wip:
logs.out("1", db.post_wip, False)
err_pub = 1
if err_pub:
if process == 'all': return
elif process == 'one': sys.exit(err_pub)
#===============#
# Let's publish #
#---------------#
def publish_article():
# Copy wip page to www page
if not os.makedirs('%s%s'%(dom.srv_www, db.direc_src), exist_ok=True):
logs.out("33", '%s%s'%(dom.srv_www, db.direc_src), False)
# Replace in DB hash_wip and date_wip
tyto.replace_in_db(db.config, 'www', db.hash_post)
# Copy needed files (Also create sub-folders)
tyto.files_to_srv('www')
# Replace publish HTML line
replace_lines_pub()
#=================================================#
# Replace line in article containing publish date #
#-------------------------------------------------#
def replace_lines_pub():
html.create_html_time_meta('publish')
in_pub = False
wip_html_post = open(db.post_wip, 'r').read()
www_html_post = wip_html_post
for line in wip_html_post.rsplit('\n'):
if line.startswith('<!--Tyto_Published-->'):
in_pub = True
time_wip_pub = line
continue
elif line.startswith('<!--/Tyto_Published-->'):
time_wip_pub = '%s\n%s'%(time_wip_pub, line)
in_pub = False
break
elif line.startswith('<!--Tyto_Meta-->'):
time_wip_meta = line
continue
if in_pub:
time_wip_pub = '%s\n%s'%(time_wip_pub, line)
# Update file with new time meta
try:
www_html_post = \
www_html_post.replace(time_wip_meta,
html.meta_pub
)
except:
logs.out("45", db.post_www, False)
# update file with new article time
try:
www_html_post = \
www_html_post.replace(time_wip_pub,
html.time_html_pub
)
except:
logs.out("46", db.post_www, False)
tyto.set_file(db.post_www, 'New', www_html_post)
#================================#
# Publish template in www server #
#--------------------------------#
def publish_template(option):
form.asking('%s%s > %s '%(
langs.site.uptpl, langs.site.q,
dom.srv_www_tpl_d
), True)
# Copy all file in wip server template, except "nofiles"
nofiles = (
'footer.html',
'metas.html',
'navbar.html',
'sidebar.html'
)
for item in os.listdir(dom.srv_wip_tpl_d):
if item.startswith(nofiles):
continue
item_src = '%s%s'%(dom.srv_wip_tpl_d, item)
item_dst = '%s%s'%(dom.srv_www_tpl_d, item)
if os.path.isdir(item_src):
shutil.copytree(item_src, item_dst, dirs_exist_ok=True)
logs.out("33", item_dst, False)
else:
shutil.copy2(item_src, item_dst)
logs.out("32", item_dst, False)
# Create new file from _configs/ files
html.create_sidebar('pub')
html.create_navbar('pub')
html.create_user_metas('pub')
html.create_user_footer('pub')

View File

@ -0,0 +1,125 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Create feed RSS/Atom
# File: /var/lib/tyto/program/rss.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#*********************************************************************
import os
from pathlib import Path
import logs, dom, db, tyto, langs
#============================#
# Create ATOM/RSS feed #
# only with publish argument #
#----------------------------#
def create_feed():
# Generic fedd Header
set_f = \
'<?xml version="1.0" encoding="utf-8"?>\n' + \
'<rss version="2.0">\n' + \
' <channel>\n' + \
' <title>%s - %s - Flux RSS 2.0</title>\n'%(
dom.title, dom.www_url
) + \
' <link>%s</link>\n'%dom.www_url + \
' <description>RSS 2.0 - %s (%s)</description>\n'%(
dom.title, dom.about
) + \
' <image>\n' + \
' <url>%s/%s</url>\n'%(dom.www_url, dom.logo) + \
' <title>logo %s</title>\n'%dom.title + \
' <link>%s</link>\n'%dom.www_url + \
' </image>\n' + \
' <language>%s</language>\n'%dom.lang_site + \
' <category>%s</category>\n'%dom.tags + \
' <lastBuildDate>%s</lastBuildDate>\n'%tyto.nowdate() + \
' <copyright>%s</copyright>\n'%dom.license + \
' <webMaster>%s</webMaster>\n'%dom.mail + \
' <generator>%s</generator>'%tyto.Tyto
# Sort by newer articles (created by last check)
db_articles = sorted(Path(dom.articles_db_d).iterdir(),
key=os.path.getmtime,
reverse=True
)
rss_item = False
nbr_item = 0
# Loop published articles. Get databases of articles
for post_db in db_articles:
if not str(post_db).endswith('.config'):
continue
# Load DB
exec(open(post_db).read(),globals())
if not hash_www or hash_chk != hash_www:
continue
rss_item = True
nbr_item += 1
if nbr_item > dom.rss_items:
break
set_f = \
'%s\n'%set_f + \
'\n <item>\n' + \
' <title>%s</title>\n'%title + \
' <link>%s</link>\n'%http_www + \
' <guid>%s</guid>\n'%http_www + \
' <pubDate>%s</pubDate>\n'%date_www + \
' <description>%s</description>\n'%about + \
' <author>%s</author>\n'%author + \
' <image>\n' + \
' <url>%s</url>\n'%snpic + \
' <title>%s</title>\n'%(title) + \
' <link>%s</link>\n'%http_www + \
' </image>\n' + \
' <category>%s</category>\n'%tags + \
' </item>'
# Do nothing if no item
if not rss_item:
logs.out("28", '(ATOM/RSS)', False)
return
set_f = \
'%s\n'%set_f + \
' </channel>\n' + \
'</rss>'
print('\n ├─ %s'%langs.site.rss_c)
tyto.set_file(dom.www_rss_f, 'New', set_f)

View File

@ -0,0 +1,203 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Manage show*/edit* arguments.
# Read or edit file from [target] argument
# File: /var/lib/tyto/program/show.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os, sys, importlib
import args, logs, langs, dom, db, form, tyto, check, html, stats
#========================#
# Read lines from a file #
# alone: True/False #
#------------------------#
def read_lines(f, alone):
if not f: return
if not tyto.exists(f): logs.out("1", f, True)
datas = open(f).read()
# Align content line, after line number
ln_datas = len(datas.splitlines()) + 1
sp_max = len(str(ln_datas))
print('', f)
print(' ├─%s─┐'%(sp_max * ''))
for ln, line in enumerate(datas.rsplit('\n'), 1):
sp = sp_max - len(str(ln))
print('%s %s%s'%(int(sp) * " ", ln, line))
# Ends for show. False should be for form
if alone: decor = ''
else: decor = ''
print(' %s%s─┘'%(decor, sp_max * ''))
if not f == dom.config: dom.valid()
#======================#
# From command line: #
# Show or edit file #
# final html, db, src #
#----------------------#
def manage(target):
if not dom.exists: logs.out("10", '', True)
dom.valid()
actions_read = ('show', 'show-about', 'show-db', 'show-wip', 'show-www')
actions_edit = ('edit', 'edit-about', 'edit-db', 'edit-wip', 'edit-www')
post_src = post_db = post_wip = post_www = False
# Set file from post DB when target is an article
#------------------------------------------------
try: post_src = db.uri_file
except: pass
if post_src:
target = "post"
try: post_db = db.config
except: pass
try: post_wip = db.post_wip
except: pass
try: post_www = db.post_www
except: pass
# Except for show-about > Show post DB
if args.action == "show-about":
target = 'post'
# Convert command action to do[]
# as edit* &nd show* [action] have same target file
actions = \
{
"show" : 'src',
"edit" : 'src',
"post" : 'src',
"show-db" : 'db',
"edit-db" : 'db',
"show-about" : 'about',
"edit-about" : 'about',
"show-wip" : 'wip',
"edit-wip" : 'wip',
"show-www" : 'www',
"edit-www" : 'www'
}
action = actions[args.action]
# Set target file from "new" [action]
do = \
{
'src' : {
"domain" : dom.config,
"footer" : dom.footer_f,
"metas" : dom.metas_f,
"navbar" : dom.navbar_f,
"sidebar" : dom.sidebar_f,
"post" : post_src
},
'db' : {
"domain" : dom.config,
"footer" : dom.footer_f,
"metas" : dom.metas_f,
"navbar" : dom.navbar_f,
"sidebar" : dom.sidebar_f,
"post" : post_db
},
'about' : {
"domain" : dom.config,
"footer" : dom.footer_about_f,
"metas" : dom.metas_f,
"navbar" : dom.navbar_f,
"sidebar" : dom.sidebar_f,
"post" : post_db
},
'wip' : {
"domain" : dom.config,
"footer" : dom.wip_footer_f,
"metas" : dom.wip_metas_f,
"navbar" : dom.wip_navbar_f,
"sidebar" : dom.wip_sidebar_f,
"post" : post_wip,
"stats" : dom.wip_stats_f,
},
'www' : {
"domain" : dom.config,
"footer" : dom.www_footer_f,
"metas" : dom.www_metas_f,
"navbar" : dom.www_navbar_f,
"sidebar" : dom.www_sidebar_f,
"post" : post_www,
"stats" : dom.www_stats_f,
},
}
# Read or edit file, according to legacy args.action
try:
file = do[action][target]
if args.action in actions_read:
read_lines(file, True)
elif args.action in actions_edit:
curr_hash = tyto.get_filesum(file, True)
tyto.edit_file(file)
except:
logs.out("28", '%s + %s'%(args.action, target), True)
# If edit article and hash changed, ask to check
if args.action == "edit":
new_hash = tyto.get_filesum(file, True)
if curr_hash == new_hash: return
# Launch process for some changed file
#-------------------------------------
if file == post_src:
form.asking('%s%s '%(
langs.site.post_chg, langs.site.q
), True)
# Reload post DB (if edited article, and check it if ask "y")
importlib.reload(db)
check.manage(post_src)
elif file == dom.sidebar_f: html.create_sidebar('wip')
elif file == dom.navbar_f: html.create_navbar('wip')
elif file == dom.metas_f: html.create_user_metas('wip')

View File

@ -0,0 +1,225 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Create total statistics file for www or wip
# File: /var/lib/tyto/program/stats.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os, importlib
import args, dom, logs, form, tyto, show, langs
sti_articles = 0
#=======================#
# Manage "stats" option #
#-----------------------#
def manage(process):
dom.valid()
global file_uri, domain_srv
if process == 'wip':
file_uri = dom.wip_stats_f
domain_srv = dom.wip_url
elif process == 'www':
file_uri = dom.www_stats_f
domain_srv = dom.www_url
loop_articles(process)
#==========================#
# Check databases' article #
#--------------------------#
def loop_articles(process):
global sti_articles
# Get databases of articles
for db in os.listdir(dom.articles_db_d):
if not db.endswith('.config'):
continue
# Load DB
db = '%s%s'%(dom.articles_db_d, db)
exec(open(db).read(),globals())
# Check hash status (wip/www)
hash_srv = ''
if process == 'wip': hash_srv = hash_wip
elif process == 'www': hash_srv = hash_www
# - Now generic for wip and www
# - Article has changed and could have different stats
if not hash_srv or \
hash_srv != hash_chk:
continue
sti_articles += 1
if sti_articles == 1: count_stats(False)
else: count_stats(True)
# Create file if article
if sti_articles > 0: create_stats_file(file_uri)
else: logs.out("28", '%s stats'%process, True)
#===============================#
# False: Set First statistics #
# True: Count total statistics #
#-------------------------------#
def count_stats(add):
# Set
if not add:
global stats, authors, author_names
# Specific for Authors (not in database stats)
author_names = author.replace(' ', '').split(",")
authors = 0
stats = { \
"sti_uniq_anchors" : uniq_anchors,
"sti_uniq_abbrs" : uniq_abbrs,
"sti_uniq_links" : uniq_links,
"sti_uniq_images" : uniq_images,
"sti_uniq_files" : uniq_files,
"sti_uniq_codes" : uniq_codes,
"sti_uniq_raws" : uniq_raws,
"sti_comments" : comments,
"sti_tags" : tags,
"sti_lines" : lines,
"sti_words" : words,
"sti_titles" : titles,
"sti_paragraphs" : paragraphs,
"sti_links" : links,
"sti_images" : images,
"sti_anchors" : anchors,
"sti_abbrs" : abbrs,
"sti_strongs" : strongs,
"sti_bolds" : bolds,
"sti_emphasis" : emphasis,
"sti_italics" : italics,
"sti_dels" : dels,
"sti_underlines" : underlines,
"sti_cites" : cites,
"sti_customs" : customs,
"sti_icodes" : icodes,
"sti_bcodes" : bcodes,
"sti_quotes" : quotes,
"sti_lists" : lists,
"sti_files" : files,
"sti_raws" : raws,
"sti_codes" : codes,
}
# Count
else:
# Authors are not set in database stats
new_authors = author.replace(' ', '').split(",")
# Do not count author if known
for name in new_authors:
if name in author_names:
continue
author_names = author_names + [name]
# From database stats
for i in stats:
stat_db = i.rsplit("sti_")[1]
stats[i] = stats[i] + eval(stat_db)
#============================#
# Create stat file in server #
#----------------------------#
def create_stats_file(file_uri):
# Count authors
authors = len(author_names)
sti = \
'# Statistics file created by %s\n'%tyto.Tyto + \
'# Website: %s\n'%domain_srv + \
'# File: %s\n'%file_uri + \
'# Generated: %s\n'%tyto.nowdate() + \
'\n' + \
'# Uniq statistics from articles headers\n' + \
'articles = %d\n'%int(sti_articles) + \
'uniq_authors = %d\n'%int(authors) + \
'uniq_anchors = %d\n'%stats["sti_uniq_anchors"] + \
'uniq_abbrs = %d\n'%stats["sti_uniq_abbrs"] + \
'uniq_links = %d\n'%stats["sti_uniq_links"] + \
'uniq_images = %d\n'%stats["sti_uniq_images"] + \
'uniq_files = %d\n'%stats["sti_uniq_files"] + \
'uniq_codes = %d\n'%stats["sti_uniq_codes"] + \
'uniq_raws = %d\n'%stats["sti_uniq_raws"] + \
'\n' + \
'# Statistics from articles contents\n' + \
'comments = %d\n'%stats["sti_comments"] + \
'tags = %d\n'%stats["sti_tags"] + \
'lines = %d\n'%stats["sti_lines"] + \
'words = %d\n'%stats["sti_words"] + \
'titles = %d\n'%stats["sti_titles"] + \
'paragraphs = %d\n'%stats["sti_paragraphs"] + \
'links = %d\n'%stats["sti_links"] + \
'images = %d\n'%stats["sti_images"] + \
'anchors = %d\n'%stats["sti_anchors"] + \
'abbrs = %d\n'%stats["sti_abbrs"] + \
'strongs = %d\n'%stats["sti_strongs"] + \
'bolds = %d\n'%stats["sti_bolds"] + \
'emphasis = %d\n'%stats["sti_emphasis"] + \
'italics = %d\n'%stats["sti_italics"] + \
'dels = %d\n'%stats["sti_dels"] + \
'underlines = %d\n'%stats["sti_underlines"] + \
'cites = %d\n'%stats["sti_cites"] + \
'customs = %d\n'%stats["sti_customs"] + \
'icodes = %d\n'%stats["sti_icodes"] + \
'bcodes = %d\n'%stats["sti_bcodes"] + \
'quotes = %d\n'%stats["sti_quotes"] + \
'lists = %d\n'%stats["sti_lists"] + \
'\n' + \
'# Included files in articles contents\n' + \
'files = %d\n'%stats["sti_files"] + \
'codes = %d\n'%stats["sti_codes"] + \
'raws = %d\n'%stats["sti_raws"]
tyto.set_file(file_uri, 'New', sti)
try:
print('', langs.site.stats_f%(
sti_articles, stats["sti_words"]
)
)
except:
print(' └ Articles = %s ; Words = %s'%(
sti_articles, stats["sti_words"]
)
)

View File

@ -0,0 +1,133 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Show statuses for domain
# File: /var/lib/tyto/program/status.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import args, dom, logs, tyto, form, db
def domain():
if dom.hole: logs.out("13", '', True)
elif args.action == 'new': return
elif args.act_err: logs.out("11", args.action, True)
elif not dom.exists: logs.out("10", '', True)
elif dom.corrupt: logs.out("39", dom.shortname, True)
print("")
if dom.incomplete: logs.out("41", dom.shortname, False)
elif dom.active: logs.out("42", dom.shortname, False)
elif not dom.active: logs.out("40", dom.shortname, False)
# No backward in target
if "../" in args.target:
logs.out("11", '"../"', True)
# Show unused values
for err_val in dom.err_val:
logs.out("16", err_val, False)
# Missing directories (was created)
for dir_new in dom.dir_new:
logs.out("33", dir_new, False)
# Create missing modules files
create_files = \
{
'navbar_f' : form.create_navbar,
'sidebar_f' : form.create_sidebar,
'metas_f' : form.create_metas,
'footer_f' : form.create_footer,
'footer_about_f': form.create_footer_about
}
for value in dom.file_mod:
create_files[value]('form')
for file_mods in dom.wip_html_mods:
if not tyto.exists(file_mods):
logs.out("1", file_mods, False)
#==============================#
# On demand with status action #
#------------------------------#
def check(target):
# target needed
if not target:
logs.out("5", '[target]', True)
elif target == "domain":
conf_err = False
if dom.dir_unu or dom.file_unu:
logs.out("60", '', False)
for dir_unu in dom.dir_unu:
logs.out("1", dir_unu, False)
conf_err = True
for file_unu in dom.file_unu:
logs.out("24", file_unu, False)
if conf_err:
logs.out("31", '', True)
return
# Unused file
elif not db.post:
logs.out("1", db.uri_file, True)
# Article has DB
elif db.exists:
# Article datas
print('\n ├ [%s] > %s'%(db.title, db.uri_file))
# chk
if db.old_chk: logs.out("94", db.uri_file, False)
else: logs.out("20", db.uri_file, False)
# wip
if not db.file_wip: logs.out("71", db.post_wip, False)
else: logs.out("72", db.post_wip, False)
if db.no_wip: logs.out("73", db.post_wip, False)
elif db.old_wip: logs.out("74", db.post_wip, False)
# www
if not db.file_www: logs.out("81", db.post_www, False)
else: logs.out("82", db.post_www, False)
if db.no_www: logs.out("83", db.post_www, False)
elif db.old_www: logs.out("84", db.post_www, False)
return
# Article has NO DB
elif not db.exists:
logs.out("25", db.uri_file, True)

View File

@ -0,0 +1,566 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Tools and some seetings.
# File: /var/lib/tyto/program/tyto.py
#----------------------------------------------------------------------
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os, sys, re, subprocess, locale, base64, datetime, shutil
from hashlib import blake2b
import args, dom, logs, langs
# :D
Tyto = 'Tyto - Littérateur'
Tytogit = 'https://git.a-lec.org/echolib/tyto-litterateur'
Tytoweb = 'https://tyto.echolib.re'
# Needed header tags
needed_header_tags = \
(
'title',
'about',
'author',
'tags',
'date'
)
# Optional header tags
opt_header_tags = \
(
'file',
'image',
'link',
'abbr',
'raw',
'code',
'snpic'
)
opt_tags_long_name = \
(
'link',
'file'
)
opt_tags_check_uri = \
(
'image',
'file',
'raw',
'code'
)
# Set all tags used in article's header
headers = \
(
'title:',
'about:',
'author:',
'tags:',
'date:',
'link:',
'image:',
'file:',
'abbr:',
'code:',
'raw:',
'#',
'snpic:',
)
# Words and template Tags (paragraphs, lists, bold, strong...)
# Used to check, and replace (wip) tags
# As base64 is used, do NOT set marker: =_ _=
# [5] = name for stats and log.
# [6] = Check content differently. 't' = startswith
#-------------------------------------------------------------
words_tags = [
('>_', '_<', '<a class="anchor_link" href="#%s">', '</a>', 'anchors', 'w'),
('*_', '_*', '<strong class="strong">', '</strong>', 'strongs', 'w'),
('+_', '_+', '<b class="bold">', '</b>', 'bolds', 'w'),
('/_', '_/', '<em class="em">', '</em>', 'emphasis', 'w'),
('[_', '_]', '<i class="italic">', '</i>', 'italics', 'w'),
('~_', '_~', '<del class="del">', '</del>', 'dels', 'w'),
('._', '_.', '<u class="underline">', '</u>', 'underlines', 'w'),
(':_', '_:', '<cite class="cite">', '</cite>', 'cites', 'w'),
('%_', '_%', '<span class="custom">', '</span>', 'customs', 'w'),
('{_', '_}', '<code class="icode">', '</code>', 'codes', 'w'),
('((', '))', '<p class="%s">', '</p>', 'paragraphs', 't'),
('[[', ']]', '[[', ']]', 'quotes', 't'),
('{{', '}}', '{{', '}}', 'bcodes', 't'),
('-(', '-)', '-(', '-)', 'lists', 't')
]
# Tags that do not need to be paired
#-----------------------------------
single_tags = [
('|', '<br class="%s" />'), # New Line
('->', '<a class="anchor_target" id="%s"></a>') # Anchors
]
# When counting words, do no count line starting with:
nolinewords = \
(
words_tags[10][0], words_tags[10][1], # paragraphs
words_tags[11][0], words_tags[11][1], # quotes
words_tags[12][0], words_tags[12][1], # bcodes
words_tags[13][0], words_tags[13][1], # lists
single_tags[0][0], single_tags[1][0], # New line, anchor
'_%s:'%opt_header_tags[1], '_%s:'%opt_header_tags[4], # _image:, _raw:
'_%s:'%opt_header_tags[5] # _code
)
# warning symbols (Check if paired)
#----------------------------------
tpl_tags = [
('(', ')'),
('[', ']'),
('{', '}'),
('«', '»'),
]
# When including HTML in article, check some paired tags
#-------------------------------------------------------
leg_html_tags = [
('<!--', '-->'),
('<div', '</div>'),
('<ul', '</ul>'),
('<li', '</li>'),
('<p', '</p>'),
('<span','</span>'),
]
# Markers for lists, to check in list content
#--------------------------------------------
markers_lists = ('+', '=', ' ', '#')
# Tags used for titles
#---------------------
titles_tags = ('#1 ', '#2 ', '#3 ', '#4 ', '#5 ', '#6 ')
# Tags for quote
quote_tags = [
('_cite:', 'author'),
('_date:', 'date'),
('_link:', 'link'),
('_book:', 'book'),
('_lang:', 'lang')
]
# Tags to check in header in content _TAG
head_tags = ("image:", "raw:", "code;")
# Valid characters for some datas
chrs_invalid = \
set('{}[]_()+*=/:%~´')
# Stats for icodes, bcodes, quotes
nbr_icodes = 0
#=======#
# TOOLS #
#=======#--------------------------------------------------------------
#
# Return True if file exists
#
def exists(uri):
if os.path.exists(uri): return(True)
else: return(False)
#========================================#
# Return converted valid HTML characters #
#----------------------------------------#
def convert_altname(altname):
altname = altname.replace('<', '&lt;')
altname = altname.replace('>', '&gt;')
altname = altname.replace('"', '&quot;')
altname = altname.replace("'", '&apos;')
return altname
#=======================#
# Return sum of srcfile #
# src: True = Content #
# False = URI #
#-----------------------#
def get_filesum(path, src):
#if not src and not exists(path):
# logs.out("1", path, True)
file_sum = blake2b(digest_size=4)
if src: file_sum.update(open(path, 'rb').read())
else: file_sum.update(path.encode())
return file_sum.hexdigest()
#==============================#
# Set and return date and time #
#------------------------------#
def nowdate():
now = datetime.datetime.now()
return(now.strftime('%Y-%m-%d %H:%M:%S'))
#======================#
# Open and edit a file #
#----------------------#
def edit_file(edit_file):
if not os.path.exists(edit_file):
logs.out("1", edit_file, True)
try:
file_edit = subprocess.run(
[
'/usr/bin/nano',
'--linenumbers',
edit_file
]
)
except:
logs.out("1", "/usr/bin/nano", True)
#=====================#
# Create a file #
# Or append text #
# new: True = create #
# False = Append #
#---------------------#
def set_file(path, new, text):
if new: opt = "w"
else: opt = "a"
try:
file = open(path, opt)
file.write(text + '\n')
file.close()
if opt == 'w':
logs.out("32", path, False)
except:
logs.out("4", path, True)
#==========================#
# Get CSS from line if set #
#--------------------------#
def get_css(line):
# Use this default, if not in conf
css = 'tyto'
try: css = dom.css
except: pass
# Get CSS from line
try: css = re.search (r'(?<=' ') +([^ -.]*)', line).group(1)
except: pass
return css
#=============================================#
# First check process to protect contents #
# Protect block-Codes, quotes #
# Also remove empty/commented lines #
# Used in check and wip #
# check: create string without quotes, bcodes #
# wip: remplace quotes, bcode with base64 #
#---------------------------------------------#
def protect_bcodes_quotes(process, post_bottom):
global protect_article
global nbr_titles, nbr_bcodes, nbr_quotes # Stats for DB
in_bcode = in_quote = False
protect_article = ''
bcode = quote = '' # Only for wip process
for line in post_bottom.rsplit('\n'):
start_bcode = close_bcode = False
start_quote = close_quote = False
# Settings and counters
#----------------------
# Bcode (at close, replace with base64)
if not in_quote:
if line.startswith(words_tags[12][0]): # Open
start_bcode = True
in_bcode = True
elif line.startswith(words_tags[12][1]): # Close
close_bcode = True
in_bcode = False
if process == "wip":
bcode = '%s\n%s'%(bcode, line)
bcode = convert_altname(bcode)
b64_bcode = b64('Encode', bcode, 'B64.', '.B64')
line = b64_bcode
# Quote (at close, replace with base64)
if not in_bcode:
if line.startswith(words_tags[11][0]): # Open
start_quote = True
in_quote = True
elif line.startswith(words_tags[11][1]): # Close
close_quote = True
in_quote = False
if process == "wip":
quote = '%s\n%s'%(quote, line)
quote = convert_altname(quote)
b64_quote = b64('Encode', quote, 'Q64.', '.Q64')
line = b64_quote
# Counters and keep tags for check process
#-----------------------------------------
if process == "check":
if in_bcode and not start_bcode \
or in_quote and not start_quote :
line = '#-Protectedline-'
# Set new article content for wip process
#----------------------------------------
elif process == "wip":
# Remove empty line and comments
if not in_quote and not in_bcode:
if not line:
continue
elif line.startswith('#') and not line.startswith(titles_tags):
continue
# bcode convertion to base64
elif in_bcode:
# Convert lines to b64
if not bcode: bcode = line
else: bcode = '%s\n%s'%(bcode, line)
line = ''
elif in_quote:
# Convert lines to b64
if not quote: quote = line
else: quote = '%s\n%s'%(quote, line)
line = ''
# Set new content
#----------------
# check: remove quote/bcode, keep tags
# wip: replace close tag with quote/bcode (keep in open tag)
if not protect_article: protect_article = line
else: protect_article = '%s\n%s'%(protect_article, line)
# Clean in wip process for new quote/bcode
if process == "wip":
if close_bcode: bcode = b64_bcode = ''
if close_quote: quote = b64_quote = ''
#=======================#
# Protec iCodes #
# Used in check and wip #
#-----------------------~
def protect_icodes(post_bottom):
global protect_article
global nbr_icodes
protect_article = post_bottom
in_icode = False
src_code = rep_code = ''
# Get only lines that contains code
for ln, line in enumerate(post_bottom.rsplit('\n')):
if not words_tags[9][0] in line: continue
# Iterate (c)haracter in line
for i, c in enumerate(line):
c_b = c_bb = c_a = ""
if c == '_':
c_b = line[i-1] # before
c_bb = line[i-2] # before, before
c_a = line[i+1] # after
# incode if
if c_b == '{' and not c_bb == '\\':
in_icode = True
nbr_icodes += 1
code = words_tags[9][2]
continue
# No more in code if
if c_a == '}' and not c_b == '\\':
in_icode = False
src_code = convert_altname(src_code)
code = '%s%s%s'%(code, src_code, words_tags[9][3])
b64_code = b64('Encode', code, 'I64.', '.I64')
rep_code = "%s%s%s"%(
words_tags[9][0], rep_code, words_tags[9][1]
)
protect_article = protect_article.replace(rep_code, b64_code)
src_code = rep_code = b64_code = ''
continue
# Construct original replacement code and source code
if in_icode:
rep_code = '%s%s'%(rep_code, c)
if c == '\\': continue
src_code = '%s%s'%(src_code, c)
#=====================================#
# Encode/Decode string to/from base64 #
# Data protection in UTF8 #
#-------------------------------------#
def b64(action, content, before, after):
if action == 'Encode':
global b64_content
b64_base64 = ''
content_bytes = content.encode("utf8")
base64_bytes = base64.b64encode(content_bytes)
b64_content = before + base64_bytes.decode("utf8") + after
return b64_content
elif action == 'Decode':
global src_content
src_content = ''
content_bytes = content.encode("utf8")
base64_bytes = base64.b64decode(content_bytes)
src_content = base64_bytes.decode("utf8")
return src_content
else:
print("Options: 'Encode', 'Decode'")
sys.exit(1)
#====================================#
# Replace in post_db #
# Used for wip and publish #
# to replace hash and date when done #
#------------------------------------#
def replace_in_db(post_db, process, hash_post):
try:
file_db = open(post_db, "r")
lines = file_db.readlines()
except:
logs.out("1", post_db, True)
new_file = ''
for line in lines:
if line.startswith('hash_%s'%process):
line = line.replace(line, 'hash_%s = "%s"'%(process, hash_post))
new_file = '%s%s\n'%(new_file, line)
elif line.startswith('date_%s'%process):
line = line.replace(line, 'date_%s = "%s"'%(process, nowdate()))
new_file = '%s%s\n'%(new_file, line)
else:
if new_file: new_file = '%s%s'%(new_file, line)
else: new_file = line
try:
file = open(post_db, 'w')
file.write(new_file)
file.close()
except:
logs.out("1", post_db, True)
#===================================#
# Copy files used by article to srv #
#-----------------------------------#
def files_to_srv(server):
import db
for uri in db.uris:
# Extract Directories from uri file
d_in = uri.split("/")[-1]
d_in = uri.rsplit(d_in)[0]
# Destination file and directories according to server
# (remove last / from domain directory value)
f_src = '%s%s'%(dom.articles_d[:-1], uri)
if server == 'wip':
f_dst = '%s%s'%(dom.srv_wip[:-1], uri)
d_dst = '%s%s'%(dom.srv_wip[:-1], d_in)
elif server == 'www':
f_dst = '%s%s'%(dom.srv_www[:-1], uri)
d_dst = '%s%s'%(dom.srv_www[:-1], d_in)
# Create sub-directories in server
try:
if os.makedirs(d_dst, exist_ok=True):
logs.out("33", d_dst, False)
except:
logs.out('4', d_dst, True)
# COpy files to server
try:
shutil.copy2(f_src, f_dst)
logs.out("32", f_dst, False)
except:
logs.out('4', f_dst, True)
# Copy source post file in server
# if article_code is True in domain DB
if dom.article_code:
if server == "wip": base_srv = dom.srv_wip
elif server == "www": base_srv = dom.srv_www
f_dst = "%s%s"%(base_srv, db.short_src)
try:
shutil.copy2(db.post_src, f_dst)
logs.out("32", f_dst, False)
except:
logs.out('4', f_dst, True)
#========================================#
# For mass treatment, show message about #
#----------------------------------------#
def show_multi_message(server, srv_dir):
if args.target == "added":
print("%s '%s' > %s"%(langs.site.srv_added, server, srv_dir))
elif args.target == "updated":
print("%s '%s' > %s "%(langs.site.srv_updated, server, srv_dir))
elif args.target == "again":
print("%s '%s' > %s"%(langs.site.srv_again, server, srv_dir))

View File

@ -1,412 +0,0 @@
#!/usr/bin/python
# Name: Tyto - Littérateur
# Type: Global functions for wip
# Description: Converters from Source to HTML
# file: wip.py
# Folder: /var/lib/tyto/scripts/
# By echolib (XMPP: im@echolib.re)
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#------------
# funny stats
#------------
# lines:
# functions:
# comments:
#----------------------------------------------------------------------
#**********************************************************************
import os, sys
import check,log,domain
Tyto_Err = False
post_uri = ''
#
# Manage WIP argument
#
def manage_wip(file_post, Force):
# Check if argument's file (.tyto)
if not file_post:
print(':( Unused argument file')
sys.exit(1)
# Check if file exists
post_uri = '%s%s'%(domain.domain_articles,file_post)
if not os.path.exists(post_uri):
print(':( Unused file: %s'%post_uri)
sys.exit(1)
# Get ID from URI (to get DB file)
post_ID = check.get_filesum(post_uri,False)
# Set database file for this article
# Check if DB exists
post_db = '%s%s.db'%(domain.domain_db, post_ID)
if not os.path.exists(post_db):
print(':( Use "check" before "wip".')
sys.exit(1)
# Set and check/create logs file for this article
post_logs = '%s%s.log'%(domain.domain_logs,post_ID)
#========#
# #
# Basics #
# #
#========#-------------------------------------------------------------
#===========================#
# Convert file to post_temp #
#---------------------------#
def post_to_string(file_path):
global post_temp
post_temp = ''
post_html = ''
with open(file_path, "r") as file:
post_temp = file.read()
remove_empty_lines(post_temp.split('\n'))
post_html = post_temp
#===========================#
# Convert content TO base64 #
#---------------------------#
def convert_to_b64(post_content):
import base64
global b64_content
post_content_base64 = ''
content_bytes = post_content.encode("ascii")
base64_bytes = base64.b64encode(content_bytes)
b64_content = 'B64_' + base64_bytes.decode("ascii") + '_B64'
#================================#
# Convert FROM base64 to content #
#--------------------------------#
def convert_from_b64(post_content):
import base64
global src_content
post_content_src = ''
content_bytes = post_content.encode("ascii")
base64_bytes = base64.b64decode(content_bytes)
src_content = base64_bytes.decode("ascii")
#==========================#
# Get Writer's CSS config #
# For compatible's markers #
#--------------------------#
def get_css(css,css_gen):
global css_set
try:
css_set = line.split(" ")[1]
except:
css_set = '%s%s'%(css,css_gen)
#=============================#
# Get post, witout empty line #
#-----------------------------#
def remove_empty_lines(post):
global post_html, post_temp, line
post_temp = ''
post_html = ''
for line in post:
c = len(line)
if c > 0:
#print(c,line)
if not post_temp:
post_temp = line
else:
post_temp = '%s\n%s'%(post_temp,line)
post_html = post_temp
#============#
# #
# Converters #
# #
#============#---------------------------------------------------------
#==========================#
# Convert bCodes to base64 #
#--------------------------#
def convert_bcodes(post,fm,lm,css):
import re
global post_html, line, css_set
post_temp = ''
span_nbr = '<span class="%s_bcode_ln">'%css
span_code = '<span class="%s_bcode_ct">'%css
span_end = '</span>'
pre_end = '</pre>'
ln_nbr = 0
bCode = False
blines = ''
for line in post:
if line.startswith(fm): # Starting bcode marker
ln_nbr = 0
bCode = True
get_css(css,'_bcode')
pre_start = '<pre class="%s">'%css_set
blines = '%s'%pre_start
css_set = ''
continue
elif line.startswith(lm): # Ending bcode marker
bCode = False
line = ''
blines = '%s\n%s'%(blines,pre_end)
convert_to_b64(blines)
post_temp = '%s\n%s'%(post_temp,b64_content)
if not bCode:
post_temp = '%s\n%s'%(post_temp,line)
else:
ln_nbr += 1
blines = '%s\n %s%d%s%s%s%s'%\
(
blines,span_nbr,ln_nbr,span_end,span_code,line,span_end
)
remove_empty_lines(post_temp.split('\n'))
post_html = post_temp
#============================================#
# Convert Base64 strings to original content #
#--------------------------------------------#
def convert_b64_lines(post):
import re
global post_html,line
post_temp = ''
post_html = ''
b64_contents = ''
for line in post:
if not 'B64_' in line:
post_temp = '%s\n%s'%(post_temp,line)
else:
b64_contents = re.findall(r"B64_(.*?)_B64", line)
for b64_content in b64_contents:
convert_from_b64(b64_content)
line = line.replace('B64_%s_B64'%b64_content, src_content)
post_temp = '%s\n%s'%(post_temp,line)
remove_empty_lines(post_temp)
post_html = post_temp
#==========================#
# Convert iCodes to base64 #
# fm = FIRST Marker #
# lm = LAST Marker #
#--------------------------#
def convert_icodes(post, fm, lm, css):
import re
global post_html
post_temp = '' # Temp string to become post_html string page
icodes_contents = '' # strings containing icode
fm_html = '<code class="%s_icode">'%css
lm_html = '</code>'
fm_spe = '!%s'%(fm) # Special for !<_
lm_spe = '%s!'%lm # Special for _>!
for line in post:
# Special marker containting legacy one
if lm_spe and fm_spe in line:
icodes_contents = re.findall(r"%s(.*?)%s"%(fm_spe,lm_spe), line)
for icode in icodes_contents:
content_rep = '%s%s%s'%(fm_spe,icode,lm_spe)
icode = '<code class="%s_icode">%s</code>'%(css,icode)
convert_to_b64(icode)
line = line.replace(content_rep,b64_content)
# Legacy marker
if lm and fm in line:
icodes_contents = re.findall(r"%s(.*?)%s"%(fm,lm), line)
for icode in icodes_contents:
content_rep = '%s%s%s'%(fm,icode,lm)
icode = '<code class="%s_icode">%s</code>'%(css,icode)
convert_to_b64(icode)
line = line.replace(content_rep,b64_content)
post_temp = '%s\n%s'%(post_temp,line)
post_html = post_temp
#====================================#
# Convert Quotes #
# 2 types: #
# - Advanced, with author #
# - Simple, with no author #
# mt = marker type (Should be 3 '-') #
#------------------------------------#---------------------------------
#=========================#
# Return datas after term #
#-------------------------#
def get_quote_datas(term,line):
import re
term_data = re.compile('%s(.*)$'%term)
if term_data:
return term_data.search(line).group(1)
#=====================#
# Loop in Post #
# Convert quotes only #
#---------------------#
def convert_quotes(post,mt,css):
import re
global post_html,line,htmlquote, cite
post_temp = '' # Temp string to become post_html string page
Quote = False
bquote = htmlquote = htmllines = ''
cite = ''
link = cite_HTML = ''
lang = lang_HTML = ''
book = year = title_HTML = ''
quote_nbr = 0
for line in post:
# Starting quote
if line.startswith(mt):
if not Quote:
Quote = True
get_css(css,'_quote')
quote_nbr += 1
line = '_QUOTE_%d'%quote_nbr
if post_temp:
post_temp = '%s\n%s'%(post_temp,line)
else:
post_temp = line
continue
# End of quote
# Create HTML and convert marker to Base64
else:
Quote = False
# Create HTML datas
if cite and book and year:
title_HTML = ' title="%s - %s (%s)"'%(cite,book,year)
elif book and year:
title_HTML = ' title="%s (%s)"'%(book,year)
elif book:
title_HTML = ' title="%s"'%book
elif year:
title_HTML = ' title="%s"'%year
htmlquote = '<blockquote class="%s"%s'%(css_set,lang_HTML)
htmlquote = '%s%s%s>'%(htmlquote,cite_HTML,title_HTML)
# Create Advance quote
if cite:
sp = ' '*4
htmlquote = '<figure class="%s">\n %s'%(css_set,htmlquote)
for bline in bquote.split('\n'):
htmllines = '%s\n%s%s'%(htmllines, sp, bline)
htmlquote = '%s%s\n </blockquote>'%(htmlquote,htmllines)
htmlquote = '%s\n <figcaption>\n%s<cite>\n'%(htmlquote,sp)
htmlquote = '%s%s <a href="%s">%s</a>'%(htmlquote,sp,link,cite)
htmlquote = '%s\n%s</cite>\n </figcaption>\n</figure>'%(htmlquote,sp)
# Create SIMPLE HTML quote with indents
else:
sp = ' '*2
for bline in bquote.split('\n'):
htmllines = '%s\n%s%s'%(htmllines, sp, bline)
htmlquote = '%s%s\n</blockquote>'%(htmlquote,htmllines)
# Convert quote to Base64
convert_to_b64(htmlquote)
post_temp = post_temp.replace('_QUOTE_%s'%quote_nbr,b64_content)
bquote = htmlquote = htmllines = ''
continue
# If in quote, get datas (if exist)
if Quote:
if line.startswith('_cite: '):
cite = get_quote_datas('_cite: ',line)
elif line.startswith('_link: '):
link = get_quote_datas('_link: ',line)
if link:
cite_HTML = ' cite="%s"'%(link)
elif line.startswith('_lang: '):
lang = get_quote_datas('_lang: ',line)
if lang:
lang_HTML = ' lang="%s"'%lang
elif line.startswith('_book: '):
book = get_quote_datas('_book: ',line)
elif line.startswith('_year: '):
year = get_quote_datas('_year: ',line)
elif line.startswith('('):
line = '<p class="%s_p %s_p-quote">'%(css,css)
if bquote:
bquote = '%s\n%s'%(bquote,line)
else:
bquote = line
elif line.startswith(')'):
line = '</p>'
bquote = '%s\n%s'%(bquote,line)
else:
if bquote:
bquote = '%s\n %s'%(bquote,line)
else:
bquote = line
# if NOT in quote
else:
if post_temp:
post_temp = '%s\n%s'%(post_temp,line)
else:
post_temp = line
post_html = post_temp
# Replace line inplace, except those begining with #
def replace_in_file(file_path, old_text, new_text):
import fileinput
with fileinput.input(file_path, inplace=True) as file:
for line in file:
new_line = line.replace(old_text, new_text)
print(new_line, end='')
# Replace text with file content
# WILLNOT BE USED
def replace_with_file(file_path, old_text):
import os
files = sorted(os.listdir('/tmp'),reverse=True)
for filename in files:
if filename.startswith(old_text):
with open('/tmp/%s'%filename, 'r') as fsrc:
src = fsrc.read()
src = src.rstrip()
with open(file_path, 'r') as fdst:
dst = fdst.read()
rep_file = dst.replace(filename, src)
with open(file_path, 'w') as fdst:
fdst.write(rep_file)
os.remove('/tmp/%s'%filename)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
#!/usr/bin/env python3
# Name: Tyto - Littérateur
# Type: translation file
# Description: Only for logs (internal messages) [en]
# file: logs_en.py
# Folder: /var/lib/tyto/translations/
# By echolib (XMPP: im@echolib.re)
# Repo: https://git.a-lec.org/echolib/tyto.git
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#**********************************************************************
# Generic
sidebar = 'Sidebar'
navbar = 'Navbar'
meta_t = '<meta> tag'
time_t = '<time> tag'
metas = 'Metas Tags'
footer = 'Footer'
line = "Ligne"
no_up = "not updated"
ntd = "Nothing to do"
all_ok = "All is OK"
unused_r = "Unused ressource"
unused_c = "Unused database value"
db_inv = "Corrupted article's database"
err_arg = "Argument error"
no_arg = "Unused argument"
no_fidi = "Black Hole: no file or directory here"
dom_ina = "Inactive domain"
dom_inc = "Incomplete domain"
dom_act = "Active domain"
dom_cor = "Corrupted domain"
data_inc = "Incomplete data"
data_inv = "Invalid data"
dom_no = "No domain found"
file_c = "File created"
file_n = "File changed"
file_e = "File exists"
dir_c = "Directory created"
dir_e = "Directory exists"
# chk
nycheck = "Article not yet checked"
was_chk = "Article was 'check'"
st_chk_o = "Old 'check' status"
post_inc = "Unused in article"
post_inv = "Article not valid"
post_val = "Article is valid"
# wip
nywip = "Article not yet wip"
was_wip = "Article was 'wip'"
post_nwi = "Article not in 'wip'"
st_wip_n = "Unused 'wip' status"
st_wip_o = "Old 'wip' status"
post_wip = "Article is in 'wip'"
# www
was_pub = "Article was published"
post_nww = "Article not in 'www'"
st_www_n = "Unused 'www' status"
st_www_o = "Old 'www' status"
post_www = "Article is in 'www'"
# Misc
check_m = "Check manually"
post_chg = "Article changed: 'check' it first"
sep_inv = "Unused separator in article"
unused_v = "Unused value in article"
unused_t = "Unused value in header"
unused_p = "Empty article"
mark_np = "Not paired marks"
symb_np = "Not paired symbols"
snpic_d = "Using default snpic. Not found"
anch_nu = "Anchor not uniq"
nyfile = "file not yet created"
add = "Add:"
nomods = "Create HTML modules first"
status_r = "Checking unused ressources..."
was_wip = "Article already 'wip'"
laterout = "Maybe later..."

View File

@ -0,0 +1,85 @@
#!/usr/bin/env python3
# Nom: Tyto - Littérateur
# Type: Fichier de traduction
# Description: Seulement pour les logs (messages internes) [fr]
# Fichier: logs_fr.py
# Dossier: /var/lib/tyto/translations/
# Par echolib (XMPP: im@echolib.re)
# Dépôt: https://git.a-lec.org/echolib/tyto.git
# Licence: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#**********************************************************************
# Generique
sidebar = 'Barre Latérale'
navbar = 'Barre de navigation'
meta_t = 'Balise <meta>'
time_t = 'Balise <time>'
metas = 'Balises Metas'
footer = "Pied de Page"
line = "Line"
no_up = "non mise à jour"
ntd = "Rien à faire"
all_ok = "Tout va bien"
unused_r = "Ressource manquante"
unused_c = "Valeur de la base de donnée manquante"
db_inv = "Base de donnée de l'article corrompue"
err_arg = "Erreur d'argument"
no_arg = "Argument manquant"
no_fidi = "Trou Noir: aucun fichier ou dossier ici"
dom_ina = "Domaine inactif"
dom_inc = "Domaine incomplet"
dom_act = "Domaine actif"
dom_cor = "Domaine corrompu"
data_inc = "Donnée incomplète"
data_inv = "Donnée invalide"
dom_no = "Aucun domaine trouvé"
file_c = "Fichier créé"
file_n = "Fichier modifié"
file_e = "Fichier présent"
dir_c = "Dossier créé"
dir_e = "Dossier présent"
# chk
nycheck = "Article pas encore 'check'"
was_chk = "Article déjà vérifié"
st_chk_o = "Statut 'check' Ancien"
post_inc = "Donnée manquante dans l'article"
post_inv = "Article non valide"
post_val = "Article valide"
# Wip
nywip = "Article pas encore 'wip'"
was_wip = "Article déjà 'wip'"
post_nwi = "Article non présent dans 'wip'"
st_wip_n = "Statut 'wip' Non présent"
st_wip_o = "Statut 'wip' Ancien"
post_wip = "Article présent dans 'wip'"
# www
was_pub = "Article déjà publié"
post_nww = "Article non présent dans 'www'"
st_www_n = "Statut 'www' Non présent"
st_www_o = "Statut 'www' Ancien"
post_www = "Article présent dans 'www'"
# Misc
check_m = "Vérifier manuellement"
post_chg = "Article modifié : commencer par 'check'"
sep_inv = "Séparateur manquant dans l'article"
unused_v = "Valeur manquante dans l'article"
unused_t = "Valeur manquante dans l'entête"
unused_p = "L'article est vide"
mark_np = "Marqueurs non jumelés"
symb_np = "Symboles non jumelés"
snpic_d = "snpic utilisé par défaut. Manquant"
anch_nu = "Ancre non unique"
nyfile = "Fichier pas encore créé"
add = "Ajout:"
nomods = "Créer d'abord les modules HTML"
status_r = "Vérification des ressources manquantes..."
laterout = "Pour plus tard..."

View File

@ -0,0 +1,334 @@
#!/usr/bin/env python3
# Name: Tyto - Littérateur
# Type: translation file
# Description: Only for website [en]
# file: site_en.py
# Folder: /var/lib/tyto/translations/
# By echolib (XMPP: im@echolib.re)
# Repo: https://git.a-lec.org/echolib/tyto.git
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#**********************************************************************
# IMPORTANT Instructions
#-----------------------
# This is a python file, so... DO NOT REMOVE:
# - "#"
# - "%s", "%d"
# - "\n"
# - "+ \"
# Generic
article = "Article"
sidebar = 'Sidebar'
navbar = 'Navbar'
metas = 'Metas Tags'
footer = 'Footer'
title = 'Title'
File = 'File'
name = 'Name'
by = "by"
le = "the"
fo = "for"
proceed = "Continue"
q = '?'
i = '!'
pp = ":"
# Website
#----------------------------------------------------------------------
# Misc.
source_code = "Source code"
home = "Home"
go_home = "Go to Homepage"
read = "Read"
tyto_psrc = "Source code in Tyto format of"
w_written = "was written the"
w_published = "was published the"
written = "written the"
author_of = "is the uthor of"
# Sidebar
site_sdb_t = "Featured..."
# Footer
tyto_site_t = "Official website of %s, the Libre websites generator"
tyto_git_t = "%s's official source code repository"
legal_t = "Legal notice"
terms_t = "Terms of Use"
terms_s = "T.o.U"
law = "Law"
about = "About"
add_inf = "additional Informations %s"%about.lower()
licence = "License"
contact = "Contact"
mail = "Mail"
mail_to = "Contact by %s the admin of"%mail.lower()
feed = "Feed"
generator = "Generator"
# Misc for Tyto
#--------------
# Check
check_a = "Check again this article"
post_chg = "Article was edited. Check it"
# Wip
wip_new = "Create a new HTML page in 'wip' server again"
srv_again = "Create again converted HTMl pages in server"
srv_added = "Create missing HTML pages in server"
srv_updated = "Update HTMl pages in server"
# publish
publish_a = "Publish again this article"
rss_c = "Create ATOM/RSS feed"
# Other
uptpl = "Update directory"
stats_f = "Articles: %s (%s words)"
reg_domains = 'Registred domains'
# Form
#----------------------------------------------------------------------
form_edit = "Edit the domain with the form"
form_start = ' ├──────────────────────────────────────────────┐\n' + \
' │ Configure a new domain for current directory │\n' + \
' │ Answer Y/y = yes. Enter to keep {default}\n' + \
' │ Empty Answer cancel process, except for │\n' + \
' │ - [Optional] │\n' + \
' │ - known {default} value │\n' + \
' ├──────────────────────────────────────────────┘'
form_warn = '\n' + \
' ├──────────────────────────────────────┐\n' + \
' │ Please, READ the configuration datas │\n' + \
' ├──────────────────────────────────────┘'
form_ready = '\n' + \
' ├──────────────────────────────────────┐\n' + \
' │ Domain is ready. Have fun, writers ! │\n' + \
' └──────────────────────────────────────┘'
form_inv = '\n' + \
' ├─────────────────────────────────────┐\n' + \
' │ Domain is INVALID. Try form again ! │\n' + \
' └─────────────────────────────────────┘'
form_opt = "[Optional]"
form_url = "URL to official website?"
form_wip = "URL to 'wip' website?"
form_db_new = "Created new database"
form_trlog = "[2 char.] Logs language?"
form_srv = "Local server directory?"
form_logo = "Logo filename?"
form_rss_f = "Atom/RSS filename?"
form_rss_i = "Atom/RSS articles' number?"
form_title = "Website title?"
form_date = "Domain creation year?"
form_about = "Domain Description?"
form_mail = "Webmaster's mail?"
form_tags = "[comma separated] Domain tags?"
form_lic = "Domain License?"
form_licurl = "License URL?"
form_legal = "Legal Notice URL?"
form_terms = "Terms of Use URL?"
form_css = "[alnum] CSS Prefix?"
form_sep = "[1 char.] Pages titles separator?"
form_pscode = "Show Article source code?"
form_relme = 'rel="me" URL?'
form_trsite = "[2 char.] Website language?"
form_sdb_i = "Article number?"
form_activ = "Activate and prepare domain?"
form_dir_e = "Directory exists"
form_dir_c = "Directory created"
form_file_e = "File exists"
form_file_c = "File created"
form_reset = "Reset configuration?"
form_rep = "Replace HTML file"
# Documentation of configuration files
#-------------------------------------
metas_inf = "Create <meta> tags"
metas_doc = \
'# For %s\n' + \
'# Type text/HTML file\n' + \
'# Description Configuration file for HTML <metas> tags\n' + \
'# Content inserted in <head> section\n' + \
'# File %s\n' + \
'# How Insert <metas ...> and <link ...>\n' + \
'# Notes - Ony these tags are added :\n' + \
'# - <metas>\n' + \
'~ - <link>\n' + \
'# - Do NOT copy this file to template directory\n' + \
'# - These tags are already set'
navbar_inf = "Create navbar"
navbar_doc = \
'# For %s\n' + \
'# Type: Text file\n' + \
'# Description Configuration file for navbar"\n' + \
'# (directories\'s list)\n' + \
'# Commands tyto new navbar (reset)\n' + \
'# tyto wip/publish navbar (Create)\n' + \
'# tyto show navbar (show config)\n' + \
'# tyto show-wip/show-www navbar (Show HTML)\n' + \
'# tyto edit navbar (edit this file)\n' + \
'# File %s\n' + \
'# Comment 1 folder name per line *1\n' + \
'# (from articles/)\n' + \
'# not begining with "/"\n' + \
'# Order in sidebar position\n' + \
'# Remember To avoid 404 error, you must:\n' + \
'# - add article index.{tyto}\n' + \
'# in set folder\n' + \
'# - check and wip article\n' + \
'# *1 Option To define a title link:' + \
'# - add "# title link"\n' + \
'\n# %s\n'%(20 * "-") +\
'# Examples :\n' + \
'# documentation\n' + \
'# about # infos about this website\n' + \
'# %s\n\n'%(20 * "-")
sidebar_inf = "Create sidebar"
sidebar_doc = \
'# For %s\n' + \
'# Type Text file\n' + \
'# Description Configuration file for sidebar\n' + \
'# (articles\'s list)\n' + \
'# File %s\n' + \
'# Commands tyto new sidebar (reset)\n' + \
'# tyto wip/publish sidebar (Create)\n' + \
'# tyto show sidebar (Show config)\n' + \
'# tyto show-wip/show-www sidebar (Show HTML)\n' + \
'# tyto edit sidebar (edit this file)\n' + \
'# How 1 article URI per line\n' + \
'# (from articles/)\n' + \
'# not begining with "/"\n' + \
'# Order in sidebar position\n' + \
'# Max articles = %d\n' + \
'# Option Tp set sidebar title:\n' + \
'# ": Sidebar Title"\n' + \
'\n# %s\n'%(20 * "-") + \
'# Examples :\n' + \
'# : My new articles list'
'# index.tyto\n' + \
'# dir1/index.tyto\n' + \
'# %s\n\n'%(20 * "-")
footer_inf = "Create footer"
footer_doc = \
'# For %s\n' + \
'# Type text/HTML file\n' + \
'# Description Configuration file for footer\n' + \
'# File %s\n' + \
'# Commands tyto new footer (reset)\n' + \
'# tyto wip/publish footer (Create)\n' + \
'# tyto show footer (Show config)\n' + \
'# tyto show-wip/show-www footer (Show HTML)\n' + \
'# tyto edit footer (edit this file)\n' + \
'# How Put any HTML code\n' + \
'# Notes - Lines are ignored if:\n' + \
'# - empty\n' + \
'# - begin with "#"\n' + \
'# - Do NOT copy to template directory'
'# %s\n'%(20 * "-")
footer_about_doc = \
'# For %s\n' + \
'# Type text/HTML file\n' + \
'# Description Used when a footer is generated\n' + \
'# Content inserted in "about" section\n' + \
'# File %s\n' + \
'# How Put any HTML code\n' + \
'# Notes - Lines are ignored if:\n' + \
'# - empty\n' + \
'# - begin with "#"\n' + \
'# - Do NOT copy to template directory\n' + \
'# %s\n'%(20 * "-")
# Help with Tyto commands
args_helps = """\n# New domain :
- Create directory and go in
- Create domain with 'tyto new domain [URL]'
- Create .tyto file in directory "articles/"
- Use these actions: check > wip > publish
! - Modules files are in directory "_configs/"
and used to custom some website parts
- (css, logo...) files go in "wip/template/"
# Usage: tyto [action] [target]
# Actions
- [action] > According to [target]
# Edit a file
edit : Source file, configuration module
edit-about: [footer] Edit description section in footer
or same as [edit-db]
edit-db : Edit database/configuration file
edit-wip : Edit a file in server 'wip'
edit_www : Edit a file in server 'www'
new : [domain] Créer un domaine ou le modifier via le formulaire
[sidebar, navbar, footer, metas] Create and replace
with default module configuration file
# Show contents file (with line number)
show : Show source file, source configuration module
show-about: [footer] Show description footer file
or same as [show-db]
show-db : Show database/configuration file
show-wip : Show a file in server 'wip'
show-www : Show a file in server 'www'
# Create HTML page
check : Check the validity of a tyto format file
wip : Create article HTML page in server 'wip'
publish : Create article HTML page in server 'www'
# Targets
- [target] > According to [action]
# Multiple articles
updated : Update articles (already checked)
again : Force all articles (already checked)
added : [check] Search and check for .tyto articles in domain
(not yet checked)
[wip, publish] Create articles HTML pages
that were edited and checked
# Update modules/files template
template : - Create (replace) modules in directory "template/"
- [publish] Also, copy all other files from "wip/template/"
# Domain and files
domain : Create or edit a domain
[file] : URI file (autocompletion friendly)
# Modules
footer : Footer configuration file
metas : <meta>, <link> configuration file
navbar : Navbar configuration file
sidebar : Sidebar configuration file
stats : Stats file (server 'wip' er 'www')
# Examples :
# Check article (according to sub-folder)
$ tyto check mysubdir/index.tyto
# Create (replace) default sidebar configuration file
$ tyto new sidebar
# Edit navbar configuration file
$ tyto edit navbar
# edit doc/index.html in server 'www'
$ tyto edit-www doc/index.tyto
# Create HTML sidebar file in server 'wip'
$ tyto wip sidebar
# Show footer HTML file in server 'wip'
$ tyto show-wip footer
# Create statistics file in serveur 'www'
$ tyto publish stats"""

View File

@ -0,0 +1,335 @@
#!/usr/bin/env python3
# Nom: Tyto - Littérateur
# Type: Fichier de traduction
# Description: Seulement pour le site web [fr]
# Fichier: site_fr.py
# Dossier: /var/lib/tyto/translations/
# Par echolib (XMPP: im@echolib.re)
# Dépôt: https://git.a-lec.org/echolib/tyto.git
# Licence: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#**********************************************************************
# Instructions IMPORTANTES
#-------------------------
# Ceci est un fichier python, donc... NE PAS ENLEVER :
# - "#"
# - "%s", "%d"
# - "\n"
# - "+ \"
# Generic
article = "Article"
sidebar = 'Barre Latérale'
navbar = 'Barre de menu'
metas = 'Balises Metas'
footer = 'Pied de Page'
title = 'Titre'
File = 'Fichier'
name = 'Nom'
by = "par"
le = "le"
fo = "pour"
proceed = "Continuer"
q = ' ?'
i = ' !'
pp = " :"
# Site web
#----------------------------------------------------------------------
# Divers
source_code = "Code source"
home = "Accueil"
go_home = "Aller à la page d'accueil"
read = "À lire"
tyto_psrc = "Code source au format Tyto de"
w_written = "a été écrit le"
w_published = "a été publié le"
written = "écrit le"
author_of = "est l'auteur de"
# Barre latérale
site_sdb_t = "À l'affiche..."
# Pied de page
tyto_site_t = "Site web officiel du générateur de sites web Libre %s"
tyto_git_t = "Dépôt officiel du code source de %s"
legal_t = "Mentions légales"
terms_t = "Conditions Générales d'Utilisation"
terms_s = "C.G.U"
law = "Loi"
about = "À propos de"
add_inf = "Information supplémentaires %s"%about.lower()
licence = "Licence"
contact = "Contact"
mail = "Courriel"
mail_to = "Contacter par %s l'administrateur de"%mail.lower()
feed = "Flux"
generator = "Generateur"
# Misc for Tyto
#--------------
# Check
check_a = "Vérifier encore l'article"
post_chg = "Article édité. Le vérifier"
# Wip
wip_new = "Créer encore une page HTML dans le serveur 'wip'"
srv_again = "Créer encore les pages dans le serveur"
srv_added = "Créer les pages HTML manquantes dans le serveur"
srv_updated = "Mise à jour des pages HTML dans le serveur"
# publish
publish_a = "Publier encore l'article"
rss_c = "Créer le flux ATOM/RSS"
# Autre
uptpl = "Mettre à jour le dossier"
stats_f = "Articles : %s (%s mots)"
reg_domains = 'Domaines enregistrés'
# Formulaire
#----------------------------------------------------------------------
form_edit = "Éditer le domaine avec le formulaire"
form_start = ' ├───────────────────────────────────────────────┐\n' + \
' │ Configurer un domaine pour le dossier courant │\n' + \
' │ Répondre O/o = Oui. Entrer garde le {default}\n' + \
' │ Sans réponse : arrêt, sauf pour │\n' + \
' │ - [Optionnel] │\n' + \
' │ - Valeur {default} connue │\n' + \
' ├───────────────────────────────────────────────┘'
form_warn = '\n' + \
' ├──────────────────────────────────────────┐\n' + \
' │ SVP, lisez les données de configurations │\n' + \
' ├──────────────────────────────────────────┘'
form_ready = '\n' + \
' ├─────────────────────────────────────────┐\n' + \
' │ Le domaine est prêt. Amusez-vous bien ! │\n' + \
' └─────────────────────────────────────────┘'
form_inv = '\n' + \
' ├───────────────────────────────────────────┐\n' + \
' │ Le Domaine est INVALIDE. Essayez encore ! │\n' + \
' └───────────────────────────────────────────┘'
form_opt = "[Optionnel]"
form_url = "URL du site web officiel"
form_wip = "URL du site web 'wip'"
form_db_new = "Nouvelle base de données crée"
form_trlog = "[2 car.] Langue des messages"
form_srv = "Dossier du serveur local"
form_logo = "Nom du fichier du logo"
form_rss_f = "Nom du fichier Atom/RSS"
form_rss_i = "Nombre d'articles Atom/RSS"
form_title = "Titre du site web"
form_date = "Année de création du domaine"
form_about = "Description du domaine"
form_mail = "Courriel du webmestre"
form_tags = "[séparées par une virgule] Étiquettes du domaine"
form_lic = "Licence du domaine"
form_licurl = "URL de la licence"
form_legal = "URL des mentions légales"
form_terms = "URL des CGU"
form_css = "[alnum] Préfix CSS"
form_sep = "[1 car.] Séparateur des titres de pages"
form_pscode = "Montrer le code source des articles"
form_relme = 'URL pour rel="me"'
form_trsite = "[2 car.] Langue du site web"
form_sdb_i = "Nombre d'articles"
form_activ = "Activer et preparer le domaine"
form_dir_e = "Dossier présent"
form_dir_c = "Dossier créé"
form_file_e = "Fichier présent"
form_file_c = "Fichier créé"
form_reset = "Réinitialiser la configuration"
form_rep = "Remplacer le fichier HTML"
# Documentation des fichiers de configuration
#--------------------------------------------
metas_inf = "Créer les balises <meta>"
metas_doc = \
'# Pour %s\n' + \
'# Type Fichier text/HTML\n' + \
'# Description Fichier de configuration des balises <meta> HTML \n' + \
'# Contenu inséré dans la section <head>\n' + \
'# Fichier %s\n' + \
'# Comment Insérer des balises <metas ...> et <link ...>\n' + \
'# Notes - Sont ajoutées uniquement les balises :\n' + \
'# - <metas>\n' + \
'~ - <link>\n' + \
'# - Ne PAS copier ce fichier dans le dossier template\n' + \
'# - Les balises suivantes sont déjà présentes'
navbar_inf = "Créer la barre de menu"
navbar_doc = \
'# Pour %s\n' + \
'# Type fichier texte\n' + \
'# Description Utilisé par "wip/publish navbar"\n' + \
'# (Liste des dossiers)\n' + \
"# Commandes tyto new navbar (réinitialiser)\n" + \
'# tyto wip/publish navbar (créer)\n' + \
'# tyto show navbar (afficher la configuration)\n' + \
'# tyto show-wip/show-www navbar (afficher l\'HTML)\n' + \
'# tyto edit navbar (editer ce fichier)\n' + \
'# Fichier %s\n' + \
'# Comment 1 nom de dossier par ligne *1\n' + \
'# (depuis articles/)\n' + \
'# Ne commence pas par "/"\n' + \
'# L\'ordre définit la position\n' + \
'# Note Pour éviter l\'erreur 404 :\n' + \
'# - ajouter un article index.{ext}\n' + \
'# dans le dossier mentionné\n' + \
'# - check et wip sur l\'article\n' + \
'# *1 Option Pour définir un titre de lien :\n' + \
'# - ajouter "# titre du lien"\n' + \
'\n# %s\n'%(20 * "-") +\
'# Exemples :\n' + \
'# documentation\n' + \
'# a-propos # Informations concernant ce site\n' + \
'# %s\n\n'%(20 * "-")
sidebar_inf = "Créer la barre latérale"
sidebar_doc = \
'# Pour %s\n' + \
'# Type fichier texte\n' + \
'# Description Fichier de configuration de la barre latérale\n' + \
'# (Liste d\'articles)\n' + \
'# Fichier %s\n' + \
"# Commandes tyto new sidebar (réinitialiser)\n" + \
'# tyto wip/publish sidebar (créer)\n' + \
'# tyto show sidebar (afficher la configuration)\n' + \
'# tyto show-wip/show-www sidebar (afficher l\'HTML)\n' + \
'# tyto edit sidebar (editer ce fichier)\n' + \
'# Comment 1 URI de l\'article par ligne\n' + \
'# (depuis articles/)\n' + \
'# Ne commence pas par "/"\n' + \
'# L\'ordre définit la position\n' + \
'# Articles max = %d\n' + \
'# Option Pour définir un titre à la barre latérale:\n' + \
'# ": Titre de la sidebar"\n' + \
'\n# %s\n'%(20 * "-") + \
'# Exemples :\n' + \
'# : Ma liste des nouveaux articles\n' + \
'# index.tyto\n' + \
'# dir1/index.tyto\n' + \
'# %s\n\n'%(20 * "-")
footer_inf = "Créer le pied de page"
footer_doc = \
'# Pour %s\n' + \
'# Type Fichier text/HTML\n' + \
'# Description Fichier de configuration du pied de page\n' + \
'# Fichier %s\n' + \
"# Commandes tyto new footer (réinitialiser)\n" + \
'# tyto wip/publish footer (créer)\n' + \
'# tyto show footer (afficher la configuration)\n' + \
'# tyto show-wip/show-www footer (afficher l\'HTML)\n' + \
'# tyto edit footer (editer ce fichier)\n' + \
'# Comment Insérer du code HTML\n' + \
'# Notes - Les lignes sont ignorées si :\n' + \
'# - vides\n' + \
'# - commencent par "#"\n' + \
'# - Ne PAS copier ce fichier dans le dossier template\n' + \
'# %s\n'%(20 * "-")
footer_about_doc = \
'# Pour %s\n' + \
'# Type Fichier text/HTML\n' + \
'# Description Utilisé lors de la génération du pied de page\n' + \
'# Contenu inséré dans la section "about"\n' + \
'# Fichier %s\n' + \
'# Comment Insérer du code HTML\n' + \
'# Notes - Les lignes sont ignorées si :\n' + \
'# - vides\n' + \
'# - commencent par "#"\n' + \
'# - Ne PAS copier ce fichier dans le dossier template\n' + \
'# %s\n'%(20 * "-")
# Help with Tyto commands
args_helps = """\n# Nouveau domaine :
- Créer un dossier et aller dedans
- Créer un domain avec 'tyto new domain [URL]'
- Créer un fichier .tyto dans le dossier "articles/"
- Utiliser les actions check > wip > publish
! - Les fichiers des modules sont dans le dossier "_configs/"
et utilisés pour personnaliser certaines parties du site
- Les fichier (css, logo...) vont dans le dossier serveur "wip/template/"
# Usage: tyto [action] [target]
# Les actions
- [action] > Selon l'argument [target]
# Modifier un ficher
edit : Fichier source, module de configuration
edit-about: [footer] Modifier la section description du pied de page
sinon comme l'action [edit-db]
edit-db : Modifier une base de données/fichier de configuration
edit-wip : Modifier un fichier dans le serveur 'wip'
edit_www : Modifier un fichier dans le serveur 'www'
new : [domain] Créer un domaine ou le modifier via le formulaire
[sidebar, navbar, footer, metas] Créer ou remplacer le
fichier de configuration du module par le défaut
# Afficher un fichier (avec numéros de ligne)
show : Fichier source, module de configuration
show-about: [footer] Afficher la section description du pied de page
sinon comme l'action [show-db]
show-db : Afficher une base de données/fichier de configuration
show-wip : Afficher un fichier dans le serveur 'wip'
show-www : Afficher un fichier dans le serveur 'www'
# Processus de création / Mise en ligne
check : Vérifier la validité d'un article au format tyto
wip : Créer une page HTML de l'article dans le serveur 'wip'
publish : Créer une page HTML de l'article dans le serveur 'www'
# Les cibles
- [target] > Selon l'action [action]
# Traitement en masse
updated : Mise à jour des articles modifiés (déjà vérifiés)
again : Forcer TOUS les articles déjà vérifiés
added : [check] Vérifier tous les article .tyto dans le domaine
qui n'ont pas été déjà validés
[wip, publish] Créer les pages HTML des articles
qui ont été modifiés et vérifiés
# Mise en ligne du thème et des modules
template : - Recréer les modules HTML dans "template/"
- Copie tous les autres fichier du dossier wip/template/
# Domaine et fichier
domain : Créer un domain ou le modifier
[file] : URI du fichier (l'autocompletion est votre amie)
# Les modules
footer : Fichier de configuration du pied de page
metas : Fichier de configuration des balises HTML <meta>, <link>
navbar : Fichier de configuration du menu de navigation
sidebar : Fichier de configuration de la barre latérale
stats : Fichier de statistiques (serveur 'wip' ou 'www')
# Exemples :
# Vérifier l'article dans le sous dossier (suivant l'emplacement)
$ tyto check mysubdir/index.tyto
# Créer ou remettre par défaut la barre latérale
$ tyto new sidebar
# Modifier la configuration du menu de navigation
$ tyto edit navbar
# Modifier doc/index.html dans le serveur 'www'
$ tyto edit-www doc/index.tyto
# Créer le fichier HTML de la barre latérale (serveur 'wip')
$ tyto wip sidebar
# Afficher le contenu du pied de page HTML dans le serveur 'wip'
$ tyto show-wip footer
# Créer le fichier de statistiques dans le serveur 'www'
$ tyto publish stats"""

View File

@ -0,0 +1,75 @@
# Home Domain
directory = ""
database = ""
# Local user configuration
lang_sys = "SYS"
local_user = ""
lang_logs = "SYS"
articles_db_d = ""
# Working directories
articles_d = ""
files_d = ""
images_d = ""
modules_d = ""
# Modules files
navbar_f = ""
sidebar_f = ""
metas_f = ""
footer_f = ""
footer_about_f = ""
# Domain
shortname = ""
www_url = ""
wip_url = ""
# Servers directories
srv_root = ""
srv_domain = ""
srv_wip = ""
srv_wip_tpl_d = ""
srv_wip_images_d = ""
srv_wip_files_d = ""
srv_www = ""
srv_www_tpl_d = ""
srv_www_images_d = ""
srv_www_files_d = ""
# Servers files
wip_navbar_f = ""
wip_sidebar_f = ""
wip_metas_f = ""
wip_footer_f = ""
www_navbar_f = ""
www_sidebar_f = ""
www_metas_f = ""
www_footer_f = ""
wip_logo_f = ""
www_logo_f = ""
www_rss_f = ""
# Domain user's settings
logo = "logo.png"
rss = "rss.xml"
rss_items = 100
title = ""
date = ""
about = ""
lang_site = "SYS"
mail = ""
tags = ""
license = ""
license_url = ""
legal_url = ""
terms_url = ""
css = "tyto"
sep = "-"
article_code = False
relme = ""
sidebar_title = ""
sidebar_items = 6
activated = False