Files

180 lines
6.1 KiB
Python
Executable File

#!/usr/bin/env python3
import asyncio
import httpx # Switched from requests to prevent async loop freezing
from twitchAPI.helper import first
from twitchAPI.type import VideoType
import package.twitch.config as config
from package.config import DB as DB
from package.database.database import TwitchVideo
GAME_CACHE = {} # Local cache dictionary to store game_id -> game_name mapping
async def get_game_id_by_name(game_name: str) -> str:
if config.SECRETS is None:
await config.get_twitch()
# Query the 'get_games' endpoint using the names parameter
# The API expects a list, even for a single game name
async for game in config.TWITCH.get_games(names=[game_name]):
print(f"Game Name: {game.name}")
print(f"Game ID: {game.id}")
print(f"IGDB ID: {game.igdb_id}")
return game.id
print(f"No game found with the exact name: '{game_name}'")
return None
async def get_game_name_by_id(game_id: str) -> str:
"""Helper function to fetch game names and cache them locally."""
if not game_id:
return "Unknown / No Category"
if game_id in GAME_CACHE:
return GAME_CACHE[game_id]
try:
game_generator = config.TWITCH.get_games(game_ids=[game_id])
game = await first(game_generator)
if game:
GAME_CACHE[game_id] = game.name
return game.name
except Exception:
pass
return "Unknown Game"
async def get_vod_game_name(vod_id: str) -> tuple:
"""Asynchronously query Twitch GQL endpoint for VOD game metadata."""
game_id = "0"
game_name = "Unknown Game"
url = "https://gql.twitch.tv/gql"
headers = {
"Client-ID": "kimne78kx3ncx6brgo4mv6wki5h1ko",
"Content-Type": "application/json"
}
payload = [{
"operationName": "VideoMetadata",
"variables": {
"channelLogin": "",
"videoID": str(vod_id)
},
"extensions": {
"persistedQuery": {
"version": 1,
"sha256Hash": "45111672eea2e507f8ba44d101a61862f9c56b11dee09a15634cb75cb9b9084d"
}
}
}]
# Using httpx async client to prevent blocking the asyncio event loop
async with httpx.AsyncClient() as client:
try:
response = await client.post(url, headers=headers, json=payload)
if response.status_code == 200:
data = response.json()
video_info = data[0].get('data', {}).get('video')
if video_info and video_info.get('game'):
game_id = str(video_info['game']['id'])
game_name = video_info['game']['displayName']
print(f"GQL Found: {game_name} (ID: {game_id})")
else:
print(f"No game information found in GQL for VOD {vod_id}.")
except Exception as e:
print(f"Error fetching GQL metadata for VOD {vod_id}: {e}")
return game_id, game_name
async def get_streamer_vods() -> list:
await config.get_twitch()
print(f"Starting VOD extraction for {config.USER.display_name}...")
vod_generator = config.TWITCH.get_videos(user_id=config.USER.id, first=100, video_type=VideoType.ALL)
all_vods = []
async for v in vod_generator:
# Resolving game category safely without freezing the event loop
game_id, game_name = await get_vod_game_name(v.id)
# Safely convert game_id to integer if possible, otherwise default to 0
try:
clean_game_id = game_id
except ValueError:
clean_game_id = 0
vod_data = TwitchVideo()
vod_data.id = v.id
vod_data.title = v.title
vod_data.created_at = str(v.published_at)
vod_data.view_count = int(v.view_count) if v.view_count else 0
vod_data.duration = v.duration
vod_data.url = v.url
vod_data.thumbnail_url = v.thumbnail_url
vod_data.game_id = clean_game_id
vod_data.game_name = game_name
vod_data.stream_id = str(v.stream_id) if v.stream_id else "0"
vod_data.creator_name = config.CHANNEL_NAME
vod_data.clip_is = False
all_vods.append(vod_data)
print(f"Collected VOD: {v.title} | Category: {game_name} ({v.duration})")
print(f"\nFinished extracting VODs. Total gathered: {len(all_vods)}")
return all_vods
async def get_streamer_clips() -> list:
await config.get_twitch()
print(f"Starting clip extraction for {config.USER.display_name}...")
clip_generator = config.TWITCH.get_clips(broadcaster_id=config.USER.id, first=100)
all_clips = []
async for c in clip_generator:
game_name = await get_game_name_by_id(c.game_id)
clip_data = TwitchVideo()
clip_data.id = c.id
clip_data.title = c.title
clip_data.created_at = str(c.created_at)
clip_data.view_count = int(c.view_count) if c.view_count else 0
clip_data.duration = c.duration
clip_data.url = c.url
clip_data.thumbnail_url = c.thumbnail_url
clip_data.game_id = c.game_id
clip_data.game_name = game_name
clip_data.stream_id = "0"
clip_data.creator_name = c.creator_name
clip_data.clip_is = True
all_clips.append(clip_data)
print(f"Collected clip: {c.title} | Category: {game_name} ({c.view_count} views)")
print(f"\nFinished extracting clips. Total gathered: {len(all_clips)}")
return all_clips
async def video_info():
print("--- Script Started ---")
vods_list = await get_streamer_vods()
for v in vods_list:
DB.insert(v)
if vods_list:
print("====================================================")
print(f"Recent VOD: '{vods_list[0].title}'")
print("====================================================")
clips_list = await get_streamer_clips()
for v in clips_list:
DB.insert(v)
if clips_list:
print("====================================================")
print(f"Recent VOD: '{clips_list[0].title}'")
print("====================================================")
if __name__ == "__main__":
asyncio.run(video_info())