pavoni / pyroon Goto Github PK
View Code? Open in Web Editor NEWpython library to interface with the Roon API
License: Apache License 2.0
python library to interface with the Roon API
License: Apache License 2.0
Log from home assistant.
Should fail gracefully!
Logger: homeassistant.components.automation.hifi_sources_on
Source: components/roon/media_player.py:383
Integration: Automation (documentation, issues)
First occurred: 11:21:04 (8 occurrences)
Last logged: 11:31:51
Hi Fi - sources on: Error executing script. Unexpected error for call_service at pos 1: 'NoneType' object is not subscriptable
While executing automation automation.hifi_sources_on
Hi Fi - sources on: Error executing script. Unexpected error for call_service at pos 2: 'NoneType' object is not subscriptable
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 451, in _async_step
await getattr(self, handler)()
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 684, in _async_call_service_step
await service_task
File "/usr/src/homeassistant/homeassistant/core.py", line 1755, in async_call
task.result()
File "/usr/src/homeassistant/homeassistant/core.py", line 1792, in _execute_service
await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 213, in handle_service
await service.entity_service_call(
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 678, in entity_service_call
future.result() # pop exception if have
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 958, in async_request_call
await coro
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 715, in _handle_entity_call
await result
File "/usr/src/homeassistant/homeassistant/components/media_player/__init__.py", line 791, in async_play_media
await self.hass.async_add_executor_job(
File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/src/homeassistant/homeassistant/components/roon/media_player.py", line 383, in play_media
if not self._server.roonapi.play_media(self.zone_id, path_list):
File "/usr/local/lib/python3.10/site-packages/roonapi/roonapi.py", line 488, in play_media
total_count = self.browse_browse(opts)["list"]["count"]
TypeError: 'NoneType' object is not subscriptable
In the examples there is the following code:
# get target zone output_id
zones = roonapi.zones
output_id = [
output["zone_id"]
for output in zones.values()
if output["display_name"] == target_zone
][0]
print("OUTPUT ID", output_id)
The specified target_zone must match the returned output display_name exactly. I replaced that == match with the Python 'in' keyword to do substring matching as follows:
# get target zone output_id
zones = roonapi.zones
output_id = [
output["zone_id"]
for output in zones.values()
if target_zone in output["display_name"]
][0]
print("OUTPUT ID", output_id)
This matches target_zone if it is grouped or ungrouped.
I suppose it is a design decision. Do you want the API acting on a grouped zone if only one of the zones in the grouping is specified. In my case, I do so I made this change. Maybe it's not an issue so much as something that would be good to add to the examples. Anyway, thanks for the effort! I'm using this project successfully to control Roon via Siri + SSH Shortcuts + shell scripts and python scripts on a server that can reach my Roon Core. It all works pretty well for an early release.
api.play_media(self.zone_id, ['Playlists', 'wellenrauschen], action="Play Now")
ERROR roonapi: Could not find media path element 'wellenrauschen' in []
first of all, thank you so much for working on this library; I am so excited to start using it. Anyway, when I use the example code just to print out the zones, it seems to completely disregard the "host" variable. My local machine is 192.168.1.7, where I am running Roon, but my Roon Server is 192.168.1.27, and my bridge is 1.10. With the host set to 1.27, it still goes straight to the local machine, and if I close Roon on the local machine, it will try to use 1.10. When I close both 7 and 10, it does find 27 and everything seems to work from there.
when calling play_media with a genre & subgenre, pyroon errors out:
e.g Genres/Jazz/Cool
File "/usr/local/lib/python3.8/site-packages/roonapi/roonapi.py", line 521, in play_media
total_count = self.browse_browse(opts)["list"]["count"]
TypeError: 'NoneType' object is not subscriptable
I've started getting this error:
2023-08-16 14:00:58,998 WARNING roonapisocket -- Session unexpectedly disconnected!
2023-08-16 14:01:00,933 WARNING roonapi -- Socket connection lost! Will try to reconnect in 20s
2023-08-16 14:01:21,940 ERROR roonapisocket -- Error while parsing message '<websocket._app.WebSocketApp object at 0x7f99ce7c5dd0>'
Traceback (most recent call last):
File "/home/ovos/.venv/lib/python3.11/site-packages/roonapi/roonapisocket.py", line 127, in on_message
message = message.decode("utf-8")
roonapi == 1.4.1
websocket-client == 1.6.1
Will do some investigating
More details here home-assistant/core#73393
My suspicion is that the socket library leaks resources when repeatedly trying to reconnect.
The socket library used is old - and is now being maintained again - so try updating to the latest.
I have a development version of RoonCommandLine with volume control implemented using the pyroon 'change_volume' method. I am currently testing my implementation and it is working fairly well. One issue I am encountering is the occasionally playback stop after setting the volume. I cannot yet reliably reproduce this issue. It just happens sometimes and not in response to the same command.
I am opening this issue in hopes that you may be able to inform me of known issues with change_volume
or the underlying SERVICE_TRANSPORT. I have just begun testing so it may be something I am doing wrong. But the fact that it works most of the time leads me to suspect either my Roon setup or the API or something external to my scripts.
I am using pyroon 0.1.1
I will try to come up with a more detailed description of the problem and a reproducible test case.
I think we should be able to specify strings without having case sensitivity.
e.g - both examples should work, but currently only the first one does:
Library/Artists/Neil Young/Harvest
Library/Artists/neil young/harvest
The play
methods are dependent on roon maintaining their top level menu names.
1.7 change the radio name - and broke the play_radio
call.
This is fragile - and needs a better solution.
The roon api docs say:
* { "type": "db", "min": -80, "max": 0, "value": -50.5, "step": 0.5 }
* { "type": "db", "min": -80, "max": 10, "value": 4, "step": 1.0 }
* { "type": "number" "min": 0, "max": 100, "value": 80, "step": 1.0 }
* { "type": "number" "min": 1, "max": 99, "value": 65, "step": 1.0 }
* { "type": "incremental" }
The code in HA currently assumes that a number volume control is 0 to 100 and a db one is -80 to 0.
It should ask roon for the data before doing the calculation.
Probably best to add some utility conversion routines in the roon api.
Probably causing this issue: home-assistant/core#81138 (comment)
Hello,
When calling roonapi.zone_by_name, the "seek_position" value is updated only if we change "volume" or "state"
The callback return : "zones_seek_changed: [u'160160ebd918de93c888a51a481101e89859']"
But I have no idea how to get the new seek value when callback is detected ?
Thanks for your tips.
Hi,
I would like to use your integration in my Gentoo Overlay for Home Assistant, hope you don't mind.
Therefor I would need a release file either at Pypi in SDIST format, or as a tar.gz on github.
Home Assistant currently requires: roonapi-0.0.21
A release on Github would be easy and OK, but a Pypi tar.gz release would be preferred, because this could take use of Gentoo's mirror system. Most of the other integrations do both.
Thanks
\B.
This is causing a problem playing albums that includes slash characters
Problem: You cannot play tags with roon.play_media(zone_id, ["Library", "Tags", "mytag"])
It also doesn't work in HA when using the media browser.
Error:
File "/var/home/ramblurr/src/mycroft/mycroft-core/.venv/lib/python3.10/site-packages/roonapi/roonapi.py", line 579, in play_media
if take_action["hint"] != "action":
KeyError: 'hint'
Looking at the JSON output from the roon api, you can see that the action hint is not there:
{
"items": [
{
"title": "Brass",
"subtitle": "1 Item",
"image_key": null,
"item_key": "730:0",
"hint": "list"
}
],
"offset": 0,
"list": {
"level": 1,
"title": "Tags",
"subtitle": "1 Result",
"image_key": null,
"count": 1,
"display_offset": null
}
}
Yet from the Roon app one can search for a tag and then shuffle it, so there's got to be some way to play tags.. any ideas?
If I restart my roon server - the library doesn't handle it - and needs to be restarted.
Hi,
many thanks for this app in Python but when installing it into a virtual environment botch websocket and websocket-client are missing as dependencies in the packet description.
BR,
Sebastian Mangelsen
Roon's loop mode has three states: 'loop' | 'loop_one' | 'disabled'
source: https://roonlabs.github.io/node-roon-api/Zone.html
Currently this library only exposes loop
and disabled
It would be great to have support for this in the API (and eventually HA).
Hello,
I am trying to write some python code to fetch the cover art for the track that is currently playing, the JS code is here
https://roonlabs.github.io/node-roon-api/other_node-roon-api-image_lib.js.html
I have had a look in
https://github.com/pavoni/pyroon/blob/master/roonapi/roonapi.py
and I do not think that functionality has been implemented yet, am I wrong?
Many thanks
Jason
The current browse api works well for home assistant, but is perhaps not idea for use outside.
It would be pretty easy to add something similar to play_media
perhaps list_media
that was easier to use, to replace the older calls removed by #29
Will wait until someone says they would like this!
One can subscribe to receive state updates for a zone, but we should be able to unsubscribe to prevent the leaking of resources in a long lived process environment.
Hi,
I've updated roonapi from very old version and i've noticed that support for volume control endpoints was removed.
Is it possible to bring it back?
I'm using this functionality in my plugin for controlling volume on soekris Dam1021 DAC.
With current version of pyroon it is not achievable.
Thanks in advance for your reply.
BR,
Seba
Is it possible to get details about sample rate etc?
Would be nice to have a physical light set to the colour of the roon quality indicator.
The same errors always appear and I can't solve it, it seems that some files are missing, such as test_core_server_file
what am i doing wrong
See error log
tests/test__discovery.py::test_discovery FAILED [ 1/12]
tests/test_basic.py::test_basic FAILED [ 2/12]
tests/test_path_parser.py::test_simple_paths PASSED [ 3/12]
tests/test_path_parser.py::test_edge_cases PASSED [ 4/12]
tests/test_path_parser.py::test_quoted_paths PASSED [ 5/12]
tests/test_volume.py::test_get_volume_db ERROR [ 6/12]
tests/test_volume.py::test_get_volume_perent ERROR [ 7/12]
tests/test_volume.py::test_set_volume_db ERROR [ 8/12]
tests/test_volume.py::test_set_volume_percent ERROR [ 9/12]
tests/test_volume.py::test_change_volume_db ERROR [10/12]
tests/test_volume.py::test_change_volume_percent ERROR [11/12]
tests/test_with_callbacks.py::test_callbacks FAILED [12/12]
========================================================================================================================================= ERRORS =========================================================================================================================================
__________________________________________________________________________________________________________________________ ERROR at setup of test_get_volume_db __________________________________________________________________________________________________________________________
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
E FileNotFoundError: [Errno 2] No such file or directory: 'test_core_server_file'
request = <SubRequest 'roon_api' for >
tests/test_volume.py:14: FileNotFoundError
During handling of the above exception, another exception occurred:
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
port = open("test_core_port_file").read()
token = open("my_token_file").read()
except OSError:
print("Please authorise first using discovery.py")
exit()
request = <SubRequest 'roon_api' for >
tests/test_volume.py:19:
self = Use exit() or Ctrl-D (i.e. EOF) to exit, code = None
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
E SystemExit: None
code = None
self = Use exit() or Ctrl-D (i.e. EOF) to exit
/usr/lib/python3.10/_sitebuiltins.py:26: SystemExit
--------------------------------------------------------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------------------------------------------------------
Please authorise first using discovery.py
________________________________________________________________________________________________________________________ ERROR at setup of test_get_volume_perent ________________________________________________________________________________________________________________________
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
E FileNotFoundError: [Errno 2] No such file or directory: 'test_core_server_file'
request = <SubRequest 'roon_api' for >
tests/test_volume.py:14: FileNotFoundError
During handling of the above exception, another exception occurred:
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
port = open("test_core_port_file").read()
token = open("my_token_file").read()
except OSError:
print("Please authorise first using discovery.py")
exit()
request = <SubRequest 'roon_api' for >
tests/test_volume.py:19:
self = Use exit() or Ctrl-D (i.e. EOF) to exit, code = None
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
E SystemExit: None
code = None
self = Use exit() or Ctrl-D (i.e. EOF) to exit
/usr/lib/python3.10/_sitebuiltins.py:26: SystemExit
--------------------------------------------------------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------------------------------------------------------
Please authorise first using discovery.py
__________________________________________________________________________________________________________________________ ERROR at setup of test_set_volume_db __________________________________________________________________________________________________________________________
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
E FileNotFoundError: [Errno 2] No such file or directory: 'test_core_server_file'
request = <SubRequest 'roon_api' for >
tests/test_volume.py:14: FileNotFoundError
During handling of the above exception, another exception occurred:
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
port = open("test_core_port_file").read()
token = open("my_token_file").read()
except OSError:
print("Please authorise first using discovery.py")
exit()
request = <SubRequest 'roon_api' for >
tests/test_volume.py:19:
self = Use exit() or Ctrl-D (i.e. EOF) to exit, code = None
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
E SystemExit: None
code = None
self = Use exit() or Ctrl-D (i.e. EOF) to exit
/usr/lib/python3.10/_sitebuiltins.py:26: SystemExit
--------------------------------------------------------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------------------------------------------------------
Please authorise first using discovery.py
_______________________________________________________________________________________________________________________ ERROR at setup of test_set_volume_percent ________________________________________________________________________________________________________________________
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
E FileNotFoundError: [Errno 2] No such file or directory: 'test_core_server_file'
request = <SubRequest 'roon_api' for >
tests/test_volume.py:14: FileNotFoundError
During handling of the above exception, another exception occurred:
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
port = open("test_core_port_file").read()
token = open("my_token_file").read()
except OSError:
print("Please authorise first using discovery.py")
exit()
request = <SubRequest 'roon_api' for >
tests/test_volume.py:19:
self = Use exit() or Ctrl-D (i.e. EOF) to exit, code = None
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
E SystemExit: None
code = None
self = Use exit() or Ctrl-D (i.e. EOF) to exit
/usr/lib/python3.10/_sitebuiltins.py:26: SystemExit
--------------------------------------------------------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------------------------------------------------------
Please authorise first using discovery.py
________________________________________________________________________________________________________________________ ERROR at setup of test_change_volume_db _________________________________________________________________________________________________________________________
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
E FileNotFoundError: [Errno 2] No such file or directory: 'test_core_server_file'
request = <SubRequest 'roon_api' for >
tests/test_volume.py:14: FileNotFoundError
During handling of the above exception, another exception occurred:
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
port = open("test_core_port_file").read()
token = open("my_token_file").read()
except OSError:
print("Please authorise first using discovery.py")
exit()
request = <SubRequest 'roon_api' for >
tests/test_volume.py:19:
self = Use exit() or Ctrl-D (i.e. EOF) to exit, code = None
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
E SystemExit: None
code = None
self = Use exit() or Ctrl-D (i.e. EOF) to exit
/usr/lib/python3.10/_sitebuiltins.py:26: SystemExit
--------------------------------------------------------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------------------------------------------------------
Please authorise first using discovery.py
______________________________________________________________________________________________________________________ ERROR at setup of test_change_volume_percent ______________________________________________________________________________________________________________________
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
E FileNotFoundError: [Errno 2] No such file or directory: 'test_core_server_file'
request = <SubRequest 'roon_api' for >
tests/test_volume.py:14: FileNotFoundError
During handling of the above exception, another exception occurred:
request = <SubRequest 'roon_api' for >
@pytest.fixture()
def roon_api(request):
try:
host = open("test_core_server_file").read()
port = open("test_core_port_file").read()
token = open("my_token_file").read()
except OSError:
print("Please authorise first using discovery.py")
exit()
request = <SubRequest 'roon_api' for >
tests/test_volume.py:19:
self = Use exit() or Ctrl-D (i.e. EOF) to exit, code = None
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
E SystemExit: None
code = None
self = Use exit() or Ctrl-D (i.e. EOF) to exit
/usr/lib/python3.10/_sitebuiltins.py:26: SystemExit
--------------------------------------------------------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------------------------------------------------------
Please authorise first using discovery.py
======================================================================================================================================== FAILURES ========================================================================================================================================
_____________________________________________________________________________________________________________________________________ test_discovery _____________________________________________________________________________________________________________________________________
def test_discovery():
try:
core_id = open("my_core_id_file").read()
E FileNotFoundError: [Errno 2] No such file or directory: 'my_core_id_file'
tests/test__discovery.py:22: FileNotFoundError
During handling of the above exception, another exception occurred:
def test_discovery():
try:
core_id = open("my_core_id_file").read()
token = open("my_token_file").read()
except OSError:
print("Please authorise first using discovery.py")
exit()
tests/test__discovery.py:26:
self = Use exit() or Ctrl-D (i.e. EOF) to exit, code = None
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
E SystemExit: None
code = None
self = Use exit() or Ctrl-D (i.e. EOF) to exit
/usr/lib/python3.10/_sitebuiltins.py:26: SystemExit
---------------------------------------------------------------------------------------------------------------------------------- Captured stdout call ----------------------------------------------------------------------------------------------------------------------------------
Please authorise first using discovery.py
_______________________________________________________________________________________________________________________________________ test_basic _______________________________________________________________________________________________________________________________________
def test_basic():
try:
host = open("test_core_server_file").read()
E FileNotFoundError: [Errno 2] No such file or directory: 'test_core_server_file'
tests/test_basic.py:14: FileNotFoundError
During handling of the above exception, another exception occurred:
def test_basic():
try:
host = open("test_core_server_file").read()
port = open("test_core_port_file").read()
token = open("my_token_file").read()
except OSError:
print("Please authorise first using discovery.py")
exit()
tests/test_basic.py:19:
self = Use exit() or Ctrl-D (i.e. EOF) to exit, code = None
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
E SystemExit: None
code = None
self = Use exit() or Ctrl-D (i.e. EOF) to exit
/usr/lib/python3.10/_sitebuiltins.py:26: SystemExit
---------------------------------------------------------------------------------------------------------------------------------- Captured stdout call ----------------------------------------------------------------------------------------------------------------------------------
Please authorise first using discovery.py
_____________________________________________________________________________________________________________________________________ test_callbacks _____________________________________________________________________________________________________________________________________
def test_callbacks():
callback_count = 0
events = []
try:
host = open("test_core_server_file").read()
E FileNotFoundError: [Errno 2] No such file or directory: 'test_core_server_file'
callback_count = 0
events = []
tests/test_with_callbacks.py:16: FileNotFoundError
During handling of the above exception, another exception occurred:
def test_callbacks():
callback_count = 0
events = []
try:
host = open("test_core_server_file").read()
port = open("test_core_port_file").read()
token = open("my_token_file").read()
except OSError:
print("Please authorise first using discovery.py")
exit()
callback_count = 0
events = []
tests/test_with_callbacks.py:21:
self = Use exit() or Ctrl-D (i.e. EOF) to exit, code = None
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
E SystemExit: None
code = None
self = Use exit() or Ctrl-D (i.e. EOF) to exit
/usr/lib/python3.10/_sitebuiltins.py:26: SystemExit
---------------------------------------------------------------------------------------------------------------------------------- Captured stdout call ----------------------------------------------------------------------------------------------------------------------------------
Please authorise first using discovery.py
================================================================================================================================ short test summary info =================================================================================================================================
ERROR tests/test_volume.py::test_get_volume_db - SystemExit: None
ERROR tests/test_volume.py::test_get_volume_perent - SystemExit: None
ERROR tests/test_volume.py::test_set_volume_db - SystemExit: None
ERROR tests/test_volume.py::test_set_volume_percent - SystemExit: None
ERROR tests/test_volume.py::test_change_volume_db - SystemExit: None
ERROR tests/test_volume.py::test_change_volume_percent - SystemExit: None
FAILED tests/test__discovery.py::test_discovery - SystemExit: None
FAILED tests/test_basic.py::test_basic - SystemExit: None
FAILED tests/test_with_callbacks.py::test_callbacks - SystemExit: None
========================================================================================================================= 3 failed, 3 passed, 6 errors in 0.61s ==========================================================================================================================
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.