183 lines
6.4 KiB
Python
183 lines
6.4 KiB
Python
import dataclasses
|
|
from typing import Annotated
|
|
|
|
from fastapi import HTTPException, Request
|
|
from fastapi.params import Form
|
|
from fastapi.responses import HTMLResponse
|
|
from folkugat_web.api import router
|
|
from folkugat_web.fragments import temes
|
|
from folkugat_web.fragments.tema import scores as scores_fragments
|
|
from folkugat_web.services import auth, files
|
|
from folkugat_web.services.lilypond import build as lilypond_build
|
|
from folkugat_web.services.lilypond import render as lilypond_render
|
|
from folkugat_web.services.lilypond import source as lilypond_source
|
|
from folkugat_web.services.temes import scores as scores_service
|
|
|
|
|
|
@router.get("/api/tema/{tema_id}/score/{score_id}")
|
|
def score(request: Request, logged_in: auth.LoggedIn, tema_id: int, score_id: int):
|
|
score = scores_service.get_score_by_id(score_id=score_id, tema_id=tema_id)
|
|
if not score:
|
|
raise HTTPException(status_code=404, detail="Could not find lyric!")
|
|
return scores_fragments.score(request=request, logged_in=logged_in, score=score)
|
|
|
|
|
|
@router.put("/api/tema/{tema_id}/score/{score_id}")
|
|
async def set_score(
|
|
request: Request,
|
|
logged_in: auth.RequireLogin,
|
|
tema_id: int,
|
|
score_id: int,
|
|
title: Annotated[str, Form()],
|
|
source: Annotated[str, Form()],
|
|
):
|
|
source = source.strip()
|
|
score = scores_service.get_score_by_id(score_id=score_id, tema_id=tema_id)
|
|
if not score:
|
|
raise HTTPException(status_code=404, detail="Could not find lyric!")
|
|
|
|
tune = lilypond_build.tune_from_tema_id(tema_id=tema_id, score_source=source)
|
|
tune_source = lilypond_source.tune_source(tune=tune)
|
|
pdf_result, png_result = await render_tune(tune_source=tune_source, tema_id=tema_id)
|
|
if errors := pdf_result.error:
|
|
new_score = dataclasses.replace(
|
|
score,
|
|
source=source,
|
|
title=title,
|
|
errors=errors,
|
|
)
|
|
elif png_result is None:
|
|
raise RuntimeError(f"Received empty png_result with pdf_result: {pdf_result}")
|
|
elif errors := png_result.error:
|
|
new_score = dataclasses.replace(
|
|
score,
|
|
source=source,
|
|
title=title,
|
|
errors=errors,
|
|
)
|
|
else:
|
|
pdf_file = pdf_result.result
|
|
png_file = png_result.result
|
|
new_score = dataclasses.replace(
|
|
score,
|
|
source=source,
|
|
title=title,
|
|
pdf_url=files.get_db_file_path(pdf_file) if pdf_file else None,
|
|
img_url=files.get_db_file_path(png_file) if png_file else None,
|
|
errors=[],
|
|
)
|
|
scores_service.update_score(score=new_score)
|
|
files.clean_orphan_files()
|
|
return scores_fragments.score(request=request, logged_in=logged_in, score=new_score)
|
|
|
|
|
|
async def render_tune(
|
|
tune_source: str,
|
|
tema_id: int,
|
|
) -> tuple[lilypond_render.RenderResult, lilypond_render.RenderResult | None]:
|
|
async with files.tmp_file(content=tune_source) as source_file:
|
|
pdf_file = files.create_tema_filename(tema_id=tema_id)
|
|
pdf_result = await lilypond_render.render_file(
|
|
input_file=source_file,
|
|
output=lilypond_render.RenderOutput.PDF,
|
|
output_file=pdf_file,
|
|
)
|
|
if pdf_result.error:
|
|
return pdf_result, None
|
|
png_file = files.create_tema_filename(tema_id=tema_id)
|
|
png_result = await lilypond_render.render_file(
|
|
input_file=source_file,
|
|
output=lilypond_render.RenderOutput.PNG_CROPPED,
|
|
output_file=png_file,
|
|
)
|
|
return pdf_result, png_result
|
|
|
|
|
|
@router.post("/api/tema/{tema_id}/score")
|
|
def add_score(
|
|
request: Request,
|
|
logged_in: auth.RequireLogin,
|
|
tema_id: int,
|
|
):
|
|
score = scores_service.create_score(tema_id=tema_id)
|
|
return scores_fragments.score_editor(
|
|
request=request,
|
|
logged_in=logged_in,
|
|
score=score,
|
|
)
|
|
|
|
|
|
@router.delete("/api/tema/{tema_id}/score/{score_id}")
|
|
def delete_score(request: Request, logged_in: auth.RequireLogin, tema_id: int, score_id: int):
|
|
scores_service.delete_score(score_id=score_id, tema_id=tema_id)
|
|
files.clean_orphan_files()
|
|
return HTMLResponse()
|
|
|
|
|
|
@router.get("/api/tema/{tema_id}/editor/score/{score_id}")
|
|
def score_editor(
|
|
request: Request,
|
|
logged_in: auth.RequireLogin,
|
|
tema_id: int,
|
|
score_id: int,
|
|
):
|
|
score = scores_service.get_score_by_id(score_id=score_id, tema_id=tema_id)
|
|
if not score:
|
|
raise HTTPException(status_code=404, detail="Could not find lyric!")
|
|
return scores_fragments.score_editor(
|
|
request=request,
|
|
logged_in=logged_in,
|
|
score=score,
|
|
)
|
|
|
|
|
|
@router.post("/api/tema/{tema_id}/editor/score/{score_id}/render")
|
|
async def render(
|
|
request: Request,
|
|
_: auth.RequireLogin,
|
|
tema_id: int,
|
|
score_id: int,
|
|
source: Annotated[str, Form()],
|
|
):
|
|
tune = lilypond_build.tune_from_tema_id(tema_id=tema_id, score_source=source)
|
|
full_source = lilypond_source.tune_source(tune=tune)
|
|
png_result = await lilypond_render.render(
|
|
source=full_source,
|
|
output=lilypond_render.RenderOutput.PNG_CROPPED,
|
|
)
|
|
if output_filename := png_result.result:
|
|
score_render_url = files.get_db_file_path(output_filename)
|
|
return temes.score_render(request=request, score_id=score_id, score_render_url=score_render_url)
|
|
else:
|
|
return temes.score_render(request=request, score_id=score_id, errors=png_result.error)
|
|
|
|
|
|
@router.put("/api/tema/{tema_id}/score/{score_id}/show")
|
|
async def show_score(
|
|
request: Request,
|
|
logged_in: auth.RequireLogin,
|
|
tema_id: int,
|
|
score_id: int,
|
|
):
|
|
score = scores_service.get_score_by_id(score_id=score_id, tema_id=tema_id)
|
|
if not score:
|
|
raise HTTPException(status_code=404, detail="Could not find lyric!")
|
|
new_score = dataclasses.replace(score, hidden=False)
|
|
scores_service.update_score(score=new_score)
|
|
return scores_fragments.score(request=request, logged_in=logged_in, score=new_score)
|
|
|
|
|
|
@router.put("/api/tema/{tema_id}/score/{score_id}/hide")
|
|
async def hide_score(
|
|
request: Request,
|
|
logged_in: auth.RequireLogin,
|
|
tema_id: int,
|
|
score_id: int,
|
|
):
|
|
score = scores_service.get_score_by_id(score_id=score_id, tema_id=tema_id)
|
|
if not score:
|
|
raise HTTPException(status_code=404, detail="Could not find lyric!")
|
|
new_score = dataclasses.replace(score, hidden=True)
|
|
scores_service.update_score(score=new_score)
|
|
return scores_fragments.score(request=request, logged_in=logged_in, score=new_score)
|