#!/usr/bin/env python3 """ Jamie YouTube Channel Status Check Fetches current status of all Jamie clinic videos. """ import os import sys from pathlib import Path from dotenv import load_dotenv from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request from googleapiclient.discovery import build import pickle # Load environment variables load_dotenv(Path(__file__).parent / '.env') SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl'] TOKEN_FILE = Path(__file__).parent / 'jamie_youtube_token.pickle' CLIENT_SECRETS_FILE = Path(os.getenv('GOOGLE_CLIENT_SECRETS_FILE', '/Users/ourdigital/.config/gcloud/keys/jamie-youtube-manager.json')) # Jamie video IDs JAMIE_VIDEOS = [ "P-ovr-aaD1E", # 병원 소개 "qZQwAX6Onj0", # 눈 성형 "_m6H4F_nLYU", # 퀵 매몰법 "CBAGAY_b0HU", # 하이브리드 쌍꺼풀 "TxFajDli1QQ", # 안검하수 눈매교정술 "Ey5eR4dCi_I", # 눈밑지방 재배치 "ffUmrE-Ckt0", # 듀얼 트임 수술 "1MA0OJJYcQk", # 눈썹밑 피부절개술 "UoeOnT1j41Y", # 눈 재수술 "a7FcFMiGiTs", # 이마 성형 "lIq816rp4js", # 내시경 이마 거상술 "EwgtJUH46dc", # 내시경 눈썹 거상술 "gfbJlqlAIfg", # 동안 성형 "lRtAatuhcC4", # 동안 시술 "7saghBp2a_A", # 앞광대 리프팅 "Mq6zcx_8owY", # 스마스 리프팅 "_bCJDZx2L2I", # 자가 지방이식 "kXbP1T6ICxY", # 하이푸 리프팅 ] def get_authenticated_service(): """Authenticate and return YouTube API service.""" creds = None if TOKEN_FILE.exists(): with open(TOKEN_FILE, 'rb') as token: creds = pickle.load(token) if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES) creds = flow.run_local_server(port=8080) with open(TOKEN_FILE, 'wb') as token: pickle.dump(creds, token) return build('youtube', 'v3', credentials=creds) def get_channel_info(youtube, channel_id): """Get channel information.""" response = youtube.channels().list( part="snippet,statistics,brandingSettings", id=channel_id ).execute() if response.get('items'): return response['items'][0] return None def get_videos_status(youtube, video_ids): """Get status of multiple videos.""" # YouTube API allows max 50 videos per request videos = [] for i in range(0, len(video_ids), 50): batch = video_ids[i:i+50] response = youtube.videos().list( part="snippet,status,statistics,contentDetails", id=",".join(batch) ).execute() videos.extend(response.get('items', [])) return videos def format_duration(duration): """Convert ISO 8601 duration to readable format.""" import re match = re.match(r'PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?', duration) if match: hours, minutes, seconds = match.groups() parts = [] if hours: parts.append(f"{hours}h") if minutes: parts.append(f"{minutes}m") if seconds: parts.append(f"{seconds}s") return " ".join(parts) if parts else "0s" return duration def main(): print("=" * 70) print("Jamie Clinic (제이미성형외과) - YouTube Channel Status") print("=" * 70) youtube = get_authenticated_service() # Get all Jamie videos videos = get_videos_status(youtube, JAMIE_VIDEOS) if not videos: print("\n❌ No videos found or accessible") return # Get channel info from first video channel_id = videos[0]['snippet']['channelId'] channel = get_channel_info(youtube, channel_id) if channel: stats = channel.get('statistics', {}) print(f"\n📺 Channel: {channel['snippet']['title']}") print(f" ID: {channel_id}") print(f" Subscribers: {stats.get('subscriberCount', 'Hidden')}") print(f" Total Views: {stats.get('viewCount', '0')}") print(f" Total Videos: {stats.get('videoCount', '0')}") print("\n" + "-" * 70) print(f"{'No':<3} {'Title':<40} {'Status':<10} {'Views':<8} {'Duration'}") print("-" * 70) total_views = 0 status_counts = {'public': 0, 'unlisted': 0, 'private': 0} for i, video in enumerate(videos): snippet = video['snippet'] status = video['status']['privacyStatus'] stats = video.get('statistics', {}) views = int(stats.get('viewCount', 0)) duration = format_duration(video['contentDetails']['duration']) title = snippet['title'][:38] + '..' if len(snippet['title']) > 40 else snippet['title'] status_icon = {'public': '🟢', 'unlisted': '🟡', 'private': '🔴'}.get(status, '⚪') print(f"{i+1:<3} {title:<40} {status_icon} {status:<8} {views:<8} {duration}") total_views += views status_counts[status] = status_counts.get(status, 0) + 1 print("-" * 70) print(f"\n📊 Summary") print(f" Total Videos: {len(videos)}") print(f" Total Views: {total_views:,}") print(f" Public: {status_counts.get('public', 0)} | Unlisted: {status_counts.get('unlisted', 0)} | Private: {status_counts.get('private', 0)}") if __name__ == "__main__": main()