Files
audiobook-maker-pro-v4/routes/project_routes.py
Ashim Kumar 8e02b9ad09 first commit
2026-02-20 13:53:36 +06:00

270 lines
8.4 KiB
Python

# routes/project_routes.py - Project Management Routes
import json
from flask import Blueprint, request, jsonify
from db import get_db, vacuum_db
from auth import login_required
project_bp = Blueprint('project', __name__)
@project_bp.route('/api/projects', methods=['GET'])
@login_required
def list_projects():
"""List all projects."""
db = get_db()
cursor = db.cursor()
cursor.execute('''
SELECT p.id, p.name, p.created_at, p.updated_at,
(SELECT COUNT(*) FROM chapters WHERE project_id = p.id) as chapter_count,
(SELECT COUNT(*) FROM markdown_blocks mb
JOIN chapters c ON mb.chapter_id = c.id
WHERE c.project_id = p.id) as block_count
FROM projects p
ORDER BY p.updated_at DESC
''')
projects = []
for row in cursor.fetchall():
projects.append({
'id': row['id'],
'name': row['name'],
'created_at': row['created_at'],
'updated_at': row['updated_at'],
'chapter_count': row['chapter_count'],
'block_count': row['block_count']
})
return jsonify({'projects': projects})
@project_bp.route('/api/projects', methods=['POST'])
@login_required
def create_project():
"""Create a new project."""
data = request.json
name = data.get('name', '').strip()
if not name:
return jsonify({'error': 'Project name is required'}), 400
db = get_db()
cursor = db.cursor()
try:
cursor.execute('INSERT INTO projects (name) VALUES (?)', (name,))
db.commit()
return jsonify({
'success': True,
'project_id': cursor.lastrowid,
'name': name
})
except Exception as e:
if 'UNIQUE constraint' in str(e):
return jsonify({'error': 'Project with this name already exists'}), 400
return jsonify({'error': str(e)}), 500
@project_bp.route('/api/projects/<int:project_id>', methods=['GET'])
@login_required
def get_project(project_id):
"""Get a project with all its chapters and blocks."""
db = get_db()
cursor = db.cursor()
cursor.execute('SELECT * FROM projects WHERE id = ?', (project_id,))
project = cursor.fetchone()
if not project:
return jsonify({'error': 'Project not found'}), 404
cursor.execute('''
SELECT * FROM chapters WHERE project_id = ? ORDER BY chapter_number
''', (project_id,))
chapters = cursor.fetchall()
chapters_data = []
for chapter in chapters:
cursor.execute('''
SELECT * FROM markdown_blocks WHERE chapter_id = ? ORDER BY block_order
''', (chapter['id'],))
blocks = cursor.fetchall()
blocks_data = []
for block in blocks:
cursor.execute('''
SELECT * FROM block_images WHERE block_id = ? ORDER BY id
''', (block['id'],))
images = cursor.fetchall()
blocks_data.append({
'id': block['id'],
'block_order': block['block_order'],
'block_type': block['block_type'],
'content': block['content'],
'tts_text': block['tts_text'],
'audio_data': block['audio_data'],
'audio_format': block['audio_format'],
'transcription': json.loads(block['transcription']) if block['transcription'] else [],
'images': [{
'id': img['id'],
'data': img['image_data'],
'format': img['image_format'],
'alt_text': img['alt_text'],
'position': img['position']
} for img in images]
})
chapters_data.append({
'id': chapter['id'],
'chapter_number': chapter['chapter_number'],
'voice': chapter['voice'],
'blocks': blocks_data
})
return jsonify({
'id': project['id'],
'name': project['name'],
'created_at': project['created_at'],
'updated_at': project['updated_at'],
'chapters': chapters_data
})
@project_bp.route('/api/projects/<int:project_id>', methods=['PUT'])
@login_required
def update_project(project_id):
"""Update project name."""
data = request.json
name = data.get('name', '').strip()
if not name:
return jsonify({'error': 'Project name is required'}), 400
db = get_db()
cursor = db.cursor()
cursor.execute('''
UPDATE projects SET name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?
''', (name, project_id))
db.commit()
if cursor.rowcount == 0:
return jsonify({'error': 'Project not found'}), 404
return jsonify({'success': True})
@project_bp.route('/api/projects/<int:project_id>', methods=['DELETE'])
@login_required
def delete_project(project_id):
"""Delete a project and all its data."""
db = get_db()
cursor = db.cursor()
cursor.execute('SELECT id FROM projects WHERE id = ?', (project_id,))
if not cursor.fetchone():
return jsonify({'error': 'Project not found'}), 404
cursor.execute('''
DELETE FROM block_images WHERE block_id IN (
SELECT mb.id FROM markdown_blocks mb
JOIN chapters c ON mb.chapter_id = c.id
WHERE c.project_id = ?
)
''', (project_id,))
cursor.execute('''
DELETE FROM markdown_blocks WHERE chapter_id IN (
SELECT id FROM chapters WHERE project_id = ?
)
''', (project_id,))
cursor.execute('DELETE FROM chapters WHERE project_id = ?', (project_id,))
cursor.execute('DELETE FROM projects WHERE id = ?', (project_id,))
db.commit()
vacuum_db()
return jsonify({'success': True})
@project_bp.route('/api/projects/<int:project_id>/save', methods=['POST'])
@login_required
def save_project_content(project_id):
"""Save all chapters and blocks for a project."""
data = request.json
chapters = data.get('chapters', [])
db = get_db()
cursor = db.cursor()
cursor.execute('SELECT id FROM projects WHERE id = ?', (project_id,))
if not cursor.fetchone():
return jsonify({'error': 'Project not found'}), 404
cursor.execute('''
DELETE FROM block_images WHERE block_id IN (
SELECT mb.id FROM markdown_blocks mb
JOIN chapters c ON mb.chapter_id = c.id
WHERE c.project_id = ?
)
''', (project_id,))
cursor.execute('''
DELETE FROM markdown_blocks WHERE chapter_id IN (
SELECT id FROM chapters WHERE project_id = ?
)
''', (project_id,))
cursor.execute('DELETE FROM chapters WHERE project_id = ?', (project_id,))
for chapter in chapters:
cursor.execute('''
INSERT INTO chapters (project_id, chapter_number, voice)
VALUES (?, ?, ?)
''', (project_id, chapter['chapter_number'], chapter.get('voice', 'af_heart')))
chapter_id = cursor.lastrowid
for block in chapter.get('blocks', []):
cursor.execute('''
INSERT INTO markdown_blocks
(chapter_id, block_order, block_type, content, tts_text, audio_data, audio_format, transcription)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
''', (
chapter_id,
block['block_order'],
block.get('block_type', 'paragraph'),
block['content'],
block.get('tts_text'),
block.get('audio_data'),
block.get('audio_format', 'mp3'),
json.dumps(block.get('transcription', []))
))
block_id = cursor.lastrowid
for img in block.get('images', []):
cursor.execute('''
INSERT INTO block_images (block_id, image_data, image_format, alt_text, position)
VALUES (?, ?, ?, ?, ?)
''', (
block_id,
img['data'],
img.get('format', 'png'),
img.get('alt_text', ''),
img.get('position', 'before')
))
cursor.execute('''
UPDATE projects SET updated_at = CURRENT_TIMESTAMP WHERE id = ?
''', (project_id,))
db.commit()
return jsonify({'success': True, 'message': 'Project saved successfully'})