Initial commit — YT Hub
Self-hosted personal YouTube management app. FastAPI + SQLite backend, React + Vite + Tailwind frontend. Dockerfiles and compose included for Portainer deployment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
81
backend/routers/export.py
Normal file
81
backend/routers/export.py
Normal file
@@ -0,0 +1,81 @@
|
||||
from datetime import datetime
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi.responses import JSONResponse
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import text
|
||||
|
||||
from ..auth_utils import get_current_user
|
||||
from ..database import get_db
|
||||
from ..models import User
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("")
|
||||
def export_data(
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
uid = current_user.id
|
||||
|
||||
watch_history = db.execute(text("""
|
||||
SELECT v.youtube_video_id, v.title, c.name AS channel_name,
|
||||
uv.watch_progress_seconds, uv.last_watched_at
|
||||
FROM user_videos uv
|
||||
JOIN videos v ON v.id = uv.video_id
|
||||
LEFT JOIN channels c ON c.id = v.channel_id
|
||||
WHERE uv.user_id = :uid AND uv.watched = 1
|
||||
ORDER BY uv.last_watched_at DESC
|
||||
"""), {"uid": uid}).mappings().all()
|
||||
|
||||
ratings = db.execute(text("""
|
||||
SELECT v.youtube_video_id, v.title, c.name AS channel_name, uv.rating
|
||||
FROM user_videos uv
|
||||
JOIN videos v ON v.id = uv.video_id
|
||||
LEFT JOIN channels c ON c.id = v.channel_id
|
||||
WHERE uv.user_id = :uid AND uv.rating IS NOT NULL
|
||||
ORDER BY v.title
|
||||
"""), {"uid": uid}).mappings().all()
|
||||
|
||||
liked = db.execute(text("""
|
||||
SELECT v.youtube_video_id, v.title, c.name AS channel_name, uv.liked_at
|
||||
FROM user_videos uv
|
||||
JOIN videos v ON v.id = uv.video_id
|
||||
LEFT JOIN channels c ON c.id = v.channel_id
|
||||
WHERE uv.user_id = :uid AND uv.liked = 1
|
||||
ORDER BY uv.liked_at DESC
|
||||
"""), {"uid": uid}).mappings().all()
|
||||
|
||||
bookmarks = db.execute(text("""
|
||||
SELECT v.youtube_video_id, v.title, c.name AS channel_name,
|
||||
vb.timestamp_seconds, vb.note, vb.created_at
|
||||
FROM video_bookmarks vb
|
||||
JOIN videos v ON v.id = vb.video_id
|
||||
LEFT JOIN channels c ON c.id = v.channel_id
|
||||
WHERE vb.user_id = :uid
|
||||
ORDER BY vb.created_at DESC
|
||||
"""), {"uid": uid}).mappings().all()
|
||||
|
||||
queue = db.execute(text("""
|
||||
SELECT v.youtube_video_id, v.title, c.name AS channel_name
|
||||
FROM user_videos uv
|
||||
JOIN videos v ON v.id = uv.video_id
|
||||
LEFT JOIN channels c ON c.id = v.channel_id
|
||||
WHERE uv.user_id = :uid AND uv.queued = 1
|
||||
ORDER BY v.title
|
||||
"""), {"uid": uid}).mappings().all()
|
||||
|
||||
payload = {
|
||||
"exported_at": datetime.utcnow().isoformat(),
|
||||
"username": current_user.username,
|
||||
"watch_history": [dict(r) for r in watch_history],
|
||||
"ratings": [dict(r) for r in ratings],
|
||||
"liked": [dict(r) for r in liked],
|
||||
"bookmarks": [dict(r) for r in bookmarks],
|
||||
"queue": [dict(r) for r in queue],
|
||||
}
|
||||
|
||||
return JSONResponse(
|
||||
content=payload,
|
||||
headers={"Content-Disposition": f"attachment; filename=ythub-export-{datetime.utcnow().strftime('%Y%m%d')}.json"},
|
||||
)
|
||||
Reference in New Issue
Block a user