videoNote / backend /app /routers /trend_subscription.py
zhoujiaangyao
deploy videomemo backend to HF Space
6cfe55f
Raw
History Blame Contribute Delete
5.29 kB
from __future__ import annotations
from typing import Optional
from fastapi import APIRouter, Query
from pydantic import BaseModel
from app.services.trend_subscription import TrendSubscriptionService
from app.utils.response import ResponseWrapper as R
router = APIRouter()
class CreateSubscriptionRequest(BaseModel):
name: str
keywords: list[str]
platforms: Optional[list[str]] = None
match_mode: str = "any"
push_enabled: bool = False
push_channel_ids: Optional[list[int]] = None
class UpdateSubscriptionRequest(BaseModel):
name: Optional[str] = None
keywords: Optional[list[str]] = None
platforms: Optional[list[str]] = None
match_mode: Optional[str] = None
enabled: Optional[bool] = None
push_enabled: Optional[bool] = None
push_channel_ids: Optional[list[int]] = None
# โ”€โ”€โ”€ Collection-level routes (no path param) MUST come before parameterized routes โ”€โ”€
@router.get("/trend_subscriptions")
def get_trend_subscriptions():
return R.success(TrendSubscriptionService().list_subscriptions())
@router.post("/trend_subscriptions")
def create_trend_subscription(data: CreateSubscriptionRequest):
return R.success(
TrendSubscriptionService().create_subscription(
name=data.name,
keywords=data.keywords,
platforms=data.platforms,
match_mode=data.match_mode,
push_enabled=data.push_enabled,
push_channel_ids=data.push_channel_ids,
)
)
@router.post("/trend_subscriptions/match_all")
def match_all_subscriptions():
from app.services.scheduler import get_scheduler
summary = get_scheduler().run_now()
return R.success(summary)
@router.get("/trend_matches")
def get_all_matches(
limit: int = Query(100, ge=1, le=500),
unread_only: bool = Query(False),
):
return R.success(
TrendSubscriptionService().list_matches(subscription_id=None, limit=limit, unread_only=unread_only)
)
# โ”€โ”€โ”€ Parameterized routes (with {subscription_id}) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
@router.get("/trend_subscriptions/{subscription_id}")
def get_trend_subscription(subscription_id: int):
result = TrendSubscriptionService().get_subscription(subscription_id)
if result is None:
return R.error(msg=f"่ฎข้˜… {subscription_id} ไธๅญ˜ๅœจ", code=404)
return R.success(result)
@router.put("/trend_subscriptions/{subscription_id}")
def update_trend_subscription(subscription_id: int, data: UpdateSubscriptionRequest):
result = TrendSubscriptionService().update_subscription(
subscription_id=subscription_id,
name=data.name,
keywords=data.keywords,
platforms=data.platforms,
match_mode=data.match_mode,
enabled=data.enabled,
push_enabled=data.push_enabled,
push_channel_ids=data.push_channel_ids,
)
if result is None:
return R.error(msg=f"่ฎข้˜… {subscription_id} ไธๅญ˜ๅœจ", code=404)
return R.success(result)
@router.delete("/trend_subscriptions/{subscription_id}")
def delete_trend_subscription(subscription_id: int):
ok = TrendSubscriptionService().delete_subscription(subscription_id)
if not ok:
return R.error(msg=f"่ฎข้˜… {subscription_id} ไธๅญ˜ๅœจ", code=404)
return R.success(msg="ๅทฒๅˆ ้™ค")
@router.post("/trend_subscriptions/{subscription_id}/match")
def match_trend_subscription(subscription_id: int):
try:
result = TrendSubscriptionService().match_subscription(subscription_id)
# Also send push notifications if enabled and new matches found
if result["new_matches"] > 0:
try:
from app.services.notification import NotificationService
sub = TrendSubscriptionService().get_subscription(subscription_id)
if sub and sub.get("push_enabled") and sub.get("push_channel_ids"):
match_titles = [m["title"] for m in result["matches"]]
title = f"๐Ÿ”ฅ VideoMemo: {sub['name']} โ€” {len(match_titles)} ๆกๆ–ฐ็ƒญ็‚น"
body = "\n\n".join(f"โ€ข {t}" for t in match_titles[:10])
if len(match_titles) > 10:
body += f"\n\nโ€ฆๅ…ฑ {len(match_titles)} ๆก"
NotificationService().send_batch(sub["push_channel_ids"], title, body)
result["push_sent"] = True
except Exception:
result["push_sent"] = False
return R.success(result)
except ValueError as exc:
return R.error(msg=str(exc), code=404)
@router.get("/trend_subscriptions/{subscription_id}/matches")
def get_subscription_matches(
subscription_id: int,
limit: int = Query(100, ge=1, le=500),
unread_only: bool = Query(False),
):
return R.success(
TrendSubscriptionService().list_matches(
subscription_id=subscription_id,
limit=limit,
unread_only=unread_only,
)
)
@router.post("/trend_subscriptions/{subscription_id}/matches/read-all")
def mark_subscription_matches_read(subscription_id: int):
count = TrendSubscriptionService().mark_all_read(subscription_id)
return R.success({"marked_read": count})