107 lines
2.6 KiB
Python
107 lines
2.6 KiB
Python
import dataclasses
|
|
import zlib
|
|
from typing import Self
|
|
|
|
from folkugat_web.model import temes
|
|
from folkugat_web.utils import batched
|
|
|
|
|
|
def get_hash(*v: bytes) -> bytes:
|
|
return zlib.adler32(b"".join(v)).to_bytes(4)
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class LyricsParagraph:
|
|
lines: list[str]
|
|
|
|
def hash(self) -> bytes:
|
|
return get_hash(*(get_hash(line.encode()) for line in self.lines))
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class LyricsLine:
|
|
paragraphs: list[LyricsParagraph]
|
|
|
|
def hash(self) -> bytes:
|
|
return get_hash(*(paragraph.hash() for paragraph in self.paragraphs))
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class LyricsText:
|
|
lines: list[LyricsLine]
|
|
|
|
@classmethod
|
|
def from_lyrics(cls, lyrics: temes.Lyrics, max_cols: int = 3) -> Self:
|
|
# Use stored max_columns if available, otherwise use the provided max_cols
|
|
effective_max_cols = lyrics.max_columns if lyrics.max_columns is not None else max_cols
|
|
# Remove ~ characters before processing
|
|
paragraphs = [
|
|
LyricsParagraph(lines=[line.replace("~", "") for line in par_str.splitlines()])
|
|
for par_str in lyrics.content.split("\n\n") if par_str
|
|
]
|
|
return cls(lines=[
|
|
LyricsLine(paragraphs=list(line_pars))
|
|
for line_pars in batched(paragraphs, effective_max_cols)
|
|
])
|
|
|
|
def hash(self) -> bytes:
|
|
return get_hash(*(line.hash() for line in self.lines))
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class HeaderData:
|
|
title: str
|
|
composer: str | None
|
|
|
|
@classmethod
|
|
def from_tema(cls, tema: temes.Tema) -> Self:
|
|
return cls(
|
|
title=tema.title,
|
|
composer=tema.composer() or tema.origin(),
|
|
)
|
|
|
|
def hash(self) -> bytes:
|
|
return get_hash(
|
|
self.title.encode(),
|
|
(self.composer or "").encode(),
|
|
)
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class LilypondTune:
|
|
header: HeaderData
|
|
score_source: str | None
|
|
lyrics: LyricsText | None
|
|
is_unknown: bool = False
|
|
|
|
def hash(self) -> bytes:
|
|
return get_hash(
|
|
self.header.hash(),
|
|
(self.score_source or "").encode(),
|
|
self.lyrics.hash() if self.lyrics else b"",
|
|
)
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class LilypondSet:
|
|
title: str
|
|
tunes: list[LilypondTune]
|
|
|
|
def hash(self) -> bytes:
|
|
return get_hash(
|
|
self.title.encode(),
|
|
*(tune.hash() for tune in self.tunes),
|
|
)
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class LilypondPlaylist:
|
|
title: str
|
|
sets: list[LilypondSet]
|
|
|
|
def hash(self) -> bytes:
|
|
return get_hash(
|
|
self.title.encode(),
|
|
*(lilypond_set.hash() for lilypond_set in self.sets),
|
|
)
|