Giter VIP home page Giter VIP logo

synology-api's People

Contributors

adamoutler avatar ajarzyn avatar bambutz avatar cardenastw avatar dangsonbk avatar danieletrimarchi avatar eddybl avatar eincl avatar fboissadier avatar fcouziniedevy avatar fipwmaqzufheoxq92ebc avatar fortysix2ahead avatar hrko avatar insanity67 avatar joeperpetua avatar kidburglar avatar liuerfire avatar lukas-hetzenecker avatar malinovsku avatar marcelrv avatar n4s4 avatar pnearing avatar raph2i avatar shenjackyuanjie avatar tduboys avatar therealj4nd3rs0n avatar ttw225 avatar vincentroma avatar xpsnets avatar yurzs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

synology-api's Issues

Connection Error

I am trying to log in to NAS file station it is giving me following error
ConnectionError: HTTPSConnectionPool(host='https', port=443): Max retries exceeded with url: //IP:portwebapi/auth.cgi?api=SYNO.API.Auth&version=2&method=login&account=username&passwd=password&session=FileStation&format=cookie (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7f94b4092f10>: Failed to establish a new connection: [Errno -2] Name or service not known

HTTPS support

If I usefl = filestation.FileStation('ip', 'port', 'user', 'pass', True)
with flag True i get error сertificate not verify, and then i do in auth.py
I add verify=Fasle in source code, please do it as parametr

session_request = requests.get(self._base_url + login_api, param, verify=False)
response = requests.get(self._base_url + query_path, list_query, verify=False).json()
response = requests.get(url, req_param, verify=False)
response = requests.post(url, req_param, verify=False)

KeyError: 'data'

synology-api/auth.py line42 in login
self._sid = session_request.json()['data']['sid']
KeyError: 'data'

Connect tot DSM7

Hi,
I just upgraded my synology nas to DSM7. It seems that I can't connect anymore.
image

image

Issues using additional parameters during get_file_info()

Hello ! Thanks for the amazing project :)
I have got some issues using multiple additional parameters while using get_file_info method

Neither :
fl.get_file_info(path,additional = {'size','time','real_path'})
or
fl.get_file_info(path,additional = ['size','time','real_path'])
works.

