first commit
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import pychromecast
|
||||
from pychromecast.controllers.media import MediaController
|
||||
import time
|
||||
import threading
|
||||
from typing import List, Optional
|
||||
from .utils import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
class CastManager:
|
||||
def __init__(self):
|
||||
self.chromecast = None
|
||||
self.mc: Optional[MediaController] = None
|
||||
self.queue: List[str] = []
|
||||
self.current_index = -1
|
||||
self.is_playing = False
|
||||
self._lock = threading.Lock()
|
||||
self._discover_thread = None
|
||||
self.browser = None
|
||||
|
||||
def discover(self, timeout=5):
|
||||
logger.info("Discovering Chromecasts...")
|
||||
chromecasts, browser = pychromecast.get_chromecasts(timeout=timeout)
|
||||
self.browser = browser
|
||||
if chromecasts:
|
||||
# For simplicity, pick the first one found or allow selection later
|
||||
# In a real scenario, we might want to target a specific name
|
||||
self.chromecast = chromecasts[0]
|
||||
logger.info(f"Found Chromecast: {self.chromecast.name}")
|
||||
self.chromecast.wait()
|
||||
self.mc = self.chromecast.media_controller
|
||||
self.mc.register_status_listener(self)
|
||||
else:
|
||||
logger.error("No Chromecasts found.")
|
||||
|
||||
def play_queue(self, urls: List[str]):
|
||||
with self._lock:
|
||||
self.queue = urls
|
||||
self.current_index = 0
|
||||
self._play_current()
|
||||
|
||||
def _play_current(self):
|
||||
if 0 <= self.current_index < len(self.queue):
|
||||
url = self.queue[self.current_index]
|
||||
logger.info(f"Playing {self.current_index + 1}/{len(self.queue)}: {url}")
|
||||
if not self.chromecast:
|
||||
self.discover()
|
||||
|
||||
if self.chromecast:
|
||||
self.chromecast.wait()
|
||||
# Use generic video type, or try to guess from URL
|
||||
self.mc.play_media(url, 'video/mp4')
|
||||
self.is_playing = True
|
||||
else:
|
||||
logger.error("Cannot play: No Chromecast connected.")
|
||||
else:
|
||||
logger.info("Queue finished.")
|
||||
self.is_playing = False
|
||||
self.current_index = -1
|
||||
|
||||
def stop(self):
|
||||
with self._lock:
|
||||
if self.mc:
|
||||
self.mc.stop()
|
||||
self.queue = []
|
||||
self.current_index = -1
|
||||
self.is_playing = False
|
||||
|
||||
def new_media_status(self, status):
|
||||
"""Callback from pychromecast when media status changes."""
|
||||
logger.debug(f"Media status update: {status.player_state}")
|
||||
|
||||
# Check if the current video finished
|
||||
if status.player_state == "IDLE" and status.idle_reason == "FINISHED":
|
||||
logger.info("Current track finished. Moving to next...")
|
||||
with self._lock:
|
||||
if self.current_index != -1:
|
||||
self.current_index += 1
|
||||
# Small delay to ensure state transitions
|
||||
threading.Timer(1.0, self._play_current).start()
|
||||
|
||||
def get_status(self):
|
||||
status = {
|
||||
"is_playing": self.is_playing,
|
||||
"queue_len": len(self.queue),
|
||||
"current_index": self.current_index,
|
||||
}
|
||||
if self.mc and self.mc.status:
|
||||
status.update({
|
||||
"player_state": self.mc.status.player_state,
|
||||
"current_time": self.mc.status.current_time,
|
||||
"duration": self.mc.status.duration,
|
||||
})
|
||||
return status
|
||||
|
||||
# Singleton instance
|
||||
cast_manager = CastManager()
|
||||
Reference in New Issue
Block a user