Pàgines llista de reproducció

This commit is contained in:
marc
2025-12-20 23:29:11 +01:00
parent 5428d49e89
commit 56ab91bd42
11 changed files with 291 additions and 20 deletions

View File

@@ -1,14 +1,76 @@
from typing import Annotated from typing import Annotated
from fastapi import Form, Request from fastapi import Form, HTTPException, Request
from folkugat_web.api.router import get_router from folkugat_web.api.router import get_router
from folkugat_web.fragments import playlist from folkugat_web.fragments import playlist
from folkugat_web.services import auth from folkugat_web.services import auth
from folkugat_web.services import playlists as playlists_service
from folkugat_web.services.temes import write as temes_service from folkugat_web.services.temes import write as temes_service
from folkugat_web.templates import templates
router = get_router() router = get_router()
@router.get("/playlist/{playlist_id}")
def page(
request: Request,
logged_in: auth.LoggedIn,
playlist_id: int,
):
playlist = playlists_service.get_playlist(playlist_id=playlist_id)
if not playlist:
raise HTTPException(status_code=404, detail="Could not find playlist")
return templates.TemplateResponse(
"index.html",
{
"request": request,
"page_title": "Folkugat - Setlist",
"page_description": playlist.name or "Llista de temes",
"page_card": None,
"content": f"/api/content/playlist/{playlist_id}",
"logged_in": logged_in,
}
)
@router.get("/api/content/playlist/{playlist_id}")
def contingut(
request: Request,
logged_in: auth.LoggedIn,
playlist_id: int,
):
return playlist.pagina(request, playlist_id, logged_in)
@router.get("/api/playlist/{playlist_id}/name")
def get_name(
request: Request,
logged_in: auth.LoggedIn,
playlist_id: int,
):
return playlist.name(request=request, playlist_id=playlist_id, logged_in=logged_in)
@router.get("/api/playlist/{playlist_id}/editor/name")
def name_editor(
request: Request,
logged_in: auth.RequireLogin,
playlist_id: int,
):
return playlist.name_editor(request=request, playlist_id=playlist_id, logged_in=logged_in)
@router.put("/api/playlist/{playlist_id}/name")
def set_name(
request: Request,
logged_in: auth.RequireLogin,
playlist_id: int,
name: Annotated[str, Form()],
):
_ = playlists_service.update_name(playlist_id=playlist_id, name=name)
return playlist.name(request=request, playlist_id=playlist_id, logged_in=logged_in)
@router.post("/api/playlist/{playlist_id}/set") @router.post("/api/playlist/{playlist_id}/set")
def add_set( def add_set(
request: Request, request: Request,

View File

@@ -0,0 +1,26 @@
<div class="flex flex-row flex-wrap justify-center"
id="playlist-name">
<form>
<input name="name"
placeholder="Nom de la playlist"
value="{{ playlist.name if playlist.name else '' }}"
class="border border-beige focus:outline-none
rounded text-3xl
bg-brown p-2 m-0"
/>
<button title="Desa"
class="text-beige text-3xl mx-1"
hx-put="/api/playlist/{{ playlist.id }}/name"
hx-target="#playlist-name"
hx-swap="outerHTML">
<i class="fa fa-check" aria-hidden="true"></i>
</button>
<button title="Descarta"
class="text-beige text-3xl mx-1"
hx-get="/api/playlist/{{ playlist.id }}/name"
hx-target="#playlist-name"
hx-swap="outerHTML">
<i class="fa fa-times" aria-hidden="true"></i>
</button>
</form>
</div>

View File

@@ -0,0 +1,19 @@
<div class="flex flex-row flex-wrap justify-center"
id="playlist-name">
<h3 class="text-3xl text-center p-4">
{% if playlist.name %}
{{ playlist.name }}
{% else %}
Llista de temes
{% endif %}
</h3>
{% if logged_in %}
<button title="Canvia el nom"
class="text-beige text-2xl mx-2"
hx-get="/api/playlist/{{ playlist.id }}/editor/name"
hx-target="#playlist-name"
hx-swap="outerHTML">
<i class="fa fa-pencil" aria-hidden="true"></i>
</button>
{% endif %}
</div>

View File

@@ -0,0 +1,13 @@
{% include "fragments/menu.html" %}
<div class="flex justify-center">
<div class="m-12 grow max-w-4xl">
<div id="playlist-name">
{% include "fragments/playlist/name.html" %}
</div>
<div class="text-left">
{% set playlist_id = playlist.id %}
{% set playlist = playlist %}
{% include "fragments/playlist/playlist.html" %}
</div>
</div>
</div>

View File

@@ -39,7 +39,11 @@
{% endif %} {% endif %}
{% if logged_in or (session.slowjam and session.slowjam.sets) %} {% if logged_in or (session.slowjam and session.slowjam.sets) %}
<div class="text-left"> <div class="text-left">
<h4 class="py-4 text-xl text-beige mt-2">Slow Jam</h4> <h4 class="py-4 text-xl text-beige mt-2">
<a href="/playlist/{{ session.slowjam.id }}" class="text-beige">
Slow Jam
</a>
</h4>
{% set playlist_id = session.slowjam.id %} {% set playlist_id = session.slowjam.id %}
{% set playlist = session.slowjam %} {% set playlist = session.slowjam %}
{% include "fragments/playlist/playlist.html" %} {% include "fragments/playlist/playlist.html" %}
@@ -47,7 +51,11 @@
{% endif %} {% endif %}
{% if logged_in or (session.setlist and session.setlist.sets) %} {% if logged_in or (session.setlist and session.setlist.sets) %}
<div class="text-left"> <div class="text-left">
<h4 class="py-4 text-xl text-beige mt-2">Temes tocats</h4> <h4 class="py-4 text-xl text-beige mt-2">
<a href="/playlist/{{ session.setlist.id }}" class="text-beige">
Temes tocats
</a>
</h4>
{% set playlist_id = session.setlist.id %} {% set playlist_id = session.setlist.id %}
{% set playlist = session.setlist %} {% set playlist = session.setlist %}
{% include "fragments/playlist/playlist.html" %} {% include "fragments/playlist/playlist.html" %}

View File

@@ -55,3 +55,17 @@ def get_playlist_entries(
cur = con.cursor() cur = con.cursor()
_ = cur.execute(query, data) _ = cur.execute(query, data)
return map(conversion.row_to_playlist_entry, cur.fetchall()) return map(conversion.row_to_playlist_entry, cur.fetchall())
def get_playlist_name(playlist_id: int, con: Connection | None = None) -> str | None:
query = """
SELECT name
FROM playlists
WHERE id = :playlist_id
"""
data = dict(playlist_id=playlist_id)
with get_connection(con) as con:
cur = con.cursor()
_ = cur.execute(query, data)
row = cur.fetchone()
return row[0] if row else None

View File

@@ -103,3 +103,20 @@ def delete_playlist_set(
cur = con.cursor() cur = con.cursor()
_ = cur.execute(query, data) _ = cur.execute(query, data)
return return
def update_playlist_name(
playlist_id: int,
name: str | None,
con: Connection | None = None,
):
query = """
UPDATE playlists SET
name = :name
WHERE id = :id
"""
data = dict(id=playlist_id, name=name)
with get_connection(con) as con:
cur = con.cursor()
_ = cur.execute(query, data)
return

View File

@@ -1,5 +1,7 @@
from fastapi import Request from fastapi import Request
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from folkugat_web.model.pagines import Pages
from folkugat_web.model.playlists import PlaylistType
from folkugat_web.services import playlists as playlists_service from folkugat_web.services import playlists as playlists_service
from folkugat_web.services import sessions as sessions_service from folkugat_web.services import sessions as sessions_service
from folkugat_web.services.temes import query as query_service from folkugat_web.services.temes import query as query_service
@@ -170,3 +172,54 @@ def set_tema(request: Request, logged_in: bool, playlist_id: int, set_id: int, e
"tema_entry": tema_entry, "tema_entry": tema_entry,
} }
) )
def pagina(request: Request, playlist_id: int, logged_in: bool):
playlist = playlists_service.get_playlist(playlist_id=playlist_id)
if not playlist:
from fastapi import HTTPException
raise HTTPException(status_code=404, detail="Could not find playlist")
playlist = playlists_service.add_temes_to_playlist(playlist)
return templates.TemplateResponse(
"fragments/playlist/pagina.html",
{
"request": request,
"logged_in": logged_in,
"playlist_id": playlist_id,
"playlist": playlist,
"Pages": Pages,
"PlaylistType": PlaylistType
}
)
def name(request: Request, playlist_id: int, logged_in: bool):
playlist = playlists_service.get_playlist(playlist_id=playlist_id)
if not playlist:
from fastapi import HTTPException
raise HTTPException(status_code=404, detail="Could not find playlist")
return templates.TemplateResponse(
"fragments/playlist/name.html",
{
"request": request,
"logged_in": logged_in,
"playlist_id": playlist_id,
"playlist": playlist,
}
)
def name_editor(request: Request, playlist_id: int, logged_in: bool):
playlist = playlists_service.get_playlist(playlist_id=playlist_id)
if not playlist:
from fastapi import HTTPException
raise HTTPException(status_code=404, detail="Could not find playlist")
return templates.TemplateResponse(
"fragments/playlist/editor/name.html",
{
"request": request,
"logged_in": logged_in,
"playlist_id": playlist_id,
"playlist": playlist,
}
)

View File

@@ -79,6 +79,7 @@ class Set:
@dataclasses.dataclass @dataclasses.dataclass
class Playlist: class Playlist:
id: int id: int
name: str | None
sets: list[Set] sets: list[Set]
def to_playlist_entries(self) -> Iterator[PlaylistEntry]: def to_playlist_entries(self) -> Iterator[PlaylistEntry]:
@@ -86,11 +87,12 @@ class Playlist:
yield from set_entry.to_playlist_entries(playlist_id=self.id) yield from set_entry.to_playlist_entries(playlist_id=self.id)
@classmethod @classmethod
def from_playlist_entries(cls, playlist_id: int, entries: list[PlaylistEntry]) -> Self: def from_playlist_entries(cls, playlist_id: int, name: str | None, entries: list[PlaylistEntry]) -> Self:
if any(entry.playlist_id != playlist_id for entry in entries): if any(entry.playlist_id != playlist_id for entry in entries):
raise ValueError("All PlaylistEntries must have the same playlist_id") raise ValueError("All PlaylistEntries must have the same playlist_id")
return cls( return cls(
id=playlist_id, id=playlist_id,
name=name,
sets=[ sets=[
Set.from_playlist_entries(set_id, set_entries) Set.from_playlist_entries(set_id, set_entries)
for set_id, set_entries in groupby(entries, key_fn=lambda e: e.set_id, group_fn=list) for set_id, set_entries in groupby(entries, key_fn=lambda e: e.set_id, group_fn=list)

View File

@@ -41,12 +41,20 @@ def add_tema_to_tema_in_set(tema_in_set: playlists.TemaInSet) -> playlists.TemaI
def get_playlist(playlist_id: int, con: Connection | None = None) -> playlists.Playlist: def get_playlist(playlist_id: int, con: Connection | None = None) -> playlists.Playlist:
with get_connection(con) as playlist_con:
playlist_name = query.get_playlist_name(playlist_id=playlist_id, con=playlist_con)
return playlists.Playlist.from_playlist_entries( return playlists.Playlist.from_playlist_entries(
playlist_id=playlist_id, playlist_id=playlist_id,
entries=list(query.get_playlist_entries(playlist_id=playlist_id, con=con)) name=playlist_name,
entries=list(query.get_playlist_entries(playlist_id=playlist_id, con=playlist_con))
) )
def update_name(playlist_id: int, name: str | None) -> playlists.Playlist:
write.update_playlist_name(playlist_id=playlist_id, name=name)
return get_playlist(playlist_id=playlist_id)
def add_set(playlist_id: int, con: Connection | None = None) -> playlists.Set: def add_set(playlist_id: int, con: Connection | None = None) -> playlists.Set:
with get_connection(con) as con: with get_connection(con) as con:
curr_playlist = get_playlist(playlist_id=playlist_id, con=con) curr_playlist = get_playlist(playlist_id=playlist_id, con=con)

View File

@@ -75,6 +75,7 @@ def insert_session(session: model.Session):
def set_session(session: model.Session): def set_session(session: model.Session):
write.update_session(session) write.update_session(session)
_update_session_playlist_names(session)
def delete_session(session_id: int): def delete_session(session_id: int):
@@ -167,21 +168,69 @@ def get_commonly_played_temes(
return session_playlists.get_commonly_played_tunes(tema_id=tema_id) return session_playlists.get_commonly_played_tunes(tema_id=tema_id)
def _get_playlist_names(session: model.Session) -> tuple[str, str]:
date_names = get_date_names(session.date)
setlist_name = f"Sessió del {date_names.day} {date_names.month_name} de {date_names.year}"
slowjam_name = f"Slow Jam del {date_names.day} {date_names.month_name} de {date_names.year}"
return setlist_name, slowjam_name
def _create_session_playlists(session_id: int): def _create_session_playlists(session_id: int):
session = get_session(session_id=session_id)
if not session:
return
setlist_name, slowjam_name = _get_playlist_names(session=session)
setlist_playlist_id = playlists_write.create_playlist(name=setlist_name, con=None)
slowjam_playlist_id = playlists_write.create_playlist(name=slowjam_name, con=None)
with get_connection() as con: with get_connection() as con:
setlist_playlist_id = playlists_write.create_playlist(con=con)
slowjam_playlist_id = playlists_write.create_playlist(con=con)
session_playlists.insert_playlist( session_playlists.insert_playlist(
session_id=session_id, session_id=session_id,
playlist_type=PlaylistType.SESSION_SETLIST, playlist_type=PlaylistType.SESSION_SETLIST,
playlist_id=setlist_playlist_id, playlist_id=setlist_playlist_id,
con=con, con=con
) )
session_playlists.insert_playlist( session_playlists.insert_playlist(
session_id=session_id, session_id=session_id,
playlist_type=PlaylistType.SESSION_SLOWJAM, playlist_type=PlaylistType.SESSION_SLOWJAM,
playlist_id=slowjam_playlist_id, playlist_id=slowjam_playlist_id,
con=con, con=con
)
def _update_session_playlist_names(session: model.Session):
if session.id is None:
return
setlist_name, slowjam_name = _get_playlist_names(session=session)
with get_connection() as con:
setlist_playlist_id = session_playlists.get_playlist_id(
session_id=session.id,
playlist_type=PlaylistType.SESSION_SETLIST,
con=con
)
slowjam_playlist_id = session_playlists.get_playlist_id(
session_id=session.id,
playlist_type=PlaylistType.SESSION_SLOWJAM,
con=con
)
if setlist_playlist_id is not None:
playlists_write.update_playlist_name(
playlist_id=setlist_playlist_id,
name=setlist_name,
con=con
)
if slowjam_playlist_id is not None:
playlists_write.update_playlist_name(
playlist_id=slowjam_playlist_id,
name=slowjam_name,
con=con
) )
@@ -199,22 +248,22 @@ def _delete_session_playlists(session_id: int):
) )
if setlist_playlist_id is not None: if setlist_playlist_id is not None:
session_playlists.delete_playlist(
session_id=session_id,
playlist_type=PlaylistType.SESSION_SETLIST,
con=con,
)
playlists_write.delete_playlist( playlists_write.delete_playlist(
playlist_id=setlist_playlist_id, playlist_id=setlist_playlist_id,
con=con, con=con,
) )
if slowjam_playlist_id is not None:
session_playlists.delete_playlist( session_playlists.delete_playlist(
session_id=session_id, session_id=session_id,
playlist_type=PlaylistType.SESSION_SETLIST, playlist_type=PlaylistType.SESSION_SLOWJAM,
con=con con=con,
) )
if slowjam_playlist_id is not None:
playlists_write.delete_playlist( playlists_write.delete_playlist(
playlist_id=slowjam_playlist_id, playlist_id=slowjam_playlist_id,
con=con, con=con,
) )
session_playlists.delete_playlist(
session_id=session_id,
playlist_type=PlaylistType.SESSION_SLOWJAM,
con=con
)