Files
pi-weekly-newspaper/src/routes/issues.py

148 lines
4.5 KiB
Python
Raw Normal View History

import os
import json
from flask import Blueprint, render_template, send_file, redirect, url_for, flash
from app import db
from src.models import Issue, Article, Image
from src.cover import generate_cover
from src.epub_builder import build_epub
import config
issues_bp = Blueprint("issues", __name__)
@issues_bp.route("/issues")
def index():
issues = Issue.query.order_by(Issue.created_at.desc()).all()
issue_data = []
for issue in issues:
article_count = len(json.loads(issue.article_ids))
issue_data.append({
"issue": issue,
"article_count": article_count,
})
return render_template("issues.html", issues=issue_data)
@issues_bp.route("/issues/<int:issue_id>/download")
def download(issue_id):
issue = Issue.query.get_or_404(issue_id)
if not os.path.exists(issue.epub_path):
flash("ePub file not found.", "error")
return redirect(url_for("issues.index"))
return send_file(
issue.epub_path,
as_attachment=True,
download_name=os.path.basename(issue.epub_path),
)
@issues_bp.route("/issues/<int:issue_id>/epub")
def epub_file(issue_id):
issue = Issue.query.get_or_404(issue_id)
if not os.path.exists(issue.epub_path):
flash("ePub file not found.", "error")
return redirect(url_for("issues.index"))
return send_file(issue.epub_path, mimetype="application/epub+zip")
@issues_bp.route("/issues/<int:issue_id>/cover")
def cover_image(issue_id):
issue = Issue.query.get_or_404(issue_id)
if not issue.cover_path or not os.path.exists(issue.cover_path):
flash("Cover image not found.", "error")
return redirect(url_for("issues.index"))
return send_file(issue.cover_path, mimetype="image/jpeg")
@issues_bp.route("/issues/<int:issue_id>/read")
def read(issue_id):
issue = Issue.query.get_or_404(issue_id)
if not os.path.exists(issue.epub_path):
flash("ePub file not found.", "error")
return redirect(url_for("issues.index"))
article_count = len(json.loads(issue.article_ids))
if issue.issue_type == "single_article":
article_ids = json.loads(issue.article_ids)
article = Article.query.get(article_ids[0]) if article_ids else None
title = article.title if article else "Single Article"
elif issue.issue_type == "multi_week":
w1 = issue.week_start.isocalendar()[1]
w2 = issue.week_end.isocalendar()[1]
title = f"Weeks {w1}\u2013{w2}"
else:
title = f"Week {issue.week_start.isocalendar()[1]}"
return render_template(
"reader.html",
issue=issue,
title=title,
article_count=article_count,
)
@issues_bp.route("/issues/<int:issue_id>/delete", methods=["POST"])
def delete(issue_id):
issue = Issue.query.get_or_404(issue_id)
if issue.epub_path and os.path.exists(issue.epub_path):
os.remove(issue.epub_path)
if issue.cover_path and os.path.exists(issue.cover_path):
os.remove(issue.cover_path)
db.session.delete(issue)
db.session.commit()
flash("Issue deleted.")
return redirect(url_for("issues.index"))
@issues_bp.route("/issues/<int:issue_id>/regenerate", methods=["POST"])
def regenerate(issue_id):
issue = Issue.query.get_or_404(issue_id)
article_ids = json.loads(issue.article_ids)
articles_for_issue = (
Article.query.filter(Article.id.in_(article_ids))
.order_by(Article.pub_date.asc())
.all()
)
headlines = [
a.title for a in articles_for_issue
if "Obituaries" not in json.loads(a.categories)
]
image_paths = []
for a in articles_for_issue:
if "Obituaries" in json.loads(a.categories):
continue
first_image = Image.query.filter_by(article_id=a.id).first()
if first_image:
image_paths.append(first_image.local_path)
cover_method = issue.cover_method
if cover_method == "ai":
issue.cover_method = "mosaic"
cover_method = "mosaic"
try:
cover_path = generate_cover(
cover_method, config.ISSUES_DIR,
issue.week_start, issue.week_end, headlines, image_paths
)
epub_path = build_epub(
issue.week_start, issue.week_end, article_ids,
cover_path, config.ISSUES_DIR
)
issue.cover_path = cover_path
issue.epub_path = epub_path
db.session.commit()
flash("Issue regenerated successfully.")
except Exception as e:
flash(f"Regeneration failed: {e}", "error")
return redirect(url_for("issues.index"))