Python module to talk to Google Chromecast.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive media playback control supporting various content types, streaming protocols, and playback states. The MediaController provides queue management, seek operations, subtitle control, and detailed status monitoring for all media operations.
Main controller for playing and controlling media on Chromecast devices.
class MediaController:
"""Controller to interact with the Chromecast media namespace."""
def play_media(self, url, content_type, *, title=None, thumb=None,
current_time=None, autoplay=True, stream_type=STREAM_TYPE_LIVE,
metadata=None, subtitles=None, subtitles_lang="en-US",
subtitles_mime="text/vtt", subtitle_id=1, enqueue=False,
media_info=None, callback_function=None):
"""
Start playing media.
Parameters:
- url: str, URL of the media to play
- content_type: str, MIME type of the media (e.g., 'video/mp4', 'audio/mp3')
- title: str | None, Media title
- thumb: str | None, Thumbnail image URL
- current_time: float | None, Start position in seconds (None for beginning)
- autoplay: bool, Start playing immediately (default True)
- stream_type: str, Stream type (default STREAM_TYPE_LIVE)
- metadata: dict | None, Additional metadata
- subtitles: str | None, Subtitle track URL
- subtitles_lang: str, Subtitle language code (default "en-US")
- subtitles_mime: str, Subtitle MIME type (default "text/vtt")
- subtitle_id: int, Subtitle track ID (default 1)
- enqueue: bool, Add to queue instead of playing immediately
- media_info: dict | None, Custom media information
- callback_function: callable | None, Callback for request completion
"""Usage Example:
# Access media controller
media_ctrl = cast.media_controller
# Play a video file
media_ctrl.play_media(
url="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
content_type="video/mp4",
title="Big Buck Bunny",
thumb="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg"
)
# Play audio with metadata
media_ctrl.play_media(
url="https://example.com/audio.mp3",
content_type="audio/mp3",
title="My Song",
metadata={
"artist": "Artist Name",
"album": "Album Name",
"albumArtist": "Album Artist",
"duration": 240.5
}
)
# Play with subtitles
media_ctrl.play_media(
url="https://example.com/video.mp4",
content_type="video/mp4",
title="Movie with Subtitles",
subtitles="https://example.com/subtitles.vtt",
subtitles_lang="en-US",
subtitles_mime="text/vtt"
)Control media playback state and position.
def play(self):
"""Resume media playback."""
def pause(self):
"""Pause media playback."""
def stop(self):
"""Stop media playback."""
def rewind(self):
"""Rewind media playback."""
def skip(self):
"""Skip current media item."""
def seek(self, position):
"""
Seek to specific position in media.
Parameters:
- position: float, Position in seconds to seek to
"""
def set_playback_rate(self, playback_rate):
"""
Set playback rate/speed.
Parameters:
- playback_rate: float, Playback rate (1.0 = normal speed)
"""Usage Example:
# Wait for media to start
media_ctrl.block_until_active()
# Control playback
media_ctrl.pause()
time.sleep(2)
media_ctrl.play()
# Seek to 1 minute mark
media_ctrl.seek(60.0)
# Change playback speed
media_ctrl.set_playback_rate(1.5) # 1.5x speed
media_ctrl.set_playback_rate(1.0) # Back to normal
# Stop playback
media_ctrl.stop()Manage media queue for playlist functionality.
def queue_next(self):
"""Skip to next item in queue."""
def queue_prev(self):
"""Skip to previous item in queue."""
def queue_insert_items(self, items, current_item_id=None,
current_item_index=None, insert_before=None):
"""
Insert items into the media queue.
Parameters:
- items: list, List of media items to insert
- current_item_id: int | None, Current item ID reference
- current_item_index: int | None, Current item index reference
- insert_before: int | None, Insert before this item ID
"""
def queue_update_items(self, items):
"""
Update items in the media queue.
Parameters:
- items: list, List of media items with updates
"""Usage Example:
# Add items to queue
queue_items = [
{
"contentId": "https://example.com/song1.mp3",
"contentType": "audio/mp3",
"metadata": {"title": "Song 1", "artist": "Artist"}
},
{
"contentId": "https://example.com/song2.mp3",
"contentType": "audio/mp3",
"metadata": {"title": "Song 2", "artist": "Artist"}
}
]
media_ctrl.queue_insert_items(queue_items)
# Navigate queue
media_ctrl.queue_next() # Skip to next song
media_ctrl.queue_prev() # Go back to previous songControl media-specific volume and muting.
def set_volume(self, volume):
"""
Set media volume level.
Parameters:
- volume: float, Volume level (0.0 to 1.0)
"""
def set_volume_muted(self, muted):
"""
Set media mute state.
Parameters:
- muted: bool, True to mute, False to unmute
"""Monitor media status and wait for state changes.
def update_status(self, callback_function=None):
"""
Request updated media status from device.
Parameters:
- callback_function: callable | None, Function to call when status received
"""
def block_until_active(self, timeout=None):
"""
Block until the media controller is active (media is loaded).
Parameters:
- timeout: float | None, Maximum time to wait. None for no timeout.
Raises:
- RequestTimeout: If timeout expires before becoming active
"""
@property
def status(self) -> MediaStatus:
"""Current media status"""
@property
def is_active(self) -> bool:
"""True if media controller is active"""
@property
def is_playing(self) -> bool:
"""True if media is currently playing"""
@property
def is_paused(self) -> bool:
"""True if media is currently paused"""
@property
def is_idle(self) -> bool:
"""True if media controller is idle"""Usage Example:
# Wait for media to load
try:
media_ctrl.block_until_active(timeout=10.0)
print("Media is loaded and ready")
except pychromecast.RequestTimeout:
print("Media did not load within timeout")
# Check status
if media_ctrl.is_playing:
print(f"Playing: {media_ctrl.status.title}")
print(f"Position: {media_ctrl.status.adjusted_current_time:.1f}s")
print(f"Duration: {media_ctrl.status.duration:.1f}s")
# Request status update
media_ctrl.update_status()Register listeners for media status changes.
def register_status_listener(self, listener):
"""
Register a listener for media status updates.
Parameters:
- listener: MediaStatusListener, Object with new_media_status method
"""
class MediaStatusListener:
"""Abstract listener for media status events"""
def new_media_status(self, status: MediaStatus) -> None: ...
class MediaStatus:
"""Media status information"""
def load_media_status(self, data: dict) -> None: ...Usage Example:
class MyMediaListener:
def new_media_status(self, status):
if status.player_state == pychromecast.MEDIA_PLAYER_STATE_PLAYING:
print(f"Now playing: {status.title}")
elif status.player_state == pychromecast.MEDIA_PLAYER_STATE_PAUSED:
print("Playback paused")
elif status.player_state == pychromecast.MEDIA_PLAYER_STATE_IDLE:
print("Playback idle")
# Register listener
listener = MyMediaListener()
media_ctrl.register_status_listener(listener)class MediaStatus:
"""Current media playback status"""
current_time: float
content_id: str | None
content_type: str | None
duration: float | None
stream_type: str
idle_reason: str | None
media_session_id: int | None
playback_rate: float
player_state: str
supported_media_commands: int
volume_level: float
volume_muted: bool
media_custom_data: dict
media_metadata: dict
subtitle_tracks: dict
current_subtitle_tracks: list
last_updated: datetime | None
@property
def adjusted_current_time(self) -> float | None:
"""Returns calculated current seek time accounting for playback rate"""
@property
def title(self) -> str | None:
"""Returns media title from metadata"""
class MediaImage:
"""Media image metadata container"""
url: str | None
height: int | None
width: int | None
class MediaStatusListener:
"""Abstract listener for media status events"""
def new_media_status(self, status: MediaStatus) -> None: ...# Stream Types
STREAM_TYPE_UNKNOWN = "UNKNOWN"
STREAM_TYPE_BUFFERED = "BUFFERED"
STREAM_TYPE_LIVE = "LIVE"
# Media Player States
MEDIA_PLAYER_STATE_PLAYING = "PLAYING"
MEDIA_PLAYER_STATE_BUFFERING = "BUFFERING"
MEDIA_PLAYER_STATE_PAUSED = "PAUSED"
MEDIA_PLAYER_STATE_IDLE = "IDLE"
MEDIA_PLAYER_STATE_UNKNOWN = "UNKNOWN"
# Metadata Types
METADATA_TYPE_GENERIC = 0
METADATA_TYPE_MOVIE = 1
METADATA_TYPE_TVSHOW = 2
METADATA_TYPE_MUSICTRACK = 3
METADATA_TYPE_PHOTO = 4
# Command Support Flags (bitfield)
CMD_SUPPORT_PAUSE = 1
CMD_SUPPORT_SEEK = 2
CMD_SUPPORT_STREAM_VOLUME = 4
CMD_SUPPORT_STREAM_MUTE = 8
CMD_SUPPORT_SKIP_FORWARD = 16
CMD_SUPPORT_SKIP_BACKWARD = 32
CMD_SUPPORT_QUEUE_NEXT = 64
CMD_SUPPORT_QUEUE_PREV = 128
CMD_SUPPORT_QUEUE_SHUFFLE = 256
CMD_SUPPORT_SKIP_AD = 512
CMD_SUPPORT_QUEUE_REPEAT_ALL = 1024
CMD_SUPPORT_QUEUE_REPEAT_ONE = 2048
CMD_SUPPORT_EDIT_TRACKS = 4096
CMD_SUPPORT_PLAYBACK_RATE = 8192
CMD_SUPPORT_LIKE = 16384
CMD_SUPPORT_DISLIKE = 32768
CMD_SUPPORT_FOLLOW = 65536
CMD_SUPPORT_UNFOLLOW = 131072
CMD_SUPPORT_STREAM_TRANSFER = 262144
CMD_SUPPORT_ALL_BASIC_MEDIA = 12303
# Media Error Codes
MEDIA_PLAYER_ERROR_CODES = {
100: "MEDIA_UNKNOWN",
101: "MEDIA_ABORTED",
102: "MEDIA_DECODE",
103: "MEDIA_NETWORK",
104: "MEDIA_SRC_NOT_SUPPORTED",
# ... (many more error codes)
}Install with Tessl CLI
npx tessl i tessl/pypi-pychromecast