#!/usr/bin/python import sys import pychromecast # pip3 install pychromecast import os import random import time from http.server import HTTPServer, SimpleHTTPRequestHandler import threading import socket import asyncio from aiohttp import web # Configuration PORT = 8000 # Port for the local HTTP server HOST = "0.0.0.0" # Bind to all interfaces CAST = "Greg" # Substring to match Chromecast device name def get_local_ip(): """Get the local IP address of the machine.""" return '192.168.0.2' ip = socket.gethostbyname(socket.gethostname()) if ip.startswith("127."): raise Exception("Failed to get a valid local IP address.") return ip def start_http_server(video_dir): """Start a simple HTTP server to serve video files.""" os.chdir(video_dir) # Change to video directory server = HTTPServer((HOST, PORT), SimpleHTTPRequestHandler) print(f"Serving videos at http://{get_local_ip()}:{PORT}") server.serve_forever() async def start_aiohttp_server(video_dir): """Start an aiohttp server to serve video files.""" async def handle_file_request(req): """Handle file requests for the aiohttp server.""" file_path = os.path.join(video_dir, req.match_info['filename']) print('REQUESTED:', file_path) if not os.path.exists(file_path) or not file_path.endswith('.mp4'): raise web.HTTPNotFound() return web.FileResponse(file_path) app = web.Application() app.router.add_get('/{filename:.+}', handle_file_request) runner = web.AppRunner(app) await runner.setup() site = web.TCPSite(runner, HOST, PORT) print(f"Serving videos at http://{get_local_ip()}:{PORT}") await site.start() # Keep the server running indefinitely await asyncio.Event().wait() def run_aiohttp_in_thread(video_dir): """Run the aiohttp server in a separate thread.""" asyncio.run(start_aiohttp_server(video_dir)) def get_video_files(video_dir): """Get a list of MP4 files in the video directory.""" return [f for f in os.listdir(video_dir) if f.endswith(".mp4")] def main(video_dir): # Start aiohttp server in a separate thread, passing VIDEO_DIR server_thread = threading.Thread(target=run_aiohttp_in_thread, args=(video_dir,), daemon=True) server_thread.start() # Discover Chromecast devices chromecasts, browser = pychromecast.get_chromecasts() if not chromecasts: print("No Chromecast devices found.") return # Select Chromecast matching CAST substring cast = None for device in chromecasts: if CAST.lower() in device.cast_info.friendly_name.lower(): cast = device break if not cast: print(f"No Chromecast device found with name containing '{CAST}'.") return cast.wait() # Wait for connection (synchronous) print(f"Connected to Chromecast: {cast.cast_info.friendly_name}") print('STATUS:', cast.status) # Get media controller mc = cast.media_controller # Get list of video files and shuffle videos = get_video_files(video_dir) if not videos: print(f"No MP4 files found in {video_dir}.") return random.seed() # uses current time random.shuffle(videos) local_ip = get_local_ip() # Play videos in a loop while True: for video in videos: video_url = f"http://{local_ip}:{PORT}/{video}" print(f"Playing: {video_url}") mc.play_media(video_url, "video/mp4") mc.block_until_active() # Synchronous wait until media is active # Signal if we're in an unknown state. while mc.status.player_state not in { 'IDLE', 'PLAYING', 'BUFFERING', 'PAUSED', }: print('UNKNOWN STATUS:', mc.status) time.sleep(5) # Wait for the video to start. while mc.status.player_state == 'IDLE': print('Waiting...') time.sleep(5) # Wait until the video finishes or an error occurs while mc.status.player_state in { 'PLAYING', 'BUFFERING', 'PAUSED', }: time.sleep(1) print('DONE:', mc.status.player_state) # Reshuffle for the next loop random.shuffle(videos) if __name__ == "__main__": main(sys.argv[1])