Add playlist export and SEO meta tags
Add text/CSV export endpoints for playlists and saved recommendations. Add export buttons to PlaylistDetail and Recommendations pages. Add Open Graph and Twitter meta tags to index.html for better SEO.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from fastapi.responses import PlainTextResponse
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
@@ -49,6 +50,39 @@ async def get_playlist(
|
||||
return playlist
|
||||
|
||||
|
||||
@router.get("/{playlist_id}/export")
|
||||
async def export_playlist(
|
||||
playlist_id: int,
|
||||
format: str = Query("text", pattern="^(text|csv)$"),
|
||||
user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
result = await db.execute(
|
||||
select(Playlist).options(selectinload(Playlist.tracks))
|
||||
.where(Playlist.id == playlist_id, Playlist.user_id == user.id)
|
||||
)
|
||||
playlist = result.scalar_one_or_none()
|
||||
if not playlist:
|
||||
raise HTTPException(status_code=404, detail="Playlist not found")
|
||||
|
||||
if format == "csv":
|
||||
lines = ["Title,Artist,Album"]
|
||||
for t in playlist.tracks:
|
||||
# Escape commas in CSV
|
||||
title = f'"{t.title}"' if ',' in t.title else t.title
|
||||
artist = f'"{t.artist}"' if ',' in t.artist else t.artist
|
||||
album = f'"{t.album}"' if t.album and ',' in t.album else (t.album or '')
|
||||
lines.append(f"{title},{artist},{album}")
|
||||
return PlainTextResponse("\n".join(lines), media_type="text/csv",
|
||||
headers={"Content-Disposition": f'attachment; filename="{playlist.name}.csv"'})
|
||||
else:
|
||||
lines = [f"{playlist.name}", "=" * len(playlist.name), ""]
|
||||
for i, t in enumerate(playlist.tracks, 1):
|
||||
lines.append(f"{i}. {t.artist} - {t.title}")
|
||||
return PlainTextResponse("\n".join(lines), media_type="text/plain",
|
||||
headers={"Content-Disposition": f'attachment; filename="{playlist.name}.txt"'})
|
||||
|
||||
|
||||
@router.delete("/{playlist_id}")
|
||||
async def delete_playlist(
|
||||
playlist_id: int,
|
||||
|
||||
Reference in New Issue
Block a user