webclient / app /routes /youtube.py
ariansyahdedy's picture
fix keep comment
27e17be
from fastapi import APIRouter, Request, HTTPException, Depends
from fastapi import FastAPI, Request, Form, File, UploadFile, HTTPException, Depends
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from typing import List, Dict, Optional, Set, Tuple
from app.services.gambling_filter import GamblingFilter
from app.models import User, UserDatabase
from app.config import templates, user_moderator, filter_instance
from app.services.youtube_moderator import keep_comment
import googleapiclient.discovery
import logging
# Configure logging at the top of the file
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)
router = APIRouter()
def get_credentials_from_session(session) -> Credentials:
"""Utility to build a Credentials object from stored session data."""
creds_data = session.get("credentials")
if not creds_data:
return None
return Credentials(
token=creds_data["token"],
refresh_token=creds_data["refresh_token"],
token_uri=creds_data["token_uri"],
client_id=creds_data["client_id"],
client_secret=creds_data["client_secret"],
scopes=creds_data["scopes"]
)
def get_current_user_from_cookie(request: Request):
token = request.cookies.get("token")
if not token:
raise HTTPException(status_code=401, detail="Not authenticated")
user = UserDatabase.get_user(token)
if not user:
raise HTTPException(status_code=401, detail="Invalid authentication credentials")
return user
@router.get("/list-channels")
async def list_channels(request: Request):
"""Return the user’s list of YouTube channels."""
creds = get_credentials_from_session(request.session)
if not creds or not creds.valid:
raise HTTPException(status_code=401, detail="Unauthorized. Please /login first.")
youtube = build("youtube", "v3", credentials=creds)
response = youtube.channels().list(
part="id,snippet",
mine=True
).execute()
channels = []
for item in response.get("items", []):
channels.append({
"channelId": item["id"],
"title": item["snippet"]["title"]
})
return {"channels": channels}
@router.get("/list-videos")
async def list_videos(request: Request, channel_id: str):
"""List videos for the specified channel."""
creds = get_credentials_from_session(request.session)
if not creds or not creds.valid:
raise HTTPException(status_code=401, detail="Unauthorized. Please /login first.")
youtube = build("youtube", "v3", credentials=creds)
# Example: listing videos from a channel’s "uploads" playlist
# 1) Retrieve the uploads playlist from channel
channel_response = youtube.channels().list(
part="contentDetails",
id=channel_id
).execute()
uploads_playlist_id = channel_response["items"][0]["contentDetails"]["relatedPlaylists"]["uploads"]
# 2) Retrieve items from the uploads playlist
playlist_items_response = youtube.playlistItems().list(
part="snippet",
playlistId=uploads_playlist_id,
maxResults=10
).execute()
videos = []
for item in playlist_items_response.get("items", []):
snippet = item["snippet"]
videos.append({
"videoId": snippet["resourceId"]["videoId"],
"title": snippet["title"]
})
return {"videos": videos}
@router.post("/api/comments/keep/{comment_id}")
async def api_keep_comment(
request: Request,
comment_id: str,
video_id: str
):
try:
logging.debug(f"Received keep request for comment_id: {comment_id}, video_id: {video_id}")
# Get current user's credentials
current_user = get_current_user_from_cookie(request)
logging.debug(f"Current user: {current_user.username}")
user_creds = Credentials.from_authorized_user_info(current_user.youtube_credentials)
# Create a moderator instance with user credentials
user_moderator.youtube_service = googleapiclient.discovery.build(
"youtube", "v3",
credentials=user_creds
)
logging.debug("Setting moderation status to 'published' on YouTube...")
# Mark comment as approved on YouTube
result = user_moderator.youtube_service.comments().setModerationStatus(
id=comment_id,
moderationStatus="published" # This marks the comment as approved
).execute()
logging.debug(f"YouTube API response: {result}")
# Add the comment ID to the manual overrides so it won't be reflagged
keep_comment(comment_id, video_id) # Ensure this function is defined and working
logging.debug("Manual override saved for comment.")
return {"success": True, "message": "Comment kept successfully"}
except Exception as e:
logging.error(f"Error keeping comment: {e}", exc_info=True)
return {"success": False, "error": str(e)}
@router.get("/videos", response_class=HTMLResponse)
async def list_videos(request: Request, current_user: User = Depends(get_current_user_from_cookie)):
# Reconstruct the credentials from the stored dictionary
user_creds = Credentials.from_authorized_user_info(current_user.youtube_credentials)
user_moderator.youtube_service = googleapiclient.discovery.build(
"youtube", "v3", credentials=user_creds
)
videos = user_moderator.get_channel_videos()
return templates.TemplateResponse("videos.html", {
"request": request,
"current_user": current_user,
"videos": videos
})
@router.get("/refresh_comments/{video_id}")
async def refresh_video_comments(
request: Request,
video_id: str,
threshold: float = 0.55
):
"""
Refresh comments for a specific video, reapplying moderation.
:param request: Request object
:param video_id: ID of the video to refresh comments for
:param threshold: Gambling confidence threshold
:return: Rendered template with updated comments
"""
# Get current user's credentials
current_user = get_current_user_from_cookie(request)
if not current_user:
return RedirectResponse(url="/login", status_code=303)
try:
# Recreate moderator with current user's credentials
user_creds = Credentials.from_authorized_user_info(current_user.youtube_credentials)
user_moderator.youtube_service = googleapiclient.discovery.build(
"youtube", "v3",
credentials=user_creds
)
# Moderate comments for the video
result = user_moderator.moderate_video_comments(video_id, threshold)
# Fetch video details to pass to template
youtube_service = googleapiclient.discovery.build(
"youtube", "v3",
credentials=user_creds
)
video_request = youtube_service.videos().list(
part="snippet",
id=video_id
)
video_response = video_request.execute()
video_info = video_response['items'][0]['snippet'] if video_response['items'] else {}
return templates.TemplateResponse("video_comments.html", {
"request": request,
"video": {
"id": video_id,
"title": video_info.get('title', 'Unknown Video')
},
"safe_comments": result.get('safe_comments', []),
"flagged_comments": result.get('gambling_comments', []),
"total_comments": result.get('total_comments', 0)
})
except Exception as e:
logging.error(f"Error refreshing comments: {e}")
return templates.TemplateResponse("error.html", {
"request": request,
"error": f"Failed to refresh comments: {str(e)}"
})
@router.post("/moderate_video")
async def moderate_video(request: Request, video_id: str = Form(...), threshold: float = Form(0.55)):
if not user_moderator.youtube_service:
result = {"error": "YouTube service not authenticated. Please authenticate first."}
else:
result = user_moderator.moderate_video_comments(video_id, threshold)
return templates.TemplateResponse("index.html", {
"request": request,
"result": result,
"video_id": video_id,
"rules": {
"platform": sorted(list(filter_instance._platform_names)),
"gambling_term": sorted(list(filter_instance._gambling_terms)),
"safe_indicator": sorted(list(filter_instance._safe_indicators)),
"gambling_context": sorted(list(filter_instance._gambling_contexts)),
"ambiguous_term": sorted(list(filter_instance._ambiguous_terms))
}
})
@router.delete("/api/comments/{comment_id}")
async def api_delete_comment(
request: Request,
comment_id: str,
video_id: str
):
current_user = get_current_user_from_cookie(request)
user_creds = Credentials.from_authorized_user_info(current_user.youtube_credentials)
user_moderator.youtube_service = googleapiclient.discovery.build(
"youtube", "v3",
credentials=user_creds
)
success = user_moderator.delete_comment(comment_id)
return {"success": success}
@router.get("/video/{video_id}", response_class=HTMLResponse)
async def moderate_video_comments(
request: Request,
video_id: str,
current_user: User = Depends(get_current_user_from_cookie)
):
# Reconstruct the Credentials object from the stored dict
user_creds = Credentials.from_authorized_user_info(current_user.youtube_credentials)
user_moderator.youtube_service = googleapiclient.discovery.build(
"youtube", "v3",
credentials=user_creds
)
moderation_results = user_moderator.moderate_video_comments(video_id)
return templates.TemplateResponse("video_comments.html", {
"request": request,
"current_user": current_user,
"video": {"id": video_id, "title": "Sample Video Title"}, # Optionally fetch actual title
"safe_comments": moderation_results.get('safe_comments', []),
"flagged_comments": moderation_results.get('gambling_comments', [])
})