Added tune previews

This commit is contained in:
marc
2025-04-27 17:00:04 +02:00
parent 695e0b54bf
commit bc3d98aba2
14 changed files with 123 additions and 131 deletions

View File

@@ -97,7 +97,8 @@ def get_orphan_files() -> Iterator[Path]:
link_urls = {link.url for link in links_dal.get_links()}
score_pdf_urls = {score.pdf_url for score in scores_dal.get_scores() if score.pdf_url is not None}
score_img_urls = {score.img_url for score in scores_dal.get_scores() if score.img_url is not None}
alive_urls = link_urls | score_pdf_urls | score_img_urls
score_preview_urls = {score.preview_url for score in scores_dal.get_scores() if score.preview_url is not None}
alive_urls = link_urls | score_pdf_urls | score_img_urls | score_preview_urls
return filter(
lambda p: p.is_file() and get_db_file_path(p) not in alive_urls,
itertools.chain(

View File

@@ -18,7 +18,7 @@ RenderResult = Result[Path, list[RenderError]]
class RenderOutput(enum.Enum):
PDF = "pdf"
PNG_CROPPED = "png-cropped"
PNG_PREVIEW = "png-preview"
PREVIEW = "preview"
async def render(
@@ -61,16 +61,16 @@ async def render_file(
]
output_file = output_file.with_suffix(".cropped.png")
# output_file = output_file.with_suffix(".png")
case RenderOutput.PNG_PREVIEW:
case RenderOutput.PREVIEW:
command = [
"lilypond",
"-f", "png",
"-f", "svg",
"-dpreview=#t",
"-dno-print-pages",
"-o", str(output_file),
str(input_file)
]
output_file = output_file.with_suffix(".preview.png")
output_file = output_file.with_suffix(".preview.svg")
proc = await asyncio.create_subprocess_exec(
*command,

View File

@@ -11,6 +11,13 @@ def tune_source(tune: LilypondTune) -> str:
)
def preview_source(tune: LilypondTune) -> str:
return templates.get_template("lilypond/preview.ly").render(
score_beginning=SCORE_BEGINNING,
tune=tune,
)
def set_source(tune_set: LilypondSet) -> str:
return templates.get_template("lilypond/tune_set.ly").render(
score_beginning=SCORE_BEGINNING,

View File

@@ -1,14 +1,12 @@
import dataclasses
from collections.abc import Iterable, Iterator
from fastapi import HTTPException
from folkugat_web.dal.sql.temes import scores as scores_dal
from folkugat_web.model import temes as model
from folkugat_web.model.lilypond import score as lilypond_model
from folkugat_web.services import lilypond
from folkugat_web.services.temes import lyrics as lyrics_service
from folkugat_web.services.temes import properties as properties_service
from folkugat_web.services.temes import query as temes_q
from folkugat_web.utils import FnChain
from folkugat_web.services import files as files_service
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
def add_scores_to_tema(tema: model.Tema) -> model.Tema:
@@ -42,34 +40,56 @@ def create_score(tema_id: int) -> model.Score:
errors=[],
img_url=None,
pdf_url=None,
preview_url=None,
hidden=True,
)
return scores_dal.insert_score(score=new_score)
def build_tune_set_full_source(tema_ids: list[int]) -> str:
temes = (
FnChain.transform(temes_q.get_temes_by_ids(tema_ids=tema_ids)) |
properties_service.add_properties_to_temes |
lyrics_service.add_lyrics_to_temes |
add_scores_to_temes |
list
).result()
if not temes:
return ""
set_title = " i ".join(filter(bool, [
", ".join([tema.title for tema in temes[:-1]]),
temes[-1].title
]))
tune_set = lilypond_model.LilypondSet(
title=set_title,
tunes=[
lilypond_model.LilypondTune(
header=lilypond_model.HeaderData.from_tema(tema=tema),
score_source=tema.scores[0].source if tema.scores else None,
lyrics=lilypond_model.LyricsText.from_lyrics(lyrics=tema.lyrics[0]) if tema.lyrics else None,
) for tema in temes
]
async def render_score(score: model.Score, title: str, source: str) -> model.Score:
tune = lilypond_build.tune_from_tema_id(tema_id=score.tema_id, score_source=source)
output_file = files_service.create_tema_filename(tema_id=score.tema_id)
tune_source = lilypond_source.tune_source(tune=tune)
async with files_service.tmp_file(content=tune_source) as source_file:
# Render PDF
pdf_result = await lilypond_render.render_file(
input_file=source_file,
output=lilypond_render.RenderOutput.PDF,
output_file=output_file,
)
if errors := pdf_result.error:
return dataclasses.replace(score, source=source, title=title, errors=errors)
# Render IMAGE
img_result = await lilypond_render.render_file(
input_file=source_file,
output=lilypond_render.RenderOutput.PNG_CROPPED,
output_file=output_file,
)
if errors := img_result.error:
return dataclasses.replace(score, source=source, title=title, errors=errors)
preview_source = lilypond_source.preview_source(tune=tune)
async with files_service.tmp_file(content=preview_source) as source_file:
# Render PREVIEW
preview_result = await lilypond_render.render_file(
input_file=source_file,
output=lilypond_render.RenderOutput.PREVIEW,
output_file=output_file,
)
if errors := preview_result.error:
return dataclasses.replace(score, source=source, title=title, errors=errors)
pdf_file = pdf_result.result
img_file = img_result.result
preview_file = preview_result.result if preview_result.result and preview_result.result.exists() else None
return dataclasses.replace(
score,
source=source,
title=title,
pdf_url=files_service.get_db_file_path(pdf_file) if pdf_file else None,
img_url=files_service.get_db_file_path(img_file) if img_file else None,
preview_url=files_service.get_db_file_path(preview_file) if preview_file else None,
errors=[],
)
print("TUNE SET HASH: ", tune_set.hash().hex())
return lilypond.tune_set_score(tune_set=tune_set)