- New split layout: waveform/transport/queue left, comment panel right
- Avatar pins above waveform positioned by timestamp with hover tooltips
- Transport bar: speed selector, ±30s skip, 46px amber play/pause, volume
- Comment compose: live timestamp pill, suggestion/issue/keeper tag buttons
- Comment list: per-author colour avatars, amber timestamp seek chips,
playhead-proximity highlight, delete only shown on own comments
- Queue panel showing other songs in the same session
- Waveform colours updated to amber/dim palette (104px height)
- Add GET /songs/{song_id} endpoint for song metadata
- Add tag field to SongComment (model, schema, router, migration 0005)
- Fix migration 0005 down_revision to use short ID "0004"
- Fix ESLint no-unused-expressions in keyboard shortcut handler
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
41 lines
1.1 KiB
Python
41 lines
1.1 KiB
Python
from __future__ import annotations
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
|
|
from pydantic import BaseModel, ConfigDict
|
|
|
|
|
|
class SongCommentCreate(BaseModel):
|
|
body: str
|
|
timestamp: float | None = None
|
|
tag: str | None = None
|
|
|
|
|
|
class SongCommentRead(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: uuid.UUID
|
|
song_id: uuid.UUID
|
|
body: str
|
|
author_id: uuid.UUID
|
|
author_name: str
|
|
author_avatar_url: str | None
|
|
timestamp: float | None
|
|
tag: str | None
|
|
created_at: datetime
|
|
|
|
@classmethod
|
|
def from_model(cls, c: object) -> "SongCommentRead":
|
|
return cls(
|
|
id=getattr(c, "id"),
|
|
song_id=getattr(c, "song_id"),
|
|
body=getattr(c, "body"),
|
|
author_id=getattr(c, "author_id"),
|
|
author_name=getattr(getattr(c, "author"), "display_name"),
|
|
author_avatar_url=getattr(getattr(c, "author"), "avatar_url"),
|
|
timestamp=getattr(c, "timestamp"),
|
|
tag=getattr(c, "tag", None),
|
|
created_at=getattr(c, "created_at"),
|
|
)
|