Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- """
- AudioChan Stream Capture Tool (Manual Mode Only)
- Uses Playwright to capture stream URLs and full headers (including HttpOnly cookies).
- Generates the robust FFmpeg command for manual copy-pasting.
- """
- import argparse
- import asyncio
- from playwright.async_api import async_playwright
- import os
- import re
- import sys
- # Path to store browser session (cookies, etc.) so you don't have to login every time
- USER_DATA_DIR = os.path.join(os.getcwd(), 'playwright_data')
- async def capture_stream_manual(url):
- print(f"š Launching browser for: {url}")
- print(f"š User Data Dir: {USER_DATA_DIR}")
- async with async_playwright() as p:
- # Launch persistent context to save login state
- context = await p.chromium.launch_persistent_context(
- user_data_dir=USER_DATA_DIR,
- headless=False, # Change if cloudflare is an issue
- channel="chrome", # Try to use installed Chrome if available for better realism
- args=[
- '--disable-blink-features=AutomationControlled', # Hide automation flag
- ]
- )
- page = await context.new_page()
- # storage for captured info
- stream_info = {
- 'url': None,
- 'headers': None
- }
- # Event listener for requests
- async def handle_request(request):
- try:
- # Filter strictly for the stream URL
- if 'stream.audiochan.com' in request.url and '&st=' in request.url:
- print(f"\nā CAPTURED STREAM REQUEST! (Updating...)")
- stream_info['url'] = request.url
- try:
- # This can sometimes fail if the request is closed too quickly
- stream_info['headers'] = await request.all_headers()
- except Exception as e:
- print(f"ā ļø Warning: Could not fetch full headers: {e}")
- # Fallback to basic headers if available, or just use what we have
- if not stream_info['headers']: # Only overwrite if we don't have good headers yet
- stream_info['headers'] = request.headers
- except Exception as e:
- # Catch-all for any other issues in the handler to prevent loop crash
- pass
- page.on("request", handle_request)
- try:
- print("ā³ Navigating to page...")
- await page.goto(url)
- print("š Waiting for stream to start... (Press Play on the page if needed)")
- # Wait until we capture the stream AND it stabilizes
- stability_count = 0
- required_stability = 3
- for _ in range(60):
- if stream_info['url'] and stream_info['headers']:
- stability_count += 1
- print(f" Stream detected... stabilizing ({stability_count}/{required_stability})")
- if stability_count >= required_stability:
- break
- else:
- stability_count = 0 # Reset if lost (unlikely but good safety)
- await asyncio.sleep(1)
- if stream_info['url'] and stream_info['headers']:
- title = await page.title()
- # Sanitize title: Replace invalid Windows filename characters with underscore
- # Invalid characters for Windows filenames: < > : " / \ | ? *
- invalid_chars = r'[<>:"/\\|?*]'
- safe_title = re.sub(invalid_chars, '_', title).strip()
- # Also remove any trailing periods or spaces that Windows dislikes
- safe_title = re.sub(r'[ .]+$', '', safe_title)
- print("\n" + "="*80)
- print("š SUCCESS! Stream info captured.")
- print("="*80)
- # Construct FFmpeg Command
- headers_dict = stream_info['headers']
- # Format headers for FFmpeg (-headers "Key: Value\r\nKey: Value\r\n")
- ffmpeg_headers = ""
- # Critical headers
- keys_to_keep = ['user-agent', 'referer', 'cookie', 'accept', 'accept-language', 'origin']
- for key, value in headers_dict.items():
- if key.lower() in keys_to_keep:
- # Escape double quotes inside header values with a backslash
- safe_val = value.replace('"', '\\"')
- # Capitalize keys nicely
- nice_key = key.title()
- ffmpeg_headers += f"{nice_key}: {safe_val}\r\n"
- # Add connection keep-alive if missing
- if 'connection' not in headers_dict:
- ffmpeg_headers += "Connection: keep-alive\r\n"
- # Construct the full command
- # Note: We use .mp4 container for better compatibility with streams
- output_filename = f"{safe_title}.mp4"
- # String version for manual copy-pasting
- cmd_str = f'ffmpeg -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 -headers "{ffmpeg_headers}" -i "{stream_info["url"]}" -c copy "{output_filename}"'
- print("\nš FFmpeg Command (Auto-Generated):")
- print("-" * 20)
- print(cmd_str)
- print("-" * 20)
- print("\nā ļø Copy the command above and run it in your terminal.")
- else:
- print("\nā Timeout: Stream request not found.")
- print("Did you play the audio? Is the site asking for login?")
- except Exception as e:
- print(f"\nā Error: {e}")
- finally:
- # Safely close the browser context
- try:
- if context.pages: # Simple check if it might still be open
- print("\nClosing browser...")
- await context.close()
- except Exception as e:
- # Ignore errors during shutdown (e.g., Target closed, Loop closed)
- pass
- def main():
- if sys.platform == 'win32':
- asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
- parser = argparse.ArgumentParser(description="AudioChan Stream Capture Tool (Manual Mode Only)")
- parser.add_argument('url', nargs='?', help='The URL of the AudioChan page (optional)')
- args = parser.parse_args()
- target_url = args.url
- # Interactive URL Input if not provided
- if not target_url:
- print("Enter the AudioChan URL:")
- target_url = input("> ").strip()
- if not target_url:
- print("Error: No URL provided. Exiting.")
- return
- asyncio.run(capture_stream_manual(target_url))
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment