@bharper/atv-js 0.2.6 → 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.
Files changed (283) hide show
  1. package/dist/index.d.ts +15 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +89 -9
  4. package/dist/index.js.map +1 -1
  5. package/dist/mdns.d.ts.map +1 -1
  6. package/dist/mdns.js +96 -11
  7. package/dist/mdns.js.map +1 -1
  8. package/examples/print-device-json.js +22 -0
  9. package/package.json +2 -3
  10. package/pyatv/.codecov.yml +38 -0
  11. package/pyatv/.github/FUNDING.yml +3 -0
  12. package/pyatv/.github/ISSUE_TEMPLATE/bug_report.yml +80 -0
  13. package/pyatv/.github/ISSUE_TEMPLATE/config.yml +1 -0
  14. package/pyatv/.github/ISSUE_TEMPLATE/feature_request.yml +22 -0
  15. package/pyatv/.github/ISSUE_TEMPLATE/implementation-proposal.yml +29 -0
  16. package/pyatv/.github/ISSUE_TEMPLATE/investigation.yml +16 -0
  17. package/pyatv/.github/ISSUE_TEMPLATE/minor-change.yml +10 -0
  18. package/pyatv/.github/ISSUE_TEMPLATE/question-or-idea.yml +11 -0
  19. package/pyatv/.github/dependabot.yml +26 -0
  20. package/pyatv/.github/workflows/codeql-analysis.yml +71 -0
  21. package/pyatv/.github/workflows/release.yml +160 -0
  22. package/pyatv/.github/workflows/tests.yml +104 -0
  23. package/pyatv/.gitpod.yml +23 -0
  24. package/pyatv/CHANGES.md +3708 -0
  25. package/pyatv/CODE_OF_CONDUCT.md +76 -0
  26. package/pyatv/CONTRIBUTING.md +72 -0
  27. package/pyatv/CONTRIBUTORS.md +3 -0
  28. package/pyatv/Dockerfile +15 -0
  29. package/pyatv/LICENSE.md +9 -0
  30. package/pyatv/MANIFEST.in +14 -0
  31. package/pyatv/README.md +111 -0
  32. package/pyatv/base_versions.txt +13 -0
  33. package/pyatv/chickn.yaml +75 -0
  34. package/pyatv/docs/404.html +24 -0
  35. package/pyatv/docs/CNAME +1 -0
  36. package/pyatv/docs/Gemfile +31 -0
  37. package/pyatv/docs/_config.yml +121 -0
  38. package/pyatv/docs/_includes/api +10 -0
  39. package/pyatv/docs/_includes/atvremote_scan +32 -0
  40. package/pyatv/docs/_includes/code +6 -0
  41. package/pyatv/docs/_includes/issue +14 -0
  42. package/pyatv/docs/_includes/pypi +5 -0
  43. package/pyatv/docs/_layouts/template.html +109 -0
  44. package/pyatv/docs/api/pyatv.conf.html +312 -0
  45. package/pyatv/docs/api/pyatv.const.html +974 -0
  46. package/pyatv/docs/api/pyatv.convert.html +106 -0
  47. package/pyatv/docs/api/pyatv.exceptions.html +489 -0
  48. package/pyatv/docs/api/pyatv.helpers.html +102 -0
  49. package/pyatv/docs/api/pyatv.html +120 -0
  50. package/pyatv/docs/api/pyatv.interface.html +2369 -0
  51. package/pyatv/docs/api/pyatv.settings.html +484 -0
  52. package/pyatv/docs/api/pyatv.storage.file_storage.html +102 -0
  53. package/pyatv/docs/api/pyatv.storage.html +186 -0
  54. package/pyatv/docs/api/pyatv.storage.memory_storage.html +83 -0
  55. package/pyatv/docs/assets/css/custom.css +19 -0
  56. package/pyatv/docs/assets/css/hljs.css +1 -0
  57. package/pyatv/docs/assets/css/normalize.css +349 -0
  58. package/pyatv/docs/assets/css/pdoc.css +287 -0
  59. package/pyatv/docs/assets/css/sanitize.css +566 -0
  60. package/pyatv/docs/assets/css/style.scss +9 -0
  61. package/pyatv/docs/assets/img/logo.svg +63 -0
  62. package/pyatv/docs/assets/js/highlight.9.12.0.min.js +3 -0
  63. package/pyatv/docs/assets/js/mermaid.8.9.2.min.js +32 -0
  64. package/pyatv/docs/assets/js/mermaid.min.js.map +1 -0
  65. package/pyatv/docs/development/apps.md +81 -0
  66. package/pyatv/docs/development/audio.md +42 -0
  67. package/pyatv/docs/development/control.md +56 -0
  68. package/pyatv/docs/development/development.md +15 -0
  69. package/pyatv/docs/development/device_info.md +36 -0
  70. package/pyatv/docs/development/examples.md +44 -0
  71. package/pyatv/docs/development/features.md +70 -0
  72. package/pyatv/docs/development/keyboard.md +51 -0
  73. package/pyatv/docs/development/listeners.md +144 -0
  74. package/pyatv/docs/development/logging.md +55 -0
  75. package/pyatv/docs/development/metadata.md +115 -0
  76. package/pyatv/docs/development/power_management.md +53 -0
  77. package/pyatv/docs/development/scan_pair_and_connect.md +331 -0
  78. package/pyatv/docs/development/services.md +9 -0
  79. package/pyatv/docs/development/storage.md +259 -0
  80. package/pyatv/docs/development/stream.md +241 -0
  81. package/pyatv/docs/development/testing.md +9 -0
  82. package/pyatv/docs/documentation/atvlog.md +64 -0
  83. package/pyatv/docs/documentation/atvproxy.md +244 -0
  84. package/pyatv/docs/documentation/atvremote.md +639 -0
  85. package/pyatv/docs/documentation/atvscript.md +275 -0
  86. package/pyatv/docs/documentation/concepts.md +168 -0
  87. package/pyatv/docs/documentation/documentation.md +130 -0
  88. package/pyatv/docs/documentation/getting_started.md +248 -0
  89. package/pyatv/docs/documentation/protocols.md +1959 -0
  90. package/pyatv/docs/documentation/supported_features.md +246 -0
  91. package/pyatv/docs/documentation/tutorial.md +1062 -0
  92. package/pyatv/docs/documentation/workspace.code-workspace +7 -0
  93. package/pyatv/docs/favicon.ico +0 -0
  94. package/pyatv/docs/index.md +109 -0
  95. package/pyatv/docs/internals/design.md +354 -0
  96. package/pyatv/docs/internals/documentation.md +84 -0
  97. package/pyatv/docs/internals/interfaces.md +95 -0
  98. package/pyatv/docs/internals/internals.md +157 -0
  99. package/pyatv/docs/internals/submit_pr.md +56 -0
  100. package/pyatv/docs/internals/testing.md +176 -0
  101. package/pyatv/docs/internals/tools.md +574 -0
  102. package/pyatv/docs/pdoc_templates/config.mako +46 -0
  103. package/pyatv/docs/pdoc_templates/html.mako +454 -0
  104. package/pyatv/docs/support/acknowledgements.md +87 -0
  105. package/pyatv/docs/support/faq.md +214 -0
  106. package/pyatv/docs/support/migration.md +138 -0
  107. package/pyatv/docs/support/scanning_issues.md +110 -0
  108. package/pyatv/docs/support/support.md +18 -0
  109. package/pyatv/docs/support/troubleshooting.md +83 -0
  110. package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeMessage.proto +13 -0
  111. package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeMessage_pb2.pyi +37 -0
  112. package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeResponseMessage.proto +11 -0
  113. package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeResponseMessage_pb2.pyi +32 -0
  114. package/pyatv/pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage.proto +5 -0
  115. package/pyatv/pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage_pb2.pyi +27 -0
  116. package/pyatv/pyatv/protocols/mrp/protobuf/ClientUpdatesConfigMessage.proto +16 -0
  117. package/pyatv/pyatv/protocols/mrp/protobuf/ClientUpdatesConfigMessage_pb2.pyi +44 -0
  118. package/pyatv/pyatv/protocols/mrp/protobuf/CommandInfo.proto +117 -0
  119. package/pyatv/pyatv/protocols/mrp/protobuf/CommandInfo_pb2.pyi +325 -0
  120. package/pyatv/pyatv/protocols/mrp/protobuf/CommandOptions.proto +36 -0
  121. package/pyatv/pyatv/protocols/mrp/protobuf/CommandOptions_pb2.pyi +115 -0
  122. package/pyatv/pyatv/protocols/mrp/protobuf/Common.proto +79 -0
  123. package/pyatv/pyatv/protocols/mrp/protobuf/Common_pb2.pyi +228 -0
  124. package/pyatv/pyatv/protocols/mrp/protobuf/ConfigureConnectionMessage.proto +11 -0
  125. package/pyatv/pyatv/protocols/mrp/protobuf/ConfigureConnectionMessage_pb2.pyi +32 -0
  126. package/pyatv/pyatv/protocols/mrp/protobuf/ContentItem.proto +27 -0
  127. package/pyatv/pyatv/protocols/mrp/protobuf/ContentItemMetadata.proto +213 -0
  128. package/pyatv/pyatv/protocols/mrp/protobuf/ContentItemMetadata_pb2.pyi +630 -0
  129. package/pyatv/pyatv/protocols/mrp/protobuf/ContentItem_pb2.pyi +94 -0
  130. package/pyatv/pyatv/protocols/mrp/protobuf/CryptoPairingMessage.proto +15 -0
  131. package/pyatv/pyatv/protocols/mrp/protobuf/CryptoPairingMessage_pb2.pyi +46 -0
  132. package/pyatv/pyatv/protocols/mrp/protobuf/DeviceInfoMessage.proto +69 -0
  133. package/pyatv/pyatv/protocols/mrp/protobuf/DeviceInfoMessage_pb2.pyi +226 -0
  134. package/pyatv/pyatv/protocols/mrp/protobuf/GenericMessage.proto +12 -0
  135. package/pyatv/pyatv/protocols/mrp/protobuf/GenericMessage_pb2.pyi +35 -0
  136. package/pyatv/pyatv/protocols/mrp/protobuf/GetKeyboardSessionMessage.proto +11 -0
  137. package/pyatv/pyatv/protocols/mrp/protobuf/GetKeyboardSessionMessage_pb2.pyi +26 -0
  138. package/pyatv/pyatv/protocols/mrp/protobuf/GetRemoteTextInputSessionMessage.proto +10 -0
  139. package/pyatv/pyatv/protocols/mrp/protobuf/GetRemoteTextInputSessionMessage_pb2.pyi +26 -0
  140. package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeMessage.proto +11 -0
  141. package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeMessage_pb2.pyi +32 -0
  142. package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeResultMessage.proto +11 -0
  143. package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeResultMessage_pb2.pyi +32 -0
  144. package/pyatv/pyatv/protocols/mrp/protobuf/KeyboardMessage.proto +88 -0
  145. package/pyatv/pyatv/protocols/mrp/protobuf/KeyboardMessage_pb2.pyi +261 -0
  146. package/pyatv/pyatv/protocols/mrp/protobuf/LanguageOption.proto +9 -0
  147. package/pyatv/pyatv/protocols/mrp/protobuf/LanguageOption_pb2.pyi +42 -0
  148. package/pyatv/pyatv/protocols/mrp/protobuf/ModifyOutputContextRequestMessage.proto +23 -0
  149. package/pyatv/pyatv/protocols/mrp/protobuf/ModifyOutputContextRequestMessage_pb2.pyi +86 -0
  150. package/pyatv/pyatv/protocols/mrp/protobuf/NotificationMessage.proto +12 -0
  151. package/pyatv/pyatv/protocols/mrp/protobuf/NotificationMessage_pb2.pyi +38 -0
  152. package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingClient.proto +12 -0
  153. package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingClient_pb2.pyi +49 -0
  154. package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingInfo.proto +24 -0
  155. package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingInfo_pb2.pyi +79 -0
  156. package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingPlayer.proto +11 -0
  157. package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingPlayer_pb2.pyi +45 -0
  158. package/pyatv/pyatv/protocols/mrp/protobuf/Origin.proto +17 -0
  159. package/pyatv/pyatv/protocols/mrp/protobuf/OriginClientPropertiesMessage.proto +11 -0
  160. package/pyatv/pyatv/protocols/mrp/protobuf/OriginClientPropertiesMessage_pb2.pyi +32 -0
  161. package/pyatv/pyatv/protocols/mrp/protobuf/Origin_pb2.pyi +63 -0
  162. package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueue.proto +15 -0
  163. package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities.proto +7 -0
  164. package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities_pb2.pyi +33 -0
  165. package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueContext.proto +5 -0
  166. package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueContext_pb2.pyi +27 -0
  167. package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueRequestMessage.proto +29 -0
  168. package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueRequestMessage_pb2.pyi +87 -0
  169. package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueue_pb2.pyi +53 -0
  170. package/pyatv/pyatv/protocols/mrp/protobuf/PlayerClientPropertiesMessage.proto +13 -0
  171. package/pyatv/pyatv/protocols/mrp/protobuf/PlayerClientPropertiesMessage_pb2.pyi +37 -0
  172. package/pyatv/pyatv/protocols/mrp/protobuf/PlayerPath.proto +11 -0
  173. package/pyatv/pyatv/protocols/mrp/protobuf/PlayerPath_pb2.pyi +39 -0
  174. package/pyatv/pyatv/protocols/mrp/protobuf/ProtocolMessage.proto +171 -0
  175. package/pyatv/pyatv/protocols/mrp/protobuf/ProtocolMessage_pb2.pyi +377 -0
  176. package/pyatv/pyatv/protocols/mrp/protobuf/RegisterForGameControllerEventsMessage.proto +18 -0
  177. package/pyatv/pyatv/protocols/mrp/protobuf/RegisterForGameControllerEventsMessage_pb2.pyi +54 -0
  178. package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceMessage.proto +12 -0
  179. package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceMessage_pb2.pyi +34 -0
  180. package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceResultMessage.proto +12 -0
  181. package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceResultMessage_pb2.pyi +35 -0
  182. package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceMessage.proto +12 -0
  183. package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceMessage_pb2.pyi +34 -0
  184. package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceResponseMessage.proto +12 -0
  185. package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceResponseMessage_pb2.pyi +35 -0
  186. package/pyatv/pyatv/protocols/mrp/protobuf/RemoteTextInputMessage.proto +13 -0
  187. package/pyatv/pyatv/protocols/mrp/protobuf/RemoteTextInputMessage_pb2.pyi +38 -0
  188. package/pyatv/pyatv/protocols/mrp/protobuf/RemoveClientMessage.proto +12 -0
  189. package/pyatv/pyatv/protocols/mrp/protobuf/RemoveClientMessage_pb2.pyi +34 -0
  190. package/pyatv/pyatv/protocols/mrp/protobuf/RemoveEndpointsMessage.proto +11 -0
  191. package/pyatv/pyatv/protocols/mrp/protobuf/RemoveEndpointsMessage_pb2.pyi +34 -0
  192. package/pyatv/pyatv/protocols/mrp/protobuf/RemoveOutputDevicesMessage.proto +12 -0
  193. package/pyatv/pyatv/protocols/mrp/protobuf/RemoveOutputDevicesMessage_pb2.pyi +38 -0
  194. package/pyatv/pyatv/protocols/mrp/protobuf/RemovePlayerMessage.proto +12 -0
  195. package/pyatv/pyatv/protocols/mrp/protobuf/RemovePlayerMessage_pb2.pyi +34 -0
  196. package/pyatv/pyatv/protocols/mrp/protobuf/SendButtonEventMessage.proto +13 -0
  197. package/pyatv/pyatv/protocols/mrp/protobuf/SendButtonEventMessage_pb2.pyi +38 -0
  198. package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandMessage.proto +16 -0
  199. package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandMessage_pb2.pyi +43 -0
  200. package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandResultMessage.proto +100 -0
  201. package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandResultMessage_pb2.pyi +286 -0
  202. package/pyatv/pyatv/protocols/mrp/protobuf/SendHIDEventMessage.proto +41 -0
  203. package/pyatv/pyatv/protocols/mrp/protobuf/SendHIDEventMessage_pb2.pyi +63 -0
  204. package/pyatv/pyatv/protocols/mrp/protobuf/SendPackedVirtualTouchEventMessage.proto +24 -0
  205. package/pyatv/pyatv/protocols/mrp/protobuf/SendPackedVirtualTouchEventMessage_pb2.pyi +64 -0
  206. package/pyatv/pyatv/protocols/mrp/protobuf/SendVoiceInputMessage.proto +38 -0
  207. package/pyatv/pyatv/protocols/mrp/protobuf/SendVoiceInputMessage_pb2.pyi +134 -0
  208. package/pyatv/pyatv/protocols/mrp/protobuf/SetArtworkMessage.proto +11 -0
  209. package/pyatv/pyatv/protocols/mrp/protobuf/SetArtworkMessage_pb2.pyi +32 -0
  210. package/pyatv/pyatv/protocols/mrp/protobuf/SetConnectionStateMessage.proto +18 -0
  211. package/pyatv/pyatv/protocols/mrp/protobuf/SetConnectionStateMessage_pb2.pyi +54 -0
  212. package/pyatv/pyatv/protocols/mrp/protobuf/SetDefaultSupportedCommandsMessage.proto +28 -0
  213. package/pyatv/pyatv/protocols/mrp/protobuf/SetDefaultSupportedCommandsMessage_pb2.pyi +74 -0
  214. package/pyatv/pyatv/protocols/mrp/protobuf/SetDiscoveryModeMessage.proto +12 -0
  215. package/pyatv/pyatv/protocols/mrp/protobuf/SetDiscoveryModeMessage_pb2.pyi +35 -0
  216. package/pyatv/pyatv/protocols/mrp/protobuf/SetHiliteModeMessage.proto +11 -0
  217. package/pyatv/pyatv/protocols/mrp/protobuf/SetHiliteModeMessage_pb2.pyi +32 -0
  218. package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingClientMessage.proto +12 -0
  219. package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingClientMessage_pb2.pyi +34 -0
  220. package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingPlayerMessage.proto +12 -0
  221. package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingPlayerMessage_pb2.pyi +34 -0
  222. package/pyatv/pyatv/protocols/mrp/protobuf/SetRecordingStateMessage.proto +17 -0
  223. package/pyatv/pyatv/protocols/mrp/protobuf/SetRecordingStateMessage_pb2.pyi +54 -0
  224. package/pyatv/pyatv/protocols/mrp/protobuf/SetStateMessage.proto +27 -0
  225. package/pyatv/pyatv/protocols/mrp/protobuf/SetStateMessage_pb2.pyi +72 -0
  226. package/pyatv/pyatv/protocols/mrp/protobuf/SetVolumeMessage.proto +12 -0
  227. package/pyatv/pyatv/protocols/mrp/protobuf/SetVolumeMessage_pb2.pyi +35 -0
  228. package/pyatv/pyatv/protocols/mrp/protobuf/SupportedCommands.proto +7 -0
  229. package/pyatv/pyatv/protocols/mrp/protobuf/SupportedCommands_pb2.pyi +30 -0
  230. package/pyatv/pyatv/protocols/mrp/protobuf/TextInputMessage.proto +23 -0
  231. package/pyatv/pyatv/protocols/mrp/protobuf/TextInputMessage_pb2.pyi +76 -0
  232. package/pyatv/pyatv/protocols/mrp/protobuf/TransactionKey.proto +6 -0
  233. package/pyatv/pyatv/protocols/mrp/protobuf/TransactionKey_pb2.pyi +30 -0
  234. package/pyatv/pyatv/protocols/mrp/protobuf/TransactionMessage.proto +15 -0
  235. package/pyatv/pyatv/protocols/mrp/protobuf/TransactionMessage_pb2.pyi +42 -0
  236. package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPacket.proto +11 -0
  237. package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPacket_pb2.pyi +41 -0
  238. package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPackets.proto +7 -0
  239. package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPackets_pb2.pyi +30 -0
  240. package/pyatv/pyatv/protocols/mrp/protobuf/UpdateClientMessage.proto +12 -0
  241. package/pyatv/pyatv/protocols/mrp/protobuf/UpdateClientMessage_pb2.pyi +34 -0
  242. package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemArtworkMessage.proto +14 -0
  243. package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemArtworkMessage_pb2.pyi +41 -0
  244. package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemMessage.proto +14 -0
  245. package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemMessage_pb2.pyi +41 -0
  246. package/pyatv/pyatv/protocols/mrp/protobuf/UpdateEndPointsMessage.proto +25 -0
  247. package/pyatv/pyatv/protocols/mrp/protobuf/UpdateEndPointsMessage_pb2.pyi +74 -0
  248. package/pyatv/pyatv/protocols/mrp/protobuf/UpdateOutputDeviceMessage.proto +88 -0
  249. package/pyatv/pyatv/protocols/mrp/protobuf/UpdateOutputDeviceMessage_pb2.pyi +277 -0
  250. package/pyatv/pyatv/protocols/mrp/protobuf/UpdatePlayerPath.proto +12 -0
  251. package/pyatv/pyatv/protocols/mrp/protobuf/UpdatePlayerPath_pb2.pyi +34 -0
  252. package/pyatv/pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage.proto +8 -0
  253. package/pyatv/pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage_pb2.pyi +36 -0
  254. package/pyatv/pyatv/protocols/mrp/protobuf/VoiceInputDeviceDescriptorMessage.proto +8 -0
  255. package/pyatv/pyatv/protocols/mrp/protobuf/VoiceInputDeviceDescriptorMessage_pb2.pyi +35 -0
  256. package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlAvailabilityMessage.proto +23 -0
  257. package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlAvailabilityMessage_pb2.pyi +71 -0
  258. package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlCapabilitiesDidChangeMessage.proto +14 -0
  259. package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlCapabilitiesDidChangeMessage_pb2.pyi +40 -0
  260. package/pyatv/pyatv/protocols/mrp/protobuf/VolumeDidChangeMessage.proto +13 -0
  261. package/pyatv/pyatv/protocols/mrp/protobuf/VolumeDidChangeMessage_pb2.pyi +38 -0
  262. package/pyatv/pyatv/protocols/mrp/protobuf/WakeDeviceMessage.proto +11 -0
  263. package/pyatv/pyatv/protocols/mrp/protobuf/WakeDeviceMessage_pb2.pyi +26 -0
  264. package/pyatv/pyatv/py.typed +0 -0
  265. package/pyatv/pylintrc +49 -0
  266. package/pyatv/pyproject.toml +74 -0
  267. package/pyatv/requirements/requirements.txt +14 -0
  268. package/pyatv/requirements/requirements_docs.txt +2 -0
  269. package/pyatv/requirements/requirements_test.txt +20 -0
  270. package/pyatv/scripts/build_docs.sh +17 -0
  271. package/pyatv/scripts/setup_dev_env.sh +83 -0
  272. package/pyatv/setup.cfg +14 -0
  273. package/pyatv/tests/data/README +23 -0
  274. package/pyatv/tests/data/audio_10_frames.wav +0 -0
  275. package/pyatv/tests/data/audio_1_packet_metadata.wav +0 -0
  276. package/pyatv/tests/data/audio_3_packets.wav +0 -0
  277. package/pyatv/tests/data/only_metadata.wav +0 -0
  278. package/pyatv/tests/data/only_title.wav +0 -0
  279. package/pyatv/tests/data/static_3sec.ogg +0 -0
  280. package/pyatv/tests/data/testfile.txt +1 -0
  281. package/pyatv/tests/support/pyatv.code-workspace +14 -0
  282. package/src/index.ts +122 -8
  283. package/src/mdns.ts +64 -11
@@ -0,0 +1,259 @@
1
+ ---
2
+ layout: template
3
+ title: Storage and Settings
4
+ permalink: /development/storage/
5
+ link_group: development
6
+ ---
7
+ Table of Contents
8
+ {:.no_toc}
9
+ * TOC
10
+ {:toc}
11
+
12
+ # Storage and Settings
13
+
14
+ The storage API provides a way to store and read settings persistently, e.g. in a local file or remotely
15
+ on a cloud service. Settings include things such as:
16
+
17
+ * Various metadata, e.g. remote name, MAC address
18
+ * Credentials and passwords for services
19
+ * Protocol specific settings, e.g. port numbers
20
+
21
+ As storage is still a new API, only a handful settings are supported at the time of writing. More settings
22
+ will be added over time. To request a new setting, please open a new issue.
23
+
24
+ ## Available Storage Modules
25
+
26
+ The following storage modules are shipped with pyatv:
27
+
28
+ | **Module** | **Description** | **API** |
29
+ | MemoryStorage | Stores settings within an instance in memory and are discarded when the object is no longer referenced. | {% include api i="storage/memory_storage.MemoryStorage" %}
30
+ | FileStorage | Stores settings in a file in JSON format. | {% include api i="storage/file_storage.FileStorage" %}
31
+ | AbstractStorage | Base class to ease development of custom storage modules, see [here](#custom-storage-module). | {% include api i="storage.AbstractStorage" %}
32
+
33
+ All main methods in `pyatv` ({% include api i="pyatv.connect" %}, {% include api i="pyatv.scan" %} and
34
+ {% include api i="pyatv.pair" %}) accept `storage` as an argument. Typically a storage instance is created once
35
+ and are then passed on to all mentioned methods. If no storage module is provided, a
36
+ {% include api i="storage/memory_storage.MemoryStorage" %} instance is created internally and used for storage.
37
+
38
+ ## Storage Guidelines
39
+
40
+ When using the storage API, there are a few guidelines to consider:
41
+
42
+ * All settings are device specific
43
+ * If a setting is not set, a default value is used (see {% include api i="settings" %} for values)
44
+ * Settings are generally not changed after {% include api i="pyatv.connect" %} has been called
45
+
46
+ The gist is more or less that settings are independent on device level (you can set different MAC addresses
47
+ per device for instance) and they apply instantly. It is however not certain that it will be used until the
48
+ next {% include api i="pyatv.connect" %} call, since many settings are only used when connecting.
49
+
50
+ Internally, `pyatv` will automatically populate the provided storage with new devices when scanning and also
51
+ insert credentials when pairing. Once a protocol has been successfully paired, no further credential
52
+ management is necessary as the credentials will be available via the storage.
53
+
54
+ Settings are managed via an instance of {% include api i="settings.Settings" %}, typically available via
55
+ {% include api i="interface.AppleTV.settings" %}. It is also possible to retrieve settings directly from
56
+ storage using {% include api i="interface.Storage.get_settings" %}.
57
+
58
+ *Note: All changes made to a storage are stored in memory only until
59
+ {% include api i="interface.Storage.save" %} is called. Make sure to call this method after all
60
+ relevant updates, otherwise they will be lost!*
61
+
62
+ ## Settings Priority
63
+
64
+ Storage is treated as a "first-class citizen" in pyatv. This means that internally, whenever pyatv
65
+ needs settings for a configuration, it will load whatever is in storage and overwrite what is currently
66
+ set in the configuration. If a setting is not present in storage, the corresponding setting in the
67
+ configuration will however remain unchanged.
68
+
69
+ The practical way of thinking about this is that settings and configurations are modified independently,
70
+ i.e. you can change a setting in storage to one value and corresponding setting in the configuration to
71
+ another value, thus creating an inconsistency. However, when you call a pyatv method, e.g.
72
+ {% include api i="pyatv.connect" %}, settings will be loaded from storage and overwrite whatever is
73
+ set in the configuration. Here is a simple example illustrating this:
74
+
75
+ ```python
76
+ storage = FileStorage("pyatv.conf", loop)
77
+
78
+ conf = await pyatv.scan(loop, identifier="xxx")[0] # Scan without storage
79
+ conf.get_service(Protocol.AirPlay).password ="pyatv" # Change something in configuration
80
+
81
+ settings = await storage.get_settings(conf) # "conf" does not exist in this storage => new settings
82
+ # password for AirPlay will be copied
83
+
84
+ conf.get_service(Protocol.AirPlay).password ="pass" # Change to something else
85
+ settings = await storage.get_settings(conf) # "conf" exists => return existing settings with
86
+ # AirPlay password set to "pyatv"
87
+
88
+ # connect will read settings from storage and apply to configuration (e.g. "pyatv" as AirPlay password)
89
+ atv = await pyatv.connect(conf, loop, storage=storage)
90
+ ```
91
+
92
+ If you make changes to a configuration and want to save them, use
93
+ {% include api i="interface.Storage.update_settings" %} explicitly to force an update to storage:
94
+
95
+ ```python
96
+ storage = FileStorage("pyatv.conf", loop)
97
+ conf = await pyatv.scan(loop, identifier="xxx", storage=storage)[0] # Scan and insert into storage
98
+
99
+ conf.get_service(Protocol.AirPlay).credentials ="new_creds" # Change something in configuration
100
+ await storage.update_settings(conf)
101
+
102
+ # "new_creds" have been saved to storage, so connect till use that password
103
+ atv = await pyatv.connect(conf, loop, storage=storage)
104
+ ```
105
+
106
+ The recommended way to alter settings is update settings directly in storage, i.e. by changing
107
+ the instance returned by {% include api i="interface.Storage.get_settings" %} and not
108
+ changing the configuration.
109
+
110
+ ## Using the Storage API
111
+
112
+ Create a new storage of choice:
113
+
114
+ ```python
115
+ from pyatv.storage.file_storage import FileStorage
116
+
117
+ loop = asyncio.get_event_loop()
118
+ storage = FileStorage("pyatv.json", loop)
119
+ await storage.load()
120
+ ```
121
+
122
+ Note that the storage must be loaded using {% include api i="interface.Storage.load" %} in order to fetch
123
+ settings from the underlying storage, e.g. reading from file. Not calling this method results in undefined
124
+ behavior.
125
+
126
+ Scanning with storage:
127
+
128
+ ```python
129
+ confs = await pyatv.scan(loop, storage=storage)
130
+ ```
131
+
132
+ The storage will automatically be populated with all discovered devices.
133
+
134
+ To pair with a storage:
135
+
136
+ ```python
137
+ pairing = await pair(atvs[0], Protocol.AirPlay, loop, storage=storage)
138
+ ```
139
+
140
+ When a successful pairing has been made, the resulting credentials are automatically inserted into
141
+ the storage for further references.
142
+
143
+ To connect with storage:
144
+
145
+ ```python
146
+ atv = await pyatv.connect(confs[0], loop, storage=storage)
147
+ ```
148
+
149
+ An instance of {% include api i="settings.Settings" %} containing loaded settings is available
150
+ via {% include api i="interface.AppleTV.settings" %}.
151
+
152
+ Changes made to settings in the storage are only stored in memory and must be saved using
153
+ {% include api i="interface.Storage.save" %} to make them persistent:
154
+
155
+ ```python
156
+ await storage.save()
157
+ ```
158
+
159
+ Storages are supposed to keep track of changes and only save changes if something has actually
160
+ changed.
161
+
162
+ ### Default File Storage
163
+
164
+ When using tools bundled with pyatv, e.g. `atvremote` or `atvscript`,
165
+ {% include api i="storage/file_storage.FileStorage" %} is used with the file `$HOME/.pyatv.conf`.
166
+ You can tap into this storage with your own applications, thus sharing credentials with pyatv.
167
+ There is a convenience method called
168
+ {% include api i="storage/file_storage.FileStorage.default_storage" %} that is recommended to use
169
+ as it is platform agnostic:
170
+
171
+ ```python
172
+ loop = asyncio.get_event_loop()
173
+ storage = FileStorage.default_storage(loop)
174
+ await storage.load()
175
+ ```
176
+ ## Changing Settings
177
+
178
+ As stated in [Storage Guidelines](#storage-guidelines), some settings are only used when connecting
179
+ while others can be used at any given time (e.g. port numbers). It is recommended to update settings
180
+ prior to connecting, but it is allowed to change setting even after connecting but the changes
181
+ might not apply until the next time you connect.
182
+
183
+ To get settings for a device, use {% include api i="interface.Storage.get_settings" %}:
184
+
185
+ ```python
186
+ conf = ... # Scan for device
187
+
188
+ settings = await storage.get_settings(conf)
189
+ ```
190
+
191
+ To change setting, simply set new values according to your needs:
192
+
193
+ ```python
194
+ settings.name = "My App" # Named used when pairing
195
+ settings.mac = "aa:bb:cc:dd:ee:ff" # MAC address pyatv presents itself when needed
196
+
197
+ settings.raop.password = "never_gonna_give_you_up"
198
+ ```
199
+
200
+ Remember to save changes to storage to ensure they are stored persistently
201
+ ({% include api i="interface.Storage.save" %}).
202
+
203
+ To find available settings, look at {% include api i="settings.Settings" %} in the API
204
+ reference as each field are described there (including default values when applicable).
205
+
206
+ ## Custom Storage Module
207
+
208
+ To implement your own storage module, it is recommended to inherit from
209
+ {% include api i="storage.AbstractStorage" %} and implement the missing methods. Internally `pyatv` uses
210
+ [pydantic](https://docs.pydantic.dev/) for the storage model, simplifying things like serialization when
211
+ storing and loading settings. The {% include api i="storage.AbstractStorage.storage_model" %} property
212
+ is used to get the current representation but also to update it when loading a model from an external
213
+ source.
214
+
215
+ Simply put:
216
+
217
+ * `save` shall serialize {% include api i="storage.AbstractStorage.storage_model" %} in some way, e.g.
218
+ into JSON or YAML and save that somewhere
219
+ * `load` shall take the saved data, de-serialize it and set
220
+ {% include api i="storage.AbstractStorage.storage_model" %} with the de-serialized data
221
+
222
+ A simple pseudo example looks like this:
223
+
224
+ ```python
225
+ import json
226
+ from pyatv.storage import AbstractStorage
227
+
228
+ class CloudStorage(AbstractStorage):
229
+
230
+ def __init__(self, cloud_api):
231
+ super().__init__()
232
+ self.cloud_api = cloud_api
233
+
234
+ async def save(self) -> None:
235
+ if self.changed:
236
+ json_data = self.storage_model.model_dump_json(exclude_defaults=True)
237
+ await self.cloud_api.save("myfile.json", json_data)
238
+ self.mark_as_saved()
239
+
240
+ async def load(self) -> None:
241
+ json_data = await self.cloud_api.load("myfile.json")
242
+ self.storage_model = StorageModel(**json.loads(json_data))
243
+ self.mark_as_saved()
244
+
245
+ ```
246
+
247
+ Nothing else is really needed to implement a new storage module (implementing `__str__` for debugging
248
+ purposes is also recommended). Do note how {% include api i="storage.AbstractStorage.changed" %} and
249
+ {% include api i="storage.AbstractStorage.mark_as_saved" %} are used to only save the storage model
250
+ in case it was changed. This removes unnecessary writes to disk since the same content would be
251
+ re-written every time {% include api i="interface.Storage.save" %} is called otherwise.
252
+
253
+ More complex implementations may inherit from
254
+ {% include api i="interface.Storage" %} directly, but additional care must be taken to implement the
255
+ interface correctly.
256
+
257
+ *Note: Ensure to pass `exclude_defaults=True` when dumping the model, otherwise you will also save
258
+ default values. This pollutes the output a lot, but also causes problems if default values are changed
259
+ in pyatv as the settings written to storage will be used instead, i.e. old default values.*
@@ -0,0 +1,241 @@
1
+ ---
2
+ layout: template
3
+ title: Stream
4
+ permalink: /development/stream/
5
+ link_group: development
6
+ ---
7
+ Table of Contents
8
+ {:.no_toc}
9
+ * TOC
10
+ {:toc}
11
+
12
+ # Stream
13
+
14
+ It is possible to stream audio and video to a device via the stream interface using
15
+ AirPlay. The AirPlay suite consists of two protocols:
16
+
17
+ * AirTunes/RAOP - Used for real time streaming of audio
18
+ * "AirPlay - Everything else (video, images and screen mirroring)
19
+
20
+ Currently there is some AirPlay functionality supported in pyatv, but it is
21
+ very limited. These features are currently supported:
22
+
23
+ - Device authentication ("pairing")
24
+ - Playing media via URL
25
+ - Streaming of local files
26
+
27
+ Early support for streaming audio files via RAOP is also supported
28
+ (even for non-Apple TV devices). MP3, wav, FLAC and ogg files are
29
+ supported. Devices that require a password are only supported for the AirTunes/RAOP protocol, not the AirPlay protocol.
30
+
31
+ In the external interface, AirPlay (including RAOP) support is implemented via
32
+ the {% include api i="interface.Stream" %} interface.
33
+
34
+ ## Using the streaming API
35
+
36
+ Devices supporting the AirPlay protocol (e.g. Apple TV) can play files by simply providing
37
+ a URL. It will then be streamed directly from the device. Audio can be streamed to other
38
+ devices (like AirPlay speakers) that does not support this.
39
+
40
+ ### Play from URL
41
+
42
+ Playing a URL is as simple as passing the URL to {% include api i="interface.Stream.play_url" %}:
43
+
44
+ ```python
45
+ url = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
46
+ await atv.stream.play_url(url)
47
+ ```
48
+
49
+ If the device requires device authentication, credentials must be present for
50
+ the AirPlay service. Otherwise an error message will be shown on the screen.
51
+
52
+ To play a local file, just pass a local file to {% include api i="interface.Stream.play_url" %}
53
+ instead:
54
+
55
+ ```python
56
+ url = "/home/user/BigBuckBunny.mp4"
57
+ await atv.stream.play_url(url)
58
+ ```
59
+
60
+ When doing this, pyatv will internally start web server on a random port, serving this
61
+ file only and start streaming from there. When streaming is done, the web server is shut
62
+ down.
63
+
64
+ The Apple TV will not provide any feedback if anything is not working. If you have
65
+ problems, start by testing the example file above (`BigBuckBunny.mp4`) as that is
66
+ known to work. Also make sure that you don't stream from an HTTPS server with a bad
67
+ or self-signed certificate: that will not work.
68
+
69
+ ### Stream a file
70
+
71
+ To stream a file, use {% include api i="interface.Stream.stream_file" %}:
72
+
73
+ ```python
74
+ stream = ...
75
+ await stream.stream_file("sample.mp3")
76
+ ```
77
+
78
+ Files in MP3, WAV, FLAC and OGG format are supported and will be automatically converted
79
+ to a format the receiving device supports. Metadata is also extracted from files
80
+ of these types and sent to the receiver.
81
+
82
+ It is also possible to stream directly from a buffer. In this example, a file is
83
+ read into a buffer and streamed:
84
+
85
+ ```python
86
+ import io
87
+
88
+ with io.open("myfile.mp3", "rb") as source_file:
89
+ await stream.stream_file(source_file)
90
+ ```
91
+
92
+ Streaming directly from `stdin` also works, e.g. when piping output from another
93
+ process:
94
+
95
+ ```python
96
+ await stream.stream_file(sys.stdin.buffer)
97
+ ```
98
+
99
+ As `stdin` is a text stream, the underlying binary buffer must be retrieved and used.
100
+
101
+ It is also possible to use an asyncio
102
+ [StreamReader](https://docs.python.org/3/library/asyncio-stream.html#streamreader) as
103
+ input. Here is an example piping output from ffmpeg:
104
+
105
+ ```python
106
+ import asyncio.subprocess as asp
107
+
108
+ process = await asp.create_subprocess_exec(
109
+ "ffmpeg", "-i", "file.mp3", "-f", "mp3", "-",
110
+ stdin=None, stdout=asp.PIPE, stderr=None,
111
+ )
112
+
113
+ await self.atv.stream.stream_file(process.stdout)
114
+ ```
115
+
116
+ When streaming from a buffer, it's important to know that some audio formats are
117
+ not suitable for that. MP3 works fine, WAV and OGG does not. The reason is that
118
+ seeking is done in the stream and `stdin` does for instance not support that. If
119
+ the buffer supports seeking, then all formats will work fine, otherwise stick with
120
+ MP3. For the same reason, metadata will not work if seeking is not supported as
121
+ that is extracted prior to playing the file, so seeking is needed to return to
122
+ the beginning of file again before playback.
123
+
124
+ Note 1: Since pyatv v0.13.0, buffer improvements have been made to support some
125
+ seeking, even in non-seekable streams. This is however not fool-proof and not all
126
+ audio formats (or files/streams) work, but compatibility is much better from that
127
+ version and onwards.
128
+
129
+ Note 2: that there's (roughly) a two second delay until audio starts to play. This
130
+ is part of the buffering mechanism and not much pyatv can do anything about.
131
+
132
+ #### Custom Metadata
133
+
134
+ By default, pyatv will try to extract metadata from whatever content you are playing.
135
+ Some file formats or streams either does not support nor provide any metadata,
136
+ in which case you can manually provide the metadata that pyatv will report to the
137
+ receiver by passing an instance of {% include api i="interface.MediaMetadata" %}
138
+ when starting to stream:
139
+
140
+ ```python
141
+ from pyatv.interface import MediaMetadata
142
+
143
+ metadata = MediaMetadata(artist="pyatv", title="Look at me, I'm streaming")
144
+ await stream.stream_file("myfile.mp3", metadata=metadata)
145
+ ```
146
+
147
+ All fields in {% include api i="interface.MediaMetadata" %} can be overridden (including
148
+ artwork) except for {% include api i="interface.MediaMetadata.duration" %}, which is
149
+ ignored. Please note that artwork must be in JPEG format.
150
+
151
+ Custom metadata will override any metadata provided by the streamed content. You
152
+ can however tell pyatv to only override metadata fields that are missing by setting
153
+ `override_missing_metadata` to `True`:
154
+
155
+ ```python
156
+ from pyatv.interface import MediaMetadata
157
+
158
+ metadata = MediaMetadata(artist="pyatv")
159
+ await stream.stream_file("myfile.mp3", metadata=metadata, override_missing_metadata=True)
160
+ ```
161
+
162
+ This will use all the metadata from `myfile.mp3`, but use _pyatv_ as artist but **only**
163
+ if that field is not present in the file.
164
+
165
+ #### Stream from HTTP(S)
166
+
167
+ There is experimental support for streaming directly from HTTP or HTTPS. A URL can
168
+ be passed instead of a file path:
169
+
170
+ ```python
171
+ await stream.stream_file("https://foo.bar/test.mp3")
172
+ ```
173
+
174
+ #### File Compatibility
175
+
176
+ It is possible to verify if a file is supported programmatically using
177
+ {% include api i="helpers.is_streamable" %}:
178
+
179
+ ```python
180
+ from pyatv.helpers import is_streamable
181
+
182
+ if await is_streamable("myfile.mp3"):
183
+ await atv.stream_file("myfile.mp3")
184
+ else:
185
+ print("File is not supported")
186
+ ```
187
+
188
+ There are a few caveats worth knowing:
189
+
190
+ * No exception is ever raised, even when file is not found or lack of permissions
191
+ * Only valid for {% include api i="interface.Stream.stream_file" %} (*not*
192
+ {% include api i="interface.Stream.play_url" %})
193
+ * Only a basic check is made, the file might be broken and not still not playable
194
+
195
+ ## Password
196
+
197
+ If you stream audio using the RAOP protocol and the device requires a password, you can set the password like this:
198
+
199
+ ```python
200
+ raop_service = atv_conf.get_service(Protocol.RAOP)
201
+ raop_service.password = "test"
202
+ atv = await connect(atv_conf, ...)
203
+ await atv.stream.stream_file("sample.mp3")
204
+ ```
205
+
206
+ ## Device Authentication
207
+
208
+ In tvOS 10.2, Apple started to enforce a feature called "device authentication".
209
+ This requires every device that streams content via AirPlay to enter a PIN code
210
+ the first time before playback is started. Once done, the user will never have
211
+ to do this again. The actual feature has been available for a while but as
212
+ opt-in, so it would have to be explicitly enabled. Now it is enabled by default
213
+ and cannot be disabled. Devices not running tvOS (e.g. Apple TV 2nd and 3rd
214
+ generation) are not affected, even though device authentication can be enabled
215
+ on these devices as well.
216
+
217
+ The device authentication process is based on the *Secure Remote Password*
218
+ protocol (SRP), with slight modifications. All the reverse engineering required
219
+ for this process was made by funtax (GitHub username) and has merely been ported
220
+ to python for usage in this library. Please see references at bottom of page
221
+ for reference implementation.
222
+
223
+ ### Device Pairing in pyatv
224
+
225
+ When performing device authentication, a device identifier and a private key is
226
+ required. Once authenticated, they can be used to authenticate without using a
227
+ PIN code. So they must be saved and reused whenever something is to be played.
228
+
229
+ In this library, the device identifier and private key is called
230
+ *AirPlay credentials* and are concatenated into a string, using : as separator.
231
+ An example might look like this:
232
+
233
+ ```raw
234
+ D9B75D737BE2F0F1:6A26D8EB6F4AE2408757D5CA5FF9C37E96BEBB22C632426C4A02AD4FA895A85B
235
+ ^ ^
236
+ Identifier Private key
237
+ ```
238
+
239
+ The device authentication is performed via the pairing API, just like with
240
+ any other protocol. New random credentials are generated by default, as long
241
+ as no existing credentials are provided. So there is nothing special here.
@@ -0,0 +1,9 @@
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...
@@ -0,0 +1,64 @@
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://<ip>: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
+