I only have one parameter working or less, like when I use it this way :
fl.get_file_info(path',additional = 'size')

I only have the results like this, so with only one parameter (size, time, real_path or owner) working
{'data': {'files': [{'additional': {'size': 3342336}, 'isdir': False, 'name': 'file_name', 'path': '/path'}]}, 'success': True}

get_md5_status always faild

Thanks for your convenient library, but I'm having some problem when using get_md5_status function.
My step:

  1. login to filestation
  2. use start_md5_calc and get return taskid
  3. use get_md5_status and taskid
    In step 3, I always get error code {'error': {'code': 599}, 'success': False}.

Backup get functions

I'm trying to get a proper monitoring solution in place for a new client's hyper backup and have just been testing out some of the backup functions.

The list functions work great, as does the backup_task_result, but I noticed none of the get functions like backup_task_status, backup_repository_get or backup_task_get have any parameters, and simple return an error, presumably because they're expecting the ID of a task or repository.

I gave it a quick test by altering the file myself and including a taskid parameter in the backup_task_get function and it seemed to work at that point.

Is this something that can be fixed in this manner, or do they work perfectly and I'm just not using them correctly?

Enhancement suggestion for Backup Tasks

I have been trying to get backup task status via API calls for years with no success. I found a reference to user 'leirn' and their project to monitor Syno things with nagios. In there was the key, undocumented extended attributes to pass to the 'status' method of SYNO.Backup.Task. I have no idea how 'leirn' found this, credit to him or her. I am sorry I do not have time to properly contribute the code changes, so I offer the extended attributes to someone who does. The normal 'status' method will only return the job's config status, is it a job that is configured correctly. If what you really want is the result from the last time the job ran, get the task_id with a call to backup_task_list, then use this new function:

def backup_task_result(self, taskid):
    api_name = 'SYNO.Backup.Task'
    info = self.gen_list[api_name]
    api_path = info['path']
    req_param = {'version': info['minVersion'], 'method': 'status', 'blOnline': 'false', 'additional': '["last_bkp_time","next_bkp_time","last_bkp_result","is_modified","last_bkp_progress"]', 'task_id': taskid}

I tested it against DSM6, I have not upgraded to DSM7 yet so no idea how it works there.

Chunk size in FileStation method get_file

when downloading a file, the code iterates over the request with iter_content(chunk_size=8192).
Downloading large files appears to be really slow. Would changing the chunk_size value help? Perhaps setting chunk_size to "None" ?
Can you please comment on this ?

Any / Some functions of backup.py aren't working

Hey!

Loading any of the functions of the class Backup raises a KeyError.
I think there is an problem with the info = self.core_list[api_name].
If i change this to info = self.gen_list[api_name] i'll get an Error 103 from the syno-nas.

If i then pin the version to '1' in the req_param, i'll get an Error 4400 from the syno-nas, but only at:

  • backup_repository_get
  • backup_task_status
  • backup_task_get

What i'm missing is an implementation of:

additional | "[\"last_bkp_time\",\"last_bkp_result\",\"get_source\",\"is_modified\",\"progress_title_type\"]"
api | "SYNO.Backup.Task"
method | "list"
version | "1"

which could be easily be done with:

    def backup_task_list(self):
        api_name = 'SYNO.Backup.Task'
        info = self.gen_list[api_name]
        api_path = info['path']
        req_param = {'version': '1', 'method': 'list', 'additional': '["last_bkp_time","last_bkp_result","get_source","is_modified","progress_title_type"]'}

        return self.request_data(api_name, api_path, req_param)

How are we supposed to fix this?
Should i raise a PR with the fix for the one function?

Thanks!

Newest version results in error 104 when logging in

I recently upgraded from version 0.2.1 to version 0.4.1 of this package (so quite a big leap!). After that, logging in via the api would result in a response of {'error': {'code': 104}, 'success': False}.

My machine is called the Synology RS1219+.

It works perfectly with version 0.2.1. Any idea what might have changed to break it?

Possible api change

Hi,

I'm using your module in a project, and after update to DSM 7 it throws and error on login

Screenshot 2021-09-22 at 08 15 14

Am I doing something wrong?

On closer inspection it seems the drive returns code 103 somewhere in authentification process.

always only return You are now logged in! nothting else !

install

chc@h03:~/git/sftpbox$ pip3 install git+https://github.com/N4S4/synology-api
Defaulting to user installation because normal site-packages is not writeable
Collecting git+https://github.com/N4S4/synology-api
  Cloning https://github.com/N4S4/synology-api to /tmp/pip-req-build-rfkevfpr
  Running command git clone --filter=blob:none --quiet https://github.com/N4S4/synology-api /tmp/pip-req-build-rfkevfpr
  Resolved https://github.com/N4S4/synology-api to commit fabed66871c660f01440bc64efb97d86a437a798
  Preparing metadata (setup.py) ... done
Requirement already satisfied: requests in /usr/lib/python3/dist-packages (from synology-api==0.4.4) (2.22.0)

python file

chc@h03:~/git/sftpbox$ cat 1.py
#!/bin/env python3.8
#   Version: v1.0.1
#   Filename: 1.py
#   Author: {{ author }}
#   Description: ---
#   HostName: {{ hostname }}
#   Create: 2022-10-12 17:36:26
from synology_api import filestation, downloadstation

# Initiate the classes DownloadStation & FileStation with (ip_address, port, username, password)
# it will log in automatically 

fl = filestation.FileStation('192.168.11.161', '5000', 'myaccount', 'mypassword', secure=False, cert_verify=False, dsm_version=6, debug=True, otp_code=None)

fl.get_list_share()

run the python

chc@h03:~/git/sftpbox$ python 1.py
You are now logged in!
chc@h03:~/git/sftpbox$

any suggestions ?

Use logging lib to print messages

It's a good practice, I suppose, that to not use print() function for logging purpose, but define a logger on the logging library.

The advantages are :

  • You can use different log levels
  • When another program use the lib, it can define the level he wants to print for this lib
  • You can easily forward logs to a log file or logs platform

can't create folder with just number name

I use create_folder api
path = "/mynas/example" desPath = str(302342) result = fl.create_folder(path, desPath)
but this code result is
{'error': {'code': 400}, 'success': False}
I can't create folder just number name

date_expired not used in create_sharing_link or edit_sharing_link

In filestation.py : the argument date_expired is mentioned in the function signature but it is not used (and the same for date_available) :

def create_sharing_link(self, path=None, password=None, date_expired=None, date_available=None): 
    ...

def edit_shared_link(self, link_id=None, password=None, date_expired=None,   date_available=None):
    ...

Would it be possible to allow for using this parameter ?

Use a decorator method to make api calls.

See this issue first: #7

Each api call in each class currently repeats a lot of the same code over and over. Using a decorator function could easily reduce the number of instances of the repeating code to one. This will be especially easy to do if #9 is implemented.

The decorator function would be defined as a method in the "Authentication" class:

def api_call(self, function):
        ...

and then can be used in each other class as so:

class DownloadStation(Authentication):
        @self.api_call
        def get_info(self):
                ...

Writing new methods and changing existing ones becomes much easier.

Could not install from source

Python version: 3.6.8
Pip version: 19.3.1
Install command: python setup.py install

Traceback:

Traceback (most recent call last):
  File "synology-api\setup.py", line 9, in <module>
    long_description=open('README.md').read(),
UnicodeDecodeError: 'cp949' codec can't decode byte 0xe2 in position 6173: illegal multibyte sequence

Quick fix:
Delete all content of README.md and re-run the command.

Warnings: Surprised it actually works...

"SyntaxWarning: "is" with a literal. Did you mean "=="?
  if method is 'get':"

When comparing to string literals, it's more preferred to use a value comparison than an object identity comparison. In fact, I'm surprised it actually works...
Am I missing something?

Working with Python 3.5.3

Have a problem with building the project using Python 3.5.3

File "d:\Projects\home-library\api\.venv35\lib\site-packages\synology_api\__init__.py", line 1, in 
    from . import auth, filestation, downloadstation, audiostation, sys_info, virtualization
  File "d:\Projects\home-library\api\.venv35\lib\site-packages\synology_api\filestation.py", line 438
    req_param['taskid'] = f'"{self._md5_calc_taskid}"'

Response is not a json so login syntax does not work

Hi!

Thank you first for writing this package!
I was using the official document myself and tried to use those API with python in code instead of pasting their API in browser directly.

I then encountered an error whenever I want to do response.json()

json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) 

I tried your package and it is the same error. In auth.py login function, line

self._sid = session_request.json()['data']['sid']

shows an syntax error of json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) .
I printed the response.text out and it is a long <!doctype html> <html> <head> <script async src="https://www.googletagmanager.com/gta........ HTML string.

I wonder whether you have encountered this issue when developing this package. In your case, your response.json() does not show any error?

下载的文件不完整

hi:
我这里遇到一个问题,使用filestation.git_file()下载的zip或txt不完整,文件大小大概在1kB,这个有办法解决吗?我尝试去判断文件大小,如果小于10KB则重复下载,这样更多的时候是卡在循环里

Logging with custom base_url instead of ip/port and use SSL/HTTPS

On the auth.py, you creates the base_url using the params ip_address/port.
It should be great if we can directly give a base_url for some reasons :

  • some times, the NAS is behind a reverse proxy and the base URL contains a subdirectory
  • you can choose behind http/https added with pr #42
  • only one simple param to use

I will try to submit a PR that can manage both ways, to not break something.

BUG report: upload larg file >4G . error:OverflowError: string longer than 2147483647 bytes

BUG Report:

upload file
fl = filestation.FileStation(.................
fl.upload_file('/file/dest','c:\temp\abc.zip')

if abc.zip large than 4G

Traceback (most recent call last):
File "main.py", line 43, in
File "synology_api\filestation.py", line 500, in upload_file
File "requests\sessions.py", line 590, in post
File "requests\sessions.py", line 542, in request
File "requests\sessions.py", line 655, in send
File "requests\adapters.py", line 449, in send
File "urllib3\connectionpool.py", line 706, in urlopen
File "urllib3\connectionpool.py", line 394, in _make_request
File "urllib3\connection.py", line 234, in request
File "http\client.py", line 1239, in request
File "http\client.py", line 1285, in _send_request
File "http\client.py", line 1234, in endheaders
File "http\client.py", line 1065, in _send_output
File "http\client.py", line 986, in send
File "ssl.py", line 975, in sendall
File "ssl.py", line 944, in send
File "ssl.py", line 642, in write
OverflowError: string longer than 2147483647 bytes
[6980] Failed to execute script 'main' due to unhandled exception!

OverflowError: string longer than 2147483647 bytes

Handle errors and exceptions in ways other than returning strings.

See this issue first: #7

Many functions return strings instead of raising errors, returning success or failure values, etc. This should be changed. For example, Authentication.login should be changed from this:
` def login(self, application):
login_api = 'auth.cgi?api=SYNO.API.Auth'
param = {'version': '2', 'method': 'login', 'account': self._username,
'passwd': self._password, 'session': application, 'format': 'cookie'}

    if not self._session_expire:
        if self._sid is not None:
            self._session_expire = False
            return 'User already logged'
    else:
        session_request = requests.get(self._base_url + login_api, param)
        self._sid = session_request.json()['data']['sid']
        self._session_expire = False
        return 'User logging... New session started!'`

to this:

class AlreadyLoggedInError(ConnectionRefusedError):
        pass
_login_api = 'auth.cgi?api=SYNO.API.AUTH' #we use this multiple places so I've made it a hidden attribute
def login(self, application):
        param = {'version': '2', 'method': 'login', 'account': self._username,
                 'passwd': self._password, 'session': application, 'format': 'cookie'}
        if not self.session_expire:
                if self.sid is not None:
                        self.session_expire = False
                        raise self.AlreadyLoggedInError("Already logged in.")
        self.session = self._response(self._log_api, param)
        self.sid = self.session.json()['data']['sid']
        self.session_expire = False
        return True #true for success, could also not return or return None.

This uses less memory and is quicker than allocating a string to return. We can let the user determine how they want to deal with the error or with success.

This will be a breaking change, so any existing scripts using the library would need to be updated. But doing things this way will be easier to maintain on top of the performance benefit.

get_file() function is assuming the download file path is same as file path where the downloads are saved.

Not sure if I read that correctly.

The parameter "path" is used for

  1. constructing the url

url = ('%s%s' % (self.base_url, api_path)) + '?api=%s&version=%s&method=download&path=%s&mode=%s&_sid=%s' % ( api_name, info['maxVersion'], parse.quote_plus(path), mode, self._sid)

  1. passing as the writing path of the download response.

with session.get(url, stream=True) as r: r.raise_for_status() with open(os.path.basename(path), 'wb') as f:

These 2 would not be the same in most cases.
The function should take 2 separate parameters.

Machine oriented outputs for async start function

We are using the FileStation API and this package is really helpful but it is a bit annoying to use for the asyn requests in a fully automatic mode. Usually our workflow is the following:

  • Call a *_start function (for example FileStation.search_start)
  • The output is a string containing the task_id
  • Parse the string to get the task_id
  • Call a get_* function with the task_id to get the results

The parsing could be easily prevented if the output of the "start" method was the task_id directly. If it seems ok with you, I am willing to do a PR where depending on an option in FileStation (or in the methods) the output is directly the task_id. This option would be set by default to False to keep backward compatibility.

This would lead to the following code (not sure about the parameter name):

fs = FileStation(..., dict_output=False) # default
res = fs.start_search(...)
# res is a str with the current message  "You can now ..."

fs = FileStation(..., dict_output=True)
res = fs.start_search(...)
# res is of the form {"message": "'You can now ...", "task_id": 35000}

If that sounds ok with you, I can submit a PR soon.

trying to connect and upload file with filestation

Hello,
I have been using the "python-synology 1.0.0" library and I have managed to connect to my NAS by putting ("sensor12345.synology.me", "5000", "username", "password") but with this library I can't upload files.

I have seen this other “synology-api” library that I think can help me upload files to my NAS more easily.
The thing is that I try with:

from synology_api import filestation
fl = filestation.FileStation ('sensor12345.synology.me', '5000', 'username', 'password')
fl.get_info ()

and it gives me the following error:

Traceback (most recent call last):
File "C: /Users/moti/PycharmProjects/GUItutorial/venv/synology_wrapper_test.py", line 7, in
fl = filestation.FileStation ('sensor12345.synology.me', '5000', 'username', 'password')
File "C: \ Users \ moti \ PycharmProjects \ GUItutorial \ venv \ lib \ site-packages \ synology_api \ filestation.py", line 34, in init
self.session.login ('FileStation')
File "C: \ Users \ moti \ PycharmProjects \ GUItutorial \ venv \ lib \ site-packages \ synology_api \ auth.py", line 30, in login
self._sid = session_request.json () ['data'] ['sid']
KeyError: 'data'

I hope you can help me.
Thanks in advance

Unify classes to inherit from one class

See this issue first: #7

Currently there's a lot of code repeated between each class. On top of that, each class receives an "Authentication" object as an argument. If we were use the "Authentication" object as a base class, each other class could inherit authentication attributes from the authentication object. This would make things easier to change as it would only need to change in one place instead of if every api.

As an example, downloadstation's class would change from this:

class DownloadStation:
        def __init__(self, auth_args, ...):
                self.session = syn.Authentication(auth_args)

to this:

class DownloadStation(syn.Authentication):
        def __init__(self, auth_args, ...):
                super(DownloadStation, self).__init__(auth_args)

We can then put any attributes repeated between classes into the "Authentication" class so that we aren't repeating so much code. Since the class will no longer be exclusively dealing with authentication if we make this change, I think it would be a good idea to change the Authentication class's name to just "Synology" as authentication would imply just authentication. Renaming is a separate issue however so I will open a separate issue report for it.

Offering help/Context for other issues

Before I begin with the issue, I want to say that I run the IT department for a small business that also owns a Synology. We need to automate some things on it and using you pre-written api will be quicker for us than me writing my own implementation from the ground up. That being said there are a few things that need to be changed to make the code ready for business use, and since you said you would accept help simplifying things I would like to take it upon myself to provide that help.

This issue and the next few that I plan to create are issues that I myself am working on in my fork, and I will create a pull request to implement the fixes when completed. I'm saying all this because I don't want you to see the number of issues I'm about to create and become stressed out that people are waiting on you to fix things.

Being a hobbyist, I'm not sure where your level of python skill is so if you have any questions about what I'm doing please feel free to ask. Let me know how experienced you are so that I can explain what I'm doing at the appropriate level. I don't want to talk down to you if you are more experienced than me, but I don't want to go over your head if you have less experience.

I will be writing up a few more issue reports to document what the issues I see are,and so that we can discuss how to best fix them. I don't want to come in and take your baby from you, so any feedback to what I do with the project is appreciated.

I will link this issue in the other reports. Once you've read this, feel free to close the issue.

Is there a way to check if I have read-only permissions on a file ?

The case is specific to a shared folder.
In order to check file permissions, I do :

from synology_api import filestation, downloadstation
fl = filestation.FileStation(<URL>, <port>, <userName>, <password>,secure=True)
fl.check_permissions(path="/SharedFolder/myFile.png", filename="myFile.png")

According to the permissions of the user, I get:

NO ACCESS : {'error': {'code': 407}, 'success': False}
FULL ACCESS : {'data': {'blSkip': False}, 'success': True}
READ ONLY: {'data': {'blSkip': False}, 'success': True}

Is there a way to discriminate between FULL ACCESS and READ ONLY access ?

Note that because of #54 I am still on v.0.1.3.1. I think v.0.4.0 broke that fix (but I have not investigated further yet)

Session store

Hello! I use your libs and its good) But I should ask you function save session
I every time create FileStation like this code

        fl = filestation.FileStation(cp.synology_ip, cp.synology_port, cp.synology_user,
                                     cp.synology_pass, cp.synology_https)

