133 lines
4.8 KiB
Python
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
|