mirror of
https://forge.chapril.org/tykayn/book_generator
synced 2025-06-20 01:34:43 +02:00
359 lines
No EOL
11 KiB
Python
359 lines
No EOL
11 KiB
Python
from flask import Flask, render_template, request, jsonify
|
|
import os
|
|
import json
|
|
from datetime import datetime, timedelta
|
|
import re
|
|
|
|
app = Flask(__name__, static_folder='static')
|
|
|
|
def load_org_file(filename):
|
|
if os.path.exists(filename):
|
|
with open(filename, 'r', encoding='utf-8') as f:
|
|
return f.read()
|
|
return ""
|
|
|
|
def save_org_file(filename, content):
|
|
with open(filename, 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
|
|
def extract_characters(content):
|
|
characters = []
|
|
current_character = None
|
|
current_content = []
|
|
|
|
for line in content.split('\n'):
|
|
if line.startswith('** '):
|
|
if current_character:
|
|
characters.append({
|
|
'name': current_character,
|
|
'content': '\n'.join(current_content)
|
|
})
|
|
current_character = line[3:].strip()
|
|
current_content = []
|
|
elif current_character:
|
|
current_content.append(line)
|
|
|
|
if current_character:
|
|
characters.append({
|
|
'name': current_character,
|
|
'content': '\n'.join(current_content)
|
|
})
|
|
|
|
return characters
|
|
|
|
def extract_plots(content):
|
|
plots = []
|
|
current_plot = None
|
|
current_content = []
|
|
current_level = 0
|
|
|
|
for line in content.split('\n'):
|
|
if line.startswith('*'):
|
|
if current_plot:
|
|
current_plot['content'] = '\n'.join(current_content)
|
|
plots.append(current_plot)
|
|
|
|
level = len(line) - len(line.lstrip('*'))
|
|
current_plot = {
|
|
'name': line.lstrip('*').strip(),
|
|
'level': level,
|
|
'content': '',
|
|
'subplots': []
|
|
}
|
|
current_content = []
|
|
elif current_plot:
|
|
current_content.append(line)
|
|
|
|
if current_plot:
|
|
current_plot['content'] = '\n'.join(current_content)
|
|
plots.append(current_plot)
|
|
|
|
# Organiser les intrigues en hiérarchie
|
|
hierarchical_plots = []
|
|
plot_stack = []
|
|
|
|
for plot in plots:
|
|
while plot_stack and plot['level'] <= plot_stack[-1]['level']:
|
|
plot_stack.pop()
|
|
|
|
if plot_stack:
|
|
plot_stack[-1]['subplots'].append(plot)
|
|
else:
|
|
hierarchical_plots.append(plot)
|
|
|
|
plot_stack.append(plot)
|
|
|
|
return hierarchical_plots
|
|
|
|
def update_data_json():
|
|
data = load_data()
|
|
|
|
# Charger et traiter les personnages
|
|
characters_content = load_org_file('personnages.org')
|
|
characters = extract_characters(characters_content)
|
|
data['characters'] = characters
|
|
|
|
# Charger et traiter les intrigues
|
|
plots_content = load_org_file('intrigues.org')
|
|
plots = extract_plots(plots_content)
|
|
data['plots'] = plots
|
|
|
|
save_data(data)
|
|
return data
|
|
|
|
def count_words(text):
|
|
# Ignorer les lignes de propriétés et d'export
|
|
lines = text.split('\n')
|
|
filtered_lines = [line for line in lines if not any(line.startswith(prefix) for prefix in
|
|
[':PROPERTIES:', ':ID:', ':END:', '#+BEGIN_EXPORT', '#+END_EXPORT', '#+'])]
|
|
|
|
# Compter les mots dans les lignes filtrées
|
|
words = ' '.join(filtered_lines).split()
|
|
return len(words)
|
|
|
|
def load_data():
|
|
if os.path.exists('data.json'):
|
|
with open('data.json', 'r', encoding='utf-8') as f:
|
|
return json.load(f)
|
|
return {}
|
|
|
|
def save_data(data):
|
|
with open('data.json', 'w', encoding='utf-8') as f:
|
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
|
|
|
def get_words_today():
|
|
data = load_data()
|
|
today = datetime.now().strftime('%Y-%m-%d')
|
|
yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d')
|
|
|
|
# Si on n'a pas de données pour aujourd'hui, on crée une entrée
|
|
if today not in data:
|
|
data[today] = {
|
|
'words': 0,
|
|
'last_update': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
}
|
|
save_data(data)
|
|
|
|
# Trouver le jour précédent le plus proche qui a des données
|
|
previous_day = None
|
|
previous_words = 0
|
|
current_date = datetime.now() - timedelta(days=1)
|
|
while current_date >= datetime.strptime('2000-01-01', '%Y-%m-%d'):
|
|
date_str = current_date.strftime('%Y-%m-%d')
|
|
if date_str in data:
|
|
previous_day = date_str
|
|
previous_words = data[date_str]['words']
|
|
break
|
|
current_date -= timedelta(days=1)
|
|
|
|
# Si on n'a pas trouvé de jour précédent, on utilise le nombre de mots actuel comme référence
|
|
if not previous_day:
|
|
with open('livre.org', 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
previous_words = count_words(content)
|
|
data[yesterday] = {
|
|
'words': previous_words,
|
|
'last_update': (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')
|
|
}
|
|
save_data(data)
|
|
|
|
# Calculer la progression en différence avec le jour précédent
|
|
words_today = data[today]['words']
|
|
progress = max(0, words_today - previous_words)
|
|
|
|
return progress
|
|
|
|
@app.route('/')
|
|
def index():
|
|
with open('livre.org', 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
words_today = get_words_today()
|
|
data = update_data_json()
|
|
return render_template('index.html', content=content, words_today=words_today,
|
|
characters=data.get('characters', []), plots=data.get('plots', []))
|
|
|
|
@app.route('/update', methods=['POST'])
|
|
def update():
|
|
content = request.form.get('content', '')
|
|
editor_title = request.form.get('editor_title', '')
|
|
|
|
# Déterminer le fichier de destination en fonction du titre de l'éditeur
|
|
if 'Personnage:' in editor_title:
|
|
current_file = 'personnages.org'
|
|
elif 'Intrigue:' in editor_title:
|
|
current_file = 'intrigues.org'
|
|
elif editor_title == 'Intrigues':
|
|
current_file = 'intrigues.org'
|
|
else:
|
|
current_file = 'livre.org'
|
|
|
|
with open(current_file, 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
|
|
# Mettre à jour le nombre de mots pour aujourd'hui si c'est le fichier principal
|
|
if current_file == 'livre.org':
|
|
data = load_data()
|
|
today = datetime.now().strftime('%Y-%m-%d')
|
|
data[today] = {
|
|
'words': count_words(content),
|
|
'last_update': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
}
|
|
save_data(data)
|
|
|
|
return jsonify({'words_today': get_words_today()})
|
|
|
|
@app.route('/words_today')
|
|
def words_today():
|
|
return jsonify({'words': get_words_today()})
|
|
|
|
@app.route('/progress_data')
|
|
def progress_data():
|
|
data = load_data()
|
|
# Trier les dates
|
|
dates = sorted(data.keys(), reverse=True)
|
|
# Prendre les 7 derniers jours
|
|
dates = dates[:7]
|
|
|
|
# Préparer les données pour le graphique
|
|
chart_data = {
|
|
'labels': [],
|
|
'words': [],
|
|
'progress': []
|
|
}
|
|
|
|
for date in dates:
|
|
chart_data['labels'].append(date)
|
|
if date in data and 'words' in data[date]:
|
|
chart_data['words'].append(data[date]['words'])
|
|
else:
|
|
chart_data['words'].append(0)
|
|
|
|
# Calculer la progression entre chaque jour
|
|
for i in range(len(chart_data['words'])):
|
|
if i < len(chart_data['words']) - 1:
|
|
progress = max(0, chart_data['words'][i] - chart_data['words'][i + 1])
|
|
else:
|
|
progress = 0
|
|
chart_data['progress'].append(progress)
|
|
|
|
return jsonify(chart_data)
|
|
|
|
@app.route('/update_character', methods=['POST'])
|
|
def update_character():
|
|
name = request.form.get('name')
|
|
content = request.form.get('content')
|
|
|
|
characters_content = load_org_file('personnages.org')
|
|
characters = extract_characters(characters_content)
|
|
|
|
# Mettre à jour ou ajouter le personnage
|
|
found = False
|
|
for char in characters:
|
|
if char['name'] == name:
|
|
char['content'] = content
|
|
found = True
|
|
break
|
|
|
|
if not found:
|
|
characters.append({
|
|
'name': name,
|
|
'content': content
|
|
})
|
|
|
|
# Sauvegarder le fichier
|
|
new_content = []
|
|
for char in characters:
|
|
new_content.append(f"* {char['name']}")
|
|
new_content.append(char['content'])
|
|
|
|
save_org_file('personnages.org', '\n'.join(new_content))
|
|
update_data_json()
|
|
|
|
return jsonify({'status': 'success'})
|
|
|
|
@app.route('/update_plot', methods=['POST'])
|
|
def update_plot():
|
|
name = request.form.get('name')
|
|
content = request.form.get('content')
|
|
|
|
plots_content = load_org_file('intrigues.org')
|
|
plots = extract_plots(plots_content)
|
|
|
|
# Mettre à jour ou ajouter l'intrigue
|
|
found = False
|
|
for plot in plots:
|
|
if plot['name'] == name:
|
|
plot['content'] = content
|
|
found = True
|
|
break
|
|
|
|
if not found:
|
|
plots.append({
|
|
'name': name,
|
|
'content': content
|
|
})
|
|
|
|
# Sauvegarder le fichier
|
|
new_content = []
|
|
for plot in plots:
|
|
new_content.append(f"* {plot['name']}")
|
|
new_content.append(plot['content'])
|
|
|
|
save_org_file('intrigues.org', '\n'.join(new_content))
|
|
update_data_json()
|
|
|
|
return jsonify({'status': 'success'})
|
|
|
|
@app.route('/get_character', methods=['POST'])
|
|
def get_character():
|
|
name = request.form.get('name')
|
|
characters_content = load_org_file('personnages.org')
|
|
characters = extract_characters(characters_content)
|
|
|
|
for char in characters:
|
|
if char['name'] == name:
|
|
return jsonify({
|
|
'content': f"* {char['name']}\n{char['content']}"
|
|
})
|
|
|
|
return jsonify({'error': 'Personnage non trouvé'}), 404
|
|
|
|
@app.route('/get_plot', methods=['POST'])
|
|
def get_plot():
|
|
name = request.form.get('name')
|
|
plots_content = load_org_file('intrigues.org')
|
|
plots = extract_plots(plots_content)
|
|
|
|
for plot in plots:
|
|
if plot['name'] == name:
|
|
return jsonify({
|
|
'content': f"* {plot['name']}\n{plot['content']}"
|
|
})
|
|
|
|
return jsonify({'error': 'Intrigue non trouvée'}), 404
|
|
|
|
@app.route('/get_book')
|
|
def get_book():
|
|
content = load_org_file('livre.org')
|
|
return jsonify({'content': content})
|
|
|
|
@app.route('/get_plots_file')
|
|
def get_plots_file():
|
|
try:
|
|
with open('intrigues.org', 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
return jsonify({'content': content})
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
@app.route('/get_characters_file')
|
|
def get_characters_file():
|
|
try:
|
|
with open('personnages.org', 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
return jsonify({'content': content})
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
if __name__ == '__main__':
|
|
app.run(debug=True) |