#!/usr/bin/env python3 """ Tool to check format URLs in an info.json for expiration. """ import argparse import json import sys import logging import time from datetime import datetime, timezone from urllib.parse import urlparse, parse_qs from .stress_policy import utils as sp_utils logger = logging.getLogger('check_expiry_tool') def add_check_expiry_parser(subparsers): """Add the parser for the 'check-expiry' command.""" parser = subparsers.add_parser( 'check-expiry', description='Check format URLs in an info.json for expiration.', formatter_class=argparse.RawTextHelpFormatter, help='Check if format URLs in an info.json are expired.', epilog=""" Exit Codes: 0: All checked URLs are valid. 1: At least one URL is expired or will expire within the specified time-shift. 3: No URLs with expiration info were found to check. 4: Input error (e.g., invalid JSON). """ ) parser.add_argument( '--load-info-json', type=argparse.FileType('r', encoding='utf-8'), default=sys.stdin, help="Path to the info.json file. Reads from stdin if not provided." ) parser.add_argument( '--time-shift-minutes', type=int, default=0, help='Time shift in minutes. URLs expiring within this time are also reported as expired. Default: 0.' ) parser.add_argument( '--check-all-formats', action='store_true', help='Check all available formats. By default, only the first format with an expiry timestamp is checked.' ) parser.add_argument('--verbose', action='store_true', help='Enable verbose logging.') return parser def main_check_expiry(args): """Main logic for the 'check-expiry' command.""" if args.verbose: logging.getLogger().setLevel(logging.DEBUG) logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s', stream=sys.stderr) else: logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s', stream=sys.stderr) try: info_json_content = args.load_info_json.read() if not info_json_content.strip(): logger.error("Input is empty.") return 4 info_data = json.loads(info_json_content) except json.JSONDecodeError: logger.error("Invalid JSON provided. Please check the input file.") return 4 except Exception as e: logger.error(f"An unexpected error occurred while reading input: {e}", exc_info=args.verbose) return 4 formats = info_data.get('formats', []) if not formats: logger.warning("No formats found in the provided info.json.") return 3 overall_status = 'valid' checked_any = False min_time_left = float('inf') worst_status_format_id = None for f in formats: url = f.get('url') format_id = f.get('format_id', 'N/A') if not url: logger.debug(f"Format {format_id} has no URL, skipping.") continue status, time_left = sp_utils.check_url_expiry(url, args.time_shift_minutes) if status == 'no_expiry_info': logger.debug(f"Format {format_id} has no expiration info in URL, skipping.") continue checked_any = True if time_left < min_time_left: min_time_left = time_left worst_status_format_id = format_id # Determine the "worst" status seen so far. Expired > Valid. if status == 'expired': overall_status = 'expired' if not args.check_all_formats and overall_status != 'valid': # If we found a problem and we're not checking all, we can stop. break if not args.check_all_formats: # If we checked one valid format and we're not checking all, we can stop. break if not checked_any: logger.warning("No formats with expiration timestamps were found to check.") return 3 if overall_status == 'expired': expire_datetime = datetime.fromtimestamp(time.time() + min_time_left, timezone.utc) if min_time_left <= 0: logger.error(f"URL for format '{worst_status_format_id}' is EXPIRED. It expired at {expire_datetime.strftime('%Y-%m-%d %H:%M:%S %Z')}.") else: logger.warning(f"URL for format '{worst_status_format_id}' is considered EXPIRED due to time-shift. It will expire in {min_time_left / 60:.1f} minutes (at {expire_datetime.strftime('%Y-%m-%d %H:%M:%S %Z')}).") return 1 else: # valid expire_datetime = datetime.fromtimestamp(time.time() + min_time_left, timezone.utc) logger.info(f"OK. The soonest-expiring URL (format '{worst_status_format_id}') is valid for another {min_time_left / 60:.1f} minutes (expires at {expire_datetime.strftime('%Y-%m-%d %H:%M:%S %Z')}).") return 0