151 lines
6.3 KiB
Python
151 lines
6.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Client script to get info.json from the Thrift service.
|
|
|
|
Usage:
|
|
python get_info_json_client.py [URL] --host [HOST] --port [PORT] [options]
|
|
|
|
Options:
|
|
--host HOST Thrift server host
|
|
--port PORT Thrift server port
|
|
--account-id ID Account ID to use
|
|
--output FILE Output file path
|
|
--verbose Enable verbose output
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
import logging
|
|
from typing import Dict, Any, Optional
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
)
|
|
logger = logging.getLogger('info_json_client')
|
|
|
|
# Import Thrift modules
|
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
from thrift.transport import TTransport
|
|
from pangramia.yt.common.ttypes import TokenUpdateMode
|
|
from pangramia.yt.exceptions.ttypes import PBServiceException, PBUserException
|
|
from yt_ops_services.client_utils import get_thrift_client
|
|
|
|
def parse_args():
|
|
"""Parse command line arguments"""
|
|
parser = argparse.ArgumentParser(description='Get info.json from Thrift service')
|
|
parser.add_argument('url', help='YouTube URL or video ID')
|
|
parser.add_argument('--host', default='127.0.0.1', help="Thrift server host. Using 127.0.0.1 avoids harmless connection errors when the local Envoy proxy only listens on IPv4.")
|
|
parser.add_argument('--port', type=int, default=9080, help='Thrift server port')
|
|
parser.add_argument('--profile', default='default_profile', help='The profile name (accountId) to use for the request.')
|
|
parser.add_argument('--client', help='Specific client to use (e.g., web, ios, android). Overrides server default.')
|
|
parser.add_argument('--output', help='Output file path for the info.json. If not provided, prints to stdout.')
|
|
parser.add_argument('--machine-id', help='Identifier for the client machine. Defaults to hostname.')
|
|
parser.add_argument('--verbose', action='store_true', help='Enable verbose output')
|
|
return parser.parse_args()
|
|
|
|
def main():
|
|
"""Main entry point"""
|
|
args = parse_args()
|
|
|
|
# Set log level
|
|
if args.verbose:
|
|
logger.setLevel(logging.DEBUG)
|
|
|
|
transport = None
|
|
try:
|
|
# Create Thrift client
|
|
client, transport = get_thrift_client(args.host, args.port)
|
|
|
|
# Get token data, which includes the info.json
|
|
logger.info(f"Requesting info.json for URL '{args.url}' using profile '{args.profile}'")
|
|
|
|
# Prepare arguments for the Thrift call
|
|
machine_id = args.machine_id
|
|
if not machine_id:
|
|
import socket
|
|
machine_id = socket.gethostname()
|
|
logger.info(f"No machine ID provided, using hostname: {machine_id}")
|
|
|
|
thrift_args = {
|
|
'accountId': args.profile,
|
|
'updateType': TokenUpdateMode.AUTO,
|
|
'url': args.url,
|
|
'clients': args.client,
|
|
'machineId': machine_id
|
|
}
|
|
if args.client:
|
|
logger.info(f"Requesting to use specific client: {args.client}")
|
|
else:
|
|
logger.info("No specific client requested, server will use its default.")
|
|
|
|
token_data = client.getOrRefreshToken(**thrift_args)
|
|
|
|
if not token_data or not hasattr(token_data, 'infoJson') or not token_data.infoJson:
|
|
logger.error("Server did not return valid info.json data.")
|
|
print("Error: Server did not return valid info.json data.", file=sys.stderr)
|
|
return 1
|
|
|
|
info_json_str = token_data.infoJson
|
|
|
|
# Check if the returned info.json is an error report
|
|
try:
|
|
info_data = json.loads(info_json_str)
|
|
if isinstance(info_data, dict) and 'error' in info_data:
|
|
error_code = info_data.get('errorCode', 'N/A')
|
|
error_message = info_data.get('message', info_data.get('error', 'Unknown error'))
|
|
logger.error(f"Server returned an error in info.json (Code: {error_code}): {error_message}")
|
|
print(f"Error from server (Code: {error_code}): {error_message}", file=sys.stderr)
|
|
# Optionally print the full error JSON
|
|
if args.verbose:
|
|
print(json.dumps(info_data, indent=2), file=sys.stderr)
|
|
return 1
|
|
except json.JSONDecodeError:
|
|
logger.error(f"Failed to parse info.json from server: {info_json_str[:200]}...")
|
|
print("Error: Failed to parse the info.json response from the server.", file=sys.stderr)
|
|
return 1
|
|
|
|
logger.info(f"Successfully retrieved info.json ({len(info_json_str)} bytes)")
|
|
|
|
# Write to output file if specified, otherwise print to stdout
|
|
if args.output:
|
|
try:
|
|
with open(args.output, 'w', encoding='utf-8') as f:
|
|
# Pretty-print the JSON to the file
|
|
json.dump(info_data, f, indent=2)
|
|
logger.info(f"Wrote info.json to {args.output}")
|
|
print(f"Successfully saved info.json to {args.output}")
|
|
except IOError as e:
|
|
logger.error(f"Failed to write to output file {args.output}: {e}")
|
|
print(f"Error: Failed to write to output file {args.output}: {e}", file=sys.stderr)
|
|
return 1
|
|
else:
|
|
# Pretty-print the JSON to stdout
|
|
print(json.dumps(info_data, indent=2))
|
|
|
|
return 0
|
|
except (PBServiceException, PBUserException) as e:
|
|
logger.error(f"A Thrift error occurred: {e.message}", exc_info=args.verbose)
|
|
print(f"Error: {e.message}", file=sys.stderr)
|
|
if hasattr(e, 'context') and e.context:
|
|
print(f"Context: {e.context}", file=sys.stderr)
|
|
return 1
|
|
except TTransport.TTransportException as e:
|
|
logger.error(f"Connection to server failed: {e}", exc_info=args.verbose)
|
|
print(f"Error: Connection to server at {args.host}:{args.port} failed.", file=sys.stderr)
|
|
return 1
|
|
except Exception as e:
|
|
logger.exception(f"An unexpected error occurred: {e}")
|
|
print(f"An unexpected error occurred: {e}", file=sys.stderr)
|
|
return 1
|
|
finally:
|
|
if transport and transport.isOpen():
|
|
transport.close()
|
|
logger.info("Thrift connection closed.")
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|