From 1909af9107f757d0bccefe505c7b4b4e23e30934 Mon Sep 17 00:00:00 2001 From: marc Date: Fri, 24 Oct 2025 00:05:56 +0200 Subject: [PATCH] Afegir temes coocurrents --- README.org | 2 +- folkugat_web/api/routes/tema/index.py | 19 +++++ folkugat_web/assets/static/css/main.css | 4 + .../templates/fragments/tema/played_with.html | 40 +++++++++ .../templates/fragments/tema/property.html | 7 +- .../templates/fragments/tema/stats.html | 85 ++++++++++--------- .../assets/templates/icons/notes-small.svg | 5 ++ folkugat_web/dal/sql/playlists/query.py | 35 ++++++++ folkugat_web/model/temes.py | 9 ++ folkugat_web/services/temes/query.py | 8 ++ 10 files changed, 171 insertions(+), 43 deletions(-) create mode 100644 folkugat_web/assets/templates/fragments/tema/played_with.html create mode 100644 folkugat_web/assets/templates/icons/notes-small.svg diff --git a/README.org b/README.org index 1631993..f8cf541 100644 --- a/README.org +++ b/README.org @@ -1,7 +1,7 @@ #+title: Readme * Tasques -** TODO Ordenar els resultats de la cerca de temes +** DONE Ordenar els resultats de la cerca de temes ** TODO Suport per a diverses organitzacions (no només jam de Sant Cugat) ** TODO Usuaris i permisos granulars ** Lilypond support diff --git a/folkugat_web/api/routes/tema/index.py b/folkugat_web/api/routes/tema/index.py index ec74e25..0043a54 100644 --- a/folkugat_web/api/routes/tema/index.py +++ b/folkugat_web/api/routes/tema/index.py @@ -1,3 +1,4 @@ +import dataclasses from typing import Annotated from fastapi import HTTPException, Request @@ -5,6 +6,7 @@ from fastapi.params import Form from fastapi.responses import HTMLResponse from folkugat_web.api.router import get_router from folkugat_web.fragments import tema, temes +from folkugat_web.model.temes import Tema from folkugat_web.services import auth from folkugat_web.services import files as files_service from folkugat_web.services.temes import links as links_service @@ -32,6 +34,21 @@ def page(request: Request, logged_in: auth.LoggedIn, tema_id: int): ) +def augment_played_with(tema: Tema) -> Tema: + if tema.played_with: + tema.played_with = [ + dataclasses.replace( + co_tema, + tema=( + FnChain.transform(co_tema.tema) | + scores_service.add_scores_to_tema | + properties_service.add_properties_to_tema + ).result() + ) for co_tema in tema.played_with + ] + return tema + + @router.get("/api/tema/{tema_id}") def contingut(request: Request, logged_in: auth.LoggedIn, tema_id: int): tema = temes_q.get_tema_by_id(tema_id) @@ -40,6 +57,8 @@ def contingut(request: Request, logged_in: auth.LoggedIn, tema_id: int): tema = ( FnChain.transform(tema) | temes_q.tema_compute_stats | + temes_q.tema_compute_played_with | + augment_played_with | links_service.add_links_to_tema | lyrics_service.add_lyrics_to_tema | scores_service.add_scores_to_tema | diff --git a/folkugat_web/assets/static/css/main.css b/folkugat_web/assets/static/css/main.css index 3185b00..80e96f7 100644 --- a/folkugat_web/assets/static/css/main.css +++ b/folkugat_web/assets/static/css/main.css @@ -657,6 +657,10 @@ video { margin-left: 0.5rem; } +.ml-4 { + margin-left: 1rem; +} + .ml-auto { margin-left: auto; } diff --git a/folkugat_web/assets/templates/fragments/tema/played_with.html b/folkugat_web/assets/templates/fragments/tema/played_with.html new file mode 100644 index 0000000..9759c8c --- /dev/null +++ b/folkugat_web/assets/templates/fragments/tema/played_with.html @@ -0,0 +1,40 @@ +
  • +
    + + {% if tema.properties %} + + {% endif %} + {% if tema.main_score() and tema.main_score().preview_url %} + + + + {% endif %} +
    +
    + {% include "icons/music-box.svg" %} + {% if co_tema.count == 1 %} + 1 cop + {% else %} + {{ co_tema.count }} cops + {% endif %} +
    +
    +
    +
  • diff --git a/folkugat_web/assets/templates/fragments/tema/property.html b/folkugat_web/assets/templates/fragments/tema/property.html index 023d4f7..807ef1b 100644 --- a/folkugat_web/assets/templates/fragments/tema/property.html +++ b/folkugat_web/assets/templates/fragments/tema/property.html @@ -1,11 +1,12 @@
    + class="flex flex-row items-center">
    {{ property.field.value.capitalize() }}:
    -
    + {{ property.value }} -
    + {% if logged_in %}
    diff --git a/folkugat_web/assets/templates/fragments/tema/stats.html b/folkugat_web/assets/templates/fragments/tema/stats.html index 8e3ab06..7efc101 100644 --- a/folkugat_web/assets/templates/fragments/tema/stats.html +++ b/folkugat_web/assets/templates/fragments/tema/stats.html @@ -1,42 +1,49 @@ +

    Estadístiques

    +
    {% if tema.stats %} -

    Estadístiques

    -
    -
    -

    - Aquest tema ha sigut tocat en - {% if tema.stats.times_played == 1%} - una sessió. - {% else %} - {{ tema.stats.times_played }} sessions. - {% endif %} -

    -

    - S'ha tocat a les sessions següents: -

      - {% for session in tema.stats.sessions_played %} -
    1. - - -
    2. - {% endfor %} -
    -

    +
    + {% if tema.played_with %} +
    + {% include "icons/notes-small.svg" %} +

    + S'ha tocat juntament amb: +

    +
    +
      + {% for co_tema in tema.played_with %} + {% set tema = co_tema.tema %} + {% include "fragments/tema/played_with.html" %} + {% endfor %} +
    + {% endif %} +
    + {% include "icons/music-box.svg" %} +

    + S'ha tocat en + {% if tema.stats.times_played == 1%} + una sessió: + {% else %} + {{ tema.stats.times_played }} sessions: + {% endif %} +

    +
    +
      + {% for session in tema.stats.sessions_played %} +
    1. + + {% include "icons/calendar.svg" %} +

      + {% set dn = date_names(session.date) %} {{ dn.day_name }} {{ dn.day }} {{ dn.month_name }} +

      +
      +
    2. + {% endfor %} +
    +{% else %} +
    + No s'ha tocat a cap jam (encara) +
    {% endif %} diff --git a/folkugat_web/assets/templates/icons/notes-small.svg b/folkugat_web/assets/templates/icons/notes-small.svg new file mode 100644 index 0000000..4fde372 --- /dev/null +++ b/folkugat_web/assets/templates/icons/notes-small.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/folkugat_web/dal/sql/playlists/query.py b/folkugat_web/dal/sql/playlists/query.py index 0b962b0..1a76dcd 100644 --- a/folkugat_web/dal/sql/playlists/query.py +++ b/folkugat_web/dal/sql/playlists/query.py @@ -3,7 +3,9 @@ from typing import TypedDict from folkugat_web.dal.sql import Connection, get_connection from folkugat_web.dal.sql.sessions import conversion as sessions_conversion +from folkugat_web.dal.sql.temes.conversion import row_to_tema from folkugat_web.model import playlists as model +from folkugat_web.model import temes as temes_model from folkugat_web.model.sessions import Session from folkugat_web.utils import groupby @@ -76,3 +78,36 @@ def get_tune_sessions(tema_ids: list[int], con: Connection | None = None) -> dic key_fn=lambda row: row[0], group_fn=lambda rows: list(sessions_conversion.row_to_session(row[1:]) for row in rows) )) + + +CommonlyPlayedTuneRow = tuple[int, str, str, str, str, int, int] + + +def get_commonly_played_tunes( + tema_id: int, + con: Connection | None = None, +) -> list[temes_model.CommonlyPlayedTema]: + query = """ + SELECT + id, title, alternatives, creation_date, modification_date, hidden, count + FROM ( + SELECT tema_id, count(*) count FROM playlists p JOIN ( + SELECT session_id, set_id + FROM playlists + WHERE tema_id = ? + ) s + ON p.session_id == s.session_id AND p.set_id == s.set_id + WHERE tema_id != ? + GROUP BY tema_id + ) common JOIN temes t ON common.tema_id == t.id + """ + with get_connection(con) as con: + cur = con.cursor() + _ = cur.execute(query, [tema_id, tema_id]) + result_rows: Iterable[CommonlyPlayedTuneRow] = cur.fetchall() + return [ + temes_model.CommonlyPlayedTema( + tema=row_to_tema(row[:6]), + count=row[6], + ) for row in result_rows + ] diff --git a/folkugat_web/model/temes.py b/folkugat_web/model/temes.py index d34af26..c8dcf06 100644 --- a/folkugat_web/model/temes.py +++ b/folkugat_web/model/temes.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import dataclasses import datetime import enum @@ -110,6 +112,7 @@ class Tema: creation_date: datetime.datetime = dataclasses.field(default_factory=datetime.datetime.now) # Stats stats: Stats | None = None + played_with: list[CommonlyPlayedTema] | None = None def ngrams(self) -> NGrams: return ngrams.get_text_ngrams(self.title, *self.alternatives) @@ -149,6 +152,12 @@ class Tema: return bool(self.lyrics) +@dataclasses.dataclass +class CommonlyPlayedTema: + tema: Tema + count: int + + class TemaCols(enum.Enum): NOM = "nom" COPS_TOCAT = "cops_tocat" diff --git a/folkugat_web/services/temes/query.py b/folkugat_web/services/temes/query.py index f31fc0c..6a338e9 100644 --- a/folkugat_web/services/temes/query.py +++ b/folkugat_web/services/temes/query.py @@ -35,3 +35,11 @@ def temes_compute_stats(temes: Iterable[model.Tema]) -> list[model.Tema]: tema_ids = [tema.id for tema in temes if tema.id is not None] tune_sessions_dict = playlists_q.get_tune_sessions(tema_ids=tema_ids) return [tema_compute_stats(tema=tema, tune_sessions_dict=tune_sessions_dict) for tema in temes] + + +def tema_compute_played_with( + tema: model.Tema, +) -> model.Tema: + if tema.id: + tema.played_with = playlists_q.get_commonly_played_tunes(tema_id=tema.id) + return tema