But for this need password and user. Storage pass and user require encrypt. What if I will store only session. But I cant create FileStation object only have sesiion.
Could you change your library so that you can initialize the object knowing the session.

iscsi support

I’m trying to put together something similar for a nodejs project and have found it difficult to find documentation regarding all the iscsi methods.

Have you looked into implementing here and/or know where the documentation could be found?

I don’t actually own a device I’ve just had some requests to add synology support to my project.

Improve login handling

I am just starting with the API and tried to connect using the core module.

For me, base_api_core.Core() failed on line 9:

self.session.login('Core')

Relevant part of the traceback:

<...>synology_api\base_api_core.py in __init__(self, ip_address, port, username, password, secure, cert_verify, dsm_version, debug, otp_code)
      7         self.session = syn.Authentication(ip_address, port, username, password, secure, cert_verify, dsm_version, debug, otp_code)
      8 
----> 9         self.session.login('Core')
     10         self.session.get_api_list('Core')
     11         self.session.get_api_list()

<...>synology_api\auth.py in login(self, application)
     40         else:
     41             session_request = requests.get(self._base_url + login_api, param, verify=self._verify)
---> 42             self._sid = session_request.json()['data']['sid']
     43             self._session_expire = False
     44             if self._debug is True:

KeyError: 'data'

