fix: exempt now-playing endpoints from rate limiting (#460)

the now-playing endpoints were hitting the global 100/minute rate limit
when multiple users/tabs were active simultaneously. since these endpoints
are already throttled client-side (10-second intervals, 1-second debounce,
5-second progress buckets), server-side rate limiting is unnecessary.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

authored by zzstoatzz.io Claude and committed by GitHub d840a3dd 335aa207

Changed files
+8
backend
src
backend
+8
backend/src/backend/api/now_playing.py
··· 1 1 """now playing API endpoints for external scrobbler integrations. 2 2 3 3 exposes real-time playback state for services like teal.fm/Piper. 4 + 5 + note: these endpoints are exempt from rate limiting because they're 6 + already throttled client-side (10-second intervals, 1-second debounce). 4 7 """ 5 8 6 9 from typing import Annotated ··· 13 16 from backend._internal import Session, now_playing_service, require_auth 14 17 from backend.config import settings 15 18 from backend.models import Artist, get_db 19 + from backend.utilities.rate_limit import limiter 16 20 17 21 router = APIRouter(prefix="/now-playing", tags=["now-playing"]) 18 22 ··· 59 63 60 64 61 65 @router.post("/") 66 + @limiter.exempt 62 67 async def update_now_playing( 63 68 update: NowPlayingUpdate, 64 69 session: Session = Depends(require_auth), ··· 88 93 89 94 90 95 @router.delete("/") 96 + @limiter.exempt 91 97 async def clear_now_playing( 92 98 session: Session = Depends(require_auth), 93 99 ) -> dict: ··· 100 106 101 107 102 108 @router.get("/by-handle/{handle}") 109 + @limiter.exempt 103 110 async def get_now_playing_by_handle( 104 111 handle: str, 105 112 response: Response, ··· 151 158 152 159 153 160 @router.get("/by-did/{did}") 161 + @limiter.exempt 154 162 async def get_now_playing_by_did( 155 163 did: str, 156 164 response: Response,