2025-12-26 10:05:00 +03:00

133 lines
4.8 KiB
Python

#!/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