The error is misleading, since auth.login() has no error checking on the requests.get() result, but what happens is that session_request .json() has this content:

{'error': {'code': 402}, 'success': False}

And finally, 402 seems to be permission denied.

My first suggestion would be to improve the auth.login()in a similar fashion to auth.logou() and check for

if response.json()['success'] is True:

But there is also a PR which tries to improve the situation: #100
I like the addition of the error codes, but since the original author was not responding I wonder if it makes sense to make a similar PR which resolves your requests?

Wiki to create

I think is time to create a WIKI for a better understanding

json.decoder.JSONDecodeError

Nas: DS21Plus

Code used:

from synology_api import filestation

ip = 'xx.xx.xx.xx
port = '5001'
username = 'xxxxxxxxxxxxxxxxxxx'
password = 'xxxxxxxxxxxxxxxxxxx'

fl = filestation.FileStation(ip, port, username, password, secure=False, dsm_version=7, debug=True, otp_code=None)

Exception:

Traceback (most recent call last):
  File "x\test.py", line 8, in 
    fl = downloadstation.DownloadStation(ip, port, username, password, secure=False, dsm_version=7, debug=True, otp_code=None)
  File "x\Python310\lib\site-packages\synology_api\downloadstation.py", line 11, in __init__
    self.session.login('DownloadStation')
  File "x\Python310\lib\site-packages\synology_api\auth.py", line 42, in login
    self._sid = session_request.json()['data']['sid']
  File "x\Python310\lib\site-packages\requests\models.py", line 910, in json
    return complexjson.loads(self.text, **kwargs)
  File "x\Python310\lib\json\__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "x\Python310\lib\json\decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "x\Python310\lib\json\decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Thanks for your help.

Does Auth bypass 2FA?

Does the Auth bypass 2FA? And if so, I guess I'm a little concerned about that, but glad that it does when I'm trying to access it...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.