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)