czp3009 / bilibili-api Goto Github PK
View Code? Open in Web Editor NEWBilibili API library for Kotlin
License: GNU General Public License v3.0
Bilibili API library for Kotlin
License: GNU General Public License v3.0
E/AndroidRuntime: FATAL EXCEPTION: Thread-4
Process: com.duzhaokun123.bilibilihd, PID: 18272
java.util.concurrent.ExecutionException: com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "--"
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:359)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1921)
at com.duzhaokun123.bilibilihd.pBilibiliApi.app.PAppAPI.space(PAppAPI.kt:38)
at com.duzhaokun123.bilibilihd.ui.UserSpaceActivity$2.run(UserSpaceActivity.java:73)
at java.lang.Thread.run(Thread.java:764)
Caused by: com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "--"
at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:227)
at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:217)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:39)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:223)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:121)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:174)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.NumberFormatException: For input string: "--"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at com.google.gson.stream.JsonReader.nextInt(JsonReader.java:1201)
at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:225)
at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:217)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:39)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:223)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:121)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:174)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
具体代码如下
` /**
* 获取直播分区列表,多层
*
* @return 成功时code为0
*/
@get("room/v1/Area/getList?show_pinyin=1")
Call getLiveAreaList();
/**
* 获取直播间信息(主要是拿roomId)
*
* @return LiveInfoEntity
*/
@GET("i/api/liveinfo")
Call<LiveInfoEntity> getLiveInfo();
/**
* 根据roomId 获取推流的地址
*
* @param roomId
* @return LiveRoomStreamInfoEntity
*/
@GET("live_stream/v1/StreamList/get_stream_by_roomId")
Call<LiveRoomStreamInfoEntity> getStreamByRoomId(@Query("room_id") String roomId);
/**
* 开始直播
*
* @param roomId
* @param platform 固定PC
* @param areaId 子分区id 譬如学习的id为27
* @param csrfToken (csrfToken是cookie里的bili_jct cookie这个的值)
* @return StartLiveEntity
*/
@POST("room/v1/Room/startLive")
Call<StartLiveEntity> startLive(@Query("room_id") String roomId, @Query("platform") String platform,
@Query("area_v2") String areaId, @Query("csrf_token") String csrfToken);
/**
* 停止直播
*
* @param roomId
* @param platform
* @param areaId
* @param csrfToken
* @return
*/
@POST("room/v1/Room/stopLive")
Call<StopLiveEntity> stopLive(@Query("room_id") String roomId, @Query("platform") String platform,
@Query("area_v2") String areaId, @Query("csrf_token") String csrfToken);`
希望获取到这部分数据用来进行rnn,up有这些api方面的研究吗
GET https://api.live.bilibili.com/appUser/myTitleList
access_key = 用户accessToken
获取用户拥有的所有头衔
返回
@SerializedName("code")
public int code;
@SerializedName("message")
public String message;
@SerializedName("data")
public MyTitlesEntity data;
public static class MyTitlesEntity {
@SerializedName("list")
public List<TitleEntity> list;
public static class TitleEntity {
@SerializedName("uid")
public int uid;
@SerializedName("had")
public boolean hasTitle;
@SerializedName("title")
public String titleID;
@SerializedName("status")
public int status;
@SerializedName("activity")
public String activity;
@SerializedName("score")
public int scoreLevelup;
@SerializedName("title_pic")
public TitlePicEntity pic;
public static class TitlePicEntity {
@SerializedName("id")
public String id;
@SerializedName("img")
public String imageUrl;
@SerializedName("width")
public int width;
@SerializedName("height")
public int height;
}
}
}
POST https://api.live.bilibili.com/AppExchange/silver2coin
access_key = 用户accessToken
银瓜子换硬币
返回code=403则当日已经换过(每天可换一个硬币)
返回数据仅ts. code和message
GET https://api.live.bilibili.com/AppUser/wearTitle
title = 头衔id
access_key = 用户accessToken
佩戴头衔
头衔id为获取用户所有头衔返回的data - list - title
头衔不存在返回code=-400
返回数据仅ts. code和message
(自动带可升级头衔签到,签完换回来美滋滋2333)
e[e.WS_OP_HEARTBEAT = 2] = "WS_OP_HEARTBEAT",
e[e.WS_OP_HEARTBEAT_REPLY = 3] = "WS_OP_HEARTBEAT_REPLY",
e[e.WS_OP_MESSAGE = 5] = "WS_OP_MESSAGE",
e[e.WS_OP_USER_AUTHENTICATION = 7] = "WS_OP_USER_AUTHENTICATION",
e[e.WS_OP_CONNECT_SUCCESS = 8] = "WS_OP_CONNECT_SUCCESS",
e[e.WS_PACKAGE_HEADER_TOTAL_LENGTH = 16] = "WS_PACKAGE_HEADER_TOTAL_LENGTH",
e[e.WS_PACKAGE_OFFSET = 0] = "WS_PACKAGE_OFFSET",
e[e.WS_HEADER_OFFSET = 4] = "WS_HEADER_OFFSET",
e[e.WS_VERSION_OFFSET = 6] = "WS_VERSION_OFFSET",
e[e.WS_OPERATION_OFFSET = 8] = "WS_OPERATION_OFFSET",
e[e.WS_SEQUENCE_OFFSET = 12] = "WS_SEQUENCE_OFFSET",
e[e.WS_BODY_PROTOCOL_VERSION = 1] = "WS_BODY_PROTOCOL_VERSION",
e[e.WS_HEADER_DEFAULT_VERSION = 1] = "WS_HEADER_DEFAULT_VERSION",
e[e.WS_HEADER_DEFAULT_OPERATION = 1] = "WS_HEADER_DEFAULT_OPERATION",
e[e.WS_HEADER_DEFAULT_SEQUENCE = 1] = "WS_HEADER_DEFAULT_SEQUENCE",
WS_BODY_PROTOCOL_VERSION_NORMAL: 0,
WS_BODY_PROTOCOL_VERSION_DEFLATE: 2,
protover: parseInt(n.protover, 10) || i.a.WS_BODY_PROTOCOL_VERSION_NORMAL
发送方 | 总长, 4 | head长, 2 | version, 2 | operation, 4 | sequence, 4 | body |
---|---|---|---|---|---|---|
客户端 | 16 | 1 | 7 | 1 | USER_AUTHENTICATION , 进入房间有个protover(Protocol Version)参数猜测是(指定服务端优先以什么格式给我发消息,0=NORMAL,2=DEFLATE,1=不知道,但貌似已失效) |
|
服务端 | 16 | 1 | 8 | 1 | CONNECT_SUCCESS , 进房成功 |
|
客户端 | 16 | 1 | 2 | 1 | HEARTBEAT , 心跳, body不填都行 |
|
服务端 | 16 | 1 | 3 | 1 | HEARTBEAT_REPLY , 心跳响应, body=人气(int) |
|
服务端 | 16 | 2 | 5 | 0 | MESSAGE , 消息, body=deflate压缩 |
|
└─ | 16 | 0 | 5 | 0 | 解压后同下 | |
服务端 | 16 | 0 | 5 | 0 | MESSAGE , 消息, body=字符串(utf8) |
* 查看可用的小电视抽奖
*
* @param roomId 房间号
* @return 当目标房间没有可用的小电视抽奖时返回 -400
*/
@GET("AppSmallTV/index")
Call<AppSmallTVEntity> getAppSmallTV(@Query("roomid") long roomId);
我使用python访问这个api获取的信息是这样的,不知道怎么看具体的小电视编号
{'code': 0, 'msg': 'OK', 'message': 'OK', 'data': {'lastid': 0, 'join': [], 'unjoin': []}}
求作者分析下点赞的接口
测试代码见下,第二个login总是会抛出-2001的错误。是不是我的secCode构造有误?
fun main(args: Array<String>) = runBlocking {
val bilibiliClient = BilibiliClient()
try {
val login_res = bilibiliClient.login("XXX", "YYY")
} catch (exp: BilibiliApiException) {
println(format("Login failed with code %d", exp.commonResponse.code))
if (exp.commonResponse.code == -105) {
println(format("Needs verification: %s", exp.commonResponse.data!!["url"].asString))
val re = Regex("challenge=([0-9a-zA-Z]+)")
val challenge = re.find(exp.commonResponse.data!!["url"].asString)!!.groupValues[1]
print("Please paste the validate result: ")
val validate = readLine()!!
try {
val login_res = bilibiliClient.login("XXX", "YYY", challenge, "$validate|jordan", validate)
} catch (exp: BilibiliApiException) {
println(format("2nd login failed with code %d", exp.commonResponse.code))
}
}
}
}
这是为什么呢?
我为什么要闲的蛋疼去抓动态接口
综述:/dynamic_svr/v1/dynamic_svr/dynamic_num
接口是关于动态的一系列接口的整合体。
结合web版,目前抓到了这几个:
此时的query:
uid:用户uid
type:动态的类型,如下图所示
各动态栏目有各自固定的type
栏目 | type参数的值 |
---|---|
全部 | 268435455 |
追番 | 512 |
专栏 | 64 |
小视频 | 16 |
投稿视频 | 8 |
图片 | 2 |
返回的是一个如下的描述动态页面内容的json。
{
"code": 0,
"msg": "",
"message": "",
"data": {
"new_num": 0,
"exist_gap": 1,
"open_rcmd": 1,
"archive_up_num": 2,
"up_num": {
"archive_up_num": 2,
"bangumi_up_num": 1
},
"extra_flag": {
"great_dynamic": 1
},
"cards": [{
"desc": {
"uid": __userid,
"type": 2,
"rid": __some_rid,
"acl": 0,
"view": 1255,
"repost": 0,
"like": 27,
"is_liked": 0,
"dynamic_id": __some_dynamic_id,
"timestamp": __ts,
"pre_dy_id": 0,
"orig_dy_id": 0,
"orig_type": 0,
"user_profile": {
"info": {
"uid": uid,
"uname": "username",
"face": "some_face_uri"
},
"card": {
"official_verify": {
"type": 0,
"desc": "some_description"
}
},
"vip": {
"vipType": 2,
"vipDueDate": 1584892800000,
"dueRemark": "",
"accessStatus": 0,
"vipStatus": 1,
"vipStatusWarn": "",
"themeType": 0
},
"pendant": {
"pid": 0,
"name": "",
"image": "",
"expire": 0
},
"rank": "10000",
"sign": "some_sign",
"level_info": {
"current_level": 6,
"current_min": 0,
"current_exp": 0,
"next_exp": "0"
}
},
"stype": 0,
"r_type": 1,
"inner_id": 0,
"status": 1,
"dynamic_id_str": "str"
},
"card": "some card json",
"extend_json": "some extend json"
}...],
"attentions": {
"uids": [2...],
"bangumis": [{
"season_id": 687,
"type": 1
}...]
},
"_gt_": 0
}
}
此时的query:
uid:用户uid
type:动态类型,跟随栏目的下列选择有固定的值
rsp_type:1 意义应该是指定response的类型为只返回动态更新增量
[可空] current_dynamic_id:当前的最新动态id
[可空] update_num_dy_id:获取这个动态id后的动态。
后两个参数一般置为一样同时传递。
返回参考:
{
"code": 0,
"msg": "",
"message": "",
"data": {
"new_num": 0,
"update_num": 1,
"_gt_": 0
}
}
相对于前一个response类型,data中少了cards和attentions。
调用的是同目录下的recommend
接口,参数接受uid和page,返回response结构略有不同。
如题。
已经实现通过 SSO API 获取可用于 Web API 调用的 cookies.
使用得到的 cookies 就可以使用全部的 B站 Web API.
一些内容和功能在 Android APP 上不存在, 例如奖励领取(双端观看直播奖励等), 所以 Web API 可能是必要的.
于是新一波的 API 分析又开始了(躺).
项目文档也不知道该怎么写(扶额).
README 更新了一些编码规范, 诚邀合作开发者.
需要输入验证码时,data中包含验证码url,但返回内容因为code非0被FailureResponseInterceptor拦截抛出BilibiliApiException无法从异常中获取data内容(只有message)
在使用您的api开发的过程中碰到一点问题,因此请教一下
首先,为了能在android上运行,我修改了部分代码(将lambda改为匿名类,以及自行实现部分java8新增的api),我可以确认这部分代码不会引起问题
我遇到的问题是
在我的电脑(ubuntu 14.04.5)上,经测试一切正常
但在安卓上同样的代码登录时返回了code:-400, message:"请求出错,请重试"
经过抓包对比,我并没能找到问题....看起来两个post请求没什么不对
请问这种情况有可能是什么造成的?
登录并进行验证码校验后返回了错误信息
{"ts":1610644416,"code":0,"data":{"status":2,"url":"https://www.bilibili.com/blackboard/activity-loginwarning.html","message":"你的帐号存在异常问题,请使用哔哩哔哩手机端APP最新版本验证后登录"}}
怀疑是否是使用的api版本过旧导致的
版本 0.1.2
java.lang.NullPointerException: Attempt to invoke virtual method 'long com.hiczp.bilibili.api.passport.model.LoginResponse$Data$TokenInfo.getMid()' on a null object reference
at com.hiczp.bilibili.api.passport.model.LoginResponse.getUserId(LoginResponse.kt:57)
at com.duzhaokun123.bilibilihd.ui.LoginActivity$1$1.run(LoginActivity.java:70)
测试账号 15671920364 密码 bb123456 这个账号是在B站公开的 https://www.bilibili.com/video/av95946645/?redirectFrom=h5
但是被封禁
#9 这里提及过,看来是个挺重要的参数
但愿只是我没有找到
在myInfo当中
com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: Expected an int but was 419.3 at line 1 column 117 path $.data.coins
传参avid 返回查询视频详情信息 感谢!
RT
这里的post的内容,sign加密,url都没找到。。。
实在是看不懂了
求助
可否直接把代码解析出来,我只需要实现这一个功能
在弹幕推送 socket 中, 小电视抽奖通知对应 SYS_MSG, 数据包差不多如下
{
"cmd": "SYS_MSG",
"msg": "\u3010\u5e7d\u5c0f\u591c\u5929\u5c0f\u52ab\u3011:?\u5728\u76f4\u64ad\u95f4:?\u3010392\u3011:?\u8d60\u9001 \u5c0f\u7535\u89c6\u4e00\u4e2a\uff0c\u8bf7\u524d\u5f80\u62bd\u5956",
"msg_text": "\u3010\u5e7d\u5c0f\u591c\u5929\u5c0f\u52ab\u3011:?\u5728\u76f4\u64ad\u95f4:?\u3010392\u3011:?\u8d60\u9001 \u5c0f\u7535\u89c6\u4e00\u4e2a\uff0c\u8bf7\u524d\u5f80\u62bd\u5956",
"rep": 1,
"styleType": 2,
"url": "http:\/\/live.bilibili.com\/392",
"roomid": 392,
"real_roomid": 71084,
"rnd": 44332151,
"tv_id": "29349"
}
丰收庆典以及新春抽奖等普通抽奖对应 SYS_GIFT
{
"cmd": "SYS_GIFT",
"msg": "sakamakiryoryo\u5728\u76f4\u64ad\u95f471084\u5f00\u542f\u4e86\u4e30\u6536\u796d\u5178\uff0c\u4e00\u8d77\u6765\u5206\u4eab\u6536\u83b7\u7684\u798f\u5229\u5427\uff01",
"msg_text": "sakamakiryoryo\u5728\u76f4\u64ad\u95f471084\u5f00\u542f\u4e86\u4e30\u6536\u796d\u5178\uff0c\u4e00\u8d77\u6765\u5206\u4eab\u6536\u83b7\u7684\u798f\u5229\u5427\uff01",
"tips": "sakamakiryoryo\u5728\u76f4\u64ad\u95f471084\u5f00\u542f\u4e86\u4e30\u6536\u796d\u5178\uff0c\u4e00\u8d77\u6765\u5206\u4eab\u6536\u83b7\u7684\u798f\u5229\u5427\uff01",
"url": "http:\/\/live.bilibili.com\/71084",
"roomid": 71084,
"real_roomid": 71084,
"giftId": 102,
"msgTips": 0
}
ACTIVITY_EVENT 带有某种活动的进度信息
{
"cmd": "ACTIVITY_EVENT",
"data": {
"keyword": "newspring_2018",
"type": "cracker",
"limit": 300000,
"progress": 158912
}
}
小电视和普通抽奖的通知都会带有一个 URL, 在 web 上进入这个 URL, 点击悬浮窗即可抽奖.
尚不明确 Android 上看直播时有没有 SYS_MSG 和 SYS_GIFT 的提示(印象中好像没见到过).
尚不明确 Android 上参与抽奖的 API(是一个 Restful API, 不是发弹幕, 发弹幕只是副作用)(不太清楚 Android 上能不能抽奖).
抽奖之后开奖有两种, 一种是 socket 内直接推送的大奖获得者信息(例如 TV_END)(不明确除了小电视抽奖, 其他普通抽奖会不会有类似的大奖推送).
另一种是通过 Restful API 拉取的奖励(参与抽奖至少有辣条, 所以人人都有), 这在 Android 上的 API 是怎么样的也不明确(如果 Android 不能抽奖的话那这个 API 也肯定是没有的).
以上问题尚未解决, 先留存案.
添加后出现了这个。。。请教下大佬还有其他方式使用B站api吗。。andorid新人想练练手 android.support.multidex.MultiDexApplication: java.lang.ClassNotFoundException
获奖记录只保留三个月, 而有获奖记录的人又很少, 所以这个API 在获奖记录不为空时到底会返回什么内容尚不明确.
如果您有获奖记录(在 APP 里打开 获奖记录, 里面非空), 可以通过以下方式来帮助本项目的开发.
运行本项目的测试用例, 并提供其中的 GetAwardsTest 的控制台输出.
首先克隆本项目的源代码, 然后设定用户名和密码并进行测试(见 README 中的 测试 一节), 就可以看到输出了.
运行本项目需要 Java8+, Gradle4.5+
我在一个版本中 appkey=783bbb7264451d82 找不到盐值 可不可以帮下忙
android 版本: LineageOS 16 (android 9)
bilibili-api 版本: 0.2.0
E/AndroidRuntime: FATAL EXCEPTION: Thread-15
Process: com.duzhaokun123.bilibilihd, PID: 24430
java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/xml/stream/XMLInputFactory;
at com.hiczp.bilibili.api.danmaku.DanmakuParser.parse(DanmakuParser.kt:75)
at com.duzhaokun123.bilibilihd.ui.play.PlayActivity$3.run(PlayActivity.java:363)
Caused by: java.lang.ClassNotFoundException: Didn't find class "javax.xml.stream.XMLInputFactory" on path: DexPathList[[zip file "/data/app/com.duzhaokun123.bilibilihd-EWRpYYgLTKXGbRV_tVoFSQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.duzhaokun123.bilibilihd-EWRpYYgLTKXGbRV_tVoFSQ==/lib/arm64, /data/app/com.duzhaokun123.bilibilihd-EWRpYYgLTKXGbRV_tVoFSQ==/base.apk!/lib/arm64-v8a, /system/lib64, /vendor/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at com.hiczp.bilibili.api.danmaku.DanmakuParser.parse(DanmakuParser.kt:75)
at com.duzhaokun123.bilibilihd.ui.play.PlayActivity$3.run(PlayActivity.java:363)
github上还在更新的基本上只有大佬的这个项目了,B站官网也没有API文档了,请求大佬做个说明文档,谢谢!
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.