@bharper/atv-js 0.3.0 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mdns.d.ts.map +1 -1
- package/dist/mdns.js +79 -9
- package/dist/mdns.js.map +1 -1
- package/package.json +1 -1
- package/pyatv/.codecov.yml +38 -0
- package/pyatv/.github/FUNDING.yml +3 -0
- package/pyatv/.github/ISSUE_TEMPLATE/bug_report.yml +80 -0
- package/pyatv/.github/ISSUE_TEMPLATE/config.yml +1 -0
- package/pyatv/.github/ISSUE_TEMPLATE/feature_request.yml +22 -0
- package/pyatv/.github/ISSUE_TEMPLATE/implementation-proposal.yml +29 -0
- package/pyatv/.github/ISSUE_TEMPLATE/investigation.yml +16 -0
- package/pyatv/.github/ISSUE_TEMPLATE/minor-change.yml +10 -0
- package/pyatv/.github/ISSUE_TEMPLATE/question-or-idea.yml +11 -0
- package/pyatv/.github/dependabot.yml +26 -0
- package/pyatv/.github/workflows/codeql-analysis.yml +71 -0
- package/pyatv/.github/workflows/release.yml +160 -0
- package/pyatv/.github/workflows/tests.yml +104 -0
- package/pyatv/.gitpod.yml +23 -0
- package/pyatv/CHANGES.md +3708 -0
- package/pyatv/CODE_OF_CONDUCT.md +76 -0
- package/pyatv/CONTRIBUTING.md +72 -0
- package/pyatv/CONTRIBUTORS.md +3 -0
- package/pyatv/Dockerfile +15 -0
- package/pyatv/LICENSE.md +9 -0
- package/pyatv/MANIFEST.in +14 -0
- package/pyatv/README.md +111 -0
- package/pyatv/base_versions.txt +13 -0
- package/pyatv/chickn.yaml +75 -0
- package/pyatv/docs/404.html +24 -0
- package/pyatv/docs/CNAME +1 -0
- package/pyatv/docs/Gemfile +31 -0
- package/pyatv/docs/_config.yml +121 -0
- package/pyatv/docs/_includes/api +10 -0
- package/pyatv/docs/_includes/atvremote_scan +32 -0
- package/pyatv/docs/_includes/code +6 -0
- package/pyatv/docs/_includes/issue +14 -0
- package/pyatv/docs/_includes/pypi +5 -0
- package/pyatv/docs/_layouts/template.html +109 -0
- package/pyatv/docs/api/pyatv.conf.html +312 -0
- package/pyatv/docs/api/pyatv.const.html +974 -0
- package/pyatv/docs/api/pyatv.convert.html +106 -0
- package/pyatv/docs/api/pyatv.exceptions.html +489 -0
- package/pyatv/docs/api/pyatv.helpers.html +102 -0
- package/pyatv/docs/api/pyatv.html +120 -0
- package/pyatv/docs/api/pyatv.interface.html +2369 -0
- package/pyatv/docs/api/pyatv.settings.html +484 -0
- package/pyatv/docs/api/pyatv.storage.file_storage.html +102 -0
- package/pyatv/docs/api/pyatv.storage.html +186 -0
- package/pyatv/docs/api/pyatv.storage.memory_storage.html +83 -0
- package/pyatv/docs/assets/css/custom.css +19 -0
- package/pyatv/docs/assets/css/hljs.css +1 -0
- package/pyatv/docs/assets/css/normalize.css +349 -0
- package/pyatv/docs/assets/css/pdoc.css +287 -0
- package/pyatv/docs/assets/css/sanitize.css +566 -0
- package/pyatv/docs/assets/css/style.scss +9 -0
- package/pyatv/docs/assets/img/logo.svg +63 -0
- package/pyatv/docs/assets/js/highlight.9.12.0.min.js +3 -0
- package/pyatv/docs/assets/js/mermaid.8.9.2.min.js +32 -0
- package/pyatv/docs/assets/js/mermaid.min.js.map +1 -0
- package/pyatv/docs/development/apps.md +81 -0
- package/pyatv/docs/development/audio.md +42 -0
- package/pyatv/docs/development/control.md +56 -0
- package/pyatv/docs/development/development.md +15 -0
- package/pyatv/docs/development/device_info.md +36 -0
- package/pyatv/docs/development/examples.md +44 -0
- package/pyatv/docs/development/features.md +70 -0
- package/pyatv/docs/development/keyboard.md +51 -0
- package/pyatv/docs/development/listeners.md +144 -0
- package/pyatv/docs/development/logging.md +55 -0
- package/pyatv/docs/development/metadata.md +115 -0
- package/pyatv/docs/development/power_management.md +53 -0
- package/pyatv/docs/development/scan_pair_and_connect.md +331 -0
- package/pyatv/docs/development/services.md +9 -0
- package/pyatv/docs/development/storage.md +259 -0
- package/pyatv/docs/development/stream.md +241 -0
- package/pyatv/docs/development/testing.md +9 -0
- package/pyatv/docs/documentation/atvlog.md +64 -0
- package/pyatv/docs/documentation/atvproxy.md +244 -0
- package/pyatv/docs/documentation/atvremote.md +639 -0
- package/pyatv/docs/documentation/atvscript.md +275 -0
- package/pyatv/docs/documentation/concepts.md +168 -0
- package/pyatv/docs/documentation/documentation.md +130 -0
- package/pyatv/docs/documentation/getting_started.md +248 -0
- package/pyatv/docs/documentation/protocols.md +1959 -0
- package/pyatv/docs/documentation/supported_features.md +246 -0
- package/pyatv/docs/documentation/tutorial.md +1062 -0
- package/pyatv/docs/documentation/workspace.code-workspace +7 -0
- package/pyatv/docs/favicon.ico +0 -0
- package/pyatv/docs/index.md +109 -0
- package/pyatv/docs/internals/design.md +354 -0
- package/pyatv/docs/internals/documentation.md +84 -0
- package/pyatv/docs/internals/interfaces.md +95 -0
- package/pyatv/docs/internals/internals.md +157 -0
- package/pyatv/docs/internals/submit_pr.md +56 -0
- package/pyatv/docs/internals/testing.md +176 -0
- package/pyatv/docs/internals/tools.md +574 -0
- package/pyatv/docs/pdoc_templates/config.mako +46 -0
- package/pyatv/docs/pdoc_templates/html.mako +454 -0
- package/pyatv/docs/support/acknowledgements.md +87 -0
- package/pyatv/docs/support/faq.md +214 -0
- package/pyatv/docs/support/migration.md +138 -0
- package/pyatv/docs/support/scanning_issues.md +110 -0
- package/pyatv/docs/support/support.md +18 -0
- package/pyatv/docs/support/troubleshooting.md +83 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeMessage.proto +13 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeMessage_pb2.pyi +37 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeResponseMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeResponseMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage.proto +5 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage_pb2.pyi +27 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ClientUpdatesConfigMessage.proto +16 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ClientUpdatesConfigMessage_pb2.pyi +44 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CommandInfo.proto +117 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CommandInfo_pb2.pyi +325 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CommandOptions.proto +36 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CommandOptions_pb2.pyi +115 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/Common.proto +79 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/Common_pb2.pyi +228 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ConfigureConnectionMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ConfigureConnectionMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ContentItem.proto +27 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ContentItemMetadata.proto +213 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ContentItemMetadata_pb2.pyi +630 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ContentItem_pb2.pyi +94 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CryptoPairingMessage.proto +15 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CryptoPairingMessage_pb2.pyi +46 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/DeviceInfoMessage.proto +69 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/DeviceInfoMessage_pb2.pyi +226 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GenericMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GenericMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetKeyboardSessionMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetKeyboardSessionMessage_pb2.pyi +26 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetRemoteTextInputSessionMessage.proto +10 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetRemoteTextInputSessionMessage_pb2.pyi +26 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeResultMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeResultMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/KeyboardMessage.proto +88 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/KeyboardMessage_pb2.pyi +261 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/LanguageOption.proto +9 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/LanguageOption_pb2.pyi +42 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ModifyOutputContextRequestMessage.proto +23 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ModifyOutputContextRequestMessage_pb2.pyi +86 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NotificationMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NotificationMessage_pb2.pyi +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingClient.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingClient_pb2.pyi +49 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingInfo.proto +24 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingInfo_pb2.pyi +79 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingPlayer.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingPlayer_pb2.pyi +45 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/Origin.proto +17 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/OriginClientPropertiesMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/OriginClientPropertiesMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/Origin_pb2.pyi +63 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueue.proto +15 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities.proto +7 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities_pb2.pyi +33 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueContext.proto +5 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueContext_pb2.pyi +27 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueRequestMessage.proto +29 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueRequestMessage_pb2.pyi +87 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueue_pb2.pyi +53 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlayerClientPropertiesMessage.proto +13 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlayerClientPropertiesMessage_pb2.pyi +37 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlayerPath.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlayerPath_pb2.pyi +39 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ProtocolMessage.proto +171 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ProtocolMessage_pb2.pyi +377 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterForGameControllerEventsMessage.proto +18 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterForGameControllerEventsMessage_pb2.pyi +54 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceResultMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceResultMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceResponseMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceResponseMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoteTextInputMessage.proto +13 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoteTextInputMessage_pb2.pyi +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveClientMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveClientMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveEndpointsMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveEndpointsMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveOutputDevicesMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveOutputDevicesMessage_pb2.pyi +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemovePlayerMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemovePlayerMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendButtonEventMessage.proto +13 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendButtonEventMessage_pb2.pyi +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandMessage.proto +16 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandMessage_pb2.pyi +43 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandResultMessage.proto +100 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandResultMessage_pb2.pyi +286 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendHIDEventMessage.proto +41 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendHIDEventMessage_pb2.pyi +63 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendPackedVirtualTouchEventMessage.proto +24 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendPackedVirtualTouchEventMessage_pb2.pyi +64 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendVoiceInputMessage.proto +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendVoiceInputMessage_pb2.pyi +134 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetArtworkMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetArtworkMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetConnectionStateMessage.proto +18 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetConnectionStateMessage_pb2.pyi +54 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetDefaultSupportedCommandsMessage.proto +28 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetDefaultSupportedCommandsMessage_pb2.pyi +74 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetDiscoveryModeMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetDiscoveryModeMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetHiliteModeMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetHiliteModeMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingClientMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingClientMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingPlayerMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingPlayerMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetRecordingStateMessage.proto +17 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetRecordingStateMessage_pb2.pyi +54 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetStateMessage.proto +27 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetStateMessage_pb2.pyi +72 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetVolumeMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetVolumeMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SupportedCommands.proto +7 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SupportedCommands_pb2.pyi +30 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TextInputMessage.proto +23 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TextInputMessage_pb2.pyi +76 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionKey.proto +6 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionKey_pb2.pyi +30 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionMessage.proto +15 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionMessage_pb2.pyi +42 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPacket.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPacket_pb2.pyi +41 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPackets.proto +7 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPackets_pb2.pyi +30 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateClientMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateClientMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemArtworkMessage.proto +14 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemArtworkMessage_pb2.pyi +41 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemMessage.proto +14 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemMessage_pb2.pyi +41 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateEndPointsMessage.proto +25 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateEndPointsMessage_pb2.pyi +74 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateOutputDeviceMessage.proto +88 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateOutputDeviceMessage_pb2.pyi +277 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdatePlayerPath.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdatePlayerPath_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage.proto +8 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage_pb2.pyi +36 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VoiceInputDeviceDescriptorMessage.proto +8 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VoiceInputDeviceDescriptorMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlAvailabilityMessage.proto +23 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlAvailabilityMessage_pb2.pyi +71 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlCapabilitiesDidChangeMessage.proto +14 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlCapabilitiesDidChangeMessage_pb2.pyi +40 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeDidChangeMessage.proto +13 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeDidChangeMessage_pb2.pyi +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/WakeDeviceMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/WakeDeviceMessage_pb2.pyi +26 -0
- package/pyatv/pyatv/py.typed +0 -0
- package/pyatv/pylintrc +49 -0
- package/pyatv/pyproject.toml +74 -0
- package/pyatv/requirements/requirements.txt +14 -0
- package/pyatv/requirements/requirements_docs.txt +2 -0
- package/pyatv/requirements/requirements_test.txt +20 -0
- package/pyatv/scripts/build_docs.sh +17 -0
- package/pyatv/scripts/setup_dev_env.sh +83 -0
- package/pyatv/setup.cfg +14 -0
- package/pyatv/tests/data/README +23 -0
- package/pyatv/tests/data/audio_10_frames.wav +0 -0
- package/pyatv/tests/data/audio_1_packet_metadata.wav +0 -0
- package/pyatv/tests/data/audio_3_packets.wav +0 -0
- package/pyatv/tests/data/only_metadata.wav +0 -0
- package/pyatv/tests/data/only_title.wav +0 -0
- package/pyatv/tests/data/static_3sec.ogg +0 -0
- package/pyatv/tests/data/testfile.txt +1 -0
- package/pyatv/tests/support/pyatv.code-workspace +14 -0
- package/src/mdns.ts +46 -9
|
@@ -0,0 +1,40 @@
|
|
|
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.VolumeControlAvailabilityMessage_pb2
|
|
12
|
+
import typing
|
|
13
|
+
|
|
14
|
+
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
|
15
|
+
|
|
16
|
+
@typing.final
|
|
17
|
+
class VolumeControlCapabilitiesDidChangeMessage(google.protobuf.message.Message):
|
|
18
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
19
|
+
|
|
20
|
+
CAPABILITIES_FIELD_NUMBER: builtins.int
|
|
21
|
+
ENDPOINTUID_FIELD_NUMBER: builtins.int
|
|
22
|
+
OUTPUTDEVICEUID_FIELD_NUMBER: builtins.int
|
|
23
|
+
endpointUID: builtins.str
|
|
24
|
+
outputDeviceUID: builtins.str
|
|
25
|
+
@property
|
|
26
|
+
def capabilities(self) -> pyatv.protocols.mrp.protobuf.VolumeControlAvailabilityMessage_pb2.VolumeControlAvailabilityMessage: ...
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
*,
|
|
30
|
+
capabilities: pyatv.protocols.mrp.protobuf.VolumeControlAvailabilityMessage_pb2.VolumeControlAvailabilityMessage | None = ...,
|
|
31
|
+
endpointUID: builtins.str | None = ...,
|
|
32
|
+
outputDeviceUID: builtins.str | None = ...,
|
|
33
|
+
) -> None: ...
|
|
34
|
+
def HasField(self, field_name: typing.Literal["capabilities", b"capabilities", "endpointUID", b"endpointUID", "outputDeviceUID", b"outputDeviceUID"]) -> builtins.bool: ...
|
|
35
|
+
def ClearField(self, field_name: typing.Literal["capabilities", b"capabilities", "endpointUID", b"endpointUID", "outputDeviceUID", b"outputDeviceUID"]) -> None: ...
|
|
36
|
+
|
|
37
|
+
global___VolumeControlCapabilitiesDidChangeMessage = VolumeControlCapabilitiesDidChangeMessage
|
|
38
|
+
|
|
39
|
+
VOLUMECONTROLCAPABILITIESDIDCHANGEMESSAGE_FIELD_NUMBER: builtins.int
|
|
40
|
+
volumeControlCapabilitiesDidChangeMessage: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[pyatv.protocols.mrp.protobuf.ProtocolMessage_pb2.ProtocolMessage, global___VolumeControlCapabilitiesDidChangeMessage]
|
|
@@ -0,0 +1,13 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
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]
|
|
@@ -0,0 +1,26 @@
|
|
|
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]
|
|
File without changes
|
package/pyatv/pylintrc
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
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
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "setuptools.build_meta"
|
|
3
|
+
requires = ["setuptools>=77.0"]
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name="pyatv"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE.md"]
|
|
9
|
+
description = "A client library for Apple TV and AirPlay devices"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
authors = [{ name = "Pierre Ståhl", email = "pierre.staahl@gmail.com" }]
|
|
12
|
+
requires-python = ">=3.9.0"
|
|
13
|
+
keywords = ["apple", "tv", "airplay", "raop", "companion", "dmap", "dacp"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Programming Language :: Python :: 3.14",
|
|
24
|
+
"Topic :: Software Development :: Libraries",
|
|
25
|
+
"Topic :: Home Automation",
|
|
26
|
+
"Typing :: Typed",
|
|
27
|
+
]
|
|
28
|
+
dynamic = ["version", "dependencies"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
"Homepage" = "https://pyatv.dev"
|
|
32
|
+
"Repository" = "https://github.com/postlund/pyatv"
|
|
33
|
+
"Bug Reports" = "https://github.com/postlund/pyatv/issues"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
atvremote = "pyatv.scripts.atvremote:main"
|
|
37
|
+
atvproxy = "pyatv.scripts.atvproxy:main"
|
|
38
|
+
atvscript = "pyatv.scripts.atvscript:main"
|
|
39
|
+
atvlog = "pyatv.scripts.atvlog:main"
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.dynamic]
|
|
42
|
+
version = { attr = "pyatv.const.__version__" }
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
include = ["pyatv*"]
|
|
46
|
+
|
|
47
|
+
[tool.black]
|
|
48
|
+
extend-exclude = '(protobuf/(__init__|.*_pb2).py)|__pycache__'
|
|
49
|
+
include = '(pyatv|tests|examples|scripts).*\.py'
|
|
50
|
+
|
|
51
|
+
[tool.isort]
|
|
52
|
+
skip_glob = "pyatv/protocols/mrp/protobuf/*.py"
|
|
53
|
+
profile = "black"
|
|
54
|
+
force_sort_within_sections = true
|
|
55
|
+
known_first_party = [
|
|
56
|
+
"pyatv",
|
|
57
|
+
"tests",
|
|
58
|
+
"scripts",
|
|
59
|
+
]
|
|
60
|
+
forced_separate = [
|
|
61
|
+
"tests",
|
|
62
|
+
"scripts",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[[tool.mypy.overrides]]
|
|
66
|
+
module = [
|
|
67
|
+
"miniaudio",
|
|
68
|
+
"audio_metadata",
|
|
69
|
+
"srptools",
|
|
70
|
+
]
|
|
71
|
+
ignore_missing_imports = true
|
|
72
|
+
|
|
73
|
+
[tool.pytest.ini_options]
|
|
74
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
aiohttp==3.13.3
|
|
2
|
+
async-timeout==5.0.1;python_version<'3.11'
|
|
3
|
+
cryptography==46.0.3
|
|
4
|
+
chacha20poly1305-reuseable==0.13.2
|
|
5
|
+
ifaddr==0.2.0
|
|
6
|
+
ifaddr==0.2.0
|
|
7
|
+
miniaudio==1.61
|
|
8
|
+
protobuf==6.33.2
|
|
9
|
+
pydantic==2.12.5
|
|
10
|
+
requests==2.32.5
|
|
11
|
+
srptools==1.0.1
|
|
12
|
+
tabulate==0.9.0
|
|
13
|
+
tinytag==2.1.2
|
|
14
|
+
zeroconf==0.148.0
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
black==25.11.0
|
|
2
|
+
deepdiff==8.6.1
|
|
3
|
+
flake8==7.3.0
|
|
4
|
+
isort==6.0.1
|
|
5
|
+
mutagen==1.47.0
|
|
6
|
+
pyfakefs==5.10.2
|
|
7
|
+
pylint==3.3.9
|
|
8
|
+
pytest==8.4.2
|
|
9
|
+
pytest-asyncio==0.26.0
|
|
10
|
+
pytest-cov==7.0.0
|
|
11
|
+
pytest-timeout==2.4.0
|
|
12
|
+
pytest-aiohttp==1.0.5
|
|
13
|
+
pytest_httpserver==1.1.3
|
|
14
|
+
pytest-xdist==3.8.0
|
|
15
|
+
pydocstyle==6.3.0
|
|
16
|
+
mypy==1.19.0
|
|
17
|
+
mypy-protobuf==3.7.0
|
|
18
|
+
types-protobuf==6.32.1.20251210
|
|
19
|
+
types-requests==2.32.4.20260107
|
|
20
|
+
types-tabulate==0.9.0.20241207
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Set in GitPod which breaks installation in venv
|
|
4
|
+
unset PIP_USER
|
|
5
|
+
|
|
6
|
+
VERSIONS="3.10 3.9 3.8 3.7 3.6"
|
|
7
|
+
|
|
8
|
+
found_version=
|
|
9
|
+
for p in $VERSIONS
|
|
10
|
+
do
|
|
11
|
+
which python${p} 2>&1 > /dev/null
|
|
12
|
+
if [ $? -eq 0 ]; then
|
|
13
|
+
found_version=python${p}
|
|
14
|
+
break
|
|
15
|
+
fi
|
|
16
|
+
done
|
|
17
|
+
|
|
18
|
+
set -e
|
|
19
|
+
|
|
20
|
+
if [ -z $found_version ]; then
|
|
21
|
+
>&2 echo "no python installation found"
|
|
22
|
+
exit 1
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
echo "-> Using python: $found_version"
|
|
26
|
+
|
|
27
|
+
echo "-> Creating python virtual environment..."
|
|
28
|
+
$found_version -m venv .
|
|
29
|
+
|
|
30
|
+
echo "-> Activating virtual environment..."
|
|
31
|
+
source bin/activate
|
|
32
|
+
sed -i '' 's/false/true/' pyvenv.cfg
|
|
33
|
+
|
|
34
|
+
echo "-> Upgrading pip..."
|
|
35
|
+
pip install --upgrade pip
|
|
36
|
+
|
|
37
|
+
echo "-> Installing library as develop..."
|
|
38
|
+
python setup.py develop
|
|
39
|
+
|
|
40
|
+
echo "-> Installing protobuf-setuptools..."
|
|
41
|
+
pip install protobuf-setuptools
|
|
42
|
+
|
|
43
|
+
echo "-> Installing dependencies..."
|
|
44
|
+
pip install --upgrade pyyaml -r requirements/requirements_test.txt -r requirements/requirements_docs.txt
|
|
45
|
+
|
|
46
|
+
echo "-> Running tests as verification..."
|
|
47
|
+
python setup.py test
|
|
48
|
+
|
|
49
|
+
cat <<EOF
|
|
50
|
+
==================================================
|
|
51
|
+
|
|
52
|
+
When starting a new shell, run:
|
|
53
|
+
|
|
54
|
+
source bin/activate
|
|
55
|
+
|
|
56
|
+
To run tests, run any of:
|
|
57
|
+
|
|
58
|
+
python setup.py test
|
|
59
|
+
pytest tests/test_conf.py # Single test
|
|
60
|
+
|
|
61
|
+
Test everything with chickn:
|
|
62
|
+
|
|
63
|
+
./scripts/chickn.py
|
|
64
|
+
|
|
65
|
+
To re-generate protobuf messages:
|
|
66
|
+
|
|
67
|
+
./scripts/protobuf.py --download generate
|
|
68
|
+
|
|
69
|
+
The CLI application can be used, e.g. run:
|
|
70
|
+
|
|
71
|
+
atvremote --debug commands
|
|
72
|
+
atvremote --debug playing
|
|
73
|
+
|
|
74
|
+
To preview documentation in docs, run:
|
|
75
|
+
|
|
76
|
+
./scripts/build_docs.sh
|
|
77
|
+
|
|
78
|
+
and navigate to http://127.0.0.1:4000
|
|
79
|
+
|
|
80
|
+
==================================================
|
|
81
|
+
|
|
82
|
+
Environment is configured and ready to use!
|
|
83
|
+
EOF
|
package/pyatv/setup.cfg
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[aliases]
|
|
2
|
+
test=pytest
|
|
3
|
+
|
|
4
|
+
[tool:pytest]
|
|
5
|
+
testpaths = tests
|
|
6
|
+
norecursedirs = .git
|
|
7
|
+
|
|
8
|
+
[flake8]
|
|
9
|
+
exclude = .venv,.git,.tox,docs,venv,bin,lib,deps,build
|
|
10
|
+
max-line-length = 88
|
|
11
|
+
ignore = E203, W503
|
|
12
|
+
|
|
13
|
+
[pydocstyle]
|
|
14
|
+
match_dir = ^((?!\.|www_static).)*$
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a file for testing
|
package/src/mdns.ts
CHANGED
|
@@ -4,6 +4,32 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import mdns from 'multicast-dns';
|
|
7
|
+
import * as os from 'os';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns the list of mdns constructor option objects to use for scanning.
|
|
11
|
+
* On Windows, multicast must be joined on a specific interface address rather
|
|
12
|
+
* than 0.0.0.0, so we create one entry per non-internal IPv4 address.
|
|
13
|
+
* On macOS/Linux the default (no interface option) works correctly, so we
|
|
14
|
+
* return a single entry with no options.
|
|
15
|
+
*/
|
|
16
|
+
function getMdnsOptions(): Array<object | undefined> {
|
|
17
|
+
if (process.platform !== 'win32') {
|
|
18
|
+
return [undefined];
|
|
19
|
+
}
|
|
20
|
+
const interfaces = os.networkInterfaces();
|
|
21
|
+
const addresses: string[] = [];
|
|
22
|
+
for (const iface of Object.values(interfaces)) {
|
|
23
|
+
if (!iface) continue;
|
|
24
|
+
for (const addr of iface) {
|
|
25
|
+
if (addr.family === 'IPv4' && !addr.internal) {
|
|
26
|
+
addresses.push(addr.address);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (addresses.length === 0) return [undefined];
|
|
31
|
+
return addresses.map((iface) => ({ interface: iface }));
|
|
32
|
+
}
|
|
7
33
|
|
|
8
34
|
export interface AppleTVDevice {
|
|
9
35
|
name: string;
|
|
@@ -52,13 +78,17 @@ function getPropertyIgnoreCase(properties: Record<string, string>, key: string):
|
|
|
52
78
|
|
|
53
79
|
export async function scan(timeout = 5000, onlyAppleTV = true): Promise<AppleTVDevice[]> {
|
|
54
80
|
return new Promise((resolve) => {
|
|
55
|
-
|
|
81
|
+
// On macOS/Linux a single mdns() with no options works correctly.
|
|
82
|
+
// On Windows we need one instance per interface so the multicast group is
|
|
83
|
+
// joined explicitly on each adapter (0.0.0.0 binding is silently ignored).
|
|
84
|
+
const browsers = getMdnsOptions().map((opts) => opts ? mdns(opts) : mdns());
|
|
85
|
+
|
|
56
86
|
const companionServices = new Map<string, DiscoveredService>();
|
|
57
87
|
const airplayServices = new Map<string, DiscoveredService>();
|
|
58
88
|
const deviceInfoModels = new Map<string, string>(); // device name → model from _device-info
|
|
59
89
|
const addressMap = new Map<string, string>();
|
|
60
90
|
|
|
61
|
-
|
|
91
|
+
const handleResponse = (response: any) => {
|
|
62
92
|
// Collect A/AAAA records for hostname→IP resolution
|
|
63
93
|
for (const answer of [...(response.answers || []), ...(response.additionals || [])]) {
|
|
64
94
|
if (answer.type === 'A') {
|
|
@@ -137,15 +167,22 @@ export async function scan(timeout = 5000, onlyAppleTV = true): Promise<AppleTVD
|
|
|
137
167
|
}
|
|
138
168
|
}
|
|
139
169
|
}
|
|
140
|
-
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Attach the shared response handler to every per-interface browser
|
|
173
|
+
for (const browser of browsers) {
|
|
174
|
+
browser.on('response', handleResponse);
|
|
175
|
+
}
|
|
141
176
|
|
|
142
177
|
// Send queries for companion, airplay, and device-info services
|
|
143
178
|
const queryServices = () => {
|
|
144
|
-
browser
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
179
|
+
for (const browser of browsers) {
|
|
180
|
+
browser.query([
|
|
181
|
+
{ name: '_companion-link._tcp.local', type: 'PTR' },
|
|
182
|
+
{ name: '_airplay._tcp.local', type: 'PTR' },
|
|
183
|
+
{ name: '_device-info._tcp.local', type: 'PTR' },
|
|
184
|
+
]);
|
|
185
|
+
}
|
|
149
186
|
};
|
|
150
187
|
|
|
151
188
|
// Send initial query
|
|
@@ -155,7 +192,7 @@ export async function scan(timeout = 5000, onlyAppleTV = true): Promise<AppleTVD
|
|
|
155
192
|
setTimeout(queryServices, timeout / 2);
|
|
156
193
|
|
|
157
194
|
setTimeout(() => {
|
|
158
|
-
browser.destroy();
|
|
195
|
+
for (const browser of browsers) browser.destroy();
|
|
159
196
|
|
|
160
197
|
// Merge companion and airplay services by device name
|
|
161
198
|
const devices: AppleTVDevice[] = [];
|