A Python package, command line interface and MCP server to control video players for MultiViewer, the best way to watch Formula 1.
- Command line interface for controlling MultiViewer. Useful for integrations with control interfaces like StreamDeck
- Pythonic interface for controlling MultiViewer. No GraphQL needed!
- MCP server for controlling MultiViewer - perfect for controlling the broadcast for with AI agents.
- Type hints
- Full documentation
- Test coverage
- black Praise the Dark Lord
The latest version can be installed via pip.
$ pip install mvf1$ mvf1-cli --help$ mvf1-cli mcpTo use in an AI agent, use your framework's affordance for a stdio MCP server.
Here is an example with PydanticAI.
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerStdio
server = MCPServerStdio(
'mvf1-cli',
args=[
'mcp'
]
)
agent = Agent('openai:gpt-4o', mcp_servers=[server])Displaying all players
>>> from mvf1 import MultiViewerForF1
>>> remote = MultiViewerForF1()
>>> remote.players
[6: INTERNATIONAL, 7: PER]Pause all players
>>> from mvf1 import MultiViewerForF1
>>> remote = MultiViewerForF1()
>>> for player in remote.players:
>>> player.mute()
{'data': {'playerSetMuted': True}}
{'data': {'playerSetMuted': True}}Retrieve specific player
>>> from mvf1 import MultiViewerForF1
>>> remote = MultiViewerForF1()
>>> player = remote.player(6)
>>> player.state
{'ts': 1677168293.21, 'paused': False, 'muted': True, 'volume': 100, 'live': False, 'currentTime': 10.002025, 'interpolatedCurrentTime': 363.656025}Switch stream of player to data channel
>>> from mvf1 import MultiViewerForF1
>>> remote = MultiViewerForF1()
>>> player = remote.player(6)
>>> player.switch_stream('DATA')
{'data': {'playerCreate': '12'}}Synchronize all players to specific player
>>> from mvf1 import MultiViewerForF1
>>> remote = MultiViewerForF1()
>>> player = remote.player(6)
>>> player.sync()
{'data': {'playerSync': True}}Synchornize all players to player streaming broadcast commentary
>>> from mvf1 import MultiViewerForF1
>>> remote = MultiViewerForF1()
>>> remote.player_sync_to_commentary()
{'data': {'playerSync': True}}Synchronize open players to live timing
>>> from mvf1 import MultiViewerForF1
>>> remote = MultiViewerForF1()
>>> remote.player_sync_to_live_timing()
{'data': {'meeting_id': '1279', 'session_id': '11234', 'synced_players': [...]}}The same operation is available to MCP clients as
player_sync_to_live_timing. It uses the current live-timing clock,
session start, and each feed's signed offset to seek matching open players to
the first open player's session.
The library can retrieve a content ID from an open player, or look up session content IDs using a meeting key:
from mvf1 import MultiViewerForF1
remote = MultiViewerForF1()
player = remote.players[0] # Requires an open player.
content_id = player.content_id
state = remote.f1_live_timing_state["data"]["f1LiveTimingState"]
meeting_key = state["SessionInfo"]["Meeting"]["Key"]
session_ids = remote.content_ids(meeting_key) # Session title -> content ID.content_ids() uses MultiViewer's public meetings API and needs internet
access. The live-timing example requires an active F1 timing session.
MCP exposes content_ids(meeting_key) and player_get_content_id()
(the first open player's content ID).
Additional controls are available in both Python and MCP:
subscriptions = remote.active_subscriptions["data"]["activeSubscriptions"]
remote.player_create(content_id, channel_id=player.channel_id)
player.set_always_on_top(True, level="FLOATING")
player.seek(relative=-0.25)
player.set_volume(37.5)The corresponding MCP tools are active_subscriptions, player_create,
player_set_always_on_top, player_seek_to, and player_set_volume.
The last three take a player id. Supported levels are FLOATING,
MAIN_MENU, MODAL_PANEL, NORMAL, POP_UP_MENU, SCREEN_SAVER,
STATUS, and TORN_OFF_MENU. Omitting the level uses MultiViewer's
default. Volume is normally 0-100, with up to 200 allowed for F1 TV v2 players
when volume boost is enabled in MultiViewer.
To hack on the project, clone the GitHub repo:
$ git clone https://github.com/RobSpectre/mvf1Then install in a virtualenv.
$ pip install -e ./The project uses tox for tests. Simply run from project root
$ toxThe generated schema was refreshed from MultiViewer 2.15.2. WEC live timing
now returns positions, session, and raceControl; applications
using the previous WEC fields must migrate. See
the dependency and API audit for the full
comparison, remaining coverage gaps, and schema regeneration commands.
- Written by Rob Spectre.
- Released under MIT License.
- Software is as is - no warranty expressed or implied, diggity.
- This package is not developed or maintained by MultiViewer or Formula 1 TV.
- Shout out to the excellent MultiViewer team! This app absolutely changed how I enjoy Formula 1.
- 🏎️ Go Weeyums! 🏎️