├── .codecov.yml
├── .coveragerc
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ ├── feature_request.yml
│ ├── implementation-proposal.yml
│ ├── investigation.yml
│ ├── minor-change.yml
│ └── question-or-idea.yml
├── dependabot.yml
└── workflows
│ ├── codeql-analysis.yml
│ ├── release.yml
│ └── tests.yml
├── .gitignore
├── .gitpod.yml
├── CHANGES.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── CONTRIBUTORS.md
├── Dockerfile
├── LICENSE.md
├── MANIFEST.in
├── README.md
├── base_versions.txt
├── chickn.yaml
├── docs
├── .gitignore
├── 404.html
├── CNAME
├── Gemfile
├── _config.yml
├── _includes
│ ├── api
│ ├── atvremote_scan
│ ├── code
│ ├── issue
│ └── pypi
├── _layouts
│ └── template.html
├── api
│ ├── pyatv.conf.html
│ ├── pyatv.const.html
│ ├── pyatv.convert.html
│ ├── pyatv.exceptions.html
│ ├── pyatv.helpers.html
│ ├── pyatv.html
│ ├── pyatv.interface.html
│ ├── pyatv.settings.html
│ ├── pyatv.storage.file_storage.html
│ ├── pyatv.storage.html
│ └── pyatv.storage.memory_storage.html
├── assets
│ ├── css
│ │ ├── custom.css
│ │ ├── hljs.css
│ │ ├── normalize.css
│ │ ├── pdoc.css
│ │ ├── sanitize.css
│ │ └── style.scss
│ ├── img
│ │ └── logo.svg
│ └── js
│ │ ├── highlight.9.12.0.min.js
│ │ ├── mermaid.8.9.2.min.js
│ │ └── mermaid.min.js.map
├── development
│ ├── apps.md
│ ├── audio.md
│ ├── control.md
│ ├── development.md
│ ├── device_info.md
│ ├── examples.md
│ ├── features.md
│ ├── keyboard.md
│ ├── listeners.md
│ ├── logging.md
│ ├── metadata.md
│ ├── power_management.md
│ ├── scan_pair_and_connect.md
│ ├── services.md
│ ├── storage.md
│ ├── stream.md
│ └── testing.md
├── documentation
│ ├── atvlog.md
│ ├── atvproxy.md
│ ├── atvremote.md
│ ├── atvscript.md
│ ├── concepts.md
│ ├── documentation.md
│ ├── getting_started.md
│ ├── protocols.md
│ ├── supported_features.md
│ ├── tutorial.md
│ └── workspace.code-workspace
├── favicon.ico
├── index.md
├── internals
│ ├── design.md
│ ├── documentation.md
│ ├── interfaces.md
│ ├── internals.md
│ ├── submit_pr.md
│ ├── testing.md
│ └── tools.md
├── pdoc_templates
│ ├── config.mako
│ └── html.mako
└── support
│ ├── acknowledgements.md
│ ├── faq.md
│ ├── migration.md
│ ├── scanning_issues.md
│ ├── support.md
│ └── troubleshooting.md
├── examples
├── __init__.py
├── auto_connect.py
├── connect_with_credentials.py
├── manual_connect.py
├── pairing.py
├── play_url.py
├── scan_and_connect.py
├── storage.py
├── stream.py
└── tutorial.py
├── pyatv
├── __init__.py
├── auth
│ ├── hap_channel.py
│ ├── hap_pairing.py
│ ├── hap_session.py
│ ├── hap_srp.py
│ ├── hap_tlv8.py
│ └── server_auth.py
├── conf.py
├── const.py
├── convert.py
├── core
│ ├── __init__.py
│ ├── facade.py
│ ├── mdns.py
│ ├── protocol.py
│ ├── relayer.py
│ └── scan.py
├── exceptions.py
├── helpers.py
├── interface.py
├── protocols
│ ├── __init__.py
│ ├── airplay
│ │ ├── __init__.py
│ │ ├── ap2_session.py
│ │ ├── auth
│ │ │ ├── __init__.py
│ │ │ ├── hap.py
│ │ │ ├── hap_transient.py
│ │ │ └── legacy.py
│ │ ├── channels.py
│ │ ├── mrp_connection.py
│ │ ├── pairing.py
│ │ ├── player.py
│ │ ├── server_auth.py
│ │ ├── srp.py
│ │ └── utils.py
│ ├── companion
│ │ ├── __init__.py
│ │ ├── api.py
│ │ ├── auth.py
│ │ ├── connection.py
│ │ ├── keyed_archiver.py
│ │ ├── pairing.py
│ │ ├── plist_payloads
│ │ │ ├── __init__.py
│ │ │ └── rti_text_operations.py
│ │ ├── protocol.py
│ │ └── server_auth.py
│ ├── dmap
│ │ ├── __init__.py
│ │ ├── daap.py
│ │ ├── pairing.py
│ │ ├── parser.py
│ │ ├── tag_definitions.py
│ │ └── tags.py
│ ├── mrp
│ │ ├── __init__.py
│ │ ├── auth.py
│ │ ├── connection.py
│ │ ├── messages.py
│ │ ├── pairing.py
│ │ ├── player_state.py
│ │ ├── protobuf
│ │ │ ├── AudioFadeMessage.proto
│ │ │ ├── AudioFadeMessage_pb2.py
│ │ │ ├── AudioFadeMessage_pb2.pyi
│ │ │ ├── AudioFadeResponseMessage.proto
│ │ │ ├── AudioFadeResponseMessage_pb2.py
│ │ │ ├── AudioFadeResponseMessage_pb2.pyi
│ │ │ ├── AudioFormatSettingsMessage.proto
│ │ │ ├── AudioFormatSettingsMessage_pb2.py
│ │ │ ├── AudioFormatSettingsMessage_pb2.pyi
│ │ │ ├── ClientUpdatesConfigMessage.proto
│ │ │ ├── ClientUpdatesConfigMessage_pb2.py
│ │ │ ├── ClientUpdatesConfigMessage_pb2.pyi
│ │ │ ├── CommandInfo.proto
│ │ │ ├── CommandInfo_pb2.py
│ │ │ ├── CommandInfo_pb2.pyi
│ │ │ ├── CommandOptions.proto
│ │ │ ├── CommandOptions_pb2.py
│ │ │ ├── CommandOptions_pb2.pyi
│ │ │ ├── Common.proto
│ │ │ ├── Common_pb2.py
│ │ │ ├── Common_pb2.pyi
│ │ │ ├── ConfigureConnectionMessage.proto
│ │ │ ├── ConfigureConnectionMessage_pb2.py
│ │ │ ├── ConfigureConnectionMessage_pb2.pyi
│ │ │ ├── ContentItem.proto
│ │ │ ├── ContentItemMetadata.proto
│ │ │ ├── ContentItemMetadata_pb2.py
│ │ │ ├── ContentItemMetadata_pb2.pyi
│ │ │ ├── ContentItem_pb2.py
│ │ │ ├── ContentItem_pb2.pyi
│ │ │ ├── CryptoPairingMessage.proto
│ │ │ ├── CryptoPairingMessage_pb2.py
│ │ │ ├── CryptoPairingMessage_pb2.pyi
│ │ │ ├── DeviceInfoMessage.proto
│ │ │ ├── DeviceInfoMessage_pb2.py
│ │ │ ├── DeviceInfoMessage_pb2.pyi
│ │ │ ├── GenericMessage.proto
│ │ │ ├── GenericMessage_pb2.py
│ │ │ ├── GenericMessage_pb2.pyi
│ │ │ ├── GetKeyboardSessionMessage.proto
│ │ │ ├── GetKeyboardSessionMessage_pb2.py
│ │ │ ├── GetKeyboardSessionMessage_pb2.pyi
│ │ │ ├── GetRemoteTextInputSessionMessage.proto
│ │ │ ├── GetRemoteTextInputSessionMessage_pb2.py
│ │ │ ├── GetRemoteTextInputSessionMessage_pb2.pyi
│ │ │ ├── GetVolumeMessage.proto
│ │ │ ├── GetVolumeMessage_pb2.py
│ │ │ ├── GetVolumeMessage_pb2.pyi
│ │ │ ├── GetVolumeResultMessage.proto
│ │ │ ├── GetVolumeResultMessage_pb2.py
│ │ │ ├── GetVolumeResultMessage_pb2.pyi
│ │ │ ├── KeyboardMessage.proto
│ │ │ ├── KeyboardMessage_pb2.py
│ │ │ ├── KeyboardMessage_pb2.pyi
│ │ │ ├── LanguageOption.proto
│ │ │ ├── LanguageOption_pb2.py
│ │ │ ├── LanguageOption_pb2.pyi
│ │ │ ├── ModifyOutputContextRequestMessage.proto
│ │ │ ├── ModifyOutputContextRequestMessage_pb2.py
│ │ │ ├── ModifyOutputContextRequestMessage_pb2.pyi
│ │ │ ├── NotificationMessage.proto
│ │ │ ├── NotificationMessage_pb2.py
│ │ │ ├── NotificationMessage_pb2.pyi
│ │ │ ├── NowPlayingClient.proto
│ │ │ ├── NowPlayingClient_pb2.py
│ │ │ ├── NowPlayingClient_pb2.pyi
│ │ │ ├── NowPlayingInfo.proto
│ │ │ ├── NowPlayingInfo_pb2.py
│ │ │ ├── NowPlayingInfo_pb2.pyi
│ │ │ ├── NowPlayingPlayer.proto
│ │ │ ├── NowPlayingPlayer_pb2.py
│ │ │ ├── NowPlayingPlayer_pb2.pyi
│ │ │ ├── Origin.proto
│ │ │ ├── OriginClientPropertiesMessage.proto
│ │ │ ├── OriginClientPropertiesMessage_pb2.py
│ │ │ ├── OriginClientPropertiesMessage_pb2.pyi
│ │ │ ├── Origin_pb2.py
│ │ │ ├── Origin_pb2.pyi
│ │ │ ├── PlaybackQueue.proto
│ │ │ ├── PlaybackQueueCapabilities.proto
│ │ │ ├── PlaybackQueueCapabilities_pb2.py
│ │ │ ├── PlaybackQueueCapabilities_pb2.pyi
│ │ │ ├── PlaybackQueueContext.proto
│ │ │ ├── PlaybackQueueContext_pb2.py
│ │ │ ├── PlaybackQueueContext_pb2.pyi
│ │ │ ├── PlaybackQueueRequestMessage.proto
│ │ │ ├── PlaybackQueueRequestMessage_pb2.py
│ │ │ ├── PlaybackQueueRequestMessage_pb2.pyi
│ │ │ ├── PlaybackQueue_pb2.py
│ │ │ ├── PlaybackQueue_pb2.pyi
│ │ │ ├── PlayerClientPropertiesMessage.proto
│ │ │ ├── PlayerClientPropertiesMessage_pb2.py
│ │ │ ├── PlayerClientPropertiesMessage_pb2.pyi
│ │ │ ├── PlayerPath.proto
│ │ │ ├── PlayerPath_pb2.py
│ │ │ ├── PlayerPath_pb2.pyi
│ │ │ ├── ProtocolMessage.proto
│ │ │ ├── ProtocolMessage_pb2.py
│ │ │ ├── ProtocolMessage_pb2.pyi
│ │ │ ├── RegisterForGameControllerEventsMessage.proto
│ │ │ ├── RegisterForGameControllerEventsMessage_pb2.py
│ │ │ ├── RegisterForGameControllerEventsMessage_pb2.pyi
│ │ │ ├── RegisterHIDDeviceMessage.proto
│ │ │ ├── RegisterHIDDeviceMessage_pb2.py
│ │ │ ├── RegisterHIDDeviceMessage_pb2.pyi
│ │ │ ├── RegisterHIDDeviceResultMessage.proto
│ │ │ ├── RegisterHIDDeviceResultMessage_pb2.py
│ │ │ ├── RegisterHIDDeviceResultMessage_pb2.pyi
│ │ │ ├── RegisterVoiceInputDeviceMessage.proto
│ │ │ ├── RegisterVoiceInputDeviceMessage_pb2.py
│ │ │ ├── RegisterVoiceInputDeviceMessage_pb2.pyi
│ │ │ ├── RegisterVoiceInputDeviceResponseMessage.proto
│ │ │ ├── RegisterVoiceInputDeviceResponseMessage_pb2.py
│ │ │ ├── RegisterVoiceInputDeviceResponseMessage_pb2.pyi
│ │ │ ├── RemoteTextInputMessage.proto
│ │ │ ├── RemoteTextInputMessage_pb2.py
│ │ │ ├── RemoteTextInputMessage_pb2.pyi
│ │ │ ├── RemoveClientMessage.proto
│ │ │ ├── RemoveClientMessage_pb2.py
│ │ │ ├── RemoveClientMessage_pb2.pyi
│ │ │ ├── RemoveEndpointsMessage.proto
│ │ │ ├── RemoveEndpointsMessage_pb2.py
│ │ │ ├── RemoveEndpointsMessage_pb2.pyi
│ │ │ ├── RemoveOutputDevicesMessage.proto
│ │ │ ├── RemoveOutputDevicesMessage_pb2.py
│ │ │ ├── RemoveOutputDevicesMessage_pb2.pyi
│ │ │ ├── RemovePlayerMessage.proto
│ │ │ ├── RemovePlayerMessage_pb2.py
│ │ │ ├── RemovePlayerMessage_pb2.pyi
│ │ │ ├── SendButtonEventMessage.proto
│ │ │ ├── SendButtonEventMessage_pb2.py
│ │ │ ├── SendButtonEventMessage_pb2.pyi
│ │ │ ├── SendCommandMessage.proto
│ │ │ ├── SendCommandMessage_pb2.py
│ │ │ ├── SendCommandMessage_pb2.pyi
│ │ │ ├── SendCommandResultMessage.proto
│ │ │ ├── SendCommandResultMessage_pb2.py
│ │ │ ├── SendCommandResultMessage_pb2.pyi
│ │ │ ├── SendHIDEventMessage.proto
│ │ │ ├── SendHIDEventMessage_pb2.py
│ │ │ ├── SendHIDEventMessage_pb2.pyi
│ │ │ ├── SendPackedVirtualTouchEventMessage.proto
│ │ │ ├── SendPackedVirtualTouchEventMessage_pb2.py
│ │ │ ├── SendPackedVirtualTouchEventMessage_pb2.pyi
│ │ │ ├── SendVoiceInputMessage.proto
│ │ │ ├── SendVoiceInputMessage_pb2.py
│ │ │ ├── SendVoiceInputMessage_pb2.pyi
│ │ │ ├── SetArtworkMessage.proto
│ │ │ ├── SetArtworkMessage_pb2.py
│ │ │ ├── SetArtworkMessage_pb2.pyi
│ │ │ ├── SetConnectionStateMessage.proto
│ │ │ ├── SetConnectionStateMessage_pb2.py
│ │ │ ├── SetConnectionStateMessage_pb2.pyi
│ │ │ ├── SetDefaultSupportedCommandsMessage.proto
│ │ │ ├── SetDefaultSupportedCommandsMessage_pb2.py
│ │ │ ├── SetDefaultSupportedCommandsMessage_pb2.pyi
│ │ │ ├── SetDiscoveryModeMessage.proto
│ │ │ ├── SetDiscoveryModeMessage_pb2.py
│ │ │ ├── SetDiscoveryModeMessage_pb2.pyi
│ │ │ ├── SetHiliteModeMessage.proto
│ │ │ ├── SetHiliteModeMessage_pb2.py
│ │ │ ├── SetHiliteModeMessage_pb2.pyi
│ │ │ ├── SetNowPlayingClientMessage.proto
│ │ │ ├── SetNowPlayingClientMessage_pb2.py
│ │ │ ├── SetNowPlayingClientMessage_pb2.pyi
│ │ │ ├── SetNowPlayingPlayerMessage.proto
│ │ │ ├── SetNowPlayingPlayerMessage_pb2.py
│ │ │ ├── SetNowPlayingPlayerMessage_pb2.pyi
│ │ │ ├── SetRecordingStateMessage.proto
│ │ │ ├── SetRecordingStateMessage_pb2.py
│ │ │ ├── SetRecordingStateMessage_pb2.pyi
│ │ │ ├── SetStateMessage.proto
│ │ │ ├── SetStateMessage_pb2.py
│ │ │ ├── SetStateMessage_pb2.pyi
│ │ │ ├── SetVolumeMessage.proto
│ │ │ ├── SetVolumeMessage_pb2.py
│ │ │ ├── SetVolumeMessage_pb2.pyi
│ │ │ ├── SupportedCommands.proto
│ │ │ ├── SupportedCommands_pb2.py
│ │ │ ├── SupportedCommands_pb2.pyi
│ │ │ ├── TextInputMessage.proto
│ │ │ ├── TextInputMessage_pb2.py
│ │ │ ├── TextInputMessage_pb2.pyi
│ │ │ ├── TransactionKey.proto
│ │ │ ├── TransactionKey_pb2.py
│ │ │ ├── TransactionKey_pb2.pyi
│ │ │ ├── TransactionMessage.proto
│ │ │ ├── TransactionMessage_pb2.py
│ │ │ ├── TransactionMessage_pb2.pyi
│ │ │ ├── TransactionPacket.proto
│ │ │ ├── TransactionPacket_pb2.py
│ │ │ ├── TransactionPacket_pb2.pyi
│ │ │ ├── TransactionPackets.proto
│ │ │ ├── TransactionPackets_pb2.py
│ │ │ ├── TransactionPackets_pb2.pyi
│ │ │ ├── UpdateClientMessage.proto
│ │ │ ├── UpdateClientMessage_pb2.py
│ │ │ ├── UpdateClientMessage_pb2.pyi
│ │ │ ├── UpdateContentItemArtworkMessage.proto
│ │ │ ├── UpdateContentItemArtworkMessage_pb2.py
│ │ │ ├── UpdateContentItemArtworkMessage_pb2.pyi
│ │ │ ├── UpdateContentItemMessage.proto
│ │ │ ├── UpdateContentItemMessage_pb2.py
│ │ │ ├── UpdateContentItemMessage_pb2.pyi
│ │ │ ├── UpdateEndPointsMessage.proto
│ │ │ ├── UpdateEndPointsMessage_pb2.py
│ │ │ ├── UpdateEndPointsMessage_pb2.pyi
│ │ │ ├── UpdateOutputDeviceMessage.proto
│ │ │ ├── UpdateOutputDeviceMessage_pb2.py
│ │ │ ├── UpdateOutputDeviceMessage_pb2.pyi
│ │ │ ├── UpdatePlayerPath.proto
│ │ │ ├── UpdatePlayerPath_pb2.py
│ │ │ ├── UpdatePlayerPath_pb2.pyi
│ │ │ ├── VirtualTouchDeviceDescriptorMessage.proto
│ │ │ ├── VirtualTouchDeviceDescriptorMessage_pb2.py
│ │ │ ├── VirtualTouchDeviceDescriptorMessage_pb2.pyi
│ │ │ ├── VoiceInputDeviceDescriptorMessage.proto
│ │ │ ├── VoiceInputDeviceDescriptorMessage_pb2.py
│ │ │ ├── VoiceInputDeviceDescriptorMessage_pb2.pyi
│ │ │ ├── VolumeControlAvailabilityMessage.proto
│ │ │ ├── VolumeControlAvailabilityMessage_pb2.py
│ │ │ ├── VolumeControlAvailabilityMessage_pb2.pyi
│ │ │ ├── VolumeControlCapabilitiesDidChangeMessage.proto
│ │ │ ├── VolumeControlCapabilitiesDidChangeMessage_pb2.py
│ │ │ ├── VolumeControlCapabilitiesDidChangeMessage_pb2.pyi
│ │ │ ├── VolumeDidChangeMessage.proto
│ │ │ ├── VolumeDidChangeMessage_pb2.py
│ │ │ ├── VolumeDidChangeMessage_pb2.pyi
│ │ │ ├── WakeDeviceMessage.proto
│ │ │ ├── WakeDeviceMessage_pb2.py
│ │ │ ├── WakeDeviceMessage_pb2.pyi
│ │ │ └── __init__.py
│ │ ├── protocol.py
│ │ └── server_auth.py
│ └── raop
│ │ ├── __init__.py
│ │ ├── audio_source.py
│ │ ├── fifo.py
│ │ ├── packets.py
│ │ ├── parsers.py
│ │ ├── protocols
│ │ ├── __init__.py
│ │ ├── airplayv1.py
│ │ └── airplayv2.py
│ │ ├── stream_client.py
│ │ └── timing.py
├── py.typed
├── scripts
│ ├── __init__.py
│ ├── atvlog.py
│ ├── atvproxy.py
│ ├── atvremote.py
│ └── atvscript.py
├── settings.py
├── storage
│ ├── __init__.py
│ ├── file_storage.py
│ └── memory_storage.py
└── support
│ ├── __init__.py
│ ├── buffer.py
│ ├── cache.py
│ ├── chacha20.py
│ ├── collections.py
│ ├── device_info.py
│ ├── dns.py
│ ├── http.py
│ ├── knock.py
│ ├── metadata.py
│ ├── net.py
│ ├── opack.py
│ ├── packet.py
│ ├── pydantic_compat.py
│ ├── rtsp.py
│ ├── shield.py
│ ├── state_producer.py
│ ├── url.py
│ └── variant.py
├── pylintrc
├── pyproject.toml
├── requirements
├── requirements.txt
├── requirements_docs.txt
└── requirements_test.txt
├── scripts
├── api.py
├── audiogen.py
├── build_docs.sh
├── chickn.py
├── fake_device.py
├── features.py
├── protobuf.py
├── release.py
├── setup_dev_env.sh
└── version.py
├── setup.cfg
├── setup.py
└── tests
├── __init__.py
├── auth
└── test_hap_tlv8.py
├── common_functional_tests.py
├── conftest.py
├── core
├── test_core.py
├── test_facade.py
├── test_mdns.py
├── test_mdns_functional.py
├── test_protocol.py
├── test_relayer.py
└── test_scan.py
├── data
├── README
├── audio_10_frames.wav
├── audio_1_packet_metadata.wav
├── audio_3_packets.wav
├── only_metadata.wav
├── only_title.wav
├── static_3sec.ogg
└── testfile.txt
├── fake_device
├── __init__.py
├── airplay.py
├── companion.py
├── dmap.py
├── mrp.py
└── raop.py
├── fake_knock.py
├── fake_udns.py
├── protocols
├── airplay
│ ├── auth
│ │ ├── test_airplay_legacy_auth.py
│ │ └── test_auth.py
│ ├── conftest.py
│ ├── test_airplay.py
│ ├── test_airplay_interface.py
│ ├── test_airplay_pair.py
│ ├── test_airplay_player.py
│ ├── test_airplay_scan.py
│ ├── test_airplay_verify.py
│ └── test_utils.py
├── companion
│ ├── conftest.py
│ ├── test_companion.py
│ ├── test_companion_auth.py
│ ├── test_companion_functional.py
│ ├── test_companion_interface.py
│ └── test_companion_scan.py
├── dmap
│ ├── test_daap.py
│ ├── test_dmap.py
│ ├── test_dmap_functional.py
│ ├── test_dmap_pairing.py
│ ├── test_dmap_scan.py
│ └── test_parser.py
├── mock_protocol.py
├── mrp
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_mrp.py
│ ├── test_mrp_auth.py
│ ├── test_mrp_functional.py
│ ├── test_mrp_interface.py
│ ├── test_mrp_scan.py
│ ├── test_player_state.py
│ └── test_protocol.py
└── raop
│ ├── conftest.py
│ ├── test_fifo.py
│ ├── test_parsers.py
│ ├── test_raop.py
│ ├── test_raop_functional.py
│ └── test_raop_scan.py
├── scripts
├── conftest.py
├── test_atvremote.py
└── test_atvscript.py
├── shared_helpers.py
├── storage
└── test_memory_storage.py
├── support
├── dns_utils.py
├── pyatv.code-workspace
├── test_buffer.py
├── test_cache.py
├── test_chacha20.py
├── test_collections.py
├── test_device_info.py
├── test_dns.py
├── test_http.py
├── test_knock.py
├── test_metadata.py
├── test_net.py
├── test_opack.py
├── test_packet.py
├── test_shield.py
├── test_state_producer.py
├── test_support.py
├── test_url.py
└── test_variant.py
├── test_conf.py
├── test_convert.py
├── test_helpers.py
├── test_interface.py
├── test_scan_functional.py
├── test_storage_functional.py
├── utils.py
└── zeroconf_stub.py
/.codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | branch: master
3 |
4 | coverage:
5 | range: "80..100"
6 |
7 | status:
8 | project:
9 | default:
10 | target: auto
11 | threshold: 5%
12 |
13 | flags:
14 | library:
15 | paths:
16 | - pyatv/
17 | examples:
18 | paths:
19 | - examples/
20 | configs:
21 | paths:
22 | - ".git*"
23 | - "*.yml"
24 | changelog:
25 | - CHANGES/
26 | - CHANGES.md
27 | docs:
28 | paths:
29 | - docs/
30 | - "*.md"
31 | - "*.rst"
32 | - "*.txt"
33 | scripts:
34 | paths:
35 | - scripts/
36 | tests:
37 | paths:
38 | - tests/
39 |
--------------------------------------------------------------------------------
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | source = pyatv
3 |
4 | omit =
5 | pyatv/scripts/*.py
6 | pyatv/mrp/protobuf/*.py
7 |
8 | [report]
9 | # Regexes for lines to exclude from consideration
10 | exclude_lines =
11 | # Have to re-enable the standard pragma
12 | pragma: no cover
13 |
14 | # Don't complain about missing debug-only code:
15 | def __repr__
16 |
17 | # Don't complain if tests don't hit defensive assertion code:
18 | raise AssertionError
19 | raise NotImplementedError
20 | raise exceptions.NotSupportedError
21 |
22 | # TYPE_CHECKING and @overload blocks are never executed during pytest run
23 | if TYPE_CHECKING:
24 | @overload
25 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [postlund]
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Suggest an idea for this project
3 | labels: [feature]
4 | body:
5 | - type: textarea
6 | id: short-desc
7 | attributes:
8 | label: What feature would you like?
9 | validations:
10 | required: true
11 | - type: textarea
12 | id: solution
13 | attributes:
14 | label: Describe the solution you'd like
15 | validations:
16 | required: true
17 | - type: textarea
18 | id: other
19 | attributes:
20 | label: Any other information to share?
21 | validations:
22 | required: true
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/implementation-proposal.yml:
--------------------------------------------------------------------------------
1 | name: Implementation Proposal
2 | description: Suggest how a feature should be implemented
3 | labels: [feature]
4 | body:
5 | - type: textarea
6 | id: short-desc
7 | attributes:
8 | label: Short feature/function description
9 | validations:
10 | required: true
11 | - type: textarea
12 | id: to-be-done
13 | attributes:
14 | label: What needs to be done?
15 | validations:
16 | required: true
17 | - type: textarea
18 | id: breaking-change
19 | attributes:
20 | label: Is this a breaking change?
21 | validations:
22 | required: true
23 | - type: textarea
24 | id: other
25 | attributes:
26 | label: Anything else worth knowing?
27 | validations:
28 | required: true
29 |
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/investigation.yml:
--------------------------------------------------------------------------------
1 | name: Investigation
2 | description: Use for investigations or if something is unclear before creating an implementation proposal
3 | labels: [investigate]
4 | body:
5 | - type: textarea
6 | id: to-investigate
7 | attributes:
8 | label: What to investigate?
9 | validations:
10 | required: true
11 | - type: textarea
12 | id: expected-outcome
13 | attributes:
14 | label: Expected outcome
15 | validations:
16 | required: true
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/minor-change.yml:
--------------------------------------------------------------------------------
1 | name: Minor Change
2 | description: Use this to suggest minor changes to code or documentation.
3 | body:
4 | - type: textarea
5 | id: minor-change
6 | attributes:
7 | label: What to change?
8 | description: Please describe in as much detail as possible what to change.
9 | validations:
10 | required: true
11 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question-or-idea.yml:
--------------------------------------------------------------------------------
1 | name: Question or support
2 | description: If you are using pyatv and have questions regarding how to use it in any way (e.g. development), use this template.
3 | labels: [question]
4 | body:
5 | - type: textarea
6 | id: question-support
7 | attributes:
8 | label: What do you need help with?
9 | description: Please enter your question below. Make sure to include software versions, error logs, etc. when applicable. The more information you provide, the easier it will be to help.
10 | validations:
11 | required: true
12 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: pip
4 | directory: "/requirements"
5 | schedule:
6 | interval: daily
7 | time: "04:00"
8 | open-pull-requests-limit: 10
9 | reviewers:
10 | - postlund
11 | assignees:
12 | - postlund
13 | labels:
14 | - dependencies
15 | - package-ecosystem: docker
16 | directory: /
17 | schedule:
18 | interval: daily
19 | time: "04:00"
20 | open-pull-requests-limit: 3
21 | reviewers:
22 | - postlund
23 | assignees:
24 | - postlund
25 | labels:
26 | - dependencies
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # File based on .gitignore from home-assistant.io
2 |
3 | # Hide sublime text stuff
4 | *.sublime-project
5 | *.sublime-workspace
6 |
7 | # Hide some OS X stuff
8 | .DS_Store
9 | .AppleDouble
10 | .LSOverride
11 | Icon
12 |
13 | # Thumbnails
14 | ._*
15 |
16 | .idea
17 |
18 | # pytest
19 | .cache
20 |
21 | # GITHUB Proposed Python stuff:
22 | *.py[cod]
23 |
24 | # C extensions
25 | *.so
26 |
27 | # Packages
28 | *.egg
29 | *.egg-info
30 | dist
31 | build
32 | eggs
33 | .eggs
34 | parts
35 | bin
36 | var
37 | sdist
38 | develop-eggs
39 | .installed.cfg
40 | lib
41 | lib64
42 | include
43 |
44 | # Logs
45 | *.log
46 | pip-log.txt
47 |
48 | # Unit test / coverage reports
49 | .coverage*
50 | .tox
51 | nosetests.xml
52 |
53 | # Translations
54 | *.mo
55 |
56 | # Mr Developer
57 | .mr.developer.cfg
58 | .project
59 | .pydevproject
60 |
61 | .python-version
62 |
63 | # emacs auto backups
64 | *~
65 | *#
66 | *.orig
67 |
68 | # venv stuff
69 | pyvenv.cfg
70 | pip-selfcheck.json
71 | venv
72 | .venv
73 |
74 | # vimmy stuff
75 | *.swp
76 | *.swo
77 |
78 | ctags.tmp
79 |
80 | # vagrant stuff
81 | virtualization/vagrant/setup_done
82 | virtualization/vagrant/.vagrant
83 | virtualization/vagrant/config
84 |
85 | # Visual Studio Code
86 | .vscode
87 |
88 | # Windows Explorer
89 | desktop.ini
90 |
91 | # Other directories
92 | share
93 | htmlcov
94 |
95 | artwork.png
96 | .Python
97 | .pytest_cache
98 | .mypy_cache
99 | coverage.xml
100 |
101 | # Temporary stuff can be placed here (logs, credentials, etc.)
102 | work/
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 | image: gitpod/workspace-full
2 | tasks:
3 | - name: Documentation
4 | command: ./scripts/build_docs.sh
5 | - name: Development
6 | before: "echo 'export PIP_USER=no' >> ~/.bashrc && export PIP_USER=no"
7 | init: ./scripts/setup_dev_env.sh && source bin/activate; python scripts/chickn.py
8 | command: source bin/activate
9 |
10 | ports:
11 | - port: 4000 # Used for documentation
12 | onOpen: open-preview
13 | visibility: private
14 |
15 | vscode:
16 | extensions:
17 | - ms-python.python
18 | - hbenl.test-adapter-converter
19 | - hbenl.vscode-test-explorer
20 |
21 | github:
22 | prebuilds:
23 | addBadge: true
24 |
--------------------------------------------------------------------------------
/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | # Contributors
2 |
3 | See [this page](https://pyatv.dev/support/acknowledgements/#contributors)
4 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.13.2-alpine
2 | ARG VERSION
3 |
4 | WORKDIR .
5 | COPY dist/pyatv-${VERSION}-py3-none-any.whl .
6 | COPY requirements/requirements.txt .
7 |
8 | RUN apk add gcc musl-dev build-base linux-headers libffi-dev rust cargo openssl-dev git && \
9 | pip install setuptools-rust && \
10 | pip install -r requirements.txt && \
11 | pip install pyatv-${VERSION}-py3-none-any.whl && \
12 | apk del gcc musl-dev build-base linux-headers libffi-dev rust cargo openssl-dev git && \
13 | rm pyatv-${VERSION}-py3-none-any.whl && \
14 | rm requirements.txt && \
15 | rm -rf /root/.cache /root/.cargo
16 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 |
3 | Copyright (c) 2020 Pierre Ståhl
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include CHANGES.md
2 | include README.md
3 | include LICENSE.md
4 | include CONTRIBUTORS.md
5 | include base_versions.txt
6 | graft pyatv
7 | graft tests
8 | graft docs
9 | graft examples
10 | global-exclude *~ __pycache__
11 | recursive-exclude * *.py[co] .*
12 | prune docs/vendor
13 | prune docs/_site
14 | prune docs/.sass-cache
15 |
--------------------------------------------------------------------------------
/base_versions.txt:
--------------------------------------------------------------------------------
1 | aiohttp==3.8.3,<5
2 | async-timeout==4.0.2
3 | cryptography==44.0.1
4 | chacha20poly1305-reuseable==0.13.2
5 | ifaddr==0.1.7
6 | miniaudio==1.45
7 | protobuf==6.30.2
8 | pydantic==1.10.10
9 | requests==2.30.0
10 | srptools==0.2.0
11 | tabulate==0.9.0
12 | tinytag==1.10.0
13 | zeroconf==0.129.0
14 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | .sass-cache
3 | .jekyll-metadata
4 | vendor
5 | Gemfile.lock
--------------------------------------------------------------------------------
/docs/404.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | ---
4 |
5 |
18 |
19 |
20 |
404
21 |
22 |
Page not found :(
23 |
The requested page could not be found.
24 |
25 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | pyatv.dev
--------------------------------------------------------------------------------
/docs/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | # Hello! This is where you manage which Jekyll version is used to run.
4 | # When you want to use a different version, change it below, save the
5 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
6 | #
7 | # bundle exec jekyll serve
8 | #
9 | # This will help ensure the proper Jekyll version is running.
10 | # Happy Jekylling!
11 |
12 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
13 | # uncomment the line below. To upgrade, run `bundle update github-pages`.
14 | gem "github-pages", group: :jekyll_plugins
15 |
16 | # If you have any plugins, put them here!
17 | group :jekyll_plugins do
18 | gem "jekyll-feed", "~> 0.6"
19 | gem "jemoji"
20 | end
21 |
22 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
23 | # and associated library.
24 | install_if -> { RUBY_PLATFORM =~ %r!mingw|mswin|java! } do
25 | gem "tzinfo", "~> 1.2"
26 | gem "tzinfo-data"
27 | end
28 |
29 | # Performance-booster for watching directories on Windows
30 | gem "wdm", "~> 0.1.0", :install_if => Gem.win_platform?
31 |
32 |
--------------------------------------------------------------------------------
/docs/_includes/api:
--------------------------------------------------------------------------------
1 | {%- assign module = include.i | split: "." | first -%}
2 | {%- if module == "pyatv" -%}
3 | {%- assign module = "" -%}
4 | {%- assign path = "#" | append: include.i | replace: "/", "." -%}
5 | {%- else -%}
6 | {%- assign path = "#pyatv." | append: include.i | replace: "/", "." -%}
7 | {%- endif -%}
8 | {%- assign url = '/api/' | append: module | append: path | relative_url -%}
9 | {%- assign path = include.i | replace: "/", "." -%}
10 | {{ 'PATH' | replace: "URL", url | replace: "PATH", path }}
--------------------------------------------------------------------------------
/docs/_includes/atvremote_scan:
--------------------------------------------------------------------------------
1 | ```raw
2 | $ atvremote acan
3 | Scan Results
4 | ========================================
5 | Name: Living Room
6 | Model/SW: Apple TV 4K, tvOS 16.6 build 20M73
7 | Address: 10.0.0.5
8 | MAC: AA:BB:CC:DD:EE:FF
9 | Deep Sleep: True
10 | Identifiers:
11 | - 01234567-89AB-CDEF-0123-4567890ABCDE
12 | - AA:BB:CC:DD:EE:FF
13 | - 01234567-89AB-CDEF-0123-AAAAAAAAAAAA
14 | - AABBCCDDEEFF
15 | Services:
16 | - Protocol: Companion, Port: 49153, Credentials:None, Requires Password: False, Password: None, Pairing: Mandatory
17 | - Protocol: AirPlay, Port: 7000, Credentials: None, Requires Password: False, Password: None, Pairing: Mandatory
18 | - Protocol: MRP, Port: 49154, Credentials: None, Requires Password: False, Password: None, Pairing: NotNeeded (Disabled)
19 | - Protocol: RAOP, Port: 7000, Credentials: None, Requires Password: False, Password: None, Pairing: Mandatory
20 |
21 | Name: Pierre's AirPort Express
22 | Model/SW: AirPort Express (gen 2), AirPortOS 7.8.1
23 | Address: 10.0.0.6
24 | MAC: BB:BB:BB:BB:BB:BB
25 | Deep Sleep: False
26 | Identifiers:
27 | - BB:BB:BB:BB:BB:BB
28 | - BBBBBBBBBBBB
29 | Services:
30 | - Protocol: AirPlay, Port: 7000, Credentials: None, Requires Password: False, Password: None, Pairing: NotNeeded
31 | - Protocol: RAOP, Port: 7000, Credentials: None, Requires Password: False, Password: None, Pairing: NotNeeded
32 | ```
--------------------------------------------------------------------------------
/docs/_includes/code:
--------------------------------------------------------------------------------
1 | {%- assign file = include.file -%}
2 | {%- assign name = file | replace: "_", "\_" | replace: "../", "" -%}
3 | {%- capture link -%}
4 | {{ name }}
5 | {%- endcapture -%}
6 | {{ link }}
--------------------------------------------------------------------------------
/docs/_includes/issue:
--------------------------------------------------------------------------------
1 | {%- assign numbers = include.no | split: "," -%}
2 | {%- assign output = Nil -%}
3 | {%- for number in numbers -%}
4 | {%- capture link -%}
5 | #{{ number }}
6 | {%- endcapture -%}
7 |
8 | {%- if output == Nil -%}
9 | {%- assign output = link -%}
10 | {%- else -%}
11 | {%- assign output = output | append: ", " | append: link -%}
12 | {%- endif -%}
13 | {%- endfor -%}
14 | [{{ output }}]
--------------------------------------------------------------------------------
/docs/_includes/pypi:
--------------------------------------------------------------------------------
1 | {%- assign package = include.package -%}
2 | {%- capture link -%}
3 | {{ package }}
4 | {%- endcapture -%}
5 | {{ link }}
--------------------------------------------------------------------------------
/docs/assets/css/custom.css:
--------------------------------------------------------------------------------
1 | .center_box {
2 | margin: 0 auto;
3 | display: table;
4 | border: 1px solid #606c71;
5 | background: #f3f6fa;
6 | padding: 1em 3em 1em 3em;
7 | border-radius: 5px;
8 | font-weight: bold;
9 | text-align: center
10 | }
11 |
12 | .center_box p {
13 | margin: 0px
14 | }
15 |
16 | .api_feature {
17 | font-style: italic;
18 | margin-bottom: 1em;
19 | }
--------------------------------------------------------------------------------
/docs/assets/css/hljs.css:
--------------------------------------------------------------------------------
1 | .hljs{display:block;overflow-x:auto;padding:0.5em;color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:bold}.hljs-number,.hljs-literal,.hljs-variable,.hljs-template-variable,.hljs-tag .hljs-attr{color:#008080}.hljs-string,.hljs-doctag{color:#d14}.hljs-title,.hljs-section,.hljs-selector-id{color:#900;font-weight:bold}.hljs-subst{font-weight:normal}.hljs-type,.hljs-class .hljs-title{color:#458;font-weight:bold}.hljs-tag,.hljs-name,.hljs-attribute{color:#000080;font-weight:normal}.hljs-regexp,.hljs-link{color:#009926}.hljs-symbol,.hljs-bullet{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:bold}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}
--------------------------------------------------------------------------------
/docs/assets/css/style.scss:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | @import "{{ site.theme }}";
5 | @import "sanitize.css";
6 | @import "normalize.css";
7 | @import "hljs.css";
8 | @import "pdoc.css";
9 | @import "custom.css";
--------------------------------------------------------------------------------
/docs/development/audio.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: Audio
4 | permalink: /development/audio/
5 | link_group: development
6 | ---
7 | # Audio
8 |
9 | Protocols supporting volume controls can be controlled via the audio interface.
10 |
11 | ## Using the Audio API
12 |
13 | After connecting to a device, you get the apps interface via {% include api i="interface.AppleTV.audio" %}:
14 |
15 | ```python
16 | atv = await pyatv.connect(config, ...)
17 | audio = atv.audio
18 | ```
19 |
20 | To get current volume level, use {% include api i="interface.Audio.volume" %}:
21 |
22 | ```python
23 | print("Volume:", audio.volume)
24 | ```
25 |
26 | To change current volume, use {% include api i="interface.Audio.set_volume" %}:
27 |
28 | ```python
29 | await audio.set_volume(20.0)
30 | ```
31 |
32 | The volume level is normalized in the interval 0.0-100.0, where 0.0 means
33 | the audio is muted.
34 |
35 | You can also step volume up or down using step level provided from the device (if available):
36 |
37 | ```python
38 | await audio.volume_up()
39 | await audio.volume_down()
40 | ```
41 |
42 | The audio API supports push updates via a listener, as described [here](../listeners#audio-updates).
43 |
--------------------------------------------------------------------------------
/docs/development/control.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: Control
4 | permalink: /development/control/
5 | link_group: development
6 | ---
7 | # Control
8 |
9 | Controlling a device is done with the remote control interface,
10 | {% include api i="interface.RemoteControl" %}. It allows you navigate the menus and
11 | change playback (play, pause, etc.).
12 |
13 | ## Using the Remote Control API
14 |
15 | After connecting to a device, you get the remote control via {% include api i="interface.AppleTV.remote_control" %}:
16 |
17 | ```python
18 | atv = await pyatv.connect(config, ...)
19 | rc = atv.remote_control
20 | ```
21 |
22 | You can then control via the available functions:
23 |
24 | ```python
25 | await rc.up()
26 | await rc.select()
27 | await rc.volume_up()
28 | await rc.set_position(100)
29 | ```
30 |
31 | All available actions can be found in {% include api i="interface.RemoteControl" %}.
32 |
33 | ## Input Actions
34 |
35 | Currently three types of input actions are supported:
36 |
37 | * Single tap ("click")
38 | * Double tap ("double click")
39 | * Hold
40 |
41 | These actions are supported by the following buttons:
42 |
43 | * Arrow keys (up, down, left, right)
44 | * Select
45 | * Menu
46 | * Home
47 |
48 | By default, {% include api i="const.InputAction.SingleTap" %} are used. Pass another `action`
49 | to use another input action:
50 |
51 | ```python
52 | await rc.menu(action=InputAction.Hold)
53 | await rc.home(action=InputAction.DoubleTap)
54 | ```
55 |
56 | All input actions are specified in {% include api i="const.InputAction" %}.
--------------------------------------------------------------------------------
/docs/development/development.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: Development
4 | permalink: /development/
5 | link_group: development
6 | ---
7 | # :construction_worker: Development
8 |
9 | These sections cover the basics on how you develop with pyatv.
10 | So if you are a developer and want to create some software that
11 | controls an Apple TV, you are in the right place.
12 |
13 | If you instead want develop pyatv itself, there are details for
14 | that over at the GitHub wiki. Click
15 | [here](https://github.com/postlund/pyatv/wiki) to go there.
16 |
--------------------------------------------------------------------------------
/docs/development/device_info.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: Device Information
4 | permalink: /development/device_info/
5 | link_group: development
6 | ---
7 | # Device Information
8 |
9 | pyatv can extract various information about a device, e.g. which
10 | operating system (and version) it runs or its hardware model (3, 4K, etc.).
11 | This information is exposed via the interface {% include api i="interface.DeviceInfo" %}.
12 |
13 | ## Using the Device Information API
14 |
15 | After connecting to a device, you get device info via {% include api i="interface.AppleTV.device_info" %}:
16 |
17 | ```python
18 | atv = await pyatv.connect(config, ...)
19 | devinfo = atv.device_info
20 | ```
21 |
22 | You can then access the actual information via properties:
23 |
24 | ```python
25 | print(devinfo.operating_system)
26 | print(devinfo.version)
27 | print(devinfo.mac)
28 | ```
29 |
30 | Just printing `devinfo` will produce a summary of the device information
31 | (MAC-address is not included here):
32 |
33 | ```python
34 | >>> print(devinfo)
35 | 4K tvOS 13.3.1 build 17K795
36 | ```
--------------------------------------------------------------------------------
/docs/development/keyboard.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: Keyboard
4 | permalink: /development/keyboard/
5 | link_group: development
6 | ---
7 | # Keyboard
8 |
9 | It is possible to interact with the Apple TV virtual keyboard via the Keyboard interface.
10 | To use this interface, the Companion protocol must be available.
11 |
12 | ## Using the Keyboard API
13 |
14 | After connecting to a device, you get the keyboard interface via {% include api i="interface.AppleTV.keyboard" %}:
15 |
16 | ```python
17 | atv = await pyatv.connect(config, ...)
18 | keyboard = atv.keyboard
19 | ```
20 |
21 | To check whether the virtual keyboard is focused and active, use {% include api i="interface.Keyboard.text_focus_state" %}:
22 |
23 | ```python
24 | print("Keyboard focus state:", keyboard.text_focus_state)
25 | ```
26 |
27 | To fetch the current virtual keyboard text content, use {% include api i="interface.Keyboard.text_get" %}:
28 |
29 | ```python
30 | print("Keyboard text:", await keyboard.text_get())
31 | ```
32 |
33 | To set (replace) the virtual keyboard text, use {% include api i="interface.Keyboard.text_set" %}:
34 |
35 | ```python
36 | await keyboard.text_set("text to set")
37 | ```
38 |
39 | To append to the virtual keyboard text, use {% include api i="interface.Keyboard.text_append" %}:
40 |
41 | ```python
42 | await keyboard.text_append("text to append")
43 | ```
44 |
45 | Finally, to clear the virtual keyboard text, use {% include api i="interface.Keyboard.text_clear" %}:
46 |
47 | ```python
48 | await keyboard.text_clear()
49 | ```
50 |
51 | The keyboard API supports push updates via a listener, as described [here](../listeners#keyboard-updates).
52 |
--------------------------------------------------------------------------------
/docs/development/logging.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: Logging
4 | permalink: /development/logging/
5 | link_group: development
6 | ---
7 | # Logging
8 |
9 | In case you need to troubleshoot something, you can enable additional log points in pyatv.
10 | This page describes how you do that.
11 |
12 | # Log points
13 |
14 | To enable full logging, use this:
15 |
16 | ```python
17 | logging.basicConfig(
18 | level=logging.DEBUG,
19 | datefmt="%Y-%m-%d %H:%M:%S",
20 | format="%(asctime)s %(levelname)s [%(name)s]: %(message)s",
21 | )
22 | ```
23 |
24 | This output format is preferred as it is compatible with [atvlog](../../documentation/atvlog) and
25 | contains the most useful information.
26 |
27 | In case you need to troubleshoot MDNS/Zeroconf traffic, use this:
28 |
29 | ```python
30 | logging.getLogger(
31 | "pyatv.support.mdns"
32 | ).level = logging.TRAFFIC # pylint: disable=no-member
33 | ```
34 |
35 | *NOTE: This section is WIP for now as most interesting log points are internal. In the future,
36 | a `log` module will be added to simplify enabling log points.*
37 |
38 | # Bundled scripts
39 |
40 | You can enable additional debugging information by specifying either `--verbose` or `--debug.`.
41 |
42 | # Output line cropping
43 |
44 | By default pyatv will limit some log points in length, mainly due to an excessive amount of
45 | data might be logged otherwise. This mainly applies to binary data (raw protocol data) and
46 | protobuf messages. These limits can be overridden by setting the following environment variables:
47 |
48 | ```shell
49 | $ export PYATV_BINARY_MAX_LINE=1000
50 | $ export PYATV_PROTOBUF_MAX_LINE=1000
51 | $ atvremote --debug ... playing
52 | ```
53 |
54 | In general, you shouldn't have to change these, but under some cicrumstances the complete
55 | logs might be deseriable.
56 |
--------------------------------------------------------------------------------
/docs/development/power_management.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: Power Management
4 | permalink: /development/power_management/
5 | link_group: development
6 | ---
7 | # Power Management
8 |
9 | Power management of a device is done with the power interface,
10 | {% include api i="interface.Power" %}. It allows you to turn on, turn off and get current
11 | power state. This interface is currently only supported by devices running tvOS.
12 |
13 | ## Using the Power Management API
14 |
15 | After connecting to a device, you get the power management via {% include api i="interface.AppleTV.power" %}:
16 |
17 | ```python
18 | atv = await pyatv.connect(config, ...)
19 | pwrc = atv.power
20 | ```
21 |
22 | You can then control via the available functions:
23 |
24 | ```python
25 | await pwrc.turn_on()
26 | await pwrc.turn_off()
27 | ```
28 |
29 | To get current power state use following property:
30 |
31 | ```python
32 | @property
33 | def power_state(self) -> const.PowerState:
34 | ```
35 |
36 | ## Waiting for State Change
37 |
38 | It is possible to pass `await_new_state` set to `True` when turning on
39 | or off a device to have pyatv wait for a state change. E.g. calling
40 | {% include api i="interface.Power.turn_off" %} will block until the device
41 | has powered off:
42 |
43 | ```python
44 | await pwrc.turn_off(await_new_state=True)
45 | ```
46 |
47 | If the device is already off, it will return immediately.
48 |
49 | To not block indefinitely, use `wait_for` with a timeout:
50 |
51 | ```python
52 | await asyncio.wait_for(pwrc.turn_off(await_new_state=True), timeout=5)
53 | ```
54 |
--------------------------------------------------------------------------------
/docs/development/services.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: Services
4 | permalink: /development/services/
5 | link_group: development
6 | ---
7 | # Services
8 |
9 | This page has not yet been migrated to GitHub Pages. Come back later...
--------------------------------------------------------------------------------
/docs/development/testing.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: Services
4 | permalink: /development/testing/
5 | link_group: development
6 | ---
7 | # Testing
8 |
9 | This page has not yet been migrated to GitHub Pages. Come back later...
--------------------------------------------------------------------------------
/docs/documentation/atvlog.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: atvlog
4 | permalink: /documentation/atvlog/
5 | link_group: documentation
6 | ---
7 | # Table of Contents
8 | {:.no_toc}
9 | * TOC
10 | {:toc}
11 |
12 | # atvlog
13 |
14 | The `atvlog` script simplifies log inspection by generating an HTML file with basic
15 | live filtering capabilities.
16 |
17 | *Note: This is an incubating script and may change behavior with short notice.*
18 |
19 | # Features
20 |
21 | Log output from the following tools are supported as input:
22 |
23 | * atvremote and atvscript
24 | * Home Assistant log
25 |
26 | A special `markdown` mode is supported, which extracts a log from the following
27 | format:
28 |
29 | ~~~
30 | text here is ignored
31 | ```log
32 | log data here
33 | ```
34 | also ignored
35 | ~~~
36 |
37 | Filtering can be performed on the following attributes:
38 |
39 | * Include entries based on regexp
40 | * Exclude entries based on regexp (performed prior to include regexp)
41 | * Log levels
42 | * Date can be stripped for more compact log
43 |
44 | # Serving output via web server
45 |
46 | It is possible to serve the generated log output via a built in web server using flag `-w`:
47 |
48 | ```shell
49 | $ atvlog -w pyatv.log
50 | Press ENTER to quit
51 | ```
52 |
53 | Then visit `http://:8008` to see the log. The port number can be changed
54 | with `-p xxxx`.
55 |
56 | # Examples
57 |
58 | ```shell
59 | $ atvlog pyatv.log # Print output to stdout
60 | $ atvlog --output pyatv.html pyatv.log
61 | $ cat pyatv.log | atvlog - # Read from stdin
62 | $ cat markdown.log | atvlog --format=markdown -
63 | ```
64 |
65 |
--------------------------------------------------------------------------------
/docs/documentation/workspace.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "../.."
5 | }
6 | ]
7 | }
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/postlund/pyatv/2fbdbd444b80048876e2ab6726ac945901e883b4/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/support/support.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: template
3 | title: Support
4 | permalink: /support/
5 | link_group: support
6 | ---
7 | # :fire: Support
8 |
9 | If you are having problems or questions, this section aims to help you.
10 | Check out the subpages above.
11 |
12 | In case you have found a potential bug or need help, please write issues on GitHub:
13 |
14 | **:bug: [I have found a bug](https://github.com/postlund/pyatv/issues/new?assignees=&labels=bug&template=bug_report.md&title=)**
15 |
16 | **:raised_hands: [I need help](https://github.com/postlund/pyatv/issues/new?assignees=&labels=question&template=question-or-idea.md&title=)**
17 |
18 | **:question: [Something is missing...](https://github.com/postlund/pyatv/issues/new?assignees=&labels=feature&template=feature_request.md&title=)**
--------------------------------------------------------------------------------
/examples/__init__.py:
--------------------------------------------------------------------------------
1 | """Package with pyatv examples."""
2 |
--------------------------------------------------------------------------------
/examples/auto_connect.py:
--------------------------------------------------------------------------------
1 | """Simple example that connects to a device with autodiscover."""
2 |
3 | import asyncio
4 |
5 | from pyatv import helpers
6 |
7 |
8 | # Method that is dispatched by the asyncio event loop
9 | async def print_what_is_playing(atv):
10 | """Print what is playing for the discovered device."""
11 | playing = await atv.metadata.playing()
12 | print("Currently playing:")
13 | print(playing)
14 |
15 |
16 | asyncio.get_event_loop().run_until_complete(helpers.auto_connect(print_what_is_playing))
17 |
--------------------------------------------------------------------------------
/examples/connect_with_credentials.py:
--------------------------------------------------------------------------------
1 | """Find a specific device, restore credentials and connect.
2 |
3 | Call script like this:
4 |
5 | python connect_with_credentials.py 0
6 |
7 | This connect to the first device in DEVICES (index 0). If you add
8 | another device, use 1 instead of 0 and so on. You can easily
9 | look up based on name as well (not demonstrated here).
10 | """
11 |
12 | import asyncio
13 | import sys
14 |
15 | import pyatv
16 | from pyatv.const import Protocol
17 |
18 | LOOP = asyncio.get_event_loop()
19 |
20 | # This can be stored in a file for instance
21 | DEVICES = [
22 | {
23 | "name": "Living Room",
24 | "identifiers": {"aabbccddeeff", "123456789"},
25 | "credentials": {
26 | Protocol.AirPlay: "abcdef",
27 | Protocol.Companion: "foobar",
28 | Protocol.RAOP: "123456",
29 | },
30 | },
31 | # Add more devices here
32 | ]
33 |
34 |
35 | async def print_what_is_playing(device, loop):
36 | """Find a device and print what is playing."""
37 | print(f"Discovering {device['name']} on network...")
38 | confs = await pyatv.scan(loop, identifier=device["identifiers"])
39 |
40 | if not confs:
41 | print("Device could not be found", file=sys.stderr)
42 | return
43 |
44 | conf = confs[0]
45 | for protocol, credentials in device["credentials"].items():
46 | conf.set_credentials(protocol, credentials)
47 |
48 | print(f"Connecting to {conf.address}")
49 | atv = await pyatv.connect(conf, loop)
50 |
51 | try:
52 | playing = await atv.metadata.playing()
53 | print("Currently playing:")
54 | print(playing)
55 | finally:
56 | await asyncio.gather(*atv.close())
57 |
58 |
59 | if __name__ == "__main__":
60 | LOOP.run_until_complete(print_what_is_playing(DEVICES[int(sys.argv[1])], LOOP))
61 |
--------------------------------------------------------------------------------
/examples/manual_connect.py:
--------------------------------------------------------------------------------
1 | """Simple example that shows how to manually connect to an Apple TV."""
2 |
3 | import asyncio
4 |
5 | from pyatv import conf, connect
6 | from pyatv.const import Protocol
7 |
8 | # Enter config used to connect
9 | NAME = "My Apple TV"
10 | ADDRESS = "10.0.10.22"
11 | HSGID = "00000000-1111-2222-3333-444444444444"
12 |
13 | LOOP = asyncio.get_event_loop()
14 |
15 |
16 | # Method that is dispatched by the asyncio event loop
17 | async def print_what_is_playing(loop):
18 | """Connect to device and print what is playing."""
19 | config = conf.AppleTV(ADDRESS, NAME)
20 | config.add_service(
21 | conf.ManualService("some_id", Protocol.DMAP, 3689, {}, credentials=HSGID)
22 | )
23 |
24 | print(f"Connecting to {config.address}")
25 | atv = await connect(config, loop)
26 |
27 | try:
28 | print(await atv.metadata.playing())
29 | finally:
30 | # Do not forget to close
31 | atv.close()
32 |
33 |
34 | if __name__ == "__main__":
35 | # Setup event loop and connect
36 | LOOP.run_until_complete(print_what_is_playing(LOOP))
37 |
--------------------------------------------------------------------------------
/examples/pairing.py:
--------------------------------------------------------------------------------
1 | """Simple example showing of pairing."""
2 |
3 | import asyncio
4 | import sys
5 |
6 | from pyatv import pair, scan
7 | from pyatv.const import Protocol
8 |
9 | LOOP = asyncio.get_event_loop()
10 |
11 |
12 | # Method that is dispatched by the asyncio event loop
13 | async def pair_with_device(loop):
14 | """Make it possible to pair with device."""
15 | atvs = await scan(loop, timeout=5, protocol=Protocol.AirPlay)
16 |
17 | if not atvs:
18 | print("No device found", file=sys.stderr)
19 | return
20 |
21 | pairing = await pair(atvs[0], Protocol.MRP, loop)
22 | await pairing.begin()
23 |
24 | pin = int(input("Enter PIN: "))
25 | pairing.pin(pin)
26 | await pairing.finish()
27 |
28 | # Give some feedback about the process
29 | if pairing.has_paired:
30 | print("Paired with device!")
31 | print("Credentials:", pairing.service.credentials)
32 | else:
33 | print("Did not pair with device!")
34 |
35 | await pairing.close()
36 |
37 |
38 | if __name__ == "__main__":
39 | # Setup event loop and connect
40 | LOOP.run_until_complete(pair_with_device(LOOP))
41 |
--------------------------------------------------------------------------------
/examples/play_url.py:
--------------------------------------------------------------------------------
1 | """Example of playing a video file via AirPlay.
2 |
3 | python play_url.py
4 | """
5 |
6 | import asyncio
7 | import sys
8 |
9 | import pyatv
10 | from pyatv.const import Protocol
11 |
12 |
13 | async def play_url(
14 | device_id: str, airplay_credentials: str, url: str, loop: asyncio.AbstractEventLoop
15 | ):
16 | """Connect to an Apple TV and stream file via AirPlay."""
17 | print("* Discovering device on network...")
18 | atvs = await pyatv.scan(loop, identifier=device_id)
19 | if not atvs:
20 | print("* Device found", file=sys.stderr)
21 | return
22 |
23 | conf = atvs[0]
24 | conf.set_credentials(Protocol.AirPlay, airplay_credentials)
25 | atv = await pyatv.connect(conf, loop)
26 |
27 | try:
28 | print(f"* Streaming {url} to {conf.address}")
29 | await atv.stream.play_url(url)
30 | finally:
31 | await atv.close()
32 |
33 |
34 | if __name__ == "__main__":
35 | asyncio.get_event_loop().run_until_complete(
36 | play_url(sys.argv[1], sys.argv[2], sys.argv[3], asyncio.get_event_loop())
37 | )
38 |
--------------------------------------------------------------------------------
/examples/scan_and_connect.py:
--------------------------------------------------------------------------------
1 | """Simple example that scans for devices and connects to first one found."""
2 |
3 | import asyncio
4 | import sys
5 |
6 | import pyatv
7 |
8 | LOOP = asyncio.get_event_loop()
9 |
10 |
11 | # Method that is dispatched by the asyncio event loop
12 | async def print_what_is_playing(loop):
13 | """Find a device and print what is playing."""
14 | print("Discovering devices on network...")
15 | atvs = await pyatv.scan(loop, timeout=5)
16 |
17 | if not atvs:
18 | print("No device found", file=sys.stderr)
19 | return
20 |
21 | print(f"Connecting to {atvs[0].address}")
22 | atv = await pyatv.connect(atvs[0], loop)
23 |
24 | try:
25 | playing = await atv.metadata.playing()
26 | print("Currently playing:")
27 | print(playing)
28 | finally:
29 | # Do not forget to close
30 | atv.close()
31 |
32 |
33 | if __name__ == "__main__":
34 | # Setup event loop and connect
35 | LOOP.run_until_complete(print_what_is_playing(LOOP))
36 |
--------------------------------------------------------------------------------
/examples/storage.py:
--------------------------------------------------------------------------------
1 | """Simple example using file based storage."""
2 |
3 | import asyncio
4 | import sys
5 |
6 | from pyatv import connect, scan
7 | from pyatv.storage.file_storage import FileStorage
8 |
9 | LOOP = asyncio.get_event_loop()
10 |
11 |
12 | async def connect_with_storage(host):
13 | """Connect to a device using a storage."""
14 | loop = asyncio.get_event_loop()
15 |
16 | # Load the same storage that pyatv uses internally (e.g. in atvremote)
17 | storage = FileStorage.default_storage(loop)
18 | await storage.load()
19 |
20 | atvs = await scan(loop, timeout=5, hosts=[host], storage=storage)
21 |
22 | if not atvs:
23 | print("Device not found", file=sys.stderr)
24 | return
25 |
26 | atv = await connect(atvs[0], loop, storage=storage)
27 | print(await atv.metadata.playing())
28 |
29 | atv.close()
30 |
31 |
32 | if __name__ == "__main__":
33 | asyncio.run(connect_with_storage(sys.argv[1]))
34 |
--------------------------------------------------------------------------------
/examples/stream.py:
--------------------------------------------------------------------------------
1 | """Example of streaming a file and printing status updates.
2 |
3 | python stream.py 10.0.0.4 file.mp3
4 | """
5 |
6 | import asyncio
7 | import sys
8 |
9 | import pyatv
10 | from pyatv.interface import Playing, PushListener
11 |
12 | LOOP = asyncio.get_event_loop()
13 |
14 |
15 | class PushUpdatePrinter(PushListener):
16 | """Print push updates to console."""
17 |
18 | def playstatus_update(self, updater, playstatus: Playing) -> None:
19 | """Inform about changes to what is currently playing."""
20 | print(30 * "-" + "\n", playstatus)
21 |
22 | def playstatus_error(self, updater, exception: Exception) -> None:
23 | """Inform about an error when updating play status."""
24 | print("Error:", exception)
25 |
26 |
27 | async def stream_with_push_updates(
28 | address: str, filename: str, loop: asyncio.AbstractEventLoop
29 | ):
30 | """Find a device and print what is playing."""
31 | print("* Discovering device on network...")
32 | atvs = await pyatv.scan(loop, hosts=[address], timeout=5)
33 |
34 | if not atvs:
35 | print("* Device found", file=sys.stderr)
36 | return
37 |
38 | conf = atvs[0]
39 |
40 | print("* Connecting to", conf.address)
41 | atv = await pyatv.connect(conf, loop)
42 |
43 | listener = PushUpdatePrinter()
44 | atv.push_updater.listener = listener
45 | atv.push_updater.start()
46 |
47 | try:
48 | print("* Starting to stream", filename)
49 | await atv.stream.stream_file(filename)
50 | await asyncio.sleep(1)
51 | finally:
52 | atv.close()
53 |
54 |
55 | if __name__ == "__main__":
56 | LOOP.run_until_complete(stream_with_push_updates(sys.argv[1], sys.argv[2], LOOP))
57 |
--------------------------------------------------------------------------------
/pyatv/auth/server_auth.py:
--------------------------------------------------------------------------------
1 | """Shared server authentication constants."""
2 |
3 | PIN_CODE = 1111
4 | CLIENT_IDENTIFIER = "4D797FD3-3538-427E-A47B-A32FC6CF3A6A"
5 | CLIENT_CREDENTIALS = (
6 | "E734EA6C2B6257DE72355E472AA05A4C487E6B463C029ED306DF2F01B5636B58:"
7 | + "80FD8265B0748DA90BC5C5294DABE394D3D47199994AE96AC73EE45C783537B1:"
8 | + "35443739374644332D333533382D343237452D413437422D41333246433643463"
9 | + "3413641:34443739374644332D333533382D343237452D413437422D413332464"
10 | + "336434633413641"
11 | )
12 | SERVER_IDENTIFIER = "5D797FD3-3538-427E-A47B-A32FC6CF3A6A"
13 | PRIVATE_KEY = 32 * b"\xaa"
14 |
--------------------------------------------------------------------------------
/pyatv/protocols/companion/keyed_archiver.py:
--------------------------------------------------------------------------------
1 | """Support for working with NSKeyedArchiver serialized data."""
2 |
3 | import plistlib
4 | from typing import Any, List, Optional, Tuple
5 |
6 |
7 | def read_archive_properties(archive, *paths: List[str]) -> Tuple[Optional[Any], ...]:
8 | """Get properties from NSKeyedArchiver encoded PList.
9 |
10 | In the absence of a robust NSKeyedArchiver implementation, read one or
11 | more properties from the archived plist by following UID references.
12 | """
13 | data = plistlib.loads(archive)
14 | results = []
15 |
16 | objects = data["$objects"]
17 | for path in paths:
18 | element = data["$top"]
19 | try:
20 | for key in path:
21 | element = element[key]
22 | if isinstance(element, plistlib.UID):
23 | element = objects[element]
24 | results.append(element)
25 | except (IndexError, KeyError):
26 | results.append(None)
27 |
28 | return tuple(results)
29 |
--------------------------------------------------------------------------------
/pyatv/protocols/companion/plist_payloads/__init__.py:
--------------------------------------------------------------------------------
1 | """Module with helpers for generating plist payloads for Companion protocol."""
2 |
3 | from .rti_text_operations import * # noqa
4 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/AudioFadeMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
5 |
6 | extend ProtocolMessage {
7 | optional AudioFadeMessage audioFadeMessage = 88;
8 | }
9 |
10 | message AudioFadeMessage {
11 | optional PlayerPath playerPath = 1;
12 | optional int32 fadeType = 2;
13 | }
14 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/AudioFadeMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.PlayerPath_pb2
11 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class AudioFadeMessage(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | PLAYERPATH_FIELD_NUMBER: builtins.int
21 | FADETYPE_FIELD_NUMBER: builtins.int
22 | fadeType: builtins.int
23 | @property
24 | def playerPath(self) -> pyatv.protocols.mrp.protobuf.PlayerPath_pb2.PlayerPath: ...
25 | def __init__(
26 | self,
27 | *,
28 | playerPath: pyatv.protocols.mrp.protobuf.PlayerPath_pb2.PlayerPath | None = ...,
29 | fadeType: builtins.int | None = ...,
30 | ) -> None: ...
31 | def HasField(self, field_name: typing.Literal["fadeType", b"fadeType", "playerPath", b"playerPath"]) -> builtins.bool: ...
32 | def ClearField(self, field_name: typing.Literal["fadeType", b"fadeType", "playerPath", b"playerPath"]) -> None: ...
33 |
34 | global___AudioFadeMessage = AudioFadeMessage
35 |
36 | AUDIOFADEMESSAGE_FIELD_NUMBER: builtins.int
37 | audioFadeMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___AudioFadeMessage]
38 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/AudioFadeResponseMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional AudioFadeResponseMessage audioFadeResponseMessage = 89;
7 | }
8 |
9 | message AudioFadeResponseMessage {
10 | optional int64 fadeDuration = 1;
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/AudioFadeResponseMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class AudioFadeResponseMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | FADEDURATION_FIELD_NUMBER: builtins.int
20 | fadeDuration: builtins.int
21 | def __init__(
22 | self,
23 | *,
24 | fadeDuration: builtins.int | None = ...,
25 | ) -> None: ...
26 | def HasField(self, field_name: typing.Literal["fadeDuration", b"fadeDuration"]) -> builtins.bool: ...
27 | def ClearField(self, field_name: typing.Literal["fadeDuration", b"fadeDuration"]) -> None: ...
28 |
29 | global___AudioFadeResponseMessage = AudioFadeResponseMessage
30 |
31 | AUDIOFADERESPONSEMESSAGE_FIELD_NUMBER: builtins.int
32 | audioFadeResponseMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___AudioFadeResponseMessage]
33 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | message AudioFormatSettings {
4 | optional bytes formatSettingsPlistData = 1;
5 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 |
26 |
27 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n=pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage.proto\"6\n\x13\x41udioFormatSettings\x12\x1f\n\x17\x66ormatSettingsPlistData\x18\x01 \x01(\x0c')
28 |
29 | _globals = globals()
30 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.AudioFormatSettingsMessage_pb2', _globals)
32 | if not _descriptor._USE_C_DESCRIPTORS:
33 | DESCRIPTOR._loaded_options = None
34 | _globals['_AUDIOFORMATSETTINGS']._serialized_start=65
35 | _globals['_AUDIOFORMATSETTINGS']._serialized_end=119
36 | # @@protoc_insertion_point(module_scope)
37 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.message
9 | import typing
10 |
11 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
12 |
13 | @typing.final
14 | class AudioFormatSettings(google.protobuf.message.Message):
15 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
16 |
17 | FORMATSETTINGSPLISTDATA_FIELD_NUMBER: builtins.int
18 | formatSettingsPlistData: builtins.bytes
19 | def __init__(
20 | self,
21 | *,
22 | formatSettingsPlistData: builtins.bytes | None = ...,
23 | ) -> None: ...
24 | def HasField(self, field_name: typing.Literal["formatSettingsPlistData", b"formatSettingsPlistData"]) -> builtins.bool: ...
25 | def ClearField(self, field_name: typing.Literal["formatSettingsPlistData", b"formatSettingsPlistData"]) -> None: ...
26 |
27 | global___AudioFormatSettings = AudioFormatSettings
28 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/ClientUpdatesConfigMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional ClientUpdatesConfigMessage clientUpdatesConfigMessage = 21;
7 | }
8 |
9 | message ClientUpdatesConfigMessage {
10 | optional bool artworkUpdates = 1;
11 | optional bool nowPlayingUpdates = 2;
12 | optional bool volumeUpdates = 3;
13 | optional bool keyboardUpdates = 4;
14 | optional bool outputDeviceUpdates = 5;
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/CommandOptions.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/Common.proto";
4 |
5 | message CommandOptions {
6 | optional string sourceId = 2;
7 | optional string mediaType = 3;
8 | optional bool externalPlayerCommand = 4;
9 | optional float skipInterval = 5;
10 | optional float playbackRate = 6;
11 | optional float rating = 7;
12 | optional bool negative = 8;
13 | optional double playbackPosition = 9;
14 | optional RepeatMode.Enum repeatMode = 10;
15 | optional ShuffleMode.Enum shuffleMode = 11;
16 | optional uint64 trackID = 12;
17 | optional int64 radioStationID = 13;
18 | optional string radioStationHash = 14;
19 | optional bytes systemAppPlaybackQueueData = 15;
20 | optional string destinationAppDisplayID = 16;
21 | optional uint32 sendOptions = 17;
22 | optional bool requestDefermentToPlaybackQueuePosition = 18;
23 | optional string contextID = 19;
24 | optional bool shouldOverrideManuallyCuratedQueue = 20;
25 | optional string stationURL = 21;
26 | optional bool shouldBeginRadioPlayback = 22;
27 | optional int32 playbackQueueInsertionPosition = 23;
28 | optional string contentItemID = 24;
29 | optional int32 playbackQueueOffset = 25;
30 | optional int32 playbackQueueDestinationOffset = 26;
31 | optional bytes languageOption = 27;
32 | optional bytes playbackQueueContext = 28;
33 | optional string insertAfterContentItemID = 29;
34 | optional string nowPlayingContentItemID = 30;
35 | optional int32 replaceIntent = 31;
36 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/Common.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | message RepeatMode {
4 | enum Enum {
5 | Unknown = 0;
6 | Off = 1;
7 | One = 2;
8 | All = 3;
9 | }
10 | }
11 |
12 | message ShuffleMode {
13 | enum Enum {
14 | Unknown = 0;
15 | Off = 1;
16 | Albums = 2;
17 | Songs = 3;
18 | }
19 | }
20 |
21 | message DeviceClass {
22 | enum Enum {
23 | Invalid = 0;
24 | iPhone = 1;
25 | iPod = 2;
26 | iPad = 3;
27 | AppleTV = 4;
28 | iFPGA = 5;
29 | Watch = 6;
30 | Accessory = 7;
31 | Bridge = 8;
32 | Mac = 9;
33 | }
34 | }
35 |
36 | message DeviceType {
37 | enum Enum {
38 | Unknown = 0;
39 | AirPlay = 1;
40 | Bluetooth = 2;
41 | CarPlay = 3;
42 | BuiltIn = 4;
43 | Wired = 5;
44 | }
45 | }
46 |
47 | message DeviceSubType {
48 | enum Enum {
49 | Default = 0;
50 | Speaker = 1;
51 | Headphones = 2;
52 | Headset = 3;
53 | Receiver = 4;
54 | LineOut = 5;
55 | USB = 6;
56 | DisplayPort = 7;
57 | HDMI = 8;
58 | LowEnergy = 9;
59 | SPDIF = 10;
60 | TV = 11;
61 | HomePod = 12;
62 | AppleTV = 13;
63 | Vehicle = 14;
64 | Cluster = 15;
65 | SetTopBox = 16;
66 | TVStick = 17;
67 | }
68 | }
69 |
70 | message PlaybackState {
71 | enum Enum {
72 | Unknown = 0;
73 | Playing = 1;
74 | Paused = 2;
75 | Stopped = 3;
76 | Interrupted = 4;
77 | Seeking = 5;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/ConfigureConnectionMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional ConfigureConnectionMessage configureConnectionMessage = 94;
7 | }
8 |
9 | message ConfigureConnectionMessage {
10 | optional string groupID = 1;
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/ConfigureConnectionMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class ConfigureConnectionMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | GROUPID_FIELD_NUMBER: builtins.int
20 | groupID: builtins.str
21 | def __init__(
22 | self,
23 | *,
24 | groupID: builtins.str | None = ...,
25 | ) -> None: ...
26 | def HasField(self, field_name: typing.Literal["groupID", b"groupID"]) -> builtins.bool: ...
27 | def ClearField(self, field_name: typing.Literal["groupID", b"groupID"]) -> None: ...
28 |
29 | global___ConfigureConnectionMessage = ConfigureConnectionMessage
30 |
31 | CONFIGURECONNECTIONMESSAGE_FIELD_NUMBER: builtins.int
32 | configureConnectionMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___ConfigureConnectionMessage]
33 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/ContentItem.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ContentItemMetadata.proto";
4 | import "pyatv/protocols/mrp/protobuf/LanguageOption.proto";
5 |
6 | message LanguageOptionGroup {
7 | optional bool allowEmptySelection = 1;
8 | optional LanguageOption defaultLanguageOption = 2;
9 | repeated LanguageOption languageOptions = 3;
10 | }
11 |
12 | message ContentItem {
13 | optional string identifier = 1;
14 | optional ContentItemMetadata metadata = 2;
15 | optional bytes artworkData = 3;
16 | optional string info = 4;
17 | repeated LanguageOptionGroup availableLanguageOptions = 5;
18 | repeated LanguageOption currentLanguageOptions = 6;
19 | // optional Lyrics lyrics = 7;
20 | // repeated Sections sections = 8;
21 | optional string parentIdentifier = 9;
22 | optional string ancestorIdentifier = 10;
23 | optional string queueIdentifier = 11;
24 | optional string requestIdentifier = 12;
25 | optional int32 artworkDataWidth = 13;
26 | optional int32 artworkDataHeight = 14;
27 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/CryptoPairingMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional CryptoPairingMessage cryptoPairingMessage = 39;
7 | }
8 |
9 | message CryptoPairingMessage {
10 | optional bytes pairingData = 1; // Example: <00010006 0101>
11 | optional int32 status = 2; // Example: 0
12 | optional bool isRetrying = 3;
13 | optional bool isUsingSystemPairing = 4;
14 | optional int32 state = 5;
15 | }
16 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GenericMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional GenericMessage genericMessage = 46;
7 | }
8 |
9 | message GenericMessage {
10 | optional string key = 1;
11 | optional bytes value = 2;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GenericMessage_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/GenericMessage.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/GenericMessage.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 | from pyatv.protocols.mrp.protobuf import ProtocolMessage_pb2 as pyatv_dot_protocols_dot_mrp_dot_protobuf_dot_ProtocolMessage__pb2
26 |
27 |
28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n1pyatv/protocols/mrp/protobuf/GenericMessage.proto\x1a\x32pyatv/protocols/mrp/protobuf/ProtocolMessage.proto\",\n\x0eGenericMessage\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:9\n\x0egenericMessage\x12\x10.ProtocolMessage\x18. \x01(\x0b\x32\x0f.GenericMessage')
29 |
30 | _globals = globals()
31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.GenericMessage_pb2', _globals)
33 | if not _descriptor._USE_C_DESCRIPTORS:
34 | DESCRIPTOR._loaded_options = None
35 | _globals['_GENERICMESSAGE']._serialized_start=105
36 | _globals['_GENERICMESSAGE']._serialized_end=149
37 | # @@protoc_insertion_point(module_scope)
38 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GenericMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class GenericMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | KEY_FIELD_NUMBER: builtins.int
20 | VALUE_FIELD_NUMBER: builtins.int
21 | key: builtins.str
22 | value: builtins.bytes
23 | def __init__(
24 | self,
25 | *,
26 | key: builtins.str | None = ...,
27 | value: builtins.bytes | None = ...,
28 | ) -> None: ...
29 | def HasField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ...
30 | def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ...
31 |
32 | global___GenericMessage = GenericMessage
33 |
34 | GENERICMESSAGE_FIELD_NUMBER: builtins.int
35 | genericMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___GenericMessage]
36 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GetKeyboardSessionMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional string getKeyboardSessionMessage = 29;
7 | }
8 |
9 | message GetKeyboardSessionMessage {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GetKeyboardSessionMessage_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/GetKeyboardSessionMessage.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/GetKeyboardSessionMessage.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 | from pyatv.protocols.mrp.protobuf import ProtocolMessage_pb2 as pyatv_dot_protocols_dot_mrp_dot_protobuf_dot_ProtocolMessage__pb2
26 |
27 |
28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n None: ...
22 |
23 | global___GetKeyboardSessionMessage = GetKeyboardSessionMessage
24 |
25 | GETKEYBOARDSESSIONMESSAGE_FIELD_NUMBER: builtins.int
26 | getKeyboardSessionMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, builtins.str]
27 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GetRemoteTextInputSessionMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional GetRemoteTextInputSessionMessage getRemoteTextInputSessionMessage = 72;
7 | }
8 |
9 | message GetRemoteTextInputSessionMessage {
10 | }
11 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GetRemoteTextInputSessionMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class GetRemoteTextInputSessionMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | def __init__(
20 | self,
21 | ) -> None: ...
22 |
23 | global___GetRemoteTextInputSessionMessage = GetRemoteTextInputSessionMessage
24 |
25 | GETREMOTETEXTINPUTSESSIONMESSAGE_FIELD_NUMBER: builtins.int
26 | getRemoteTextInputSessionMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___GetRemoteTextInputSessionMessage]
27 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GetVolumeMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional GetVolumeMessage getVolumeMessage = 53;
7 | }
8 |
9 | message GetVolumeMessage {
10 | optional string outputDeviceUID = 1;
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GetVolumeMessage_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/GetVolumeMessage.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/GetVolumeMessage.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 | from pyatv.protocols.mrp.protobuf import ProtocolMessage_pb2 as pyatv_dot_protocols_dot_mrp_dot_protobuf_dot_ProtocolMessage__pb2
26 |
27 |
28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n3pyatv/protocols/mrp/protobuf/GetVolumeMessage.proto\x1a\x32pyatv/protocols/mrp/protobuf/ProtocolMessage.proto\"+\n\x10GetVolumeMessage\x12\x17\n\x0foutputDeviceUID\x18\x01 \x01(\t:=\n\x10getVolumeMessage\x12\x10.ProtocolMessage\x18\x35 \x01(\x0b\x32\x11.GetVolumeMessage')
29 |
30 | _globals = globals()
31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.GetVolumeMessage_pb2', _globals)
33 | if not _descriptor._USE_C_DESCRIPTORS:
34 | DESCRIPTOR._loaded_options = None
35 | _globals['_GETVOLUMEMESSAGE']._serialized_start=107
36 | _globals['_GETVOLUMEMESSAGE']._serialized_end=150
37 | # @@protoc_insertion_point(module_scope)
38 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GetVolumeMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class GetVolumeMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | OUTPUTDEVICEUID_FIELD_NUMBER: builtins.int
20 | outputDeviceUID: builtins.str
21 | def __init__(
22 | self,
23 | *,
24 | outputDeviceUID: builtins.str | None = ...,
25 | ) -> None: ...
26 | def HasField(self, field_name: typing.Literal["outputDeviceUID", b"outputDeviceUID"]) -> builtins.bool: ...
27 | def ClearField(self, field_name: typing.Literal["outputDeviceUID", b"outputDeviceUID"]) -> None: ...
28 |
29 | global___GetVolumeMessage = GetVolumeMessage
30 |
31 | GETVOLUMEMESSAGE_FIELD_NUMBER: builtins.int
32 | getVolumeMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___GetVolumeMessage]
33 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GetVolumeResultMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional GetVolumeResultMessage getVolumeResultMessage = 54;
7 | }
8 |
9 | message GetVolumeResultMessage {
10 | optional float volume = 1;
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/GetVolumeResultMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class GetVolumeResultMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | VOLUME_FIELD_NUMBER: builtins.int
20 | volume: builtins.float
21 | def __init__(
22 | self,
23 | *,
24 | volume: builtins.float | None = ...,
25 | ) -> None: ...
26 | def HasField(self, field_name: typing.Literal["volume", b"volume"]) -> builtins.bool: ...
27 | def ClearField(self, field_name: typing.Literal["volume", b"volume"]) -> None: ...
28 |
29 | global___GetVolumeResultMessage = GetVolumeResultMessage
30 |
31 | GETVOLUMERESULTMESSAGE_FIELD_NUMBER: builtins.int
32 | getVolumeResultMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___GetVolumeResultMessage]
33 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/LanguageOption.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | message LanguageOption {
4 | optional int32 type = 1;
5 | optional string languageTag = 2;
6 | repeated string characteristics = 3;
7 | optional string displayName = 4;
8 | optional string identifier = 5;
9 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/LanguageOption_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/LanguageOption.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/LanguageOption.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 |
26 |
27 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n1pyatv/protocols/mrp/protobuf/LanguageOption.proto\"u\n\x0eLanguageOption\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\x13\n\x0blanguageTag\x18\x02 \x01(\t\x12\x17\n\x0f\x63haracteristics\x18\x03 \x03(\t\x12\x13\n\x0b\x64isplayName\x18\x04 \x01(\t\x12\x12\n\nidentifier\x18\x05 \x01(\t')
28 |
29 | _globals = globals()
30 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.LanguageOption_pb2', _globals)
32 | if not _descriptor._USE_C_DESCRIPTORS:
33 | DESCRIPTOR._loaded_options = None
34 | _globals['_LANGUAGEOPTION']._serialized_start=53
35 | _globals['_LANGUAGEOPTION']._serialized_end=170
36 | # @@protoc_insertion_point(module_scope)
37 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/LanguageOption_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import collections.abc
8 | import google.protobuf.descriptor
9 | import google.protobuf.internal.containers
10 | import google.protobuf.message
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class LanguageOption(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | TYPE_FIELD_NUMBER: builtins.int
20 | LANGUAGETAG_FIELD_NUMBER: builtins.int
21 | CHARACTERISTICS_FIELD_NUMBER: builtins.int
22 | DISPLAYNAME_FIELD_NUMBER: builtins.int
23 | IDENTIFIER_FIELD_NUMBER: builtins.int
24 | type: builtins.int
25 | languageTag: builtins.str
26 | displayName: builtins.str
27 | identifier: builtins.str
28 | @property
29 | def characteristics(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
30 | def __init__(
31 | self,
32 | *,
33 | type: builtins.int | None = ...,
34 | languageTag: builtins.str | None = ...,
35 | characteristics: collections.abc.Iterable[builtins.str] | None = ...,
36 | displayName: builtins.str | None = ...,
37 | identifier: builtins.str | None = ...,
38 | ) -> None: ...
39 | def HasField(self, field_name: typing.Literal["displayName", b"displayName", "identifier", b"identifier", "languageTag", b"languageTag", "type", b"type"]) -> builtins.bool: ...
40 | def ClearField(self, field_name: typing.Literal["characteristics", b"characteristics", "displayName", b"displayName", "identifier", b"identifier", "languageTag", b"languageTag", "type", b"type"]) -> None: ...
41 |
42 | global___LanguageOption = LanguageOption
43 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/ModifyOutputContextRequestMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional ModifyOutputContextRequestMessage modifyOutputContextRequestMessage = 52;
7 | }
8 |
9 | message ModifyOutputContextRequestType {
10 | enum Enum {
11 | SharedAudioPresentation = 1;
12 | }
13 | }
14 |
15 | message ModifyOutputContextRequestMessage {
16 | optional ModifyOutputContextRequestType.Enum type = 1;
17 | repeated string addingDevices = 2;
18 | repeated string removingDevices = 3;
19 | repeated string settingDevices = 4;
20 | repeated string clusterAwareAddingDevices = 5;
21 | repeated string clusterAwareRemovingDevices = 6;
22 | repeated string clusterAwareSettingDevices = 7;
23 | }
24 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/NotificationMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional NotificationMessage notificationMessage = 16;
7 | }
8 |
9 | message NotificationMessage {
10 | repeated string notification = 1;
11 | repeated bytes userInfo = 2;
12 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/NotificationMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import collections.abc
8 | import google.protobuf.descriptor
9 | import google.protobuf.internal.containers
10 | import google.protobuf.internal.extension_dict
11 | import google.protobuf.message
12 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
13 | import typing
14 |
15 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
16 |
17 | @typing.final
18 | class NotificationMessage(google.protobuf.message.Message):
19 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
20 |
21 | NOTIFICATION_FIELD_NUMBER: builtins.int
22 | USERINFO_FIELD_NUMBER: builtins.int
23 | @property
24 | def notification(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
25 | @property
26 | def userInfo(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.bytes]: ...
27 | def __init__(
28 | self,
29 | *,
30 | notification: collections.abc.Iterable[builtins.str] | None = ...,
31 | userInfo: collections.abc.Iterable[builtins.bytes] | None = ...,
32 | ) -> None: ...
33 | def ClearField(self, field_name: typing.Literal["notification", b"notification", "userInfo", b"userInfo"]) -> None: ...
34 |
35 | global___NotificationMessage = NotificationMessage
36 |
37 | NOTIFICATIONMESSAGE_FIELD_NUMBER: builtins.int
38 | notificationMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___NotificationMessage]
39 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/NowPlayingClient.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | message NowPlayingClient {
4 | optional int32 processIdentifier = 1;
5 | optional string bundleIdentifier = 2;
6 | optional string parentApplicationBundleIdentifier = 3;
7 | optional int32 processUserIdentifier = 4;
8 | optional int32 nowPlayingVisibility = 5;
9 | // optional TintColor tintColor = 6;
10 | optional string displayName = 7;
11 | repeated string bundleIdentifierHierarchys = 8;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/NowPlayingInfo.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/Common.proto";
4 |
5 | message NowPlayingInfo {
6 | optional string album = 1;
7 | optional string artist = 2;
8 | optional double duration = 3;
9 | optional double elapsedTime = 4;
10 | optional float playbackRate = 5;
11 | optional RepeatMode.Enum repeatMode = 6;
12 | optional ShuffleMode.Enum shuffleMode = 7;
13 | optional double timestamp = 8;
14 | optional string title = 9;
15 | optional uint64 uniqueIdentifier = 10;
16 | optional bool isExplicitTrack = 11;
17 | optional bool isMusicApp = 12;
18 | optional int64 radioStationIdentifier = 13;
19 | optional string radioStationHash = 14;
20 | optional string radioStationName = 15;
21 | optional bytes artworkDataDigest = 16;
22 | optional bool isAlwaysLive = 17;
23 | optional bool isAdvertisement = 18;
24 | }
25 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/NowPlayingPlayer.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | message NowPlayingPlayer {
4 | optional string identifier = 1;
5 | optional string displayName = 2;
6 | optional bool isDefaultPlayer = 3;
7 | optional int32 audioSessionType = 4;
8 | optional int64 mxSessionIDs = 5;
9 | optional uint32 audioSessionID = 6;
10 | optional string iconURL = 7;
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/NowPlayingPlayer_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/NowPlayingPlayer.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/NowPlayingPlayer.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 |
26 |
27 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n3pyatv/protocols/mrp/protobuf/NowPlayingPlayer.proto\"\xad\x01\n\x10NowPlayingPlayer\x12\x12\n\nidentifier\x18\x01 \x01(\t\x12\x13\n\x0b\x64isplayName\x18\x02 \x01(\t\x12\x17\n\x0fisDefaultPlayer\x18\x03 \x01(\x08\x12\x18\n\x10\x61udioSessionType\x18\x04 \x01(\x05\x12\x14\n\x0cmxSessionIDs\x18\x05 \x01(\x03\x12\x16\n\x0e\x61udioSessionID\x18\x06 \x01(\r\x12\x0f\n\x07iconURL\x18\x07 \x01(\t')
28 |
29 | _globals = globals()
30 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.NowPlayingPlayer_pb2', _globals)
32 | if not _descriptor._USE_C_DESCRIPTORS:
33 | DESCRIPTOR._loaded_options = None
34 | _globals['_NOWPLAYINGPLAYER']._serialized_start=56
35 | _globals['_NOWPLAYINGPLAYER']._serialized_end=229
36 | # @@protoc_insertion_point(module_scope)
37 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/Origin.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/DeviceInfoMessage.proto";
4 |
5 | message Origin {
6 | enum Type {
7 | Unknown = 0;
8 | Local = 1;
9 | Custom = 2;
10 | }
11 |
12 | optional Type type = 1;
13 | optional string displayName = 2;
14 | optional int32 identifier = 3;
15 | optional DeviceInfoMessage deviceInfo = 4;
16 | optional bool isLocallyHosted = 5;
17 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/OriginClientPropertiesMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional OriginClientPropertiesMessage originClientPropertiesMessage = 87;
7 | }
8 |
9 | message OriginClientPropertiesMessage {
10 | optional double lastPlayingTimestamp = 1;
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/OriginClientPropertiesMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class OriginClientPropertiesMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | LASTPLAYINGTIMESTAMP_FIELD_NUMBER: builtins.int
20 | lastPlayingTimestamp: builtins.float
21 | def __init__(
22 | self,
23 | *,
24 | lastPlayingTimestamp: builtins.float | None = ...,
25 | ) -> None: ...
26 | def HasField(self, field_name: typing.Literal["lastPlayingTimestamp", b"lastPlayingTimestamp"]) -> builtins.bool: ...
27 | def ClearField(self, field_name: typing.Literal["lastPlayingTimestamp", b"lastPlayingTimestamp"]) -> None: ...
28 |
29 | global___OriginClientPropertiesMessage = OriginClientPropertiesMessage
30 |
31 | ORIGINCLIENTPROPERTIESMESSAGE_FIELD_NUMBER: builtins.int
32 | originClientPropertiesMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___OriginClientPropertiesMessage]
33 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlaybackQueue.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ContentItem.proto";
4 | import "pyatv/protocols/mrp/protobuf/PlaybackQueueContext.proto";
5 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
6 |
7 | message PlaybackQueue {
8 | optional int32 location = 1;
9 | repeated ContentItem contentItems = 2;
10 | optional PlaybackQueueContext context = 3;
11 | optional string requestId = 4;
12 | optional PlayerPath resolvedPlayerPath = 5;
13 | optional bool sendingPlaybackQueueTransaction = 6;
14 | optional string queueIdentifier = 7;
15 | }
16 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | message PlaybackQueueCapabilities {
4 | optional bool requestByRange = 1;
5 | optional bool requestByIdentifiers = 2;
6 | optional bool requestByRequest = 3;
7 | }
8 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 |
26 |
27 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n None: ...
30 | def HasField(self, field_name: typing.Literal["requestByIdentifiers", b"requestByIdentifiers", "requestByRange", b"requestByRange", "requestByRequest", b"requestByRequest"]) -> builtins.bool: ...
31 | def ClearField(self, field_name: typing.Literal["requestByIdentifiers", b"requestByIdentifiers", "requestByRange", b"requestByRange", "requestByRequest", b"requestByRequest"]) -> None: ...
32 |
33 | global___PlaybackQueueCapabilities = PlaybackQueueCapabilities
34 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlaybackQueueContext.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | message PlaybackQueueContext {
4 | optional string revision = 1;
5 | }
6 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlaybackQueueContext_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/PlaybackQueueContext.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/PlaybackQueueContext.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 |
26 |
27 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n7pyatv/protocols/mrp/protobuf/PlaybackQueueContext.proto\"(\n\x14PlaybackQueueContext\x12\x10\n\x08revision\x18\x01 \x01(\t')
28 |
29 | _globals = globals()
30 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.PlaybackQueueContext_pb2', _globals)
32 | if not _descriptor._USE_C_DESCRIPTORS:
33 | DESCRIPTOR._loaded_options = None
34 | _globals['_PLAYBACKQUEUECONTEXT']._serialized_start=59
35 | _globals['_PLAYBACKQUEUECONTEXT']._serialized_end=99
36 | # @@protoc_insertion_point(module_scope)
37 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlaybackQueueContext_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.message
9 | import typing
10 |
11 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
12 |
13 | @typing.final
14 | class PlaybackQueueContext(google.protobuf.message.Message):
15 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
16 |
17 | REVISION_FIELD_NUMBER: builtins.int
18 | revision: builtins.str
19 | def __init__(
20 | self,
21 | *,
22 | revision: builtins.str | None = ...,
23 | ) -> None: ...
24 | def HasField(self, field_name: typing.Literal["revision", b"revision"]) -> builtins.bool: ...
25 | def ClearField(self, field_name: typing.Literal["revision", b"revision"]) -> None: ...
26 |
27 | global___PlaybackQueueContext = PlaybackQueueContext
28 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlaybackQueueRequestMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/PlaybackQueueContext.proto";
5 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
6 |
7 | extend ProtocolMessage {
8 | optional PlaybackQueueRequestMessage playbackQueueRequestMessage = 37;
9 | }
10 |
11 | message PlaybackQueueRequestMessage {
12 | optional int32 location = 1;
13 | optional int32 length = 2;
14 | optional bool includeMetadata = 3;
15 | optional double artworkWidth = 4;
16 | optional double artworkHeight = 5;
17 | optional bool includeLyrics = 6;
18 | optional bool includeSections = 7;
19 | optional bool includeInfo = 8;
20 | optional bool includeLanguageOptions = 9;
21 | optional PlaybackQueueContext context = 10;
22 | optional string requestID = 11;
23 | repeated string contentItemIdentifiers = 12;
24 | optional bool returnContentItemAssetsInUserCompletion = 13;
25 | optional PlayerPath playerPath = 14;
26 | optional int32 cachingPolicy = 15;
27 | optional string label = 16;
28 | optional bool isLegacyNowPlayingInfoRequest = 17;
29 | }
30 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlayerClientPropertiesMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
5 |
6 | extend ProtocolMessage {
7 | optional PlayerClientPropertiesMessage playerClientPropertiesMessage = 86;
8 | }
9 |
10 | message PlayerClientPropertiesMessage {
11 | optional PlayerPath playerPath = 1;
12 | optional double lastPlayingTimestamp = 2;
13 | }
14 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlayerClientPropertiesMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.PlayerPath_pb2
11 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class PlayerClientPropertiesMessage(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | PLAYERPATH_FIELD_NUMBER: builtins.int
21 | LASTPLAYINGTIMESTAMP_FIELD_NUMBER: builtins.int
22 | lastPlayingTimestamp: builtins.float
23 | @property
24 | def playerPath(self) -> pyatv.protocols.mrp.protobuf.PlayerPath_pb2.PlayerPath: ...
25 | def __init__(
26 | self,
27 | *,
28 | playerPath: pyatv.protocols.mrp.protobuf.PlayerPath_pb2.PlayerPath | None = ...,
29 | lastPlayingTimestamp: builtins.float | None = ...,
30 | ) -> None: ...
31 | def HasField(self, field_name: typing.Literal["lastPlayingTimestamp", b"lastPlayingTimestamp", "playerPath", b"playerPath"]) -> builtins.bool: ...
32 | def ClearField(self, field_name: typing.Literal["lastPlayingTimestamp", b"lastPlayingTimestamp", "playerPath", b"playerPath"]) -> None: ...
33 |
34 | global___PlayerClientPropertiesMessage = PlayerClientPropertiesMessage
35 |
36 | PLAYERCLIENTPROPERTIESMESSAGE_FIELD_NUMBER: builtins.int
37 | playerClientPropertiesMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___PlayerClientPropertiesMessage]
38 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlayerPath.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/Origin.proto";
4 | import "pyatv/protocols/mrp/protobuf/NowPlayingClient.proto";
5 | import "pyatv/protocols/mrp/protobuf/NowPlayingPlayer.proto";
6 |
7 | message PlayerPath {
8 | optional Origin origin = 1;
9 | optional NowPlayingClient client = 2;
10 | optional NowPlayingPlayer player = 3;
11 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/PlayerPath_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.message
9 | import pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2
10 | import pyatv.protocols.mrp.protobuf.NowPlayingPlayer_pb2
11 | import pyatv.protocols.mrp.protobuf.Origin_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class PlayerPath(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | ORIGIN_FIELD_NUMBER: builtins.int
21 | CLIENT_FIELD_NUMBER: builtins.int
22 | PLAYER_FIELD_NUMBER: builtins.int
23 | @property
24 | def origin(self) -> pyatv.protocols.mrp.protobuf.Origin_pb2.Origin: ...
25 | @property
26 | def client(self) -> pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2.NowPlayingClient: ...
27 | @property
28 | def player(self) -> pyatv.protocols.mrp.protobuf.NowPlayingPlayer_pb2.NowPlayingPlayer: ...
29 | def __init__(
30 | self,
31 | *,
32 | origin: pyatv.protocols.mrp.protobuf.Origin_pb2.Origin | None = ...,
33 | client: pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2.NowPlayingClient | None = ...,
34 | player: pyatv.protocols.mrp.protobuf.NowPlayingPlayer_pb2.NowPlayingPlayer | None = ...,
35 | ) -> None: ...
36 | def HasField(self, field_name: typing.Literal["client", b"client", "origin", b"origin", "player", b"player"]) -> builtins.bool: ...
37 | def ClearField(self, field_name: typing.Literal["client", b"client", "origin", b"origin", "player", b"player"]) -> None: ...
38 |
39 | global___PlayerPath = PlayerPath
40 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RegisterForGameControllerEventsMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional RegisterForGameControllerEventsMessage registerForGameControllerEventsMessage = 27;
7 | }
8 |
9 | message RegisterForGameControllerEventsMessage {
10 | enum InputModeFlags {
11 | None = 0;
12 | Motion = 1;
13 | Buttons = 2;
14 | Digitizer = 3;
15 | }
16 |
17 | optional InputModeFlags inputModeFlags = 1;
18 | }
19 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage.proto";
5 |
6 | extend ProtocolMessage {
7 | optional RegisterHIDDeviceMessage registerHIDDeviceMessage = 11;
8 | }
9 |
10 | message RegisterHIDDeviceMessage {
11 | optional VirtualTouchDeviceDescriptor deviceDescriptor = 1;
12 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import pyatv.protocols.mrp.protobuf.VirtualTouchDeviceDescriptorMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class RegisterHIDDeviceMessage(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | DEVICEDESCRIPTOR_FIELD_NUMBER: builtins.int
21 | @property
22 | def deviceDescriptor(self) -> pyatv.protocols.mrp.protobuf.VirtualTouchDeviceDescriptorMessage_pb2.VirtualTouchDeviceDescriptor: ...
23 | def __init__(
24 | self,
25 | *,
26 | deviceDescriptor: pyatv.protocols.mrp.protobuf.VirtualTouchDeviceDescriptorMessage_pb2.VirtualTouchDeviceDescriptor | None = ...,
27 | ) -> None: ...
28 | def HasField(self, field_name: typing.Literal["deviceDescriptor", b"deviceDescriptor"]) -> builtins.bool: ...
29 | def ClearField(self, field_name: typing.Literal["deviceDescriptor", b"deviceDescriptor"]) -> None: ...
30 |
31 | global___RegisterHIDDeviceMessage = RegisterHIDDeviceMessage
32 |
33 | REGISTERHIDDEVICEMESSAGE_FIELD_NUMBER: builtins.int
34 | registerHIDDeviceMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___RegisterHIDDeviceMessage]
35 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceResultMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional RegisterHIDDeviceResultMessage registerHIDDeviceResultMessage = 12;
7 | }
8 |
9 | message RegisterHIDDeviceResultMessage {
10 | optional int32 errorCode = 1;
11 | optional int32 deviceIdentifier = 2;
12 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceResultMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class RegisterHIDDeviceResultMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | ERRORCODE_FIELD_NUMBER: builtins.int
20 | DEVICEIDENTIFIER_FIELD_NUMBER: builtins.int
21 | errorCode: builtins.int
22 | deviceIdentifier: builtins.int
23 | def __init__(
24 | self,
25 | *,
26 | errorCode: builtins.int | None = ...,
27 | deviceIdentifier: builtins.int | None = ...,
28 | ) -> None: ...
29 | def HasField(self, field_name: typing.Literal["deviceIdentifier", b"deviceIdentifier", "errorCode", b"errorCode"]) -> builtins.bool: ...
30 | def ClearField(self, field_name: typing.Literal["deviceIdentifier", b"deviceIdentifier", "errorCode", b"errorCode"]) -> None: ...
31 |
32 | global___RegisterHIDDeviceResultMessage = RegisterHIDDeviceResultMessage
33 |
34 | REGISTERHIDDEVICERESULTMESSAGE_FIELD_NUMBER: builtins.int
35 | registerHIDDeviceResultMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___RegisterHIDDeviceResultMessage]
36 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/VoiceInputDeviceDescriptorMessage.proto";
5 |
6 | extend ProtocolMessage {
7 | optional RegisterVoiceInputDeviceMessage registerVoiceInputDeviceMessage = 33;
8 | }
9 |
10 | message RegisterVoiceInputDeviceMessage {
11 | optional VoiceInputDeviceDescriptor deviceDescriptor = 1;
12 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import pyatv.protocols.mrp.protobuf.VoiceInputDeviceDescriptorMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class RegisterVoiceInputDeviceMessage(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | DEVICEDESCRIPTOR_FIELD_NUMBER: builtins.int
21 | @property
22 | def deviceDescriptor(self) -> pyatv.protocols.mrp.protobuf.VoiceInputDeviceDescriptorMessage_pb2.VoiceInputDeviceDescriptor: ...
23 | def __init__(
24 | self,
25 | *,
26 | deviceDescriptor: pyatv.protocols.mrp.protobuf.VoiceInputDeviceDescriptorMessage_pb2.VoiceInputDeviceDescriptor | None = ...,
27 | ) -> None: ...
28 | def HasField(self, field_name: typing.Literal["deviceDescriptor", b"deviceDescriptor"]) -> builtins.bool: ...
29 | def ClearField(self, field_name: typing.Literal["deviceDescriptor", b"deviceDescriptor"]) -> None: ...
30 |
31 | global___RegisterVoiceInputDeviceMessage = RegisterVoiceInputDeviceMessage
32 |
33 | REGISTERVOICEINPUTDEVICEMESSAGE_FIELD_NUMBER: builtins.int
34 | registerVoiceInputDeviceMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___RegisterVoiceInputDeviceMessage]
35 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceResponseMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional RegisterVoiceInputDeviceResponseMessage registerVoiceInputDeviceResponseMessage = 34;
7 | }
8 |
9 | message RegisterVoiceInputDeviceResponseMessage {
10 | optional int32 deviceID = 1;
11 | optional int32 errorCode = 2;
12 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceResponseMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class RegisterVoiceInputDeviceResponseMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | DEVICEID_FIELD_NUMBER: builtins.int
20 | ERRORCODE_FIELD_NUMBER: builtins.int
21 | deviceID: builtins.int
22 | errorCode: builtins.int
23 | def __init__(
24 | self,
25 | *,
26 | deviceID: builtins.int | None = ...,
27 | errorCode: builtins.int | None = ...,
28 | ) -> None: ...
29 | def HasField(self, field_name: typing.Literal["deviceID", b"deviceID", "errorCode", b"errorCode"]) -> builtins.bool: ...
30 | def ClearField(self, field_name: typing.Literal["deviceID", b"deviceID", "errorCode", b"errorCode"]) -> None: ...
31 |
32 | global___RegisterVoiceInputDeviceResponseMessage = RegisterVoiceInputDeviceResponseMessage
33 |
34 | REGISTERVOICEINPUTDEVICERESPONSEMESSAGE_FIELD_NUMBER: builtins.int
35 | registerVoiceInputDeviceResponseMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___RegisterVoiceInputDeviceResponseMessage]
36 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RemoteTextInputMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional RemoteTextInputMessage remoteTextInputMessage = 71;
7 | }
8 |
9 | message RemoteTextInputMessage {
10 | optional double timestamp = 1;
11 | optional uint64 version = 2;
12 | optional bytes data = 3;
13 | }
14 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RemoteTextInputMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class RemoteTextInputMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | TIMESTAMP_FIELD_NUMBER: builtins.int
20 | VERSION_FIELD_NUMBER: builtins.int
21 | DATA_FIELD_NUMBER: builtins.int
22 | timestamp: builtins.float
23 | version: builtins.int
24 | data: builtins.bytes
25 | def __init__(
26 | self,
27 | *,
28 | timestamp: builtins.float | None = ...,
29 | version: builtins.int | None = ...,
30 | data: builtins.bytes | None = ...,
31 | ) -> None: ...
32 | def HasField(self, field_name: typing.Literal["data", b"data", "timestamp", b"timestamp", "version", b"version"]) -> builtins.bool: ...
33 | def ClearField(self, field_name: typing.Literal["data", b"data", "timestamp", b"timestamp", "version", b"version"]) -> None: ...
34 |
35 | global___RemoteTextInputMessage = RemoteTextInputMessage
36 |
37 | REMOTETEXTINPUTMESSAGE_FIELD_NUMBER: builtins.int
38 | remoteTextInputMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___RemoteTextInputMessage]
39 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RemoveClientMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/NowPlayingClient.proto";
5 |
6 | extend ProtocolMessage {
7 | optional RemoveClientMessage removeClientMessage = 57;
8 | }
9 |
10 | message RemoveClientMessage {
11 | optional NowPlayingClient client = 1;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RemoveClientMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2
11 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class RemoveClientMessage(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | CLIENT_FIELD_NUMBER: builtins.int
21 | @property
22 | def client(self) -> pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2.NowPlayingClient: ...
23 | def __init__(
24 | self,
25 | *,
26 | client: pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2.NowPlayingClient | None = ...,
27 | ) -> None: ...
28 | def HasField(self, field_name: typing.Literal["client", b"client"]) -> builtins.bool: ...
29 | def ClearField(self, field_name: typing.Literal["client", b"client"]) -> None: ...
30 |
31 | global___RemoveClientMessage = RemoveClientMessage
32 |
33 | REMOVECLIENTMESSAGE_FIELD_NUMBER: builtins.int
34 | removeClientMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___RemoveClientMessage]
35 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RemoveEndpointsMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional RemoveEndpointsMessage removeEndpointsMessage = 84;
7 | }
8 |
9 | message RemoveEndpointsMessage {
10 | repeated string endpointUIDs = 1;
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RemoveEndpointsMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import collections.abc
8 | import google.protobuf.descriptor
9 | import google.protobuf.internal.containers
10 | import google.protobuf.internal.extension_dict
11 | import google.protobuf.message
12 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
13 | import typing
14 |
15 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
16 |
17 | @typing.final
18 | class RemoveEndpointsMessage(google.protobuf.message.Message):
19 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
20 |
21 | ENDPOINTUIDS_FIELD_NUMBER: builtins.int
22 | @property
23 | def endpointUIDs(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
24 | def __init__(
25 | self,
26 | *,
27 | endpointUIDs: collections.abc.Iterable[builtins.str] | None = ...,
28 | ) -> None: ...
29 | def ClearField(self, field_name: typing.Literal["endpointUIDs", b"endpointUIDs"]) -> None: ...
30 |
31 | global___RemoveEndpointsMessage = RemoveEndpointsMessage
32 |
33 | REMOVEENDPOINTSMESSAGE_FIELD_NUMBER: builtins.int
34 | removeEndpointsMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___RemoveEndpointsMessage]
35 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RemoveOutputDevicesMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional RemoveOutputDevicesMessage removeOutputDevicesMessage = 70;
7 | }
8 |
9 | message RemoveOutputDevicesMessage {
10 | repeated string outputDeviceUIDs = 1;
11 | optional string endpointUID = 2;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RemoveOutputDevicesMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import collections.abc
8 | import google.protobuf.descriptor
9 | import google.protobuf.internal.containers
10 | import google.protobuf.internal.extension_dict
11 | import google.protobuf.message
12 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
13 | import typing
14 |
15 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
16 |
17 | @typing.final
18 | class RemoveOutputDevicesMessage(google.protobuf.message.Message):
19 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
20 |
21 | OUTPUTDEVICEUIDS_FIELD_NUMBER: builtins.int
22 | ENDPOINTUID_FIELD_NUMBER: builtins.int
23 | endpointUID: builtins.str
24 | @property
25 | def outputDeviceUIDs(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
26 | def __init__(
27 | self,
28 | *,
29 | outputDeviceUIDs: collections.abc.Iterable[builtins.str] | None = ...,
30 | endpointUID: builtins.str | None = ...,
31 | ) -> None: ...
32 | def HasField(self, field_name: typing.Literal["endpointUID", b"endpointUID"]) -> builtins.bool: ...
33 | def ClearField(self, field_name: typing.Literal["endpointUID", b"endpointUID", "outputDeviceUIDs", b"outputDeviceUIDs"]) -> None: ...
34 |
35 | global___RemoveOutputDevicesMessage = RemoveOutputDevicesMessage
36 |
37 | REMOVEOUTPUTDEVICESMESSAGE_FIELD_NUMBER: builtins.int
38 | removeOutputDevicesMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___RemoveOutputDevicesMessage]
39 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RemovePlayerMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
5 |
6 | extend ProtocolMessage {
7 | optional RemovePlayerMessage removePlayerMessage = 58;
8 | }
9 |
10 | message RemovePlayerMessage {
11 | optional PlayerPath playerPath = 1;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/RemovePlayerMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.PlayerPath_pb2
11 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class RemovePlayerMessage(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | PLAYERPATH_FIELD_NUMBER: builtins.int
21 | @property
22 | def playerPath(self) -> pyatv.protocols.mrp.protobuf.PlayerPath_pb2.PlayerPath: ...
23 | def __init__(
24 | self,
25 | *,
26 | playerPath: pyatv.protocols.mrp.protobuf.PlayerPath_pb2.PlayerPath | None = ...,
27 | ) -> None: ...
28 | def HasField(self, field_name: typing.Literal["playerPath", b"playerPath"]) -> builtins.bool: ...
29 | def ClearField(self, field_name: typing.Literal["playerPath", b"playerPath"]) -> None: ...
30 |
31 | global___RemovePlayerMessage = RemovePlayerMessage
32 |
33 | REMOVEPLAYERMESSAGE_FIELD_NUMBER: builtins.int
34 | removePlayerMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___RemovePlayerMessage]
35 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SendButtonEventMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional SendButtonEventMessage sendButtonEventMessage = 43;
7 | }
8 |
9 | message SendButtonEventMessage {
10 | optional uint32 usagePage = 1;
11 | optional uint32 usage = 2;
12 | optional bool buttonDown = 3;
13 | }
14 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SendButtonEventMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class SendButtonEventMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | USAGEPAGE_FIELD_NUMBER: builtins.int
20 | USAGE_FIELD_NUMBER: builtins.int
21 | BUTTONDOWN_FIELD_NUMBER: builtins.int
22 | usagePage: builtins.int
23 | usage: builtins.int
24 | buttonDown: builtins.bool
25 | def __init__(
26 | self,
27 | *,
28 | usagePage: builtins.int | None = ...,
29 | usage: builtins.int | None = ...,
30 | buttonDown: builtins.bool | None = ...,
31 | ) -> None: ...
32 | def HasField(self, field_name: typing.Literal["buttonDown", b"buttonDown", "usage", b"usage", "usagePage", b"usagePage"]) -> builtins.bool: ...
33 | def ClearField(self, field_name: typing.Literal["buttonDown", b"buttonDown", "usage", b"usage", "usagePage", b"usagePage"]) -> None: ...
34 |
35 | global___SendButtonEventMessage = SendButtonEventMessage
36 |
37 | SENDBUTTONEVENTMESSAGE_FIELD_NUMBER: builtins.int
38 | sendButtonEventMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___SendButtonEventMessage]
39 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SendCommandMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/CommandInfo.proto";
5 | import "pyatv/protocols/mrp/protobuf/CommandOptions.proto";
6 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
7 |
8 | extend ProtocolMessage {
9 | optional SendCommandMessage sendCommandMessage = 6;
10 | }
11 |
12 | message SendCommandMessage {
13 | optional Command command = 1;
14 | optional CommandOptions options = 2;
15 | optional PlayerPath playerPath = 3;
16 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SendHIDEventMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional SendHIDEventMessage sendHIDEventMessage = 13;
7 | }
8 |
9 | message SendHIDEventMessage {
10 | // This data corresponds to a "keyboardEvent" in IOHIDEvent.h encoded as raw
11 | // data. Here is one source:
12 | //
13 | // https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-308/IOHIDFamily/IOHIDEvent.h.auto.html
14 | //
15 | // The interesting parts are:
16 | // - usagePage (UInt32)
17 | // - usage (Uint32)
18 | // - down (bool)
19 | //
20 | // The parameters usagePage and usage corresponds to the key being pressed.
21 | // It is mapped to the USB HID values, which can be found here:
22 | //
23 | // https://github.com/Daij-Djan/DDHidLib/blob/master/usb_hid_usages.txt
24 | //
25 | // Pressing left key would for instance map to usagePage=0x01, usage=0x8B. In
26 | // the hid data, these values are stored as big endian uint16 values in the
27 | // mentioned order. So the same example would be: 0x0001008B0001, assuming
28 | // down = true (key being pressed). For each key press, the same usagePage
29 | // and usage are sent with down=true and down=false (key down + key up).
30 | //
31 | // There is a bit of magic in the raw data that's just not decoded yet, but
32 | // that doesn't matter. Just use this and it will work:
33 | //
34 | // 438922cf0802000000000000000000000100000000000000020000002000000003000000010000000000000000000000000001000000
35 | //
36 | // corresponds to the values above, e.g. 0001008B0001. The first 8
37 | // bytes is a timestamp (mach AbsoluteTime). It's a bit tricky to derive but
38 | // tvOS seems to accept old timestamps here. So it's probably fine to send
39 | // anything.
40 | optional bytes hidEventData = 1;
41 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SendPackedVirtualTouchEventMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional SendPackedVirtualTouchEventMessage sendPackedVirtualTouchEventMessage = 47;
7 | }
8 |
9 | message SendPackedVirtualTouchEventMessage {
10 |
11 | // Corresponds to "phase" in data
12 | enum Phase {
13 | Began = 1;
14 | Moved = 2;
15 | Stationary = 3;
16 | Ended = 4;
17 | Cancelled = 5;
18 | }
19 |
20 | // The packed version of VirtualTouchEvent contains X, Y, phase, deviceID
21 | // and finger stored as a byte array. Each value is written as 16bit little
22 | // endian integers.
23 | optional bytes data = 1;
24 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SendVoiceInputMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage.proto";
5 |
6 | extend ProtocolMessage {
7 | optional SendVoiceInputMessage sendVoiceInputMessage = 36;
8 | }
9 |
10 | message AudioStreamPacketDescription {
11 | optional int64 startOffset = 1;
12 | optional uint32 variableFramesInPacket = 2;
13 | optional uint32 dataByteSize = 3;
14 | }
15 |
16 | message AudioBuffer {
17 | optional AudioFormatSettings formatSettings = 1;
18 | optional int64 packetCapacity = 2;
19 | optional int64 maximumPacketSize = 3;
20 | optional int64 packetCount = 4;
21 | optional bytes contents = 5;
22 | repeated AudioStreamPacketDescription packetDescriptions = 6;
23 | }
24 |
25 | message AudioTime {
26 | optional double timestamp = 1;
27 | optional double sampleRate = 2;
28 | }
29 |
30 | message AudioDataBlock {
31 | optional AudioBuffer buffer = 1;
32 | optional AudioTime time = 2;
33 | optional double gain = 3;
34 | }
35 |
36 | message SendVoiceInputMessage {
37 | optional AudioDataBlock dataBlock = 1;
38 | }
39 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetArtworkMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional SetArtworkMessage setArtworkMessage = 10;
7 | }
8 |
9 | message SetArtworkMessage {
10 | optional bytes jpegData = 1;
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetArtworkMessage_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/SetArtworkMessage.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/SetArtworkMessage.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 | from pyatv.protocols.mrp.protobuf import ProtocolMessage_pb2 as pyatv_dot_protocols_dot_mrp_dot_protobuf_dot_ProtocolMessage__pb2
26 |
27 |
28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n4pyatv/protocols/mrp/protobuf/SetArtworkMessage.proto\x1a\x32pyatv/protocols/mrp/protobuf/ProtocolMessage.proto\"%\n\x11SetArtworkMessage\x12\x10\n\x08jpegData\x18\x01 \x01(\x0c:?\n\x11setArtworkMessage\x12\x10.ProtocolMessage\x18\n \x01(\x0b\x32\x12.SetArtworkMessage')
29 |
30 | _globals = globals()
31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.SetArtworkMessage_pb2', _globals)
33 | if not _descriptor._USE_C_DESCRIPTORS:
34 | DESCRIPTOR._loaded_options = None
35 | _globals['_SETARTWORKMESSAGE']._serialized_start=108
36 | _globals['_SETARTWORKMESSAGE']._serialized_end=145
37 | # @@protoc_insertion_point(module_scope)
38 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetArtworkMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class SetArtworkMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | JPEGDATA_FIELD_NUMBER: builtins.int
20 | jpegData: builtins.bytes
21 | def __init__(
22 | self,
23 | *,
24 | jpegData: builtins.bytes | None = ...,
25 | ) -> None: ...
26 | def HasField(self, field_name: typing.Literal["jpegData", b"jpegData"]) -> builtins.bool: ...
27 | def ClearField(self, field_name: typing.Literal["jpegData", b"jpegData"]) -> None: ...
28 |
29 | global___SetArtworkMessage = SetArtworkMessage
30 |
31 | SETARTWORKMESSAGE_FIELD_NUMBER: builtins.int
32 | setArtworkMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___SetArtworkMessage]
33 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetConnectionStateMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional SetConnectionStateMessage setConnectionStateMessage = 42;
7 | }
8 |
9 | message SetConnectionStateMessage {
10 | enum ConnectionState {
11 | None = 0;
12 | Connecting = 1;
13 | Connected = 2;
14 | Disconnected = 3;
15 | }
16 |
17 | optional ConnectionState state = 1;
18 | }
19 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetDefaultSupportedCommandsMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/NowPlayingInfo.proto";
5 | import "pyatv/protocols/mrp/protobuf/PlaybackQueue.proto";
6 | import "pyatv/protocols/mrp/protobuf/SupportedCommands.proto";
7 | import "pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities.proto";
8 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
9 | import "pyatv/protocols/mrp/protobuf/PlaybackQueueRequestMessage.proto";
10 | import "pyatv/protocols/mrp/protobuf/Common.proto";
11 |
12 | extend ProtocolMessage {
13 | optional SetDefaultSupportedCommandsMessage setDefaultSupportedCommandsMessage = 75;
14 | }
15 |
16 | // Seems to be the same as SetStateMessage
17 | message SetDefaultSupportedCommandsMessage {
18 | optional NowPlayingInfo nowPlayingInfo = 1;
19 | optional SupportedCommands supportedCommands = 2;
20 | optional PlaybackQueue playbackQueue = 3;
21 | optional string displayID = 4;
22 | optional string displayName = 5;
23 | optional PlaybackState.Enum playbackState = 6;
24 | optional PlaybackQueueCapabilities playbackQueueCapabilities = 8;
25 | optional PlayerPath playerPath = 9;
26 | optional PlaybackQueueRequestMessage request = 10;
27 | optional double playbackStateTimestamp = 11;
28 | }
29 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetDiscoveryModeMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional SetDiscoveryModeMessage setDiscoveryModeMessage = 82;
7 | }
8 |
9 | message SetDiscoveryModeMessage {
10 | optional int32 mode = 1;
11 | optional int32 features = 2;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetDiscoveryModeMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class SetDiscoveryModeMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | MODE_FIELD_NUMBER: builtins.int
20 | FEATURES_FIELD_NUMBER: builtins.int
21 | mode: builtins.int
22 | features: builtins.int
23 | def __init__(
24 | self,
25 | *,
26 | mode: builtins.int | None = ...,
27 | features: builtins.int | None = ...,
28 | ) -> None: ...
29 | def HasField(self, field_name: typing.Literal["features", b"features", "mode", b"mode"]) -> builtins.bool: ...
30 | def ClearField(self, field_name: typing.Literal["features", b"features", "mode", b"mode"]) -> None: ...
31 |
32 | global___SetDiscoveryModeMessage = SetDiscoveryModeMessage
33 |
34 | SETDISCOVERYMODEMESSAGE_FIELD_NUMBER: builtins.int
35 | setDiscoveryModeMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___SetDiscoveryModeMessage]
36 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetHiliteModeMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional SetHiliteModeMessage setHiliteModeMessage = 44;
7 | }
8 |
9 | message SetHiliteModeMessage {
10 | optional int32 hiliteMode = 1;
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetHiliteModeMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class SetHiliteModeMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | HILITEMODE_FIELD_NUMBER: builtins.int
20 | hiliteMode: builtins.int
21 | def __init__(
22 | self,
23 | *,
24 | hiliteMode: builtins.int | None = ...,
25 | ) -> None: ...
26 | def HasField(self, field_name: typing.Literal["hiliteMode", b"hiliteMode"]) -> builtins.bool: ...
27 | def ClearField(self, field_name: typing.Literal["hiliteMode", b"hiliteMode"]) -> None: ...
28 |
29 | global___SetHiliteModeMessage = SetHiliteModeMessage
30 |
31 | SETHILITEMODEMESSAGE_FIELD_NUMBER: builtins.int
32 | setHiliteModeMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___SetHiliteModeMessage]
33 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetNowPlayingClientMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/NowPlayingClient.proto";
5 |
6 | extend ProtocolMessage {
7 | optional SetNowPlayingClientMessage setNowPlayingClientMessage = 50;
8 | }
9 |
10 | message SetNowPlayingClientMessage {
11 | optional NowPlayingClient client = 1;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetNowPlayingClientMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2
11 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class SetNowPlayingClientMessage(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | CLIENT_FIELD_NUMBER: builtins.int
21 | @property
22 | def client(self) -> pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2.NowPlayingClient: ...
23 | def __init__(
24 | self,
25 | *,
26 | client: pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2.NowPlayingClient | None = ...,
27 | ) -> None: ...
28 | def HasField(self, field_name: typing.Literal["client", b"client"]) -> builtins.bool: ...
29 | def ClearField(self, field_name: typing.Literal["client", b"client"]) -> None: ...
30 |
31 | global___SetNowPlayingClientMessage = SetNowPlayingClientMessage
32 |
33 | SETNOWPLAYINGCLIENTMESSAGE_FIELD_NUMBER: builtins.int
34 | setNowPlayingClientMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___SetNowPlayingClientMessage]
35 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetNowPlayingPlayerMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
5 |
6 | extend ProtocolMessage {
7 | optional SetNowPlayingPlayerMessage setNowPlayingPlayerMessage = 51;
8 | }
9 |
10 | message SetNowPlayingPlayerMessage {
11 | optional PlayerPath playerPath = 1;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetNowPlayingPlayerMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.PlayerPath_pb2
11 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class SetNowPlayingPlayerMessage(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | PLAYERPATH_FIELD_NUMBER: builtins.int
21 | @property
22 | def playerPath(self) -> pyatv.protocols.mrp.protobuf.PlayerPath_pb2.PlayerPath: ...
23 | def __init__(
24 | self,
25 | *,
26 | playerPath: pyatv.protocols.mrp.protobuf.PlayerPath_pb2.PlayerPath | None = ...,
27 | ) -> None: ...
28 | def HasField(self, field_name: typing.Literal["playerPath", b"playerPath"]) -> builtins.bool: ...
29 | def ClearField(self, field_name: typing.Literal["playerPath", b"playerPath"]) -> None: ...
30 |
31 | global___SetNowPlayingPlayerMessage = SetNowPlayingPlayerMessage
32 |
33 | SETNOWPLAYINGPLAYERMESSAGE_FIELD_NUMBER: builtins.int
34 | setNowPlayingPlayerMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___SetNowPlayingPlayerMessage]
35 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetRecordingStateMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional SetRecordingStateMessage setRecordingStateMessage = 35;
7 | }
8 |
9 | message SetRecordingStateMessage {
10 | enum RecordingState {
11 | Unknown = 0;
12 | Recording = 1;
13 | NotRecording = 2;
14 | }
15 |
16 | optional RecordingState state = 1;
17 | }
18 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetStateMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/NowPlayingInfo.proto";
5 | import "pyatv/protocols/mrp/protobuf/PlaybackQueue.proto";
6 | import "pyatv/protocols/mrp/protobuf/SupportedCommands.proto";
7 | import "pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities.proto";
8 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
9 | import "pyatv/protocols/mrp/protobuf/PlaybackQueueRequestMessage.proto";
10 | import "pyatv/protocols/mrp/protobuf/Common.proto";
11 |
12 | extend ProtocolMessage {
13 | optional SetStateMessage setStateMessage = 9;
14 | }
15 |
16 | message SetStateMessage {
17 | optional NowPlayingInfo nowPlayingInfo = 1;
18 | optional SupportedCommands supportedCommands = 2;
19 | optional PlaybackQueue playbackQueue = 3;
20 | optional string displayID = 4;
21 | optional string displayName = 5;
22 | optional PlaybackState.Enum playbackState = 6;
23 | optional PlaybackQueueCapabilities playbackQueueCapabilities = 8;
24 | optional PlayerPath playerPath = 9;
25 | optional PlaybackQueueRequestMessage request = 10;
26 | optional double playbackStateTimestamp = 11;
27 | }
28 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetVolumeMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional SetVolumeMessage setVolumeMessage = 55;
7 | }
8 |
9 | message SetVolumeMessage {
10 | optional float volume = 1;
11 | optional string outputDeviceUID = 2;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SetVolumeMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class SetVolumeMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | VOLUME_FIELD_NUMBER: builtins.int
20 | OUTPUTDEVICEUID_FIELD_NUMBER: builtins.int
21 | volume: builtins.float
22 | outputDeviceUID: builtins.str
23 | def __init__(
24 | self,
25 | *,
26 | volume: builtins.float | None = ...,
27 | outputDeviceUID: builtins.str | None = ...,
28 | ) -> None: ...
29 | def HasField(self, field_name: typing.Literal["outputDeviceUID", b"outputDeviceUID", "volume", b"volume"]) -> builtins.bool: ...
30 | def ClearField(self, field_name: typing.Literal["outputDeviceUID", b"outputDeviceUID", "volume", b"volume"]) -> None: ...
31 |
32 | global___SetVolumeMessage = SetVolumeMessage
33 |
34 | SETVOLUMEMESSAGE_FIELD_NUMBER: builtins.int
35 | setVolumeMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___SetVolumeMessage]
36 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SupportedCommands.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/CommandInfo.proto";
4 |
5 | message SupportedCommands {
6 | repeated CommandInfo supportedCommands = 1;
7 | }
8 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SupportedCommands_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/SupportedCommands.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/SupportedCommands.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 | from pyatv.protocols.mrp.protobuf import CommandInfo_pb2 as pyatv_dot_protocols_dot_mrp_dot_protobuf_dot_CommandInfo__pb2
26 |
27 |
28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n4pyatv/protocols/mrp/protobuf/SupportedCommands.proto\x1a.pyatv/protocols/mrp/protobuf/CommandInfo.proto\"<\n\x11SupportedCommands\x12\'\n\x11supportedCommands\x18\x01 \x03(\x0b\x32\x0c.CommandInfo')
29 |
30 | _globals = globals()
31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.SupportedCommands_pb2', _globals)
33 | if not _descriptor._USE_C_DESCRIPTORS:
34 | DESCRIPTOR._loaded_options = None
35 | _globals['_SUPPORTEDCOMMANDS']._serialized_start=104
36 | _globals['_SUPPORTEDCOMMANDS']._serialized_end=164
37 | # @@protoc_insertion_point(module_scope)
38 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/SupportedCommands_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import collections.abc
8 | import google.protobuf.descriptor
9 | import google.protobuf.internal.containers
10 | import google.protobuf.message
11 | import pyatv.protocols.mrp.protobuf.CommandInfo_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class SupportedCommands(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | SUPPORTEDCOMMANDS_FIELD_NUMBER: builtins.int
21 | @property
22 | def supportedCommands(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[pyatv.protocols.mrp.protobuf.CommandInfo_pb2.CommandInfo]: ...
23 | def __init__(
24 | self,
25 | *,
26 | supportedCommands: collections.abc.Iterable[pyatv.protocols.mrp.protobuf.CommandInfo_pb2.CommandInfo] | None = ...,
27 | ) -> None: ...
28 | def ClearField(self, field_name: typing.Literal["supportedCommands", b"supportedCommands"]) -> None: ...
29 |
30 | global___SupportedCommands = SupportedCommands
31 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/TextInputMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional TextInputMessage textInputMessage = 30;
7 | }
8 |
9 | message ActionType {
10 | enum Enum {
11 | Unknown = 0;
12 | Insert = 1;
13 | Set = 2;
14 | Delete = 3;
15 | ClearAction = 4; // "Clear" clashes with something, making mypy unhappy
16 | }
17 | }
18 |
19 | message TextInputMessage {
20 | optional double timestamp = 1;
21 | optional string text = 2;
22 | optional ActionType.Enum actionType = 3;
23 | }
24 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/TransactionKey.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | message TransactionKey {
4 | optional string identifier = 1;
5 | optional bytes userData = 2;
6 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/TransactionKey_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/TransactionKey.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/TransactionKey.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 |
26 |
27 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n1pyatv/protocols/mrp/protobuf/TransactionKey.proto\"6\n\x0eTransactionKey\x12\x12\n\nidentifier\x18\x01 \x01(\t\x12\x10\n\x08userData\x18\x02 \x01(\x0c')
28 |
29 | _globals = globals()
30 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.TransactionKey_pb2', _globals)
32 | if not _descriptor._USE_C_DESCRIPTORS:
33 | DESCRIPTOR._loaded_options = None
34 | _globals['_TRANSACTIONKEY']._serialized_start=53
35 | _globals['_TRANSACTIONKEY']._serialized_end=107
36 | # @@protoc_insertion_point(module_scope)
37 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/TransactionKey_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.message
9 | import typing
10 |
11 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
12 |
13 | @typing.final
14 | class TransactionKey(google.protobuf.message.Message):
15 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
16 |
17 | IDENTIFIER_FIELD_NUMBER: builtins.int
18 | USERDATA_FIELD_NUMBER: builtins.int
19 | identifier: builtins.str
20 | userData: builtins.bytes
21 | def __init__(
22 | self,
23 | *,
24 | identifier: builtins.str | None = ...,
25 | userData: builtins.bytes | None = ...,
26 | ) -> None: ...
27 | def HasField(self, field_name: typing.Literal["identifier", b"identifier", "userData", b"userData"]) -> builtins.bool: ...
28 | def ClearField(self, field_name: typing.Literal["identifier", b"identifier", "userData", b"userData"]) -> None: ...
29 |
30 | global___TransactionKey = TransactionKey
31 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/TransactionMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/TransactionPackets.proto";
4 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
5 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
6 |
7 | extend ProtocolMessage {
8 | optional TransactionMessage transactionMessage = 38;
9 | }
10 |
11 | message TransactionMessage {
12 | optional uint64 name = 1;
13 | optional TransactionPackets packets = 2;
14 | optional PlayerPath playerPath = 3;
15 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/TransactionPacket.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/TransactionKey.proto";
4 |
5 | message TransactionPacket {
6 | optional TransactionKey key = 1;
7 | optional bytes packetData = 2;
8 | optional string identifier = 3;
9 | optional uint64 totalLength = 4;
10 | optional uint64 totalWritePosition = 5;
11 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/TransactionPacket_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.message
9 | import pyatv.protocols.mrp.protobuf.TransactionKey_pb2
10 | import typing
11 |
12 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
13 |
14 | @typing.final
15 | class TransactionPacket(google.protobuf.message.Message):
16 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
17 |
18 | KEY_FIELD_NUMBER: builtins.int
19 | PACKETDATA_FIELD_NUMBER: builtins.int
20 | IDENTIFIER_FIELD_NUMBER: builtins.int
21 | TOTALLENGTH_FIELD_NUMBER: builtins.int
22 | TOTALWRITEPOSITION_FIELD_NUMBER: builtins.int
23 | packetData: builtins.bytes
24 | identifier: builtins.str
25 | totalLength: builtins.int
26 | totalWritePosition: builtins.int
27 | @property
28 | def key(self) -> pyatv.protocols.mrp.protobuf.TransactionKey_pb2.TransactionKey: ...
29 | def __init__(
30 | self,
31 | *,
32 | key: pyatv.protocols.mrp.protobuf.TransactionKey_pb2.TransactionKey | None = ...,
33 | packetData: builtins.bytes | None = ...,
34 | identifier: builtins.str | None = ...,
35 | totalLength: builtins.int | None = ...,
36 | totalWritePosition: builtins.int | None = ...,
37 | ) -> None: ...
38 | def HasField(self, field_name: typing.Literal["identifier", b"identifier", "key", b"key", "packetData", b"packetData", "totalLength", b"totalLength", "totalWritePosition", b"totalWritePosition"]) -> builtins.bool: ...
39 | def ClearField(self, field_name: typing.Literal["identifier", b"identifier", "key", b"key", "packetData", b"packetData", "totalLength", b"totalLength", "totalWritePosition", b"totalWritePosition"]) -> None: ...
40 |
41 | global___TransactionPacket = TransactionPacket
42 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/TransactionPackets.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/TransactionPacket.proto";
4 |
5 | message TransactionPackets {
6 | repeated TransactionPacket packets = 1;
7 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/TransactionPackets_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/TransactionPackets.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/TransactionPackets.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 | from pyatv.protocols.mrp.protobuf import TransactionPacket_pb2 as pyatv_dot_protocols_dot_mrp_dot_protobuf_dot_TransactionPacket__pb2
26 |
27 |
28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n5pyatv/protocols/mrp/protobuf/TransactionPackets.proto\x1a\x34pyatv/protocols/mrp/protobuf/TransactionPacket.proto\"9\n\x12TransactionPackets\x12#\n\x07packets\x18\x01 \x03(\x0b\x32\x12.TransactionPacket')
29 |
30 | _globals = globals()
31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.TransactionPackets_pb2', _globals)
33 | if not _descriptor._USE_C_DESCRIPTORS:
34 | DESCRIPTOR._loaded_options = None
35 | _globals['_TRANSACTIONPACKETS']._serialized_start=111
36 | _globals['_TRANSACTIONPACKETS']._serialized_end=168
37 | # @@protoc_insertion_point(module_scope)
38 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/TransactionPackets_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import collections.abc
8 | import google.protobuf.descriptor
9 | import google.protobuf.internal.containers
10 | import google.protobuf.message
11 | import pyatv.protocols.mrp.protobuf.TransactionPacket_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class TransactionPackets(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | PACKETS_FIELD_NUMBER: builtins.int
21 | @property
22 | def packets(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[pyatv.protocols.mrp.protobuf.TransactionPacket_pb2.TransactionPacket]: ...
23 | def __init__(
24 | self,
25 | *,
26 | packets: collections.abc.Iterable[pyatv.protocols.mrp.protobuf.TransactionPacket_pb2.TransactionPacket] | None = ...,
27 | ) -> None: ...
28 | def ClearField(self, field_name: typing.Literal["packets", b"packets"]) -> None: ...
29 |
30 | global___TransactionPackets = TransactionPackets
31 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/UpdateClientMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/NowPlayingClient.proto";
5 |
6 | extend ProtocolMessage {
7 | optional UpdateClientMessage updateClientMessage = 59;
8 | }
9 |
10 | message UpdateClientMessage {
11 | optional NowPlayingClient client = 1;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/UpdateClientMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2
11 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class UpdateClientMessage(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | CLIENT_FIELD_NUMBER: builtins.int
21 | @property
22 | def client(self) -> pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2.NowPlayingClient: ...
23 | def __init__(
24 | self,
25 | *,
26 | client: pyatv.protocols.mrp.protobuf.NowPlayingClient_pb2.NowPlayingClient | None = ...,
27 | ) -> None: ...
28 | def HasField(self, field_name: typing.Literal["client", b"client"]) -> builtins.bool: ...
29 | def ClearField(self, field_name: typing.Literal["client", b"client"]) -> None: ...
30 |
31 | global___UpdateClientMessage = UpdateClientMessage
32 |
33 | UPDATECLIENTMESSAGE_FIELD_NUMBER: builtins.int
34 | updateClientMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___UpdateClientMessage]
35 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/UpdateContentItemArtworkMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/ContentItem.proto";
5 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
6 |
7 | extend ProtocolMessage {
8 | optional UpdateContentItemArtworkMessage updateContentItemArtworkMessage = 61;
9 | }
10 |
11 | message UpdateContentItemArtworkMessage {
12 | repeated ContentItem contentItems = 1;
13 | optional PlayerPath playerPath = 2;
14 | }
15 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/UpdateContentItemMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/ContentItem.proto";
5 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
6 |
7 | extend ProtocolMessage {
8 | optional UpdateContentItemMessage updateContentItemMessage = 60;
9 | }
10 |
11 | message UpdateContentItemMessage {
12 | repeated ContentItem contentItems = 1;
13 | optional PlayerPath playerPath = 2;
14 | }
15 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/UpdateEndPointsMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional UpdateEndPointsMessage updateEndPointsMessage = 83;
7 | }
8 |
9 | message AVEndpointDescriptor {
10 | optional string name = 1;
11 | optional string uniqueIdentifier = 2;
12 | // repeated ... outputDevices = 3;
13 | // optional ... designatedGroupLeader = 4;
14 | optional bool isLocalEndpoint = 5;
15 | optional string instanceIdentifier = 6;
16 | optional bool isProxyGroupPlayer = 7;
17 | optional int32 connectionType = 8;
18 | optional bool canModifyGroupMembership = 9;
19 | // repeated ... _personalOutputDevices = 10;
20 | }
21 |
22 | message UpdateEndPointsMessage {
23 | optional AVEndpointDescriptor endpoints = 1;
24 | optional int32 endpointFeatures = 2;
25 | }
26 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/UpdatePlayerPath.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/PlayerPath.proto";
5 |
6 | extend ProtocolMessage {
7 | optional UpdatePlayerMessage updatePlayerMessage = 62;
8 | }
9 |
10 | message UpdatePlayerMessage {
11 | optional PlayerPath playerPath = 1;
12 | }
13 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/UpdatePlayerPath_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.PlayerPath_pb2
11 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class UpdatePlayerMessage(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | PLAYERPATH_FIELD_NUMBER: builtins.int
21 | @property
22 | def playerPath(self) -> pyatv.protocols.mrp.protobuf.PlayerPath_pb2.PlayerPath: ...
23 | def __init__(
24 | self,
25 | *,
26 | playerPath: pyatv.protocols.mrp.protobuf.PlayerPath_pb2.PlayerPath | None = ...,
27 | ) -> None: ...
28 | def HasField(self, field_name: typing.Literal["playerPath", b"playerPath"]) -> builtins.bool: ...
29 | def ClearField(self, field_name: typing.Literal["playerPath", b"playerPath"]) -> None: ...
30 |
31 | global___UpdatePlayerMessage = UpdatePlayerMessage
32 |
33 | UPDATEPLAYERMESSAGE_FIELD_NUMBER: builtins.int
34 | updatePlayerMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___UpdatePlayerMessage]
35 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | message VirtualTouchDeviceDescriptor {
4 | optional bool absolute = 1;
5 | optional bool integratedDisplay = 2;
6 | optional float screenSizeWidth = 3;
7 | optional float screenSizeHeight = 4;
8 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 |
26 |
27 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\nFpyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage.proto\"~\n\x1cVirtualTouchDeviceDescriptor\x12\x10\n\x08\x61\x62solute\x18\x01 \x01(\x08\x12\x19\n\x11integratedDisplay\x18\x02 \x01(\x08\x12\x17\n\x0fscreenSizeWidth\x18\x03 \x01(\x02\x12\x18\n\x10screenSizeHeight\x18\x04 \x01(\x02')
28 |
29 | _globals = globals()
30 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.VirtualTouchDeviceDescriptorMessage_pb2', _globals)
32 | if not _descriptor._USE_C_DESCRIPTORS:
33 | DESCRIPTOR._loaded_options = None
34 | _globals['_VIRTUALTOUCHDEVICEDESCRIPTOR']._serialized_start=74
35 | _globals['_VIRTUALTOUCHDEVICEDESCRIPTOR']._serialized_end=200
36 | # @@protoc_insertion_point(module_scope)
37 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.message
9 | import typing
10 |
11 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
12 |
13 | @typing.final
14 | class VirtualTouchDeviceDescriptor(google.protobuf.message.Message):
15 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
16 |
17 | ABSOLUTE_FIELD_NUMBER: builtins.int
18 | INTEGRATEDDISPLAY_FIELD_NUMBER: builtins.int
19 | SCREENSIZEWIDTH_FIELD_NUMBER: builtins.int
20 | SCREENSIZEHEIGHT_FIELD_NUMBER: builtins.int
21 | absolute: builtins.bool
22 | integratedDisplay: builtins.bool
23 | screenSizeWidth: builtins.float
24 | screenSizeHeight: builtins.float
25 | def __init__(
26 | self,
27 | *,
28 | absolute: builtins.bool | None = ...,
29 | integratedDisplay: builtins.bool | None = ...,
30 | screenSizeWidth: builtins.float | None = ...,
31 | screenSizeHeight: builtins.float | None = ...,
32 | ) -> None: ...
33 | def HasField(self, field_name: typing.Literal["absolute", b"absolute", "integratedDisplay", b"integratedDisplay", "screenSizeHeight", b"screenSizeHeight", "screenSizeWidth", b"screenSizeWidth"]) -> builtins.bool: ...
34 | def ClearField(self, field_name: typing.Literal["absolute", b"absolute", "integratedDisplay", b"integratedDisplay", "screenSizeHeight", b"screenSizeHeight", "screenSizeWidth", b"screenSizeWidth"]) -> None: ...
35 |
36 | global___VirtualTouchDeviceDescriptor = VirtualTouchDeviceDescriptor
37 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/VoiceInputDeviceDescriptorMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage.proto";
4 |
5 | message VoiceInputDeviceDescriptor {
6 | optional AudioFormatSettings defaultFormat = 1;
7 | repeated AudioFormatSettings supportedFormats = 2;
8 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/VoiceInputDeviceDescriptorMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import collections.abc
8 | import google.protobuf.descriptor
9 | import google.protobuf.internal.containers
10 | import google.protobuf.message
11 | import pyatv.protocols.mrp.protobuf.AudioFormatSettingsMessage_pb2
12 | import typing
13 |
14 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
15 |
16 | @typing.final
17 | class VoiceInputDeviceDescriptor(google.protobuf.message.Message):
18 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
19 |
20 | DEFAULTFORMAT_FIELD_NUMBER: builtins.int
21 | SUPPORTEDFORMATS_FIELD_NUMBER: builtins.int
22 | @property
23 | def defaultFormat(self) -> pyatv.protocols.mrp.protobuf.AudioFormatSettingsMessage_pb2.AudioFormatSettings: ...
24 | @property
25 | def supportedFormats(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[pyatv.protocols.mrp.protobuf.AudioFormatSettingsMessage_pb2.AudioFormatSettings]: ...
26 | def __init__(
27 | self,
28 | *,
29 | defaultFormat: pyatv.protocols.mrp.protobuf.AudioFormatSettingsMessage_pb2.AudioFormatSettings | None = ...,
30 | supportedFormats: collections.abc.Iterable[pyatv.protocols.mrp.protobuf.AudioFormatSettingsMessage_pb2.AudioFormatSettings] | None = ...,
31 | ) -> None: ...
32 | def HasField(self, field_name: typing.Literal["defaultFormat", b"defaultFormat"]) -> builtins.bool: ...
33 | def ClearField(self, field_name: typing.Literal["defaultFormat", b"defaultFormat", "supportedFormats", b"supportedFormats"]) -> None: ...
34 |
35 | global___VoiceInputDeviceDescriptor = VoiceInputDeviceDescriptor
36 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/VolumeControlAvailabilityMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional VolumeControlAvailabilityMessage volumeControlAvailabilityMessage = 22;
7 | }
8 |
9 | message VolumeCapabilities {
10 | // This is really a bitmap but protobuf has no type for that, so lets just add a "Both"
11 | // option since only two values exist anyway
12 | enum Enum {
13 | None = 0;
14 | Relative = 1;
15 | Absolute = 2;
16 | Both = 3;
17 | }
18 | }
19 |
20 | message VolumeControlAvailabilityMessage {
21 | optional bool volumeControlAvailable = 1;
22 | optional VolumeCapabilities.Enum volumeCapabilities = 2;
23 | }
24 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/VolumeControlCapabilitiesDidChangeMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 | import "pyatv/protocols/mrp/protobuf/VolumeControlAvailabilityMessage.proto";
5 |
6 | extend ProtocolMessage {
7 | optional VolumeControlCapabilitiesDidChangeMessage volumeControlCapabilitiesDidChangeMessage = 68;
8 | }
9 |
10 | message VolumeControlCapabilitiesDidChangeMessage {
11 | optional VolumeControlAvailabilityMessage capabilities = 1;
12 | optional string endpointUID = 3;
13 | optional string outputDeviceUID = 4;
14 | }
15 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/VolumeDidChangeMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional VolumeDidChangeMessage volumeDidChangeMessage = 56;
7 | }
8 |
9 | message VolumeDidChangeMessage {
10 | optional float volume = 1;
11 | optional string endpointUID = 2;
12 | optional string outputDeviceUID = 3;
13 | }
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/VolumeDidChangeMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class VolumeDidChangeMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | VOLUME_FIELD_NUMBER: builtins.int
20 | ENDPOINTUID_FIELD_NUMBER: builtins.int
21 | OUTPUTDEVICEUID_FIELD_NUMBER: builtins.int
22 | volume: builtins.float
23 | endpointUID: builtins.str
24 | outputDeviceUID: builtins.str
25 | def __init__(
26 | self,
27 | *,
28 | volume: builtins.float | None = ...,
29 | endpointUID: builtins.str | None = ...,
30 | outputDeviceUID: builtins.str | None = ...,
31 | ) -> None: ...
32 | def HasField(self, field_name: typing.Literal["endpointUID", b"endpointUID", "outputDeviceUID", b"outputDeviceUID", "volume", b"volume"]) -> builtins.bool: ...
33 | def ClearField(self, field_name: typing.Literal["endpointUID", b"endpointUID", "outputDeviceUID", b"outputDeviceUID", "volume", b"volume"]) -> None: ...
34 |
35 | global___VolumeDidChangeMessage = VolumeDidChangeMessage
36 |
37 | VOLUMEDIDCHANGEMESSAGE_FIELD_NUMBER: builtins.int
38 | volumeDidChangeMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___VolumeDidChangeMessage]
39 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/WakeDeviceMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | import "pyatv/protocols/mrp/protobuf/ProtocolMessage.proto";
4 |
5 | extend ProtocolMessage {
6 | optional WakeDeviceMessage wakeDeviceMessage = 45;
7 | }
8 |
9 | message WakeDeviceMessage {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/WakeDeviceMessage_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # NO CHECKED-IN PROTOBUF GENCODE
4 | # source: pyatv/protocols/mrp/protobuf/WakeDeviceMessage.proto
5 | # Protobuf Python Version: 6.30.2
6 | """Generated protocol buffer code."""
7 | from google.protobuf import descriptor as _descriptor
8 | from google.protobuf import descriptor_pool as _descriptor_pool
9 | from google.protobuf import runtime_version as _runtime_version
10 | from google.protobuf import symbol_database as _symbol_database
11 | from google.protobuf.internal import builder as _builder
12 | _runtime_version.ValidateProtobufRuntimeVersion(
13 | _runtime_version.Domain.PUBLIC,
14 | 6,
15 | 30,
16 | 2,
17 | '',
18 | 'pyatv/protocols/mrp/protobuf/WakeDeviceMessage.proto'
19 | )
20 | # @@protoc_insertion_point(imports)
21 |
22 | _sym_db = _symbol_database.Default()
23 |
24 |
25 | from pyatv.protocols.mrp.protobuf import ProtocolMessage_pb2 as pyatv_dot_protocols_dot_mrp_dot_protobuf_dot_ProtocolMessage__pb2
26 |
27 |
28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n4pyatv/protocols/mrp/protobuf/WakeDeviceMessage.proto\x1a\x32pyatv/protocols/mrp/protobuf/ProtocolMessage.proto\"\x13\n\x11WakeDeviceMessage:?\n\x11wakeDeviceMessage\x12\x10.ProtocolMessage\x18- \x01(\x0b\x32\x12.WakeDeviceMessage')
29 |
30 | _globals = globals()
31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'pyatv.protocols.mrp.protobuf.WakeDeviceMessage_pb2', _globals)
33 | if not _descriptor._USE_C_DESCRIPTORS:
34 | DESCRIPTOR._loaded_options = None
35 | _globals['_WAKEDEVICEMESSAGE']._serialized_start=108
36 | _globals['_WAKEDEVICEMESSAGE']._serialized_end=127
37 | # @@protoc_insertion_point(module_scope)
38 |
--------------------------------------------------------------------------------
/pyatv/protocols/mrp/protobuf/WakeDeviceMessage_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 |
6 | import builtins
7 | import google.protobuf.descriptor
8 | import google.protobuf.internal.extension_dict
9 | import google.protobuf.message
10 | import pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2
11 | import typing
12 |
13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
14 |
15 | @typing.final
16 | class WakeDeviceMessage(google.protobuf.message.Message):
17 | DESCRIPTOR: google.protobuf.descriptor.Descriptor
18 |
19 | def __init__(
20 | self,
21 | ) -> None: ...
22 |
23 | global___WakeDeviceMessage = WakeDeviceMessage
24 |
25 | WAKEDEVICEMESSAGE_FIELD_NUMBER: builtins.int
26 | wakeDeviceMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___WakeDeviceMessage]
27 |
--------------------------------------------------------------------------------
/pyatv/protocols/raop/packets.py:
--------------------------------------------------------------------------------
1 | """Packet formats used by RAOP."""
2 |
3 | from pyatv.support.packet import defpacket
4 |
5 | RtpHeader = defpacket("RtpHeader", proto="B", type="B", seqno="H")
6 |
7 | TimingPacket = RtpHeader.extend(
8 | "TimingPacket",
9 | padding="I",
10 | reftime_sec="I",
11 | reftime_frac="I",
12 | recvtime_sec="I",
13 | recvtime_frac="I",
14 | sendtime_sec="I",
15 | sendtime_frac="I",
16 | )
17 |
18 | SyncPacket = RtpHeader.extend(
19 | "SyncPacket",
20 | now_without_latency="I",
21 | last_sync_sec="I",
22 | last_sync_frac="I",
23 | now="I",
24 | )
25 |
26 | # NB: Audio payload is not included here, shall be appended manually
27 | AudioPacketHeader = RtpHeader.extend(
28 | "AudioPacketHeader",
29 | timestamp="I",
30 | ssrc="I",
31 | )
32 |
33 | RetransmitReqeust = RtpHeader.extend(
34 | "RetransmitPacket", lost_seqno="H", lost_packets="H"
35 | )
36 |
--------------------------------------------------------------------------------
/pyatv/protocols/raop/timing.py:
--------------------------------------------------------------------------------
1 | """Methods for working with time and synchronization in RAOP.
2 |
3 | The timing routines in this module is based on the excellent work of RAOP-Player:
4 | https://github.com/philippe44/RAOP-Player
5 | """
6 |
7 | from time import time_ns
8 | from typing import Tuple
9 |
10 |
11 | def ntp_now() -> int:
12 | """Return current time in NTP format."""
13 | now_us = time_ns() / 1000
14 | seconds = int(now_us / 1000000)
15 | frac = int(now_us - seconds * 1000000)
16 | return (seconds + 0x83AA7E80) << 32 | (int((frac << 32) / 1000000))
17 |
18 |
19 | def ntp2parts(ntp: int) -> Tuple[int, int]:
20 | """Split NTP time into seconds and fraction."""
21 | return ntp >> 32, ntp & 0xFFFFFFFF
22 |
23 |
24 | def ntp2ts(ntp: int, rate: int) -> int:
25 | """Convert NTP time into timestamp."""
26 | return int((ntp >> 16) * rate) >> 16
27 |
28 |
29 | def ts2ntp(timestamp: int, rate: int) -> int:
30 | """Convert timestamp into NTP time."""
31 | return int(int(timestamp << 16) / rate) << 16
32 |
33 |
34 | def ntp2ms(ntp: int) -> int:
35 | """Convert NTP time to milliseconds."""
36 | return ((ntp >> 10) * 1000) >> 22
37 |
38 |
39 | def ts2ms(timestamp: int, rate: int) -> int:
40 | """Convert timestamp to milliseconds."""
41 | return ntp2ms(ts2ntp(timestamp, rate))
42 |
--------------------------------------------------------------------------------
/pyatv/py.typed:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/postlund/pyatv/2fbdbd444b80048876e2ab6726ac945901e883b4/pyatv/py.typed
--------------------------------------------------------------------------------
/pyatv/storage/memory_storage.py:
--------------------------------------------------------------------------------
1 | """Memory storage module."""
2 |
3 | from pyatv.storage import AbstractStorage
4 |
5 | __pdoc_dev_page__ = "/development/storage"
6 |
7 |
8 | class MemoryStorage(AbstractStorage):
9 | """Memory based storage module.
10 |
11 | This storage module stores settings in memory and everything stored with it will
12 | be forgotten when restarting the python interpreter.
13 | """
14 |
15 | async def save(self) -> None:
16 | """Save settings to active storage."""
17 | self.mark_as_saved()
18 |
19 | async def load(self) -> None:
20 | """Load settings from active storage."""
21 |
22 | def __str__(self) -> str:
23 | """Return string representation of MemoryStorage."""
24 | return "MemoryStorage"
25 |
--------------------------------------------------------------------------------
/pyatv/support/cache.py:
--------------------------------------------------------------------------------
1 | """Simple LRU cache for data based on an identifier."""
2 |
3 | from collections import OrderedDict
4 |
5 |
6 | class Cache:
7 | """Implementation of simple LRU cache."""
8 |
9 | def __init__(self, limit=16):
10 | """Initialize a new Cache instance."""
11 | self.limit = limit
12 | self.data = OrderedDict()
13 |
14 | def empty(self):
15 | """Return if cache is empty or not."""
16 | return not self.data
17 |
18 | def put(self, identifier, data):
19 | """Put something in the cache."""
20 | try:
21 | self.data.pop(identifier)
22 | except KeyError:
23 | if len(self.data) >= self.limit:
24 | self.data.popitem(last=False)
25 | finally:
26 | self.data[identifier] = data
27 |
28 | def get(self, identifier):
29 | """Get something from the cache."""
30 | value = self.data.pop(identifier)
31 | self.data[identifier] = value
32 | return value
33 |
34 | def latest(self):
35 | """Return identifier of last recently used identifier."""
36 | if self.empty():
37 | return None
38 | return list(self.data.keys())[-1]
39 |
40 | def __contains__(self, identifier):
41 | """Check if something is in the cache."""
42 | return identifier in self.data
43 |
44 | def __len__(self):
45 | """Return number of elements in cache."""
46 | return len(self.data)
47 |
--------------------------------------------------------------------------------
/pyatv/support/metadata.py:
--------------------------------------------------------------------------------
1 | """Convenience methods for extracting metadata from an audio file."""
2 |
3 | import asyncio
4 | import io
5 | from typing import Union
6 |
7 | from tinytag import TinyTag
8 |
9 | from pyatv.interface import MediaMetadata
10 |
11 | EMPTY_METADATA = MediaMetadata(None, None, None, None)
12 |
13 |
14 | def _open_file(file: io.BufferedIOBase) -> TinyTag:
15 | start_position = file.tell()
16 | in_file = TinyTag.get(file_obj=file)
17 | file.seek(start_position)
18 | return in_file
19 |
20 |
21 | async def get_metadata(file: Union[str, io.BufferedIOBase]) -> MediaMetadata:
22 | """Extract metadata from a file and return it."""
23 | loop = asyncio.get_event_loop()
24 |
25 | # TODO: TinyTag will always start by seeking to the end of a
26 | # file, which isn't possible for streaming buffers. So this
27 | # works as long as the entire file is in the buffer, otherwise
28 | # it will fail. Hopefully this can be fixed by using mutagen
29 | # directly, but will require some manual handling.
30 | if isinstance(file, str):
31 | tag = await loop.run_in_executor(None, TinyTag.get, file)
32 | else:
33 | tag = await loop.run_in_executor(None, _open_file, file)
34 |
35 | return MediaMetadata(
36 | title=tag.title,
37 | artist=tag.artist,
38 | album=tag.album,
39 | duration=tag.duration,
40 | )
41 |
42 |
43 | def merge_into(base: MediaMetadata, new_metadata: MediaMetadata) -> MediaMetadata:
44 | """Merge missing fields into base metadata.
45 |
46 | Updates all fields with a None value in "new" with corresponding values from
47 | "new_metadata". Returns "base" again.
48 | """
49 | for field in base.__dataclass_fields__.keys():
50 | if getattr(base, field) is None:
51 | setattr(base, field, getattr(new_metadata, field))
52 | return base
53 |
--------------------------------------------------------------------------------
/pyatv/support/packet.py:
--------------------------------------------------------------------------------
1 | """Generic utility for encoding and decoding binary packets."""
2 |
3 | from collections import namedtuple
4 | import struct
5 |
6 |
7 | def defpacket(name: str, **kwargs):
8 | """Define a protocol packet."""
9 | fmt: str = ">" + "".join(kwargs.values())
10 | msg_type = namedtuple(name, kwargs.keys()) # type: ignore
11 |
12 | class _MessageType:
13 | length = struct.calcsize(fmt)
14 |
15 | @staticmethod
16 | def decode(data: bytes, allow_excessive=False):
17 | """Decode binary data as message."""
18 | return msg_type._make(
19 | struct.unpack(
20 | fmt, data if not allow_excessive else data[0 : struct.calcsize(fmt)]
21 | )
22 | )
23 |
24 | @staticmethod
25 | def encode(*args) -> bytes:
26 | """Encode a message into binary data."""
27 | return struct.pack(fmt, *args)
28 |
29 | @staticmethod
30 | def extend(ext_name, **ext_kwargs):
31 | """Extend a message type with additional fields."""
32 | fields = {**kwargs, **ext_kwargs}
33 | return defpacket(ext_name, **fields)
34 |
35 | return _MessageType
36 |
--------------------------------------------------------------------------------
/pyatv/support/pydantic_compat.py:
--------------------------------------------------------------------------------
1 | """Compatibility module for pydantic.
2 |
3 | This module provides some compatibility methods to support both pydantic v1 and v2 in
4 | pyatv. Ideally only v2 should be supported, but due to Home Assistant being stuck at v1
5 | for now, backwards compatibility will be provided until that is resolved. More info in
6 | https://github.com/postlund/pyatv/issues/2261.
7 |
8 | The idea is that the rest of the code never imports anything directly from pydantic,
9 | but instead getting import from here. That makes it easy to remove these changes
10 | later on.
11 | """
12 |
13 | from typing import Any, Mapping
14 |
15 | # pylint: disable=unused-import
16 |
17 | try:
18 | from pydantic.v1 import BaseModel, Field, ValidationError # noqa
19 | from pydantic.v1 import validator as field_validator # noqa
20 | except ImportError:
21 | from pydantic import BaseModel, Field, ValidationError # noqa
22 | from pydantic import validator as field_validator # noqa
23 |
24 | # pylint: enable=unused-import
25 |
26 |
27 | def model_copy(model: BaseModel, /, update: Mapping[str, Any]) -> BaseModel:
28 | """Model copy compatible with pydantic v2.
29 |
30 | Seems like pydantic v1 carries over keys with None values even though target model
31 | doesn't have the key. Not the case with v2. This method removes keys with None
32 | values.
33 | """
34 | return model.copy(
35 | update={key: value for key, value in update.items() if value is not None}
36 | )
37 |
--------------------------------------------------------------------------------
/pyatv/support/url.py:
--------------------------------------------------------------------------------
1 | """Helpers for working with URLs."""
2 |
3 | from urllib.parse import urlparse
4 |
5 |
6 | def is_url(url):
7 | """Check if something is a URL."""
8 | url_parts = urlparse(url)
9 | return bool(url_parts.scheme and url_parts.netloc)
10 |
11 |
12 | def is_url_or_scheme(url):
13 | """Check if something is a URL or a URL scheme."""
14 | url_parts = urlparse(url)
15 | return bool(url_parts.scheme)
16 |
--------------------------------------------------------------------------------
/pyatv/support/variant.py:
--------------------------------------------------------------------------------
1 | """Module to read and write Google protobuf variants."""
2 |
3 |
4 | def read_variant(variant):
5 | """Read and parse a binary protobuf variant value."""
6 | result = 0
7 | cnt = 0
8 | for data in variant:
9 | result |= (data & 0x7F) << (7 * cnt)
10 | cnt += 1
11 | if not data & 0x80:
12 | return result, variant[cnt:]
13 | raise ValueError("invalid variant")
14 |
15 |
16 | def write_variant(number):
17 | """Convert an integer to a protobuf variant binary buffer."""
18 | if number < 128:
19 | return bytes([number])
20 | return bytes([(number & 0x7F) | 0x80]) + write_variant(number >> 7)
21 |
--------------------------------------------------------------------------------
/pylintrc:
--------------------------------------------------------------------------------
1 | [MASTER]
2 | load-plugins=pylint.extensions.no_self_use
3 | reports=no
4 |
5 | [BASIC]
6 | good-names=
7 | ex,
8 | rd,
9 | f,
10 | i,
11 | T,
12 | ws
13 |
14 | [FORMAT]
15 | max-line-length=88
16 |
17 | [TYPECHECK]
18 | ignore=protobuf
19 | ignored-modules=pyatv.protocols.mrp.protobuf
20 | ignored-classes=
21 | ProtocolMessage,
22 | SetConnectionStateMessage,
23 | SetStateMessage,
24 | ContentItemMetadata,
25 | CommandInfo,
26 | PlaybackState,
27 | ShuffleMode,
28 | RepeatMode,
29 | HandlerReturnStatus,
30 | SendError,
31 | DeviceClass
32 |
33 | disable=
34 | broad-except,
35 | cyclic-import, # TODO: Bug in pylint?
36 | locally-disabled,
37 | duplicate-code,
38 | fixme,
39 | unused-argument,
40 | no-self-use,
41 | too-few-public-methods,
42 | too-many-public-methods,
43 | too-many-arguments,
44 | too-many-instance-attributes,
45 | too-many-lines,
46 | too-many-positional-arguments
47 |
48 | [EXCEPTIONS]
49 | overgeneral-exceptions=builtins.Exception
50 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.black]
2 | target-version = ["py35", "py36", "py37", "py38"]
3 | extend-exclude = '(protobuf/(__init__|.*_pb2).py)|__pycache__'
4 | include = '(pyatv|tests|examples|scripts).*\.py'
5 |
6 | [tool.isort]
7 | skip_glob = "pyatv/protocols/mrp/protobuf/*.py"
8 | profile = "black"
9 | force_sort_within_sections = true
10 | known_first_party = [
11 | "pyatv",
12 | "tests",
13 | "scripts",
14 | ]
15 | forced_separate = [
16 | "tests",
17 | "scripts",
18 | ]
19 |
20 | [[tool.mypy.overrides]]
21 | module = [
22 | "miniaudio",
23 | "audio_metadata",
24 | "srptools",
25 | ]
26 | ignore_missing_imports = true
27 |
--------------------------------------------------------------------------------
/requirements/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp==3.11.16
2 | async-timeout==5.0.1
3 | cryptography==44.0.2
4 | chacha20poly1305-reuseable==0.13.2
5 | ifaddr==0.2.0
6 | ifaddr==0.2.0
7 | miniaudio==1.61
8 | protobuf==6.30.2
9 | pydantic==2.11.3
10 | requests==2.32.3
11 | srptools==1.0.1
12 | tabulate==0.9.0
13 | tinytag==2.1.0
14 | zeroconf==0.146.3
--------------------------------------------------------------------------------
/requirements/requirements_docs.txt:
--------------------------------------------------------------------------------
1 | codespell==2.4.1
2 | pdoc3==0.11.6
3 |
--------------------------------------------------------------------------------
/requirements/requirements_test.txt:
--------------------------------------------------------------------------------
1 | black==25.1.0
2 | deepdiff==8.4.2
3 | flake8==7.2.0
4 | isort==6.0.1
5 | mutagen==1.47.0
6 | pyfakefs==5.8.0
7 | pylint==3.3.6
8 | pytest==8.3.5
9 | pytest-asyncio==0.26.0
10 | pytest-cov==6.1.1
11 | pytest-timeout==2.3.1
12 | pytest-aiohttp==1.0.5
13 | pytest_httpserver==1.1.2
14 | pytest-xdist==3.6.1
15 | pydocstyle==6.3.0
16 | mypy==1.15.0
17 | mypy-protobuf==3.6.0
18 | types-protobuf==5.29.1.20250403
19 | types-requests==2.32.0.20250328
20 | types-tabulate==0.9.0.20241207
21 |
--------------------------------------------------------------------------------
/scripts/build_docs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | run()
4 | {
5 | docker run -p 4000:4000 --rm \
6 | -v "$PWD:/srv/jekyll" \
7 | -v "$PWD/docs/vendor/bundle:/usr/local/bundle" \
8 | -w /srv/jekyll/docs \
9 | -it jekyll/jekyll:3.8 "$@"
10 | }
11 |
12 | if [[ $GITPOD_INSTANCE_ID ]]; then
13 | cd docs && bundle install && bundle update github-pages && bundle exec jekyll serve --incremental --watch
14 | else
15 | run bundle update github-pages
16 | run jekyll serve --incremental --watch
17 | fi
18 |
--------------------------------------------------------------------------------
/scripts/features.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """Create feature list enum from code."""
3 | from pyatv import interface
4 |
5 | FEATURE_TEMPLATE = """# This enum is generated by scripts/features.py
6 | class FeatureName(Enum):
7 | \"\"\"All supported features.\"\"\"
8 |
9 | {enum}
10 | """
11 |
12 |
13 | ENUM_VALUE_TEMPLATE = """ {name} = {index}
14 | \"\"\"{doc}\"\"\"
15 | """
16 |
17 |
18 | def main():
19 | """Script starts here."""
20 | # This is an internal script that is allowed to peek into internals
21 | features = interface._ALL_FEATURES # pylint: disable=protected-access
22 | enum_values = "\n".join(
23 | ENUM_VALUE_TEMPLATE.format(name=tmp[0], index=index, doc=tmp[1])
24 | for index, tmp in features.items()
25 | )
26 | print(FEATURE_TEMPLATE.format(enum=enum_values))
27 |
28 | print("Next free index:", max(features.keys()) + 1)
29 |
30 |
31 | if __name__ == "__main__":
32 | main()
33 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [aliases]
2 | test=pytest
3 |
4 | [bdist_wheel]
5 | universal = 0
6 |
7 | [tool:pytest]
8 | testpaths = tests
9 | norecursedirs = .git
10 |
11 | [flake8]
12 | exclude = .venv,.git,.tox,docs,venv,bin,lib,deps,build
13 | max-line-length = 88
14 | ignore = E203, W503
15 |
16 | [pydocstyle]
17 | match_dir = ^((?!\.|www_static).)*$
18 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | """Test suite for pyatv."""
2 |
--------------------------------------------------------------------------------
/tests/data/README:
--------------------------------------------------------------------------------
1 | Audio files in this directory have been generated by the
2 | commands below in case they ever need to be re-generated.
3 |
4 | Only metadata, no audio:
5 |
6 | python ../../scripts/audiogen.py --title pyatv --artist postlund --album raop -n 0 -o only_metadata.wav
7 |
8 | Audio, 10 frames (=20 samples):
9 |
10 | python ../../scripts/audiogen.py -n 10 -o audio_10_frames.wav
11 |
12 | Audio, 352 * 3 frames = 3 packets (=1056 samples):
13 |
14 | python ../../scripts/audiogen.py -n 1056 -o audio_3_packets.wav
15 |
16 | Audio, 8 seconds static (no sound), ogg for compression:
17 |
18 | python ../../scripts/audiogen.py -n 132300 -s -o static_3sec.wav
19 | ffmpeg -i static_3sec.wav static_3sec.ogg
20 |
21 | Audio, 1 packets (=352 samples), with metadata:
22 |
23 | python ../../scripts/audiogen.py --title pyatv --artist postlund --album raop -n 352 -o audio_1_packet_metadata.wav
24 |
--------------------------------------------------------------------------------
/tests/data/audio_10_frames.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/postlund/pyatv/2fbdbd444b80048876e2ab6726ac945901e883b4/tests/data/audio_10_frames.wav
--------------------------------------------------------------------------------
/tests/data/audio_1_packet_metadata.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/postlund/pyatv/2fbdbd444b80048876e2ab6726ac945901e883b4/tests/data/audio_1_packet_metadata.wav
--------------------------------------------------------------------------------
/tests/data/audio_3_packets.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/postlund/pyatv/2fbdbd444b80048876e2ab6726ac945901e883b4/tests/data/audio_3_packets.wav
--------------------------------------------------------------------------------
/tests/data/only_metadata.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/postlund/pyatv/2fbdbd444b80048876e2ab6726ac945901e883b4/tests/data/only_metadata.wav
--------------------------------------------------------------------------------
/tests/data/only_title.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/postlund/pyatv/2fbdbd444b80048876e2ab6726ac945901e883b4/tests/data/only_title.wav
--------------------------------------------------------------------------------
/tests/data/static_3sec.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/postlund/pyatv/2fbdbd444b80048876e2ab6726ac945901e883b4/tests/data/static_3sec.ogg
--------------------------------------------------------------------------------
/tests/data/testfile.txt:
--------------------------------------------------------------------------------
1 | a file for testing
--------------------------------------------------------------------------------
/tests/fake_knock.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import logging
3 |
4 | import pytest
5 |
6 | _LOGGER = logging.getLogger(__name__)
7 |
8 |
9 | class KnockServer(asyncio.Protocol):
10 | def __init__(self, port):
11 | self.got_knock = False
12 | self.count = 0
13 | self.port = port
14 |
15 | def connection_made(self, transport):
16 | own = transport.get_extra_info("sockname")
17 | peername = transport.get_extra_info("peername")
18 | _LOGGER.debug("Knock on %s:%d from %s:%d", *own, *peername)
19 | self.transport = transport
20 |
21 | def connection_lost(self, exc):
22 | self.got_knock = True
23 | self.count += 1
24 | self.transport = None
25 |
26 | def data_received(self, data):
27 | assert False, "no data shall be received"
28 |
29 |
30 | async def create_knock_server(port, loop):
31 | server = KnockServer(port)
32 | return await loop.create_server(lambda: server, "127.0.0.1", port), server
33 |
--------------------------------------------------------------------------------
/tests/protocols/airplay/conftest.py:
--------------------------------------------------------------------------------
1 | """Shared test code for AirPlay test cases."""
2 |
3 | import asyncio
4 |
5 | import pytest
6 | import pytest_asyncio
7 |
8 | from pyatv.conf import AppleTV, ManualService
9 | from pyatv.const import Protocol
10 | from pyatv.support.http import http_connect
11 |
12 | from tests.fake_device import FakeAppleTV
13 |
14 |
15 | @pytest_asyncio.fixture(name="airplay_device")
16 | async def airplay_device_fixture():
17 | fake_atv = FakeAppleTV(asyncio.get_running_loop(), test_mode=False)
18 | fake_atv.add_service(Protocol.AirPlay)
19 | await fake_atv.start()
20 | yield fake_atv
21 | await fake_atv.stop()
22 |
23 |
24 | @pytest_asyncio.fixture(name="client_connection")
25 | async def client_connection_fixture(airplay_device):
26 | yield await http_connect("127.0.0.1", airplay_device.get_port(Protocol.AirPlay))
27 |
28 |
29 | @pytest.fixture(name="airplay_usecase")
30 | def airplay_usecase_fixture(airplay_device):
31 | yield airplay_device.get_usecase(Protocol.AirPlay)
32 |
33 |
34 | @pytest.fixture(name="airplay_state")
35 | def airplay_state_fixture(airplay_device):
36 | yield airplay_device.get_state(Protocol.AirPlay)
37 |
38 |
39 | @pytest.fixture(name="airplay_properties")
40 | def airplay_properties_fixture():
41 | yield {}
42 |
43 |
44 | @pytest.fixture(name="airplay_conf")
45 | def airplay_conf_fixture(airplay_device, airplay_properties):
46 | service = ManualService(
47 | "airplay_id",
48 | Protocol.AirPlay,
49 | airplay_device.get_port(Protocol.AirPlay),
50 | airplay_properties,
51 | )
52 | conf = AppleTV("127.0.0.1", "Apple TV")
53 | conf.add_service(service)
54 | yield conf
55 |
--------------------------------------------------------------------------------
/tests/protocols/airplay/test_airplay_interface.py:
--------------------------------------------------------------------------------
1 | """Unit tests for interface implementations in pyatv.protocols.airplay."""
2 |
3 | import pytest
4 |
5 | from pyatv.const import FeatureName, FeatureState
6 | from pyatv.protocols.airplay import AirPlayFeatures
7 | from pyatv.protocols.airplay.utils import parse_features
8 |
9 | # AirPlayFeatures
10 |
11 |
12 | @pytest.mark.parametrize(
13 | "flags,expected_state",
14 | [
15 | ("0x0,0x0", FeatureState.Unavailable),
16 | ("0x1,0x0", FeatureState.Available), # VideoV1
17 | ("0x00000000,0x20000", FeatureState.Available), # VideoV2
18 | ],
19 | )
20 | def test_feature_play_url(flags, expected_state):
21 | features = AirPlayFeatures(parse_features(flags))
22 | assert features.get_feature(FeatureName.PlayUrl).state == expected_state
23 |
--------------------------------------------------------------------------------
/tests/protocols/airplay/test_airplay_scan.py:
--------------------------------------------------------------------------------
1 | """Scanning tests with fake mDNS responder.."""
2 |
3 | from ipaddress import ip_address
4 |
5 | import pytest
6 |
7 | from pyatv.const import Protocol
8 |
9 | from tests import fake_udns
10 | from tests.conftest import Scanner
11 | from tests.utils import assert_device
12 |
13 | IP_1 = "10.0.0.1"
14 |
15 | AIRPLAY_NAME = "AirPlay ATV"
16 | AIRPLAY_ID = "AA:BB:CC:DD:EE:FF"
17 |
18 | pytestmark = pytest.mark.asyncio
19 |
20 |
21 | async def test_multicast_scan_airplay_device(udns_server, multicast_scan: Scanner):
22 | udns_server.add_service(
23 | fake_udns.airplay_service(AIRPLAY_NAME, AIRPLAY_ID, addresses=[IP_1])
24 | )
25 |
26 | atvs = await multicast_scan()
27 | assert len(atvs) == 1
28 | assert atvs[0].name == AIRPLAY_NAME
29 | assert atvs[0].identifier == AIRPLAY_ID
30 | assert atvs[0].address == ip_address(IP_1)
31 |
32 |
33 | async def test_unicast_scan_airplay(udns_server, unicast_scan: Scanner):
34 | udns_server.add_service(
35 | fake_udns.airplay_service(AIRPLAY_NAME, AIRPLAY_ID, addresses=[IP_1], port=7000)
36 | )
37 |
38 | atvs = await unicast_scan()
39 | assert len(atvs) == 1
40 |
41 | assert_device(
42 | atvs[0],
43 | AIRPLAY_NAME,
44 | ip_address(IP_1),
45 | AIRPLAY_ID,
46 | Protocol.AirPlay,
47 | 7000,
48 | )
49 |
--------------------------------------------------------------------------------
/tests/protocols/airplay/test_airplay_verify.py:
--------------------------------------------------------------------------------
1 | """Functional credential verification tests using the API with a fake AirPlay Apple TV."""
2 |
3 | from contextlib import nullcontext as does_not_raise
4 |
5 | import pytest
6 |
7 | from pyatv.auth.hap_pairing import TRANSIENT_CREDENTIALS, parse_credentials
8 | from pyatv.auth.server_auth import CLIENT_CREDENTIALS
9 | from pyatv.const import Protocol
10 | from pyatv.exceptions import AuthenticationError
11 | from pyatv.protocols.airplay.auth import pair_verify
12 | from pyatv.support import http
13 |
14 | from tests.fake_device.airplay import DEVICE_CREDENTIALS
15 |
16 | pytestmark = pytest.mark.asyncio
17 |
18 |
19 | @pytest.mark.parametrize(
20 | "credentials, expectation",
21 | [
22 | (parse_credentials(DEVICE_CREDENTIALS), does_not_raise()),
23 | (
24 | parse_credentials(f"{8 * '00'}:{32 * '11'}"),
25 | pytest.raises(AuthenticationError),
26 | ),
27 | (parse_credentials(CLIENT_CREDENTIALS), does_not_raise()),
28 | (
29 | parse_credentials(f"{32 * '00'}:{32 * '11'}:{36 * '22'}:{36 * '33'}"),
30 | pytest.raises(AuthenticationError),
31 | ),
32 | (TRANSIENT_CREDENTIALS, does_not_raise()),
33 | ],
34 | )
35 | async def test_verify(airplay_conf, credentials, expectation):
36 | connection = await http.http_connect(
37 | str(airplay_conf.address), airplay_conf.get_service(Protocol.AirPlay).port
38 | )
39 | verifier = pair_verify(credentials, connection)
40 | with expectation:
41 | await verifier.verify_credentials()
42 | connection.close()
43 |
--------------------------------------------------------------------------------
/tests/protocols/mrp/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/postlund/pyatv/2fbdbd444b80048876e2ab6726ac945901e883b4/tests/protocols/mrp/__init__.py
--------------------------------------------------------------------------------
/tests/protocols/mrp/conftest.py:
--------------------------------------------------------------------------------
1 | """Fixtures and code shared between MRP tests."""
2 |
3 | import asyncio
4 |
5 | import pytest
6 |
7 | from pyatv.core.protocol import MessageDispatcher
8 | from pyatv.protocols.mrp import protobuf
9 |
10 |
11 | # This mock is _extremely_ basic, so needs to be adjusted heavily when adding
12 | # new tests
13 | class MrpProtocolMock(MessageDispatcher[int, protobuf.ProtocolMessage]):
14 | def __init__(self):
15 | super().__init__()
16 | self.sent_messages = []
17 | self.device_info = None
18 |
19 | async def send(self, message):
20 | self.sent_messages.append(message)
21 |
22 | async def inject(self, message: protobuf.ProtocolMessage) -> None:
23 | await asyncio.gather(*self.dispatch(message.type, message))
24 |
25 |
26 | @pytest.fixture(name="protocol_mock")
27 | def protocol_mock_fixture(event_loop):
28 | yield MrpProtocolMock()
29 |
--------------------------------------------------------------------------------
/tests/protocols/mrp/test_mrp_scan.py:
--------------------------------------------------------------------------------
1 | """Functional tests for MRP scanning.."""
2 |
3 | from ipaddress import ip_address
4 |
5 | import pytest
6 |
7 | from pyatv.const import DeviceModel, Protocol
8 |
9 | from tests import fake_udns
10 | from tests.conftest import Scanner
11 | from tests.utils import assert_device
12 |
13 | IP_1 = "10.0.0.1"
14 |
15 | MRP_ID = "mrp_id_1"
16 | MRP_NAME = "MRP ATV"
17 | MRP_SERVICE_NAME = "MRP Service"
18 |
19 | MRP_PORT = 49152
20 |
21 | pytestmark = pytest.mark.asyncio
22 |
23 |
24 | async def test_multicast_scan_mrp_with_companion(udns_server, multicast_scan):
25 | udns_server.add_service(
26 | fake_udns.mrp_service(
27 | MRP_SERVICE_NAME, MRP_NAME, MRP_ID, addresses=[IP_1], port=MRP_PORT
28 | )
29 | )
30 |
31 | atvs = await multicast_scan(protocol=Protocol.MRP)
32 | assert len(atvs) == 1
33 |
34 | assert_device(atvs[0], MRP_NAME, ip_address(IP_1), MRP_ID, Protocol.MRP, MRP_PORT)
35 |
36 |
37 | async def test_unicast_scan_mrp(udns_server, unicast_scan):
38 | udns_server.add_service(
39 | fake_udns.mrp_service(
40 | MRP_SERVICE_NAME, MRP_NAME, MRP_ID, addresses=[IP_1], port=MRP_PORT
41 | )
42 | )
43 |
44 | atvs = await unicast_scan()
45 | assert len(atvs) == 1
46 |
47 | assert_device(atvs[0], MRP_NAME, ip_address(IP_1), MRP_ID, Protocol.MRP, MRP_PORT)
48 |
--------------------------------------------------------------------------------
/tests/protocols/raop/conftest.py:
--------------------------------------------------------------------------------
1 | """Shared test code for RAOP test cases."""
2 |
3 | import asyncio
4 | from typing import cast
5 |
6 | import pytest
7 | import pytest_asyncio
8 |
9 | from pyatv import connect
10 | from pyatv.conf import AppleTV, ManualService
11 | from pyatv.const import Protocol
12 |
13 | from tests.fake_device import FakeAppleTV, raop
14 | from tests.fake_device.raop import FakeRaopUseCases
15 |
16 |
17 | @pytest_asyncio.fixture(name="raop_device")
18 | async def raop_device_fixture():
19 | fake_atv = FakeAppleTV(asyncio.get_running_loop(), test_mode=False)
20 | fake_atv.add_service(Protocol.RAOP)
21 | await fake_atv.start()
22 | yield fake_atv
23 | await fake_atv.stop()
24 |
25 |
26 | @pytest.fixture(name="raop_state")
27 | def raop_state_fixture(raop_device):
28 | yield raop_device.get_state(Protocol.RAOP)
29 |
30 |
31 | @pytest.fixture(name="raop_usecase")
32 | def raop_usecase_fixture(raop_device) -> FakeRaopUseCases:
33 | yield cast(FakeRaopUseCases, raop_device.get_usecase(Protocol.RAOP))
34 |
35 |
36 | @pytest.fixture(name="raop_conf")
37 | def raop_conf_fixture(raop_device, raop_properties):
38 | service = ManualService(
39 | "raop_id", Protocol.RAOP, raop_device.get_port(Protocol.RAOP), raop_properties
40 | )
41 | conf = AppleTV("127.0.0.1", "Apple TV")
42 | conf.add_service(service)
43 | yield conf
44 |
45 |
46 | @pytest_asyncio.fixture(name="raop_client")
47 | async def raop_client_fixture(raop_conf):
48 | client = await connect(raop_conf, loop=asyncio.get_running_loop())
49 | yield client
50 | await asyncio.gather(*client.close())
51 |
--------------------------------------------------------------------------------
/tests/protocols/raop/test_raop_scan.py:
--------------------------------------------------------------------------------
1 | """Functional tests for RAOP scanning.."""
2 |
3 | from ipaddress import ip_address
4 |
5 | import pytest
6 |
7 | from pyatv.const import Protocol
8 |
9 | from tests import fake_udns
10 | from tests.conftest import Scanner
11 | from tests.utils import assert_device
12 |
13 | IP_1 = "10.0.0.1"
14 |
15 | RAOP_ID = "AABBCCDDEEFF"
16 | RAOP_NAME = "RAOP ATV"
17 |
18 | RAOP_PORT = 4567
19 |
20 | pytestmark = pytest.mark.asyncio
21 |
22 |
23 | async def test_multicast_scan_raop_device(udns_server, multicast_scan):
24 | udns_server.add_service(
25 | fake_udns.raop_service(RAOP_NAME, RAOP_ID, addresses=[IP_1], port=RAOP_PORT)
26 | )
27 |
28 | atvs = await multicast_scan()
29 | assert len(atvs) == 1
30 |
31 | assert_device(
32 | atvs[0], RAOP_NAME, ip_address(IP_1), RAOP_ID, Protocol.RAOP, RAOP_PORT
33 | )
34 |
35 |
36 | async def test_unicast_scan_raop(udns_server, unicast_scan):
37 | udns_server.add_service(
38 | fake_udns.raop_service(RAOP_NAME, RAOP_ID, addresses=[IP_1], port=RAOP_PORT)
39 | )
40 |
41 | atvs = await unicast_scan()
42 | assert len(atvs) == 1
43 |
44 | assert_device(
45 | atvs[0], RAOP_NAME, ip_address(IP_1), RAOP_ID, Protocol.RAOP, RAOP_PORT
46 | )
47 |
--------------------------------------------------------------------------------
/tests/shared_helpers.py:
--------------------------------------------------------------------------------
1 | """Shared test helper code."""
2 |
3 | from pyatv.const import PowerState
4 | from pyatv.interface import PowerListener
5 |
6 |
7 | class SavingPowerListener(PowerListener):
8 | def __init__(self):
9 | self.last_update = None
10 | self.all_updates = []
11 |
12 | def powerstate_update(self, old_state: PowerState, new_state: PowerState):
13 | """Device power state was updated."""
14 | self.last_update = new_state
15 | self.all_updates.append(new_state)
16 |
--------------------------------------------------------------------------------
/tests/support/pyatv.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "../.."
5 | },
6 | {
7 | "path": "../../../airplay2-receiver"
8 | },
9 | {
10 | "path": "../../../pyminiaudio"
11 | }
12 | ],
13 | "settings": {}
14 | }
--------------------------------------------------------------------------------
/tests/support/test_chacha20.py:
--------------------------------------------------------------------------------
1 | """Unit tests for pyatv.support.chacha20."""
2 |
3 | import logging
4 |
5 | from pyatv.support import chacha20
6 |
7 | fake_key = b"k" * 32
8 |
9 |
10 | def test_12_bytes_nonce():
11 | cipher = chacha20.Chacha20Cipher(fake_key, fake_key, 12)
12 | assert len(cipher.out_nonce) == chacha20.NONCE_LENGTH
13 | assert len(cipher.in_nonce) == chacha20.NONCE_LENGTH
14 | result = cipher.encrypt(b"test")
15 | assert cipher.decrypt(result) == b"test"
16 |
17 |
18 | def test_8_bytes_nonce():
19 | cipher = chacha20.Chacha20Cipher8byteNonce(fake_key, fake_key)
20 | assert len(cipher.out_nonce) == chacha20.NONCE_LENGTH
21 | assert len(cipher.in_nonce) == chacha20.NONCE_LENGTH
22 | result = cipher.encrypt(b"test")
23 | assert cipher.decrypt(result) == b"test"
24 |
--------------------------------------------------------------------------------
/tests/support/test_metadata.py:
--------------------------------------------------------------------------------
1 | """Unit tests for pyatv.support.metadata."""
2 |
3 | import math
4 | from pathlib import Path
5 |
6 | import pytest
7 |
8 | from pyatv.interface import MediaMetadata
9 | from pyatv.support.metadata import get_metadata, merge_into
10 |
11 | from tests.utils import data_path
12 |
13 |
14 | def assert_metadata(metadata: MediaMetadata) -> None:
15 | assert metadata.artist == "postlund"
16 | assert metadata.album == "raop"
17 | assert metadata.title == "pyatv"
18 | assert metadata.artwork is None
19 | assert math.isclose(metadata.duration, 0.0)
20 |
21 |
22 | @pytest.mark.asyncio
23 | async def test_get_metadata_from_file():
24 | with open(data_path("only_metadata.wav"), "rb") as fh:
25 | metadata = await get_metadata(fh)
26 | assert_metadata(metadata)
27 |
28 |
29 | @pytest.mark.asyncio
30 | async def test_get_metadata_from_buffer():
31 | metadata = await get_metadata(data_path("only_metadata.wav"))
32 | assert_metadata(metadata)
33 |
34 |
35 | METADATA_FIELDS = list(MediaMetadata.__dataclass_fields__.keys())
36 |
37 |
38 | def test_returns_base_instance():
39 | base = MediaMetadata()
40 | new_metadata = MediaMetadata()
41 | merged = merge_into(base, new_metadata)
42 | assert merged is base
43 |
44 |
45 | def test_to_empty_metadata():
46 | # This basically sets the title field to "title", artist to "artist" and so on
47 | # for all fields and assert that it is correct
48 | metadata = merge_into(MediaMetadata(), MediaMetadata(*METADATA_FIELDS))
49 | for field in METADATA_FIELDS:
50 | assert getattr(metadata, field) == field
51 |
52 |
53 | def test_no_override_set_value():
54 | metadata = merge_into(
55 | MediaMetadata(title="title"), MediaMetadata(title="new title")
56 | )
57 | assert metadata.title == "title"
58 |
--------------------------------------------------------------------------------
/tests/support/test_packet.py:
--------------------------------------------------------------------------------
1 | """Unit tests for pyatv.support.packet."""
2 |
3 | import pytest
4 |
5 | from pyatv.support.packet import defpacket
6 |
7 | Foo = defpacket("Foo", a="c", b="h")
8 | Bar = Foo.extend("Bar", c="I")
9 |
10 |
11 | def test_encode_messages():
12 | assert Foo.encode(b"\x16", 0x123) == b"\x16\x01\x23"
13 |
14 |
15 | def test_decode_message():
16 | decoded = Foo.decode(b"\x16\x01\x23")
17 | assert decoded.a == b"\x16"
18 | assert decoded.b == 0x123
19 |
20 |
21 | def test_decode_with_excessive_data():
22 | decoded = Foo.decode(b"\x17\x02\x34\x11\x22\x33", allow_excessive=True)
23 | assert decoded.a == b"\x17"
24 | assert decoded.b == 0x234
25 |
26 |
27 | def test_extend_encode():
28 | assert Bar.encode(b"\x77", 0x67, 0xAABBCCDD) == b"\x77\x00\x67\xaa\xbb\xcc\xdd"
29 |
30 |
31 | def test_extend_decode():
32 | decoded = Bar.decode(b"\x77\x00\x67\xaa\xbb\xcc\xdd")
33 | assert decoded.a == b"\x77"
34 | assert decoded.b == 0x0067
35 | assert decoded.c == 0xAABBCCDD
36 |
37 |
38 | def test_message_length():
39 | assert Foo.length == 3
40 | assert Bar.length == 3 + 4
41 |
--------------------------------------------------------------------------------
/tests/support/test_shield.py:
--------------------------------------------------------------------------------
1 | """Unit tests for pyatv.support.shield."""
2 |
3 | import pytest
4 |
5 | from pyatv.exceptions import BlockedStateError, InvalidStateError
6 | from pyatv.support import shield
7 |
8 |
9 | class Dummy:
10 | pass
11 |
12 |
13 | def test_shield_object():
14 | obj = Dummy()
15 |
16 | assert not shield.is_shielded(obj)
17 | obj2 = shield.shield(obj)
18 | assert obj == obj2
19 | assert shield.is_shielded(obj)
20 |
21 |
22 | def test_cannot_block_unshielded_object():
23 | obj = Dummy()
24 | with pytest.raises(InvalidStateError):
25 | shield.block(obj)
26 |
27 |
28 | def test_is_blocking_does_not_raise_on_unshielded_object():
29 | obj = Dummy()
30 | assert not shield.is_blocking(obj)
31 |
32 |
33 | def test_block_shielded_object():
34 | obj = Dummy()
35 | shield.shield(obj)
36 | assert not shield.is_blocking(obj)
37 | shield.block(obj)
38 | assert shield.is_blocking(obj)
39 |
40 |
41 | class GuardedClass:
42 | @shield.guard
43 | def guarded_method(self, a):
44 | return a * a
45 |
46 | def unguarded_method(self, b):
47 | return b + b
48 |
49 |
50 | def test_guarded_methods():
51 | obj = GuardedClass()
52 |
53 | shield.shield(obj)
54 |
55 | # Should work fine since object is not blocked
56 | assert obj.guarded_method(2) == 4
57 | assert obj.unguarded_method(4) == 8
58 |
59 | shield.block(obj)
60 |
61 | with pytest.raises(BlockedStateError):
62 | obj.guarded_method()
63 |
64 | obj.unguarded_method(5) == 10
65 |
--------------------------------------------------------------------------------
/tests/support/test_url.py:
--------------------------------------------------------------------------------
1 | from pyatv.support.url import is_url, is_url_or_scheme
2 |
3 |
4 | def test_is_url_accepts_http_url():
5 | assert is_url("http://example.com") is True
6 |
7 |
8 | def test_is_url_accepts_app_url():
9 | assert (
10 | is_url(
11 | "com.apple.tv://tv.apple.com/show/marvels-spidey-and-his-amazing-friends/umc.cmc.3ambs8tqwzphbn0u8e9g76x7m?profile=kids&action=play"
12 | )
13 | is True
14 | )
15 |
16 |
17 | def test_is_url_rejects_bundle_id():
18 | assert is_url("com.apple.tv") is False
19 |
20 |
21 | def test_is_url_rejects_scheme():
22 | assert is_url("com.apple.tv://") is False
23 |
24 |
25 | def test_is_url_or_scheme_accepts_http_url():
26 | assert is_url_or_scheme("http://example.com") is True
27 |
28 |
29 | def test_is_url_or_scheme_accepts_app_url():
30 | assert (
31 | is_url_or_scheme(
32 | "com.apple.tv://tv.apple.com/show/marvels-spidey-and-his-amazing-friends/umc.cmc.3ambs8tqwzphbn0u8e9g76x7m?profile=kids&action=play"
33 | )
34 | is True
35 | )
36 |
37 |
38 | def test_is_url_or_scheme_rejects_bundle_id():
39 | assert is_url_or_scheme("com.apple.tv") is False
40 |
41 |
42 | def test_is_url_or_scheme_rejects_scheme():
43 | assert is_url_or_scheme("com.apple.tv://") is True
44 |
--------------------------------------------------------------------------------
/tests/support/test_variant.py:
--------------------------------------------------------------------------------
1 | """Unit tests for pyatv.protocols.mrp.variant."""
2 |
3 | import pytest
4 |
5 | from pyatv.support.variant import read_variant, write_variant
6 |
7 |
8 | def test_read_single_byte():
9 | assert read_variant(b"\x00")[0] == 0x00
10 | assert read_variant(b"\x35")[0] == 0x35
11 |
12 |
13 | def test_read_multiple_bytes():
14 | assert read_variant(b"\xb5\x44")[0] == 8757
15 | assert read_variant(b"\xc5\x92\x01")[0] == 18757
16 |
17 |
18 | def test_read_and_return_remaining_data():
19 | value, remaining = read_variant(b"\xb5\x44\xca\xfe")
20 | assert value == 8757
21 | assert remaining == b"\xca\xfe"
22 |
23 |
24 | def test_read_invalid_variant():
25 | with pytest.raises(Exception):
26 | read_variant(b"\x80")
27 |
28 |
29 | def test_write_single_byte():
30 | assert write_variant(0x00) == b"\x00"
31 | assert write_variant(0x35) == b"\x35"
32 |
33 |
34 | def test_write_multiple_bytes():
35 | assert write_variant(8757) == b"\xb5\x44"
36 | assert write_variant(18757) == b"\xc5\x92\x01"
37 |
--------------------------------------------------------------------------------
/tests/zeroconf_stub.py:
--------------------------------------------------------------------------------
1 | """Stub for the zeroconf library.
2 |
3 | As zeroconf does not provide a stub or mock, this implementation will serve as
4 | stub here. It can fake immediate answers for any service.
5 | """
6 |
7 | from zeroconf import ServiceInfo
8 |
9 |
10 | class ServiceBrowserStub:
11 | """Stub for ServiceBrowser."""
12 |
13 | def __init__(self, zeroconf, service_type, listener):
14 | """Create a new instance of ServiceBrowser."""
15 | for service in zeroconf.services:
16 | if service.type == service_type:
17 | listener.add_service(zeroconf, service_type, service.name)
18 |
19 |
20 | class ZeroconfStub:
21 | """Stub for Zeroconf."""
22 |
23 | def __init__(self, services):
24 | """Create a new instance of Zeroconf."""
25 | self.services = services
26 | self.registered_services = []
27 |
28 | def get_service_info(self, service_type, service_name):
29 | """Look up service information."""
30 | for service in self.services:
31 | if service.name == service_name:
32 | return service
33 |
34 | def register_service(self, service):
35 | """Save services registered services."""
36 | self.registered_services.append(service)
37 |
38 | def unregister_service(self, service):
39 | """Stub for unregistering services (does nothing)."""
40 | pass
41 |
42 | def close(self):
43 | """Stub for closing zeroconf (does nothing)."""
44 | pass
45 |
46 |
47 | def stub(module, *services):
48 | """Stub a module using zeroconf."""
49 | instance = ZeroconfStub(list(services))
50 | module.Zeroconf = lambda: instance
51 | module.ServiceBrowser = ServiceBrowserStub
52 | return instance
53 |
--------------------------------------------------------------------------------