from collections.abc import Iterable from fastapi import HTTPException from folkugat_web.model import playlists as playlists_model from folkugat_web.model import temes as model from folkugat_web.model.lilypond import score as lilypond_model from folkugat_web.services import playlists as playlists_service 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.services.temes import scores as scores_service from folkugat_web.utils import FnChain UNKNOWN_TITLE = "Desconegut" def unknown_tune() -> lilypond_model.LilypondTune: return lilypond_model.LilypondTune( header=lilypond_model.HeaderData( title=UNKNOWN_TITLE, composer=None, ), score_source=None, lyrics=None, is_unknown=True, ) def tune_from_tema(tema: model.Tema | None, score_source: str | None = None) -> lilypond_model.LilypondTune: """ The given `tema` is assumed to have properties, lyrics and scores (if source is None) """ if tema is None: return unknown_tune() return lilypond_model.LilypondTune( header=lilypond_model.HeaderData.from_tema(tema=tema), score_source=score_source or (tema.scores[0].source if tema.scores else None), lyrics=lilypond_model.LyricsText.from_lyrics(lyrics=tema.lyrics[0]) if tema.lyrics else None, ) def tunes_from_temes(temes: Iterable[model.Tema | None]) -> list[lilypond_model.LilypondTune]: """ All `Tema` in `temes` are assumed to have properties, lyrics and scores """ return [tune_from_tema(tema) for tema in temes] def tune_from_tema_id(tema_id: int, score_source: str | None = None) -> lilypond_model.LilypondTune: tema = temes_q.get_tema_by_id(tema_id) if not tema: raise HTTPException(status_code=404, detail="Could not find tema!") tema = ( FnChain.transform(tema) | properties_service.add_properties_to_tema | lyrics_service.add_lyrics_to_tema ).result() if score_source is None: tema = scores_service.add_scores_to_tema(tema) return tune_from_tema(tema=tema, score_source=score_source) def tunes_from_tema_ids(tema_ids: list[int]) -> list[lilypond_model.LilypondTune]: 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 | scores_service.add_scores_to_temes | list ).result() return tunes_from_temes(temes=temes) def build_set_title(temes: list[model.Tema | None]) -> str: def build_title(tema: model.Tema | None) -> str: return tema.title if tema else UNKNOWN_TITLE return " i ".join(filter(bool, [ ", ".join([build_title(tema) for tema in temes[:-1]]), build_title(temes[-1]) ])) def set_from_set(set_entry: playlists_model.Set) -> lilypond_model.LilypondSet: """ The tune_set is assumed to be enriched with tunes """ tema_ids = [tema_in_set.tema_id for tema_in_set in set_entry.temes] temes_by_id = { tema_in_set.tema_id: tema_in_set.tema for tema_in_set in set_entry.temes if tema_in_set.id is not None and tema_in_set.tema } temes = [temes_by_id[tema_id] if tema_id is not None else None for tema_id in tema_ids] set_title = build_set_title(temes=temes) tunes = tunes_from_temes(temes) return lilypond_model.LilypondSet( title=set_title, tunes=tunes ) def playlist_from_playlist(playlist: playlists_model.Playlist) -> lilypond_model.LilypondPlaylist: """ The playlist is assumed to be enriched with tunes """ lilypond_sets = [] for set_entry in playlist.sets: lilypond_set = set_from_set(set_entry) if lilypond_set.tunes and all(map(playlists_service._elegible_for_set_score, lilypond_set.tunes)): lilypond_sets.append(lilypond_set) playlist_title = playlist.name or "Llista" return lilypond_model.LilypondPlaylist( title=playlist_title, sets=lilypond_sets )