Compare commits

...

337 Commits

Author SHA1 Message Date
3d796ce447 绝对路径处理 2022-05-30 07:59:51 +08:00
a0fa46355b 支持自定义下载位置 2022-04-05 14:42:47 +08:00
41afd11036 Changes 2022-03-30 11:57:49 +08:00
58ef92792f 弹幕尽可能及时写入,下拨后及时保存 2022-03-29 06:43:38 +08:00
db6e0be776 弹幕xml文件写入逻辑微调 2022-03-27 15:17:32 +08:00
95c984573f 接口域名更新 2022-03-27 13:03:13 +08:00
5840b75b24 弹幕录制添加礼物记录功能(兼容DanmakuFactory) 2022-03-27 10:27:03 +08:00
ce701816b9 弹幕录制功能(兼容DanmakuFactory) 2022-03-26 23:15:19 +08:00
d83761afc0 没直播时,不可以执行更新弹幕功能 2022-03-26 23:14:49 +08:00
798af607bb 片段下载完毕后,开一个线程更新下直播信息 2022-02-11 09:29:58 +08:00
3096df86b2 status True时,提示成功,而不是失败 2022-02-09 00:35:00 +08:00
0505aeaace 添加取消所有上传过的和上传队列 2022-02-09 00:16:34 +08:00
551a8b1f18 上传失败后,不重复上传了,中断 2022-02-08 23:37:14 +08:00
e646085f0b 开播后由下载进程中断后,再去更新信息(避免一直在更新信息) 2022-02-07 14:39:40 +08:00
b8d76f6273 playlist提取,优化streamUrl设置 2022-02-07 10:28:58 +08:00
29d23a38d2 删除exp参数,由max控制 2022-02-07 10:28:38 +08:00
bf2b8956ef 删除1个无用参数 2022-02-07 10:18:48 +08:00
f14860703f 删除1个无用参数 2022-02-06 22:03:22 +08:00
8d98918e39 删除两个无用参数 2022-02-04 19:44:11 +08:00
9198413cd9 add .env 2022-02-02 15:23:23 +08:00
04fb6e956f 去除无用默认设置项 2022-02-02 15:21:12 +08:00
root
8ed3e71539 requirements更新 2022-02-02 15:18:27 +08:00
1feed57b4e 重新修正了B站无法上传多P的问题 2022-02-01 23:32:41 +08:00
b1f45ee90d 合并录播 2021-05-19 14:14:54 +08:00
2facc798cd 合并录播 2021-05-19 13:18:12 +08:00
1e24129ee7 又更新了 2021-05-19 13:17:16 +08:00
0723817bc8 Merge branch 'lubo'
# Conflicts:
#	Common.py
#	Demo/Xigua.proto
#	Demo/XiguaGift.proto
#	Demo/XiguaUser.proto
#	README.md
#	WebMain.py
#	WinMain.py
#	api.py
#	bilibili.py
#	liveDownloader.py
#	templates/head.html
2021-05-19 12:28:01 +08:00
d882b03e12 又更新了 2021-05-19 12:24:33 +08:00
8a810d1869 SB bootcdn 2021-04-08 11:36:51 +08:00
3e49fa59bb 避免无法更新状态的问题 2021-02-05 09:15:13 +08:00
f4d65e9595 添加 CHANGELOG 2021-02-05 01:14:59 +00:00
d36e7e2c5c 添加 LICENSE 2021-02-05 01:12:50 +00:00
c83c984509 删除v7版本了 2021-02-03 07:56:55 +00:00
821244a0c5 避免无法更新状态的问题 2021-02-01 10:55:03 +08:00
11a73f1aca 额外更新 2021-01-30 19:56:40 +08:00
734a7204f8 额外更新 2021-01-30 19:56:40 +08:00
27f4d25591 返回isLive 2021-01-30 19:56:29 +08:00
8bbb74eae9 状态只缓存3分钟 2021-01-30 19:52:07 +08:00
8fbe139ba0 日常更新 2021-01-30 10:13:17 +08:00
root
81dad07fd5 Merge branch 'lubo' of https://git.jerryyan.top/q792602257/XiguaLiveDanmakuHelper into lubo 2021-01-12 09:43:38 +08:00
root
30a91a38f9 细节修改 2021-01-12 09:43:09 +08:00
0b4068b9e9 避免输入了换行导致requests裂开 2021-01-12 09:36:51 +08:00
302b4d4596 URL格式更新 2020-12-06 16:09:44 +08:00
d64639af20 URL格式更新 2020-12-06 16:09:03 +08:00
9e1b725c0c URL参数格式更新 2020-12-06 11:14:10 +08:00
ecdcde9230 例行升级(9.1.8->9.2.6) 2020-12-05 15:57:58 +08:00
977cb9877f 下播判断 2020-12-05 15:47:30 +08:00
6b1a4a7b0a 例行升级(9.1.8->9.2.6),删除被动更新礼物,删除抽奖检测 2020-12-05 15:36:27 +08:00
2281f872bf 更新部分逻辑 2020-12-02 08:11:16 +00:00
bf5c4f760a Update README.md 2020-11-26 07:01:00 +00:00
5ee9a63a4e
Update README.md 2020-11-22 14:49:26 +08:00
be194f4b64 处理逻辑优化 2020-11-22 14:34:07 +08:00
b72437758f 例行升级(8.4.4->9.1.8) 2020-11-22 14:31:17 +08:00
0e00579e13 例行升级(8.4.4->9.1.8) 2020-11-22 14:21:26 +08:00
5cf4ab2fc1 更换登录类型 2020-07-06 12:03:47 +08:00
6f9616ccf3 Merge branch 'lubo' of ssh://git.jerryyan.top:29022/q792602257/XiguaLiveDanmakuHelper into lubo 2020-07-02 22:05:27 +08:00
7beddaf91e 成功之后立刻更新数据 2020-07-02 22:01:39 +08:00
e0736f1658 仅下载时无限制 2020-05-28 10:20:06 +08:00
9c5d14213e UPDATE README.md 2020-05-28 10:18:43 +08:00
88012002a5 修改默认值(待修复搜索接口) 2020-04-24 23:07:43 +08:00
290767dc29 隐藏消息 2020-04-24 20:41:19 +08:00
c8d8ba8435 西瓜又升级了(用户信息接口) 2020-04-24 20:23:03 +08:00
e10c1ff928 西瓜又升级了(用户信息接口) 2020-04-24 00:39:03 +08:00
28a62ae6c3 西瓜又升级了 2020-04-23 20:57:12 +08:00
09564f1748 西瓜又升级了 2020-04-23 20:55:25 +08:00
47baa8b2e4 USE SEND_FILE INSTEAD OF blablabla 2020-04-14 14:03:13 +08:00
df4c3a34b1 添加超时 2020-04-12 20:38:41 +08:00
b38431bf4c 添加超时 2020-04-12 20:38:40 +08:00
3b7943ca23 TEST7 2020-04-11 11:48:17 +08:00
632c0ff3ca Merge branch 'lubo' of ssh://git.jerryyan.cn:29022/q792602257/XiguaLiveDanmakuHelper into lubo 2020-04-09 23:53:17 +08:00
c31e3a8106 忘记了 2020-04-09 23:53:07 +08:00
1cc824d624 TEST5 2020-04-09 17:19:48 +08:00
113c8f2a53 TEST4 2020-04-09 17:14:35 +08:00
9d7939061c TEST3 2020-04-09 10:59:06 +08:00
44b026f5ae Merge branch 'lubo' of ssh://git.jerryyan.cn:29022/q792602257/XiguaLiveDanmakuHelper into lubo 2020-04-09 08:36:13 +08:00
d0a6aadb56 TEST2 2020-04-09 08:36:01 +08:00
47cccb4aa8 例行更新 2020-04-08 16:12:11 +08:00
9e9cb58838 例行更新 2020-04-08 16:11:51 +08:00
866b789a3d 例行更新 2020-04-08 15:55:58 +08:00
0260fce845 例行更新 2020-04-08 12:24:23 +08:00
3ae8176abb TEST 2020-04-08 11:09:29 +08:00
3225952c69 TEST 2020-04-06 15:48:38 +08:00
44211bcbc9 TAT 2020-04-04 16:47:22 +08:00
bd4082f690 添加特殊判断,后期避免报错 2020-04-04 16:42:21 +08:00
9b69e90021 添加投稿日期可自定义配置 2020-04-01 11:33:23 +08:00
5a72550598 修正漏洞,避免配置文件泄露 2020-03-30 18:54:39 +08:00
7893bb0cd5 优化Windows显示方式 2020-02-12 20:19:28 +08:00
0add87dfa8 关注消息 2020-01-30 21:48:23 +08:00
4ef018a34b 竟然会反502TAT 2020-01-30 20:44:47 +08:00
db961deace URL都没了还不更新? 2020-01-15 19:08:12 +08:00
9757051c89 避免过于频繁更新状态
(cherry picked from commit 7102a45382cb52cf6b0c47663f7a6ffa891235d7)
2020-01-15 13:04:30 +08:00
7102a45382 避免过于频繁更新状态 2020-01-15 13:01:57 +08:00
27e5224b6c @property 2020-01-13 09:22:56 +08:00
d9d0778834 更新时间,更新逻辑 2020-01-13 09:21:21 +08:00
18c02b5156 stream timeout set small 2020-01-12 09:00:03 +08:00
cadfe922c0 Negative delay fix 2020-01-12 08:58:23 +08:00
53fd5c3f65 stop downloading with update room 2020-01-10 22:00:28 +08:00
179dc18ec8 Dict url 2020-01-10 21:34:21 +08:00
0f81dfd030 写错 2020-01-10 21:23:23 +08:00
11843661c0 写错 2020-01-10 20:06:47 +08:00
e36eec9dac UPDATE README.md 2020-01-10 11:50:17 +08:00
81dbc119da UPDATE README.md 2020-01-10 11:47:50 +08:00
39318a4cc9 精简 2020-01-10 11:41:14 +08:00
68fecca012 更新房间时更新更新时间,测试下播触发条件 2020-01-10 09:18:32 +08:00
cf5913e281 粉丝团升级消息 2020-01-09 09:31:59 +08:00
bb5fa72f50 不存在时的判断 2020-01-09 09:27:41 +08:00
74120850a4 灵活下播判断 2020-01-09 09:26:04 +08:00
0f71209fe8 精简接口 2020-01-08 09:20:11 +08:00
fdd809fdc2 信息更新时间 2020-01-08 09:09:44 +08:00
02562b63dc 下载完成后不自动更新(依赖外面循环更新 2020-01-08 09:06:11 +08:00
6b0433138a 投稿逻辑 2020-01-07 09:13:09 +08:00
fbeff099d0 modify common 2020-01-06 08:01:30 +08:00
17f0f4aa4e login 2020-01-06 07:31:53 +08:00
0643fe0076 写错 2020-01-05 14:52:46 +08:00
ff90542cc0 判断 2020-01-05 14:52:22 +08:00
ab545da6cd modify gitign 2020-01-04 17:25:14 +08:00
b3fb7dca43 自动登录逻辑优化,延迟投稿逻辑测试 2020-01-04 17:22:13 +08:00
e29ef65d71 更新README 2020-01-03 09:48:55 +08:00
6a2288a45d 更新README 2020-01-03 09:48:16 +08:00
6a482af97c 修正 2020-01-03 09:33:42 +08:00
ce152f617e 修正 2020-01-03 09:30:43 +08:00
6d4127c90b 下拨投稿逻辑 2020-01-03 09:19:45 +08:00
ee9556548d 主动更新礼物 2020-01-02 21:37:01 +08:00
107309c043 proto更新,粉丝团,牌子 2020-01-02 20:03:04 +08:00
d0b630262f 提交spec文件 2020-01-02 17:04:28 +08:00
ce23a67b59 回去测试下 2020-01-02 16:39:17 +08:00
7586432907 proto更新 2020-01-02 16:36:03 +08:00
5351641144 proto更新 2020-01-02 14:49:44 +08:00
f971380b5f 接口调整,Win 2020-01-01 22:39:24 +08:00
cae988e0fe 更新粉丝团 2020-01-01 21:39:20 +08:00
ff53afffb5 Proto更新--心累 2020-01-01 19:56:49 +08:00
8f1893fdb1 Proto更新 2020-01-01 17:17:53 +08:00
c335e45852 更新时间 2020-01-01 13:41:55 +08:00
81fe49daec 命名更新 2020-01-01 13:40:46 +08:00
c4f2776239 命名更新 2020-01-01 13:40:00 +08:00
7200f28cca API更新 2020-01-01 13:38:26 +08:00
ea7620bced API更新 2020-01-01 13:33:35 +08:00
1590729b51 API 2020-01-01 13:31:36 +08:00
5c0ed5e13f DEMO CHECK 2020-01-01 13:30:26 +08:00
d327a230b2 显示优化 2020-01-01 13:17:21 +08:00
560baf1b01 房间信息获取接口 2020-01-01 12:34:06 +08:00
d3cce09a7a 提取请求接口,添加ping房间 2020-01-01 11:55:12 +08:00
a3fec20b52 代码兼容性 2019-12-31 17:49:38 +08:00
c4e2d8ee14 代码兼容性 2019-12-31 17:45:27 +08:00
9d246dfcba 删除无用文件 2019-12-31 16:33:38 +08:00
d051250959 类型提示 2019-12-31 15:57:48 +08:00
452e1da468 类型提示 2019-12-31 15:56:21 +08:00
3096f742d5 判断 2019-12-31 15:47:45 +08:00
58991a8c43 控制台端 2019-12-31 15:45:48 +08:00
3cdd12644e 录播端 2019-12-31 15:43:35 +08:00
f598a5da05 默认值 2019-12-31 15:33:58 +08:00
372953b3e0 更新部分接口,待测试 2019-12-31 14:10:32 +08:00
37fdd0fa9a 搜索及详情接口OK 2019-12-31 12:59:37 +08:00
2d6a723be0 删除多余参数 2019-12-31 12:13:18 +08:00
3cd2db8f7b 避免玄学问题 2019-12-31 12:11:38 +08:00
28ed1df26b 规范输出 2019-12-31 12:11:13 +08:00
608f6924e3 命名 2019-12-31 12:06:55 +08:00
e8b981e7df 迷茫 2019-12-31 12:05:24 +08:00
d742edaff4 测试删除部分无用参数 2019-12-31 12:03:59 +08:00
0e37230f69 解析成功,待继续发掘有用数据 2019-12-31 11:27:56 +08:00
a14d1361bb 更新下proto 2019-12-31 10:48:36 +08:00
4da7e0c85d 搜索更新用户 2019-12-31 10:06:24 +08:00
a3b9f52684 DEMO 2019-12-30 18:09:26 +08:00
e402595a75 添加通用参数 2019-12-30 15:57:23 +08:00
JerryYan ECS
b15428af21 TEST Var change 2019-12-29 20:12:32 +08:00
e1eaf45e58 更多验证规则 2019-12-29 20:10:27 +08:00
d5f7306e59 Merge branch 'master' of http://github.com/q792602257/XiguaLiveDanmakuHelper 2019-12-23 20:49:03 +08:00
de8cda6846 更新等待时间 2019-12-23 20:48:34 +08:00
637046c4ef 删除无用代码 2019-12-20 13:15:49 +08:00
96c68dc608 B站接口更新 2019-12-19 19:56:51 +08:00
fb25a21c4c 忘记删除print了 2019-12-18 22:50:26 +08:00
c8198bf246 最终还是迎来了这天 2019-12-18 22:43:24 +08:00
f0f3316714 令人失智的操作TAT 2019-12-13 10:52:00 +08:00
root
cd03b04cf7 写错了 2019-12-09 20:21:42 +08:00
e3fa5d9de0 避免下播马上上播它还是把稿投出去的问题(未测试) 2019-12-09 09:35:17 +08:00
8520a36be2 避免未开播在疯狂提交发布申请 2019-12-05 09:05:37 +08:00
65be98f6b8 加点小延迟 2019-12-04 10:12:16 +08:00
53bda4d853 逻辑 2019-12-03 09:21:00 +08:00
root
1c7840c10d 修复下播延迟投稿判断 2019-11-30 19:07:45 +08:00
96fc50498c Merge remote-tracking branch 'origin/master' 2019-11-29 09:23:27 +08:00
6acc94b7c5 录播延迟投稿,注释补全 2019-11-29 09:23:11 +08:00
root
ca7dc40b03 下载出错直接更新房间数据 2019-11-25 22:17:52 +08:00
f96dd9448b Typo 2019-11-25 09:36:50 +08:00
9fb552e6dc 优化更新时间间隔 2019-11-25 09:34:06 +08:00
9b2f1a744f 登陆问题 2019-10-24 21:57:00 +08:00
172e82ba54 改改自己的沙雕代码 2019-10-22 22:00:18 +08:00
2b0adbb81a 改改自己的沙雕代码 2019-10-22 21:56:06 +08:00
83af0df5d4 登陆延迟问题 2019-10-22 21:46:11 +08:00
f80a44f1ac 方法 2019-10-22 21:34:42 +08:00
f8a602e6a3 BUG修复 2019-10-22 10:21:30 +08:00
adc6e10df1 剔除一些无效代码,优化部分逻辑 2019-10-22 10:09:50 +08:00
64fbe010ef Typo 2019-10-19 08:28:38 +08:00
204d8342bb 更新设置 2019-10-19 08:27:51 +08:00
0fc33fccff 优化逻辑 2019-10-19 08:23:41 +08:00
cf169021c6 清理逻辑 2019-10-18 23:23:57 +08:00
a307760dcc 清理逻辑 2019-10-18 23:20:57 +08:00
ae08a4398a 结构更改 2019-10-18 23:13:16 +08:00
f6501ca698 Typo 2019-10-18 22:39:16 +08:00
3be383c750 开始上传就登陆下 2019-10-18 22:37:20 +08:00
6536acb10e 删除Bypy,b站账号Common化,通过接口控制账号 2019-10-18 22:34:24 +08:00
root
586ef37874 修复忽略了30分钟内从新开播的可能 2019-09-28 21:13:00 +08:00
8f20250dee 改下自己写的sb代码 2019-09-25 09:02:18 +08:00
b9d9a8c435 改下自己写的sb代码 2019-09-24 09:21:58 +08:00
2554b537e8 防抖~~~~~~~~
最近主播老是掉线,避免误传(B站删稿件要2个硬币了TAT)
2019-09-24 09:18:40 +08:00
a0824785e5 更改主播名称判断,西瓜老是给些其他主播的名字忽悠程序TAT、 2019-08-23 11:07:43 +08:00
f25aac1fd9 Reduce Waiting Time 2019-07-29 09:11:30 +08:00
325e781758 嗯,是个很简单的防抖算法呢(硬核防抖 2019-07-20 11:11:19 +08:00
997fa950fd Fix Jumped Issue 2019-07-17 13:14:48 +08:00
081649ab58 增加测量宽度 2019-07-17 09:59:23 +08:00
71e6f829c5 Test 2019-07-17 09:57:56 +08:00
9e78994c03 Fix Divide by zero 2019-07-17 09:55:16 +08:00
359b4b43c7 提高Net精度(虽然没啥用 2019-07-17 09:53:32 +08:00
e1c9beb872 提高Net精度(虽然没啥用 2019-07-17 09:50:53 +08:00
add5a4654c Merge remote-tracking branch 'origin/master'
# Conflicts:
#	templates/status.html
2019-07-17 09:27:31 +08:00
95565c33ec 更改状态图片,更改liveDownloader的连接池,api使用连接池 2019-07-17 09:26:39 +08:00
root
3e3881022e upd template 2019-05-30 08:12:00 +08:00
76f280172b status更改 2019-05-28 19:17:49 +08:00
182c97fb84 添加判断是否显示图表 2019-05-28 11:29:41 +08:00
ee7ddbb1de 支持一下图表 2019-05-28 10:34:52 +08:00
0cb3987380 Merge remote-tracking branch 'origin/master' 2019-05-22 10:01:39 +08:00
567bf5f002 优化因退出而导致的投稿日期不变的问题,优化因下拨后下载进程退出而房间信息未更新的问题 2019-05-22 10:01:07 +08:00
fecd35844f Fix Bug 2019-05-17 21:35:48 +08:00
b4559f6771 Fix Bug 2019-05-17 21:20:25 +08:00
708218d34a 代码优化(可能是负优化,待测试) 2019-05-17 09:50:11 +08:00
a3d9e17a71 代码部分优化(可能是负优化,待测试) 2019-05-16 20:55:43 +08:00
89e9410810 Merge branch 'with_api'
# Conflicts:
#	README.md
2019-05-14 20:43:34 +08:00
a6aafd0ef2 Merge branch 'with_api'
# Conflicts:
#	README.md
2019-05-14 20:41:29 +08:00
6f1563cfb6 Update Readme 2019-05-14 20:36:45 +08:00
f5971c8429 。。。 2019-05-14 20:32:50 +08:00
1677afd975 Typo Fix 2019-05-13 23:20:49 +08:00
22925398da 修复因西瓜直播搜索接口修改导致的无法获取直播用户的问题 2019-05-12 19:31:43 +08:00
f1615957bc Update README.md 2019-05-11 21:27:15 +08:00
b61bd4c70c Avoid loop in Boardcaster is not found and stop download 2019-05-11 21:21:43 +08:00
f4bc6d847d 更新一下因为不退出而导致之后的发布日期不对的问题 2019-05-10 23:22:53 +08:00
c1141c366a Try to add a new Curses Version 2019-05-10 23:21:03 +08:00
ef0fe2cb04 trying fixing stuck at downloading 2019-05-05 14:29:58 +08:00
46b3500faa more exactly time settings 2019-04-30 10:09:42 +08:00
1f07e1046c some text changes 2019-04-29 11:44:58 +08:00
251c1e53fc simple doClean Flag 2019-04-29 10:27:52 +08:00
84a283b4c2 Time Format 2019-04-29 10:09:56 +08:00
4389016b95 Typo Error Fix 2019-04-29 10:08:18 +08:00
f1b4a878a5 添加强制清理功能,添加百度云上传功能,部分逻辑修改 2019-04-29 09:50:26 +08:00
43e161ebb6 typo fix 2019-04-27 22:17:31 +08:00
ed3ab5dc4f time fix 2019-04-27 22:11:51 +08:00
2099321f0b threading doClean 2019-04-27 22:10:02 +08:00
4ea19b4ff4 Fix when program at another disk 2019-04-27 22:08:16 +08:00
1644f52eb0 避免在无法获取下载链接是将false传入downloader内 2019-04-26 14:49:28 +08:00
f607f11b82 增加百度云链接 2019-04-26 14:48:11 +08:00
c4c6b1a752 fix: while set not upload ,it will not move any file to free disk space 2019-04-24 13:05:59 +08:00
99926827f1 small fix 2019-04-24 11:09:17 +08:00
03ce8df291 Merge remote-tracking branch 'origin/with_api' into with_api 2019-04-22 05:59:47 +08:00
5c1f712900 修改页面样式,修复网速的准确度 2019-04-22 05:59:22 +08:00
d17d0bd534 ...Typo Error 2019-04-18 10:47:29 +08:00
e520e39b72 ...Typo Error 2019-04-18 10:43:27 +08:00
b3162b1ed5 ...Typo Error 2019-04-18 10:43:04 +08:00
69b594cf8e ...Typo Error 2019-04-18 10:39:25 +08:00
86e4aa483f 强制编码上传 2019-04-18 10:37:13 +08:00
17d2cc4ebd 添加部分提醒 2019-04-18 08:02:54 +08:00
1ec9f3c922 修改i清理方式 2019-04-18 07:57:27 +08:00
9f075077ba 避免沙雕注释 2019-04-17 22:49:50 +08:00
ba40134219 Limit upload too small file 2019-04-17 07:59:14 +08:00
1ca7226cfe 主动清理 2019-04-16 21:28:22 +08:00
e50ca2fd5a Merge remote-tracking branch 'origin/with_api' into with_api 2019-04-16 21:22:32 +08:00
a9ecd1e7ab 断点续传 2019-04-16 21:21:45 +08:00
987c7aef01 Merge remote-tracking branch 'origin/with_api' into with_api 2019-04-16 15:14:52 +08:00
21009f6b51 a little typo error 2019-04-16 15:14:18 +08:00
035e71185a Merge remote-tracking branch 'origin/with_api' into with_api 2019-04-14 15:37:53 +08:00
2a51593cc3 避免下到别人的直播了 2019-04-14 15:37:13 +08:00
b813129410 自动移动 2019-04-11 15:11:18 +08:00
6c02b965b0 fix: if disk will full , delete some record file 2019-04-10 21:11:40 +08:00
e77fa5d6ad 日志记录逻辑 2019-04-10 07:04:12 +08:00
e066048e9f 增加操作日志,记录操作日志 2019-04-09 22:15:37 +08:00
612a9185eb Minify 2019-04-09 14:23:08 +08:00
a6fa88b981 支持显示网速 2019-04-09 13:48:46 +08:00
a6662450de 部分逻辑,更改名字 2019-04-09 08:11:09 +08:00
86fbf31120 Fix download a file wasnt exists 2019-04-08 23:05:06 +08:00
ef7d4c8d3e Typo Error Fix 2019-04-08 22:01:38 +08:00
9f999c013e Typo Error Fix 2019-04-08 21:19:13 +08:00
78fe5582e6 添加:系统信息查看 2019-04-08 21:13:42 +08:00
14430e79ef 添加:系统信息查看 2019-04-08 21:11:22 +08:00
5e3f9e9aee 支持不上传视频(待测试) 2019-04-08 18:33:29 +08:00
b55686d095 支持不上传视频(待测试) 2019-04-08 18:32:23 +08:00
c3a965f284 页面及逻辑修改 2019-04-08 11:32:05 +08:00
99d148666e Fix: Max Retry 2019-04-07 23:35:47 +08:00
be1a1df00b support change while running 2019-04-07 22:27:17 +08:00
ce819185eb support change while running 2019-04-07 22:26:21 +08:00
16c68e5ceb wc 2019-04-07 19:12:03 +08:00
5fa4ee929e 改善代码兼容性 2019-04-07 16:01:27 +08:00
00190468a8 支持api获取状态 2019-04-07 15:34:17 +08:00
b9b0994f4c 支持api获取状态 2019-04-07 15:30:57 +08:00
f8d4be5385 更新:Api升级了
修复:下播超过1小时才会投稿视频
2019-04-07 00:46:58 +08:00
90f6e8e1cb 修复:Test fix 2019-04-03 11:43:23 +08:00
3c872b0484 修复Api更改导致的未开播时报错问题 2019-03-31 08:06:29 +08:00
JerryYan ECS
5f949ccf34 Fix typo error 2019-03-29 08:06:30 +08:00
2750c9d25b 修复:无法更新房间信息的问题 2019-03-22 09:07:29 +08:00
6842961d42 修复小BUG导致无法上传 2019-03-22 07:59:19 +08:00
c89f84a44f 避免编码进程出错退出导致无法继续进行上传 2019-03-21 21:16:08 +08:00
5ee60d3dc7 改进:reload后删除文件 2019-03-21 15:41:08 +08:00
4c25ea3410 进程断开后,立即更新房间信息 2019-03-21 14:18:03 +08:00
6cbaa384dc .... 2019-03-21 14:16:32 +08:00
c9c962f646 .... 2019-03-21 13:05:24 +08:00
4d54e3dd6d Merge remote-tracking branch 'origin/master' 2019-03-21 13:01:23 +08:00
dd08229ff1 Fix 2019-03-21 13:00:57 +08:00
11161c4b71 Merge remote-tracking branch 'origin/master' 2019-03-21 07:47:43 +08:00
07d42c558a 添加方法,每次上传完成后,自动保存状态 2019-03-21 07:47:03 +08:00
bf8d3b48cb 对下载线程是否断开进行更频繁的检查,尽量减小更新房间信息更新的请求 2019-03-20 13:32:02 +08:00
80ac42075e Emeg Fix 2019-03-19 20:27:53 +08:00
9a3d3bd048 Encode Before upload 2019-03-19 13:40:33 +08:00
9a74b2b6e5 部分改进:下载文件大小为0时,删除文件并不上传该文件 2019-03-18 09:17:51 +08:00
9316b1e855 Fix : avoid exception when network is not stable 2019-03-17 22:12:18 +08:00
054c143e66 UPDATE README.md 2019-03-16 18:14:07 +08:00
041580e1ab 抽空写写注释 2019-03-16 18:12:17 +08:00
73d1dc6cf2 部分兼容输入中文 2019-03-16 17:55:17 +08:00
7692757091 Api: Fix showing "HEADERS incomplete" 2019-03-14 19:17:23 +08:00
426f4d6273 部分改进:录播工具提示 2019-03-14 17:59:44 +08:00
4c9d04f175 修复:下播后无法投稿的问题 2019-03-14 13:59:41 +08:00
JerryYan ECS
7bc0b85ae5 Add downlaod http flv stream 2019-03-14 13:55:26 +08:00
JerryYan ECS
179b808de6 Fix : while upload file is missing, uploader will pass the file 2019-03-12 20:51:37 +08:00
JerryYan ECS
19d48ed324 LiveDownloader : add -bsf param to avoid encode failure 2019-03-12 20:47:31 +08:00
JerryYan ECS
d1124a9370 trying yo encode to flv to avoid lagging 2019-03-11 13:10:31 +08:00
d9627a3ced Forget to start Encode Daemon TAT 2019-03-10 10:56:58 +08:00
1e039fb1c9 Try Encoding Before Upload 2019-03-10 10:54:31 +08:00
JerryYan ECS
bfbbe06cd2 liveDownloader updPlaylist when finished downloading a part 2019-03-03 00:50:53 +08:00
767b4728b5
Fix : self.Files not empty while next live start 2019-02-21 10:34:31 +08:00
dee41be85d
Emeg fix 2019-02-16 23:05:35 +00:00
1e1654a4b8
Fix duplicated user has been shown 2019-02-16 08:03:48 +00:00
b9b24fe7c6
Delete Encode function 2019-02-16 07:58:31 +00:00
216c9085c1 Improve: when server not return "MULTI_PART_SUCCESS" 2019-02-14 16:58:36 +08:00
0fd44117ec Fix: chunkSize will not upload when MultiPart PUT Error 2019-02-14 16:46:29 +08:00
ed718fa438 Trying Fix : Duplicated User had shown at Lottery finished 2019-02-11 13:18:56 +08:00
JerryYan ECS
8a61170fbf Emeg Fix : str is not callable 2019-02-08 10:48:03 +08:00
fa7a9bc102 录播工具:房间名放在设置里 2019-02-07 16:00:59 +08:00
35d97a77b1 Emeg Fix : import json TAT 2019-02-07 12:45:02 +08:00
48eccd68c5 Fix: 搜索时,出现非JSON回复导致程序退出 2019-02-06 21:07:57 +08:00
362f5c51d3 整理代码 2019-02-04 16:16:41 +08:00
0219d5d1aa Fix: Actions when upload finished will not work fixed 2019-02-02 19:21:26 +08:00
530522f51c 录播工具改进:下载完毕后用ffmpeg过一遍再上传,避免视频文件错误 2019-02-02 12:05:01 +08:00
60 changed files with 18890 additions and 980 deletions

5
.env Normal file
View File

@ -0,0 +1,5 @@
FLASK_ENV=development
FLASK_DEBUG=False
FLASK_RUN_PORT=5000
FLASK_RUN_HOST=0.0.0.0
FLASK_APP=WebMain.py

183
.gitignore vendored Normal file
View File

@ -0,0 +1,183 @@
# Created by .ignore support plugin (hsz.mobi)
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
### VirtualEnv template
# Virtualenv
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
.Python
[Bb]in
[Ii]nclude
[Ll]ib
[Ll]ib64
[Ll]ocal
[Ss]cripts
pyvenv.cfg
.venv
pip-selfcheck.json
*.mp4
*.flv
config*
.*

2
CHANGELOG Normal file
View File

@ -0,0 +1,2 @@
# 接口版本9.4.2(94214)
弹幕接口改为`/webcast/im/fetch/`发现会先连接websocket然而websocket又是魔改protobuf实在是弄不懂

31
Chat.py
View File

@ -1,31 +0,0 @@
from User import User
from Lottery import Lottery
class Chat:
content: str =""
user: User=None
filterString:list = ["",]
isFiltered = False
def __init__(self, json=None, lottery:Lottery = None):
if json:
self.parse(json)
if lottery:
self.filterString.append(lottery.content)
def parse(self, json):
self.user = User(json)
if "extra" in json:
if "content" in json["extra"]:
self.content = json["extra"]['content']
if self.content in self.filterString:
self.isFiltered = True
def __str__(self):
return "{} : {}".format(self.user,self.content)
def __unicode__(self):
return self.__str__()

478
Common.py Normal file
View File

@ -0,0 +1,478 @@
import os
import queue
from datetime import datetime, timedelta
import psutil
from api import XiGuaLiveApi
import json
import threading
from bilibili import Bilibili, VideoPart
# 默认设置
config = {
# 录像的主播ID
"l_u": "97621754276",
# 视频位置
"path": ".",
# 标题及预留时间位置
"t_t": "【永恒de草薙直播录播】直播于 {}",
# 标签
"tag": ["永恒de草薙", "三国", "三国战记", "直播录像", "录播", "怀旧", "街机"],
# 描述
"des": "西瓜直播 https://live.ixigua.com/userlive/97621754276 \n自动投递\n原主播永恒de草薙\n直播时间晚上6点多到凌晨4点左右",
# 来源, 空则为自制
"src": "",
# Log条数
"l_c": 5,
# 错误Log条数
"elc": 10,
# 每一chunk大小
"c_s": 16 * 1024,
# 每一块视频大小
"p_s": 2141000000,
# 忽略的大小
"i_s": 2048000,
"max": 75,
"dow": "echo 'clean'",
# 仅下载
"dlO": True,
# 下播延迟投稿
"dly": 30,
# 短的时间的格式
"sdf": "%Y%m%d",
"enc": "ffmpeg -i {f} -c:v copy -c:a copy -f mp4 {t} -y"
}
doCleanTime = datetime.fromtimestamp(0)
loginTime = datetime.fromtimestamp(0)
_clean_flag = None
delay = datetime.fromtimestamp(0)
b = Bilibili()
network = [{
"currentTime": datetime.now(),
"out": {
"currentByte": psutil.net_io_counters().bytes_sent,
},
"in": {
"currentByte": psutil.net_io_counters().bytes_recv,
}
}, {
"currentTime": datetime.now(),
"out": {
"currentByte": psutil.net_io_counters().bytes_sent,
},
"in": {
"currentByte": psutil.net_io_counters().bytes_recv,
}
}]
def reloadConfig():
global config
if os.path.exists('config.json'):
_config_fp = open("config.json", "r", encoding="utf8")
_config = json.load(_config_fp)
config.update(_config)
_config_fp.close()
def resetDelay():
global delay
delay = datetime.now() + timedelta(minutes=int(config['dly']))
def doDelay():
global delay
if -60 < getTimeDelta(datetime.now(), delay) < 60:
delay = datetime.fromtimestamp(0)
return True
return False
def updateNetwork():
global network
network.append({
"currentTime": datetime.now(),
"out": {
"currentByte": psutil.net_io_counters().bytes_sent,
},
"in": {
"currentByte": psutil.net_io_counters().bytes_recv,
}
})
network = network[-3:]
def getTimeDelta(a, b):
return (a - b).total_seconds()
def _doClean(_force=False):
global doCleanTime, _clean_flag
_disk = psutil.disk_usage(".")
if _disk.percent > config["max"] or _force:
_clean_flag = True
doCleanTime = datetime.now()
appendOperation("执行配置的清理命令")
os.system(config["dow"])
appendOperation("执行配置的清理命令完毕")
doCleanTime = datetime.now()
_clean_flag = False
def doClean(_force=False):
if _clean_flag:
return
p = threading.Thread(target=_doClean, args=(_force,))
p.setDaemon(True)
p.start()
def getCurrentStatus():
_disk = psutil.disk_usage(".")
_mem = psutil.virtual_memory()
_net = psutil.net_io_counters()
_delta = getTimeDelta(network[-1]["currentTime"], network[-2]["currentTime"])
if 60 > _delta > 1:
_inSpeed = (network[-1]["in"]["currentByte"] - network[-2]["in"]["currentByte"]) / _delta
_outSpeed = (network[-1]["out"]["currentByte"] - network[-2]["out"]["currentByte"]) / _delta
else:
_outSpeed = (network[-1]["in"]["currentByte"] - network[-2]["in"]["currentByte"])
_inSpeed = (network[-1]["out"]["currentByte"] - network[-2]["out"]["currentByte"])
updateNetwork()
return {
"memTotal": parseSize(_mem.total),
"memUsed": parseSize(_mem.used),
"memUsage": _mem.percent,
"diskTotal": parseSize(_disk.total),
"diskUsed": parseSize(_disk.used),
"diskUsage": _disk.percent,
"cpu": psutil.cpu_percent(),
"outSpeed": parseSize(_outSpeed),
"inSpeed": parseSize(_inSpeed),
"doCleanTime": datetime.strftime(doCleanTime, dt_format),
}
dt_format = "%Y/%m/%d %H:%M:%S"
reloadConfig()
broadcaster = ""
streamUrl = ""
forceNotDownload = False
forceNotBroadcasting = False
forceNotUpload = False
forceNotEncode = False
if config["dlO"] is True:
forceNotUpload = True
forceNotEncode = True
forceStartEncodeThread = False
forceStartUploadThread = False
uploadQueue = queue.Queue()
encodeQueue = queue.Queue()
uploadStatus = []
downloadStatus = []
encodeStatus = []
errors = []
operations = []
def appendOperation(obj):
global operations
if isinstance(obj, dict):
if "datetime" not in obj:
obj["datetime"] = datetime.strftime(datetime.now(), dt_format)
operations.append(obj)
else:
operations.append({
"datetime": datetime.strftime(datetime.now(), dt_format),
"message": str(obj)
})
operations = operations[-config["elc"]:]
def parseSize(size):
K = size / 1024.0
if K > 1000:
M = K / 1024.0
if M > 1000:
return "{:.2f}GB".format(M / 1024.0)
else:
return "{:.2f}MB".format(M)
else:
return "{:.2f}KB".format(K)
def appendUploadStatus(obj):
global uploadStatus
if isinstance(obj, dict):
if "datetime" not in obj:
obj["datetime"] = datetime.strftime(datetime.now(), dt_format)
uploadStatus.append(obj)
else:
uploadStatus.append({
"datetime": datetime.strftime(datetime.now(), dt_format),
"message": str(obj)
})
uploadStatus = uploadStatus[-config["l_c"]:]
def modifyLastUploadStatus(obj):
global uploadStatus
if isinstance(obj, dict):
if "datetime" not in obj:
obj["datetime"] = datetime.strftime(datetime.now(), dt_format)
uploadStatus[-1] = obj
else:
uploadStatus[-1]["message"] = str(obj)
uploadStatus[-1]["datetime"] = datetime.strftime(datetime.now(), dt_format)
def appendEncodeStatus(obj):
global encodeStatus
if isinstance(obj, dict):
if "datetime" not in obj:
obj["datetime"] = datetime.strftime(datetime.now(), dt_format)
encodeStatus.append(obj)
else:
encodeStatus.append({
"datetime": datetime.strftime(datetime.now(), dt_format),
"message": str(obj)
})
encodeStatus = encodeStatus[-config["l_c"]:]
def modifyLastEncodeStatus(obj):
global encodeStatus
if isinstance(obj, dict):
if "datetime" not in obj:
obj["datetime"] = datetime.strftime(datetime.now(), dt_format)
encodeStatus[-1] = obj
else:
encodeStatus[-1]["message"] = str(obj)
encodeStatus[-1]["datetime"] = datetime.strftime(datetime.now(), dt_format)
def appendDownloadStatus(obj):
global downloadStatus
if isinstance(obj, dict):
if "datetime" not in obj:
obj["datetime"] = datetime.strftime(datetime.now(), dt_format)
downloadStatus.append(obj)
else:
downloadStatus.append({
"datetime": datetime.strftime(datetime.now(), dt_format),
"message": str(obj)
})
downloadStatus = downloadStatus[-config["l_c"]:]
def modifyLastDownloadStatus(obj):
global downloadStatus
if isinstance(obj, dict):
if "datetime" not in obj:
obj["datetime"] = datetime.strftime(datetime.now(), dt_format)
downloadStatus[-1] = obj
else:
downloadStatus[-1]["message"] = str(obj)
downloadStatus[-1]["datetime"] = datetime.strftime(datetime.now(), dt_format)
def appendError(obj):
global errors
if isinstance(obj, dict):
if "datetime" not in obj:
obj["datetime"] = datetime.strftime(datetime.now(), dt_format)
errors.append(obj)
else:
errors.append({
"datetime": datetime.strftime(datetime.now(), dt_format),
"message": str(obj)
})
errors = errors[-config["elc"]:]
def loginBilibili(force=False):
if config["dlO"] is False or forceNotUpload is False:
global loginTime
global b
if getTimeDelta(datetime.now(), loginTime) < 86400 * 10 and not force:
return False
try:
b.login()
loginTime = datetime.now()
return True
except Exception as e:
appendError(e)
appendOperation("登录失败")
return False
else:
appendOperation("设置了不上传,所以不会登陆")
class downloader(XiGuaLiveApi):
__playlist = None
__danmakuFile = None
__danmakuBiasTime = None
def getDanmaku(self):
super(downloader, self).getDanmaku()
if self.__danmakuFile is not None and self.__danmakuFile.writable():
self.__danmakuFile.flush()
def onPresentEnd(self, gift):
if self.__danmakuFile is not None and self.__danmakuFile.writable():
now = datetime.now()
if self.__danmakuBiasTime is None:
return
ts = (now - self.__danmakuBiasTime).total_seconds()
_c = """<gift ts="{:.2f}" user="{}" giftname="{}" giftcount="{}"></gift>\r\n""".format(ts, gift.user.name, gift.name, gift.count)
self.__danmakuFile.write(_c.encode("UTF-8"))
def onChat(self, chat):
if self.__danmakuFile is not None and self.__danmakuFile.writable():
now = datetime.now()
if self.__danmakuBiasTime is None:
return
ts = (now - self.__danmakuBiasTime).total_seconds()
_c = """<d p="{:.2f},1,24,16777215,{:.0f},0,{},0" user="{}">{}</d>\r\n""".format(ts, now.timestamp()*1000, chat.user.ID, chat.user.name, chat.content)
self.__danmakuFile.write(_c.encode("UTF-8"))
@property
def playlist(self):
return self.__playlist
@playlist.setter
def playlist(self, value):
global streamUrl
self.__playlist = value
streamUrl = value
def _checkUsernameIsMatched(self, compare=None):
return True
def updRoomInfo(self, force=False):
global broadcaster
_prev_status = self.isLive
doClean()
if not force and self.isLive:
return _prev_status
_result = super(downloader, self).updRoomInfo(force)
if _prev_status != self.isLive and not self.isLive:
# 及时保存
self.__danmakuFile.close()
self.__danmakuFile = None
self.__danmakuBiasTime = None
resetDelay()
broadcaster = self.broadcaster
if _result:
if self.isLive:
self.updPlayList()
else:
self.playlist = False
return _result
def updPlayList(self):
if self.isLive and "stream_url" in self._rawRoomInfo:
if 'rtmp_pull_url' in self._rawRoomInfo["stream_url"]:
self.playlist = self._rawRoomInfo["stream_url"]['rtmp_pull_url']
elif 'flv_pull_url' in self._rawRoomInfo["stream_url"]:
_playlist = self._rawRoomInfo["stream_url"]["flv_pull_url"]
if type(_playlist) is dict:
for _ in _playlist.values():
self.playlist = _
break
self.playlist = self.playlist.replace("_hd5", "").replace("_sd5", "").replace("_ld5", "").replace("_md", "")
else:
self.playlist = None
def initSave(self, f):
if self.__danmakuFile is not None and not self.__danmakuFile.closed:
self.__danmakuFile.close()
self.__danmakuBiasTime = datetime.now()
self.__danmakuFile = open(f, "wb")
api = downloader(config["l_u"])
def doUpdatePlaylist(_force=False):
p = threading.Thread(target=api.updRoomInfo, args=(_force,))
p.setDaemon(True)
p.start()
def refreshDownloader():
global api
api = downloader(config["l_u"])
def uploadVideo(name):
if not os.path.exists(name):
appendError("Upload File Not Exist {}".format(name))
return
loginBilibili()
doClean()
if forceNotUpload is False:
b.preUpload(VideoPart(path=name, title=os.path.basename(name)))
else:
appendUploadStatus("设置了不上传,所以[{}]不会上传了".format(name))
if not forceNotEncode:
os.remove(name)
def publishVideo(date):
if forceNotUpload is False:
b.finishUpload(config["t_t"].format(date), 17, config["tag"], config["des"],
source=config["src"], no_reprint=0)
b.clear()
else:
appendUploadStatus("设置了不上传,所以[{}]的录播不会投了".format(date))
def encodeVideo(name):
if forceNotEncode:
appendEncodeStatus("设置了不编码,所以[{}]不会编码".format(name))
return False
if not os.path.exists(name):
appendEncodeStatus("文件[{}]不存在".format(name))
return False
if os.path.getsize(name) < 8 * 1024 * 1024:
appendEncodeStatus("Encoded File >{}< is too small, will ignore it".format(name))
return False
appendEncodeStatus("Encoding >{}< Start".format(name))
_new_name = os.path.splitext(name)[0] + ".mp4"
_code = os.system(config["enc"].format(f=name, t=_new_name))
if _code != 0:
appendError("Encode {} with Non-Zero Return.".format(name))
return False
modifyLastEncodeStatus("Encode >{}< Finished".format(name))
uploadQueue.put(_new_name)
def collectInfomation():
return {
"download": downloadStatus,
"encode": encodeStatus,
"encodeQueueSize": encodeQueue.qsize(),
"upload": uploadStatus,
"uploadQueueSize": uploadQueue.qsize(),
"error": errors,
"operation": operations,
"broadcast": {
"broadcaster": broadcaster.__str__(),
"isBroadcasting": api.isLive,
"streamUrl": streamUrl,
"updateTime": api.updateAt.strftime(dt_format),
"delayTime": delay.strftime(dt_format)
},
"config": {
"forceNotBroadcasting": forceNotBroadcasting,
"forceNotDownload": forceNotDownload,
"forceNotUpload": forceNotUpload,
"forceNotEncode": forceNotEncode,
"downloadOnly": config['dlO'],
},
}

BIN
Demo/242_.txt Normal file

Binary file not shown.

15
Demo/Xigua.proto Executable file
View File

@ -0,0 +1,15 @@
syntax = "proto2";
message XiguaLive {
message Data {
// WebcastChatMessage
// WebcastGiftMessage
required string method = 1;
required bytes raw = 2;
}
repeated Data data = 1;
required string cursor = 2;
optional int32 fetch_interval = 3;
optional int32 now = 4;
required string internal_ext = 5;
}

10
Demo/XiguaGift.proto Normal file
View File

@ -0,0 +1,10 @@
syntax = "proto2";
//
message Gift {
required string id = 1;
required string name = 2;
}
message GiftPack {
required int32 id = 1;
required Gift gift = 2;
}

89
Demo/XiguaMessage.proto Normal file
View File

@ -0,0 +1,89 @@
syntax = "proto2";
import "XiguaUser.proto";
import "XiguaGift.proto";
message Message {
required CommonInfo commonInfo = 1;
}
message FansClubMessage {
required CommonInfo commonInfo = 1;
// 12
required int32 type = 2;
//
required string content = 3;
required User user = 4;
}
message FansClubStatsMessage {
required CommonInfo commonInfo = 1;
required string title = 2;
required int32 count = 3;
}
message UserSeqMessage {
required CommonInfo commonInfo = 1;
required string popularityText = 4;
required int32 popularity = 6;
}
message DailyRankMessage {
required CommonInfo commonInfo = 1;
required int32 ranking = 10;
}
message ChatMessage {
required CommonInfo commonInfo = 1;
required User user = 2;
required string content = 3;
}
message MemberMessage {
required CommonInfo commonInfo = 1;
required User user = 2;
required string popularityText = 14;
}
message GiftMessage {
required CommonInfo commonInfo = 1;
required int32 giftId = 2;
// GroupId之类的东西
// required int32 UNKNOWN_INT = 3;
required int32 content4 = 4;
required int32 repeated = 5;
required int32 combo = 6;
optional User user = 7;
//
optional bool isFinished = 9 [ default = false ];
}
message SocialMessage {
required CommonInfo commonInfo = 1;
required User user = 2;
required int32 int4 = 4;
required int32 fansCount = 6;
}
//
message Style {
optional string color = 1;
optional int32 fontWeight = 4;
}
//
message Params {
// 1
// 11
// 12
required int32 type = 1;
optional Style style = 2;
optional string string = 11;
optional UserPack users = 21;
optional GiftPack gifts = 22;
}
//
message DisplayText {
//
required string method = 1;
required string format = 2;
optional Style bgStyle = 3;
required Params params = 4;
}
//
message CommonInfo {
required string method = 1;
required int32 msg_id = 2;
required int32 room_id = 3;
required int32 create_time = 4;
optional int32 someEnum = 6;
optional DisplayText displayText = 8;
}

81
Demo/XiguaUser.proto Normal file
View File

@ -0,0 +1,81 @@
syntax = "proto2";
message UserPack {
required User user = 1;
}
//
message Badge {
message FanClubText {
required string text = 1;
optional string color = 2;
required int32 level = 3;
}
repeated string url = 1;
// optional string localUrl = 2;
optional int32 height = 3;
optional int32 width = 4;
// 3
// 6
// 7
optional int32 type = 6;
optional string clickTo = 7;
optional FanClubText fanClubText = 8;
}
message FansClubPack {
message FansClub {
required string title = 1 [default = ''];
required int32 level = 2 [default = 0];
optional int32 someEnum = 3;
}
required FansClub fansClub = 1;
}
//
message User {
//
message Avatar {
required string url = 1;
optional string id = 2;
}
//
message Follow {
optional int32 following = 1 [default = 0];
optional int32 follower = 2 [default = 0];
}
//
message PayGrade {
required int32 current = 1;
required int32 level = 6;
optional int32 currentLevelNeed = 10;
optional int32 nextLevelNeed = 11;
optional string content = 13;
required Badge badge = 19;
optional int32 toNextLevelNeed = 21;
}
//
message HonorLevel {
required Badge badge = 19;
}
//
message Noble {
message NobleBoarder {
repeated string urlList = 1;
required string uri = 2;
optional int32 height = 3;
optional int32 width = 4;
}
required string content = 4;
optional NobleBoarder boarder = 8;
}
required int64 id = 1;
required string nickname = 3;
required int32 gender = 4;
//
required Avatar avatarThumb = 9;
optional Avatar avatarMedium = 10;
optional Avatar avatarLarge = 11;
repeated Badge badge = 21;
optional Follow follow = 22;
required PayGrade payGrade = 23;
required FansClubPack fansClub = 24;
required int32 totalPaid = 34;
}

BIN
Demo/a.txt Normal file

Binary file not shown.

BIN
Demo/fst.txt Normal file

Binary file not shown.

997
Demo/guanzhu.txt Normal file
View File

@ -0,0 +1,997 @@
1 {
1: "WebcastGiftMessage"
2 {
1 {
1: "WebcastGiftMessage"
2: 6787717978657360643
3: 6787691314156276488
4: 1580388803763
6: 1
8 {
1: "webcast_xigua_gift_message"
2: "{0:user} \351\200\201\347\273\231\344\270\273\346\222\255{2:string}\344\270\252{1:gift}"
3 {
1: "#ffff9d5c"
4: 400
}
4 {
1: 11
2 {
1: "#ffffd600"
4: 400
}
21 {
1 {
1: 105855829073
3: "\345\260\217\350\234\234\346\237\240\346\252\254\350\214\266"
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
10 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
11 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
15: 1
21 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
6: 7
8 {
1: "\346\260\270\346\201\222"
2: "#FFFFFF"
3: 14
}
}
22 {
1: 2
2: 1
}
23 {
1: 62
6: 5
10: 51
11: 99
13: "\350\267\235\347\246\2736\347\272\247\350\277\230\345\267\25638\351\222\273\347\237\263"
19 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21: 38
}
24 {
1 {
1: "\346\260\270\346\201\222"
2: 14
3: 1
4 {
1 {
1: 2
2 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
3: 48
4: 150
}
}
2: "\346\260\270\346\201\222"
}
}
}
32: ""
34: 62
37: 1
38: "0"
44: ""
46: "MS4wLjABAAAAd4R7mC-c8FCTjCqTIhJ0CoydF_FMweyatdS66xud0hY"
48: ""
1028: "105855829073"
}
2: 1
}
}
4 {
1: 12
2 {
1: "#ffff9d5c"
4: 400
}
22 {
1: 10001
2 {
1: "live_gift_10001"
2: "\350\245\277\347\223\234"
}
}
}
4 {
1: 1
2 {
1: "#ffff9d5c"
4: 400
}
11: "18"
}
}
}
2: 10001
3: 4997044
4: 1
5: 18
6: 18
7 {
1: 105855829073
3: "\345\260\217\350\234\234\346\237\240\346\252\254\350\214\266"
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
10 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
11 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
15: 1
21 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
6: 7
8 {
1: "\346\260\270\346\201\222"
2: "#FFFFFF"
3: 14
}
}
22 {
1: 2
2: 1
}
23 {
1: 62
6: 5
10: 51
11: 99
13: "\350\267\235\347\246\2736\347\272\247\350\277\230\345\267\25638\351\222\273\347\237\263"
19 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21: 38
}
24 {
1 {
1: "\346\260\270\346\201\222"
2: 14
3: 1
4 {
1 {
1: 2
2 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
3: 48
4: 150
}
}
2: "\346\260\270\346\201\222"
}
}
}
32: ""
34: 62
37: 1
38: "0"
44: ""
46: "MS4wLjABAAAAd4R7mC-c8FCTjCqTIhJ0CoydF_FMweyatdS66xud0hY"
48: ""
1028: "105855829073"
}
11: 1580388797
12: 7453182
}
}
1 {
1: "WebcastSocialMessage"
2 {
1 {
1: "WebcastSocialMessage"
2: 6787718225754295054
3: 6787691314156276488
4: 1580388803802
6: 1
}
2 {
1: 111036833136
3: "\347\224\250\346\210\2679627521617519"
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3796/2975850990~120x256.image"
}
22 {
1: 1
2: 19
}
23 {
19: ""
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAApZHNJdD-IbL7CES631w87jSXrSyXZfqETb-HYnYx6Ug"
54: 3
}
4: 1
6: 169079
}
}
1 {
1: "WebcastGiftMessage"
2 {
1 {
1: "WebcastGiftMessage"
2: 6787718023417531148
3: 6787691314156276488
4: 1580388804048
6: 1
8 {
1: "webcast_xigua_gift_message"
2: "{0:user} \351\200\201\347\273\231\344\270\273\346\222\255{2:string}\344\270\252{1:gift}"
3 {
1: "#ffff9d5c"
4: 400
}
4 {
1: 11
2 {
1: "#ffffd600"
4: 400
}
21 {
1 {
1: 105855829073
3: "\345\260\217\350\234\234\346\237\240\346\252\254\350\214\266"
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
10 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
11 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
15: 1
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
6: 7
8 {
1: "\346\260\270\346\201\222"
2: "#FFFFFF"
3: 14
}
}
22 {
1: 2
2: 1
}
23 {
1: 62
6: 5
10: 51
11: 99
13: "\350\267\235\347\246\2736\347\272\247\350\277\230\345\267\25638\351\222\273\347\237\263"
19 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21: 38
}
24 {
1 {
1: "\346\260\270\346\201\222"
2: 14
3: 1
4 {
1 {
1: 2
2 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
3: 48
4: 150
}
}
2: "\346\260\270\346\201\222"
}
}
}
32: ""
34: 62
37: 1
38: "0"
44: ""
46: "MS4wLjABAAAAd4R7mC-c8FCTjCqTIhJ0CoydF_FMweyatdS66xud0hY"
48: ""
1028: "105855829073"
}
2: 1
}
}
4 {
1: 12
2 {
1: "#ffff9d5c"
4: 400
}
22 {
1: 10001
2 {
1: "live_gift_10001"
2: "\350\245\277\347\223\234"
}
}
}
4 {
1: 1
2 {
1: "#ffff9d5c"
4: 400
}
11: "19"
}
}
}
2: 10001
3: 4997044
4: 1
5: 19
6: 19
7 {
1: 105855829073
3: "\345\260\217\350\234\234\346\237\240\346\252\254\350\214\266"
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
10 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
11 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
15: 1
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
6: 7
8 {
1: "\346\260\270\346\201\222"
2: "#FFFFFF"
3: 14
}
}
22 {
1: 2
2: 1
}
23 {
1: 62
6: 5
10: 51
11: 99
13: "\350\267\235\347\246\2736\347\272\247\350\277\230\345\267\25638\351\222\273\347\237\263"
19 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21: 38
}
24 {
1 {
1: "\346\260\270\346\201\222"
2: 14
3: 1
4 {
1 {
1: 2
2 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
3: 48
4: 150
}
}
2: "\346\260\270\346\201\222"
}
}
}
32: ""
34: 62
37: 1
38: "0"
44: ""
46: "MS4wLjABAAAAd4R7mC-c8FCTjCqTIhJ0CoydF_FMweyatdS66xud0hY"
48: ""
1028: "105855829073"
}
11: 1580388797
12: 7453182
}
}
1 {
1: "WebcastRoomUserSeqMessage"
2 {
1 {
1: "WebcastRoomUserSeqMessage"
2: 6787718227533761294
3: 6787691314156276488
4: 1580388804226
}
2 {
1: 9999
2 {
1: 4719119436
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/6368/3857576856~120x256.image"
}
23: ""
54: 3
}
3: 1
}
2 {
1: 9998
2 {
1: 60374191432
2: 259345
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/da99000fd41edfb7daa6~120x256.image"
}
23: ""
54: 3
}
3: 2
}
2 {
1: 1699
2 {
1: 3544417251634206
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/830d7e15f45946aa9b757a500cc6dcbe~120x256.image"
}
23: ""
54: 3
}
3: 3
}
2 {
1: 1099
2 {
1: 4261353838881501
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/c24df9dffd6d45929c227c5da22fe406~120x256.image"
}
23: ""
54: 3
}
3: 4
}
2 {
1: 520
2 {
1: 2933125236921479
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/2e1c9d64f34a4a3e8a326fe5394659fd~120x256.image"
}
23: ""
54: 3
}
3: 5
}
2 {
1: 300
2 {
1: 3927095572170669
9 {
1: "http://p1-xg.bytecdn.cn/thumb/daaa001914e0039994ae"
2: "daaa001914e0039994ae"
}
23: ""
54: 3
}
3: 6
}
2 {
1: 120
2 {
1: 153552343543981
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/3795/3033762272~120x256.image"
}
23: ""
54: 3
}
3: 7
}
2 {
1: 99
2 {
1: 1732418933370259
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/5941f17833524bfa9316a648c39c990f~120x256.image"
}
23: ""
54: 3
}
3: 8
}
2 {
1: 99
2 {
1: 104372509299
9 {
1: "http://p1-xg.bytecdn.cn/thumb/da920004cd041ec12061"
2: "da920004cd041ec12061"
}
23: ""
54: 3
}
3: 9
}
2 {
1: 60
2 {
1: 60518722952
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/0f9162a614bd474f9fbda57614a0c9f1~120x256.image"
}
23: ""
54: 3
}
3: 10
}
2 {
1: 30
2 {
1: 1261881879167767
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3795/3044413937~120x256.image"
}
23: ""
54: 3
}
3: 11
}
2 {
1: 22
2 {
1: 1173933315333736
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/a181c0707ff540aba16f43af049a3791~120x256.image"
}
23: ""
54: 3
}
3: 12
}
2 {
1: 20
2 {
1: 3949047076102647
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/187afa353816402cb827e9fae386ca2a~120x256.image"
}
23: ""
54: 3
}
3: 13
}
2 {
1: 2
2 {
1: 65771610619
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3793/3131589739~120x256.image"
}
23: ""
54: 3
}
3: 14
}
2 {
2 {
1: 99827340042
9 {
1: "http://p1-xg.bytecdn.cn/thumb/da74000192436fc5db6e"
2: "da74000192436fc5db6e"
}
23: ""
54: 3
}
3: 15
}
2 {
2 {
1: 99482502045
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/3793/3114521287~120x256.image"
}
23: ""
54: 3
}
3: 16
}
2 {
2 {
1: 98103952579
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3793/3131589739~120x256.image"
}
23: ""
54: 3
}
3: 17
}
2 {
2 {
1: 9746464842
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/6ad34237256e4471b16810eb098224c0~120x256.image"
}
23: ""
54: 3
}
3: 18
}
2 {
2 {
1: 97221408269
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3793/3131589739~120x256.image"
}
23: ""
54: 3
}
3: 19
}
2 {
2 {
1: 971618215795604
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3797/2889309425~120x256.image"
}
23: ""
54: 3
}
3: 20
}
3: 461
4: "15\344\270\207\344\272\272\346\260\224"
6: 158310
}
}
1 {
1: "WebcastGiftMessage"
2 {
1 {
1: "WebcastGiftMessage"
2: 6787717971278351115
3: 6787691314156276488
4: 1580388804414
6: 1
8 {
1: "webcast_xigua_gift_message"
2: "{0:user} \351\200\201\347\273\231\344\270\273\346\222\255{2:string}\344\270\252{1:gift}"
3 {
1: "#ffff9d5c"
4: 400
}
4 {
1: 11
2 {
1: "#ffffd600"
4: 400
}
21 {
1 {
1: 105855829073
3: "\345\260\217\350\234\234\346\237\240\346\252\254\350\214\266"
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
10 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
11 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
15: 1
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
6: 7
8 {
1: "\346\260\270\346\201\222"
2: "#FFFFFF"
3: 14
}
}
22 {
1: 2
2: 1
}
23 {
1: 62
6: 5
10: 51
11: 99
13: "\350\267\235\347\246\2736\347\272\247\350\277\230\345\267\25638\351\222\273\347\237\263"
19 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21: 38
}
24 {
1 {
1: "\346\260\270\346\201\222"
2: 14
3: 1
4 {
1 {
1: 2
2 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
3: 48
4: 150
}
}
2: "\346\260\270\346\201\222"
}
}
}
32: ""
34: 62
37: 1
38: "0"
44: ""
46: "MS4wLjABAAAAd4R7mC-c8FCTjCqTIhJ0CoydF_FMweyatdS66xud0hY"
48: ""
1028: "105855829073"
}
2: 1
}
}
4 {
1: 12
2 {
1: "#ffff9d5c"
4: 400
}
22 {
1: 10001
2 {
1: "live_gift_10001"
2: "\350\245\277\347\223\234"
}
}
}
4 {
1: 1
2 {
1: "#ffff9d5c"
4: 400
}
11: "20"
}
}
}
2: 10001
3: 4997044
4: 1
5: 20
6: 20
7 {
1: 105855829073
3: "\345\260\217\350\234\234\346\237\240\346\252\254\350\214\266"
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
10 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
11 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
15: 1
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
6: 7
8 {
1: "\346\260\270\346\201\222"
2: "#FFFFFF"
3: 14
}
}
22 {
1: 2
2: 1
}
23 {
1: 62
6: 5
10: 51
11: 99
13: "\350\267\235\347\246\2736\347\272\247\350\277\230\345\267\25638\351\222\273\347\237\263"
19 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21: 38
}
24 {
1 {
1: "\346\260\270\346\201\222"
2: 14
3: 1
4 {
1 {
1: 2
2 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
3: 48
4: 150
}
}
2: "\346\260\270\346\201\222"
}
}
}
32: ""
34: 62
37: 1
38: "0"
44: ""
46: "MS4wLjABAAAAd4R7mC-c8FCTjCqTIhJ0CoydF_FMweyatdS66xud0hY"
48: ""
1028: "105855829073"
}
11: 1580388797
12: 7453184
}
}
2: "6787717971278351115_1580388804554_6787718002764073739_1"
3: 1000
4: 1580388804554
5: "fetch_time:1580388804554|start_time:1580388804048|ack_ids:6787718023417531148_1b2|fetch_id:6787718004823608078|flag:1|seq:141"

165
Demo/jingyan.txt Normal file
View File

@ -0,0 +1,165 @@
1 {
1: "WebcastMemberMessage"
2 {
1 {
1: "WebcastMemberMessage"
2: 6787727734057011981
3: 6787691314156276488
6: 1
8 {
1: "member_silence_toast_3"
2: "{0:user} \350\242\253\347\256\241\347\220\206\345\221\230 {1:user} \347\246\201\350\250\200\344\272\206"
3 {
1: "#de000000"
4: 400
}
4 {
1: 11
2 {
1: "#61000000"
4: 400
}
21 {
1 {
1: 53536270159
3: "\350\243\244\350\243\206\351\207\214\347\232\204\345\244\247\345\256\235\345\211\221"
38: "0"
46: "MS4wLjABAAAAtH9p-LupXO1oQVJtlefmpryPoXqWzKs3_Nad9BlAREA"
}
}
}
4 {
1: 11
2 {
1: "#61000000"
4: 400
}
21 {
1 {
1: 2721997823950523
3: "\350\257\267\345\217\253\346\210\221\347\226\257\345\255\220\345\205\255"
38: "0"
46: "MS4wLjABAAAA1KKMtPQlRg_wecgX0G2Wl-ZIcWe-Yos95-IBwF1AzhSYzL5-zXCa4lciHj2HZho5"
}
}
}
}
}
2 {
1: 53536270159
3: "\350\243\244\350\243\206\351\207\214\347\232\204\345\244\247\345\256\235\345\211\221"
4: 1
9 {
1: "http://p3-xg.bytecdn.cn/thumb/1bf40000bd6dc5335b2d"
2: "1bf40000bd6dc5335b2d"
}
21 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_9.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_7.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_7.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_7.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_7.png"
6: 7
8 {
1: "\346\260\270\346\201\222"
2: "#FFFFFF"
3: 7
}
}
22 {
1: 1
2: 17
}
23 {
6: 9
19 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_9.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
}
24 {
1 {
1: "\346\260\270\346\201\222"
2: 7
3: 1
4 {
1 {
1: 2
2 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_7.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_7.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_7.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_7.png"
3: 48
4: 150
}
}
2: "\346\260\270\346\201\222"
}
}
}
32 {
1: 1
}
38: "0"
46: "MS4wLjABAAAAtH9p-LupXO1oQVJtlefmpryPoXqWzKs3_Nad9BlAREA"
50 {
1 {
3: 1008
4: 1125
}
3 {
3: 105
4: 111
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fnoble%2Fnoble_privilege_intro%2Findex.html%3Fforbid_right_back%3D1&type=fullscreen&hide_nav_bar=1&status_bar_color=white&status_bar_bg_color=%2300000000&noble_intercept=1&__live_platform__=webcast"
}
4: "\346\231\256\351\200\232\347\224\250\346\210\267"
6 {
3: 366
4: 615
}
7 {
3: 60
4: 108
}
8 {
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
2: "webcast/noble_boarder.png"
3: 64
4: 64
}
}
54: 3
}
3: 555
4 {
1: 2721997823950523
3: "\350\257\267\345\217\253\346\210\221\347\226\257\345\255\220\345\205\255"
38: "0"
46: "MS4wLjABAAAA1KKMtPQlRg_wecgX0G2Wl-ZIcWe-Yos95-IBwF1AzhSYzL5-zXCa4lciHj2HZho5"
}
10: 9
14: "16\344\270\207\344\272\272\346\260\224"
}
}
2: "6787727734057011981_1580391018357_6787727537927867150_1"
3: 1000
4: 1580391018357
5: "fetch_time:1580391018357|start_time:1580391017508|ack_ids:6787727734057011981_1296|fetch_id:6787727723432626957|flag:1|seq:126"

605
Demo/result5.txt Normal file
View File

@ -0,0 +1,605 @@
1 {
1: "WebcastChatMessage"
2 {
1 {
1: "WebcastChatMessage"
2: 6776883976293452551
3: 6776859660747344653
4: 1577866267927
6: 1
8 {
1: "webcast_chat_display_text"
2: "{0:user}{1:string}"
3 {
1: "#ff36c0cf"
4: 400
}
4 {
1: 11
2 {
1: "#60000000"
4: 400
}
21 {
1 {
1: 51510235218
3: "\351\222\242\346\236\252\345\205\204\345\274\237\350\266\205\345\223\245"
4: 1
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/2e8b032f45854441bd5e539ea892e00f~120x256.image"
}
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
2: "webcast/xigua_admin_badge_v2.png"
3: 16
4: 28
6: 3
}
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_16.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&__live_platform__=webcast&type=popup&gravity=bottom&height=400&radius=8"
}
21 {
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_15.png"
6: 7
8 {
1: "\351\222\242\346\236\252\346\211\213"
2: "#FFFFFF"
3: 15
}
}
22 {
1: 45
2: 17
}
23 {
6: 16
19 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_16.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&__live_platform__=webcast&type=popup&gravity=bottom&height=400&radius=8"
}
}
24 {
1 {
1: "\351\222\242\346\236\252\346\211\213"
2: 15
3: 1
4 {
1 {
1: 2
2 {
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_15.png"
3: 48
4: 150
}
}
2: "\351\222\242\346\236\252\346\211\213"
}
}
}
32 {
2: 1
}
38: "0"
46: "MS4wLjABAAAALx1qtwLJiLVbuWXt7ZYTxHxVFvZz2PITy5YfQidfGp4"
50 {
1 {
3: 1008
4: 1125
}
3 {
3: 105
4: 111
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fnoble%2Fnoble_privilege_intro%2Findex.html%3Fforbid_right_back%3D1&status_bar_bg_color=%2300000000&noble_intercept=1&__live_platform__=webcast&type=fullscreen&hide_nav_bar=1&status_bar_color=white"
}
4: "\346\231\256\351\200\232\347\224\250\346\210\267"
6 {
3: 366
4: 615
}
7 {
3: 60
4: 108
}
8 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
2: "webcast/noble_boarder.png"
3: 64
4: 64
}
}
}
2: 1
}
}
4 {
1: 1
11: "\350\277\231\346\263\242\346\223\215\344\275\234\343\200\202\346\254\272\350\264\237\344\272\272\345\221\200"
}
}
}
2 {
1: 51510235218
3: "\351\222\242\346\236\252\345\205\204\345\274\237\350\266\205\345\223\245"
4: 1
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/2e8b032f45854441bd5e539ea892e00f~120x256.image"
}
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
2: "webcast/xigua_admin_badge_v2.png"
3: 16
4: 28
6: 3
}
21 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_16.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&__live_platform__=webcast&type=popup&gravity=bottom&height=400&radius=8"
}
21 {
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_15.png"
6: 7
8 {
1: "\351\222\242\346\236\252\346\211\213"
2: "#FFFFFF"
3: 15
}
}
22 {
1: 45
2: 17
}
23 {
6: 16
19 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_16.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_16.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&__live_platform__=webcast&type=popup&gravity=bottom&height=400&radius=8"
}
}
24 {
1 {
1: "\351\222\242\346\236\252\346\211\213"
2: 15
3: 1
4 {
1 {
1: 2
2 {
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_15.png"
3: 48
4: 150
}
}
2: "\351\222\242\346\236\252\346\211\213"
}
}
}
32 {
2: 1
}
38: "0"
46: "MS4wLjABAAAALx1qtwLJiLVbuWXt7ZYTxHxVFvZz2PITy5YfQidfGp4"
50 {
1 {
3: 1008
4: 1125
}
3 {
3: 105
4: 111
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fnoble%2Fnoble_privilege_intro%2Findex.html%3Fforbid_right_back%3D1&status_bar_bg_color=%2300000000&noble_intercept=1&__live_platform__=webcast&type=fullscreen&hide_nav_bar=1&status_bar_color=white"
}
4: "\346\231\256\351\200\232\347\224\250\346\210\267"
6 {
3: 366
4: 615
}
7 {
3: 60
4: 108
}
8 {
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
2: "webcast/noble_boarder.png"
3: 64
4: 64
}
}
}
3: "\350\277\231\346\263\242\346\223\215\344\275\234\343\200\202\346\254\272\350\264\237\344\272\272\345\221\200"
}
}
1 {
1: "WebcastChatMessage"
2 {
1 {
1: "WebcastChatMessage"
2: 6776883987831969295
3: 6776859660747344653
4: 1577866267933
6: 1
}
2 {
1: 100902326983
3: "\346\211\254\345\256\266\345\206\233\347\201\254\344\272\232\351\243\236"
4: 1
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/aade000f6df1961243c5~120x256.image"
}
21 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_9.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_4.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_4.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_4.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_4.png"
6: 7
8 {
1: "\351\222\242\346\236\252\346\211\213"
2: "#FFFFFF"
3: 4
}
}
22 {
1: 45
2: 7
}
23 {
6: 9
19 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_9.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_9.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
}
24 {
1 {
1: "\351\222\242\346\236\252\346\211\213"
2: 4
3: 1
4 {
1 {
1: 2
2 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_4.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_4.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_4.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_4.png"
3: 48
4: 150
}
}
2: "\351\222\242\346\236\252\346\211\213"
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAArfQQ4YVnKMKthzbKgv2swkggu8Ovv8eQCp56JmvvRvE"
50 {
1 {
3: 1008
4: 1125
}
3 {
3: 105
4: 111
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fnoble%2Fnoble_privilege_intro%2Findex.html%3Fforbid_right_back%3D1&type=fullscreen&hide_nav_bar=1&status_bar_color=white&status_bar_bg_color=%2300000000&noble_intercept=1&__live_platform__=webcast"
}
4: "\346\231\256\351\200\232\347\224\250\346\210\267"
6 {
3: 366
4: 615
}
7 {
3: 60
4: 108
}
8 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
2: "webcast/noble_boarder.png"
3: 64
4: 64
}
}
}
3: "\351\230\277\344\274\237\345\220\271\347\211\233\346\257\224"
}
}
1 {
1: "WebcastRoomUserSeqMessage"
2 {
1 {
1: "WebcastRoomUserSeqMessage"
2: 6776884008732789507
3: 6776859660747344653
4: 1577866268029
}
2 {
1: 1975
2 {
1: 479033461313651
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/49b2bd0b157e4787917b029da02d2622~120x256.image"
}
23: ""
}
3: 1
}
2 {
1: 999
2 {
1: 3962278245043603
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/241f1001013a2e8505175~120x256.image"
}
23: ""
}
3: 2
}
2 {
1: 571
2 {
1: 53231054839
9 {
1: "http://wx.qlogo.cn/mmopen/XFJ8HdGGwGDwy1reeaMqlfQrUh81uSv81HqUsESBK8YsNQ2oEIct3ibwdq1k55HLC7m43nfFiaX3EYpw2lKH4wibw/64"
}
23: ""
}
3: 3
}
2 {
1: 520
2 {
1: 88336033429
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/647c6fcddfa84d328d9c51f0294599d0~120x256.image"
}
23: ""
}
3: 4
}
2 {
1: 520
2 {
1: 58722717092
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/8a4dc6f002b545bca632615290f4527d~120x256.image"
}
23: ""
}
3: 5
}
2 {
1: 297
2 {
1: 52379408873
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/24990023eae5e3325fcc~120x256.image"
}
23: ""
}
3: 6
}
2 {
1: 140
2 {
1: 57254508132
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/216c00283d70176a9e97~120x256.image"
}
23: ""
}
3: 7
}
2 {
1: 128
2 {
1: 3056263838569380
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/fe8f000122d925f9a0fb~120x256.image"
}
23: ""
}
3: 8
}
2 {
1: 99
2 {
1: 23239313505
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/5d4700073713949f592e~120x256.image"
}
23: ""
}
3: 9
}
2 {
1: 35
2 {
1: 3239311302
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/737/6093229802~120x256.image"
}
23: ""
}
3: 10
}
2 {
1: 30
2 {
1: 822069738617544
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/2b5f6e3d331443b3bf51875567fa2b5d~120x256.image"
}
23: ""
}
3: 11
}
2 {
1: 22
2 {
1: 83166975758782
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/0baffeeb3d2d4fa8898b275968f18564~120x256.image"
}
23: ""
}
3: 12
}
2 {
1: 14
2 {
1: 104729678256
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/db140012b3f29800ab6d~120x256.image"
}
23: ""
}
3: 13
}
2 {
1: 11
2 {
1: 5538311676
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/dad300141ece34b4e3c7~120x256.image"
}
23: ""
}
3: 14
}
2 {
1: 8
2 {
1: 109675723458
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/9cf549b429f740f6a90c41e4b5b632b9~120x256.image"
}
23: ""
}
3: 15
}
2 {
1: 6
2 {
1: 81425804261
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/9fd60005b91e43cc85e2~120x256.image"
}
23: ""
}
3: 16
}
2 {
1: 5
2 {
1: 2115111742610984
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/b20c086a5b644a6f919dfdd3dad442e6~120x256.image"
}
23: ""
}
3: 17
}
2 {
1: 3
2 {
1: 100743319316
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/6d8e7bba2195468fb24a4e3ea7992b92~120x256.image"
}
23: ""
}
3: 18
}
2 {
1: 2
2 {
1: 51035982268
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/d041e17415bc42c9a9815a8aaa2c3d8b~120x256.image"
}
23: ""
}
3: 19
}
2 {
1: 1
2 {
1: 1772009086784855
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/9fe0aa53dc254c0081a0fc2ce65f1559~120x256.image"
}
23: ""
}
3: 20
}
3: 826
4: "13\344\270\207\344\272\272\346\260\224"
6: 136763
}
}
2: "6776884008732789507_1577866268700_1_1"
3: 1000
4: 1577866268700
5: "fetch_time:1577866268700|start_time:1577866263586|fetch_id:6776884010443557636|flag:0|seq:22"

234
Demo/resulta.txt Normal file
View File

@ -0,0 +1,234 @@
1 {
1: "WebcastRoomUserSeqMessage"
2 {
1 {
1: "WebcastRoomUserSeqMessage"
2: 6776963484661500684
3: 6776943780420389640
4: 1577884770601
}
2 {
1: 132
2 {
1: 3962279791967276
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/278ac6165ba34b7aa371e1df5ea337b3~120x256.image"
}
23: ""
}
3: 1
}
2 {
1: 66
2 {
1: 2933125236921479
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/2e1c9d64f34a4a3e8a326fe5394659fd~120x256.image"
}
23: ""
}
3: 2
}
2 {
1: 45
2 {
1: 50230797308
9 {
1: "http://p9-xg.bytecdn.cn/thumb/dac400045e7008dbd42d"
2: "dac400045e7008dbd42d"
}
23: ""
}
3: 3
}
2 {
1: 5
2 {
1: 9746464842
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/6ad34237256e4471b16810eb098224c0~120x256.image"
}
23: ""
}
3: 4
}
2 {
1: 5
2 {
1: 111552853752
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/3792/5112637127~120x256.image"
}
23: ""
}
3: 5
}
2 {
1: 3
2 {
1: 16665341581
9 {
1: "http://p3-xg.bytecdn.cn/thumb/da80000309bef5b49fa0"
2: "da80000309bef5b49fa0"
}
23: ""
}
3: 6
}
2 {
2 {
1: 97942455882
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/3792/5112637127~120x256.image"
}
23: ""
}
3: 7
}
2 {
2 {
1: 97363408846
9 {
1: "http://p3-xg.bytecdn.cn/thumb/dab00018fc4fda3b5a21"
2: "dab00018fc4fda3b5a21"
}
23: ""
}
3: 8
}
2 {
2 {
1: 96959753387
9 {
1: "http://p9-xg.bytecdn.cn/thumb/173b600285dcf9f649150"
2: "173b600285dcf9f649150"
}
23: ""
}
3: 9
}
2 {
2 {
1: 96119123780
9 {
1: "http://p9-xg.bytecdn.cn/thumb/241ef00000e3f17f517d7"
2: "241ef00000e3f17f517d7"
}
23: ""
}
3: 10
}
2 {
2 {
1: 9609510451
9 {
1: "http://p3-xg.bytecdn.cn/thumb/da51000807963daceae0"
2: "da51000807963daceae0"
}
23: ""
}
3: 11
}
2 {
2 {
1: 95931639233
9 {
1: "http://p9-xg.bytecdn.cn/thumb/71a30006cf20be61eb9b"
2: "71a30006cf20be61eb9b"
}
23: ""
}
3: 12
}
2 {
2 {
1: 94602295110
9 {
1: "http://p1-xg.bytecdn.cn/thumb/173b70008753becec983c"
2: "173b70008753becec983c"
}
23: ""
}
3: 13
}
2 {
2 {
1: 94432960458
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3795/3047680722~120x256.image"
}
23: ""
}
3: 14
}
2 {
2 {
1: 94385438443
9 {
1: "http://p3-xg.bytecdn.cn/thumb/6593000eb2048e45ee0b"
2: "6593000eb2048e45ee0b"
}
23: ""
}
3: 15
}
2 {
2 {
1: 94193267099
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/da57000b43a72cedd2fc~120x256.image"
}
23: ""
}
3: 16
}
2 {
2 {
1: 93948536567
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/fe7300005f28e10f3c52~120x256.image"
}
23: ""
}
3: 17
}
2 {
2 {
1: 93175525403
9 {
1: "http://p9-xg.bytecdn.cn/thumb/da83000d9328094b90d6"
2: "da83000d9328094b90d6"
}
23: ""
}
3: 18
}
2 {
2 {
1: 93064266997
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/6588002a7fcd121c60f6~120x256.image"
}
23: ""
}
3: 19
}
2 {
2 {
1: 92866340217
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3795/3044413937~120x256.image"
}
23: ""
}
3: 20
}
3: 365
4: "5.6\344\270\207\344\272\272\346\260\224"
6: 56661
}
}
2: "6776963484661500684_1577884771191_6776957423184169736_1"
3: 1000
4: 1577884771191
5: "fetch_time:1577884771191|start_time:1577884288940|fetch_id:6776963481247042317|flag:0|seq:1283"

4732
Demo/resultb.txt Normal file

File diff suppressed because it is too large Load Diff

4489
Demo/resultc.txt Normal file

File diff suppressed because it is too large Load Diff

862
Demo/resultfst.txt Normal file
View File

@ -0,0 +1,862 @@
1 {
1: "WebcastMemberMessage"
2 {
1 {
1: "WebcastMemberMessage"
2: 6776965782439283463
3: 6776895930592398094
6: 1
8 {
1: "live_room_enter_toast"
2: "{0:user} \346\235\245\344\272\206{1:string}"
3 {
1: "#de000000"
4: 400
}
4 {
1: 11
2 {
1: "#61000000"
4: 400
}
21 {
1 {
1: 1587335753631549
3: "\345\260\217\345\244\251\346\211\215\350\264\235\345\243\263"
9 {
1: "http://p3.pstatp.com/thumb/3793/3131589739"
2: "3793/3131589739"
}
22 {
1: 33
2: 2
}
23 {
19: ""
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAh0jOEAHZj6-a55dwsKu6i0ilHwHcWPx8mLImJ5iDJzfgkYhU0mFv-oLZ6yx6wNi0"
}
}
}
}
}
2 {
1: 1587335753631549
3: "\345\260\217\345\244\251\346\211\215\350\264\235\345\243\263"
9 {
1: "http://p3.pstatp.com/thumb/3793/3131589739"
2: "3793/3131589739"
}
22 {
1: 33
2: 2
}
23 {
19: ""
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAh0jOEAHZj6-a55dwsKu6i0ilHwHcWPx8mLImJ5iDJzfgkYhU0mFv-oLZ6yx6wNi0"
}
3: 15103
10: 1
14: "132\344\270\207\344\272\272\346\260\224"
}
}
1 {
1: "WebcastMemberMessage"
2 {
1 {
1: "WebcastMemberMessage"
2: 6776965783190555404
3: 6776895930592398094
6: 1
8 {
1: "live_room_enter_toast"
2: "{0:user} \346\235\245\344\272\206{1:string}"
3 {
1: "#de000000"
4: 400
}
4 {
1: 11
2 {
1: "#61000000"
4: 400
}
21 {
1 {
1: 50909397248
3: "\347\214\223\347\214\223\347\214\223\345\255\220"
4: 1
9 {
1: "http://p1.pstatp.com/thumb/96b002412f02c3d2735"
2: "96b002412f02c3d2735"
}
21 {
1: "http://p3-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
22 {
1: 24
2: 1
}
23 {
6: 5
19 {
1: "http://p3-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAwlVH0meNefJYE9l5cBWj5vZX8ooB9bII44Cf2CRXp9s"
}
}
}
}
}
2 {
1: 50909397248
3: "\347\214\223\347\214\223\347\214\223\345\255\220"
4: 1
9 {
1: "http://p1.pstatp.com/thumb/96b002412f02c3d2735"
2: "96b002412f02c3d2735"
}
21 {
1: "http://p3-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
22 {
1: 24
2: 1
}
23 {
6: 5
19 {
1: "http://p3-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_5.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_5.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAwlVH0meNefJYE9l5cBWj5vZX8ooB9bII44Cf2CRXp9s"
}
3: 15103
10: 1
14: "132\344\270\207\344\272\272\346\260\224"
}
}
1 {
1: "WebcastRoomUserSeqMessage"
2 {
1 {
1: "WebcastRoomUserSeqMessage"
2: 6776965783814933256
3: 6776895930592398094
4: 1577885306057
}
2 {
1: 2997
2 {
1: 92747501043
2: 517409
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/feaa00016eaa01bf172e~120x256.image"
}
23: ""
}
3: 1
}
2 {
1: 2198
2 {
1: 1182693581391939
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/dae10014972e8d70953e~120x256.image"
}
23: ""
}
3: 2
}
2 {
1: 1998
2 {
1: 5981054057
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/75660014ae3215bae055~120x256.image"
}
23: ""
}
3: 3
}
2 {
1: 1099
2 {
1: 3836408254
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/6620/5484795979~120x256.image"
}
23: ""
}
3: 4
}
2 {
1: 999
2 {
1: 830872766922279
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/5a67caf5ae404432aa0524c33001241c~120x256.image"
}
23: ""
}
3: 5
}
2 {
1: 999
2 {
1: 7185332641
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/754e3527d08540089a3adf6495845240~120x256.image"
}
23: ""
}
3: 6
}
2 {
1: 520
2 {
1: 93127918477
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/3795/3044413937~120x256.image"
}
23: ""
}
3: 7
}
2 {
1: 520
2 {
1: 50073154686
9 {
1: "http://p1-xg.bytecdn.cn/thumb/da790015e9c75441ff34"
2: "da790015e9c75441ff34"
}
23: ""
}
3: 8
}
2 {
1: 520
2 {
1: 104620584571
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/daa30018abcde9559b55~120x256.image"
}
23: ""
}
3: 9
}
2 {
1: 120
2 {
1: 5994520551
9 {
1: "http://p1-xg.bytecdn.cn/thumb/aae5000ffc17e4f1f5da"
2: "aae5000ffc17e4f1f5da"
}
23: ""
}
3: 10
}
2 {
1: 100
2 {
1: 54883854814
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/da68001693847d505008~120x256.image"
}
23: ""
}
3: 11
}
2 {
1: 99
2 {
1: 82020236564
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/5042000ff6673790f6d2~120x256.image"
}
23: ""
}
3: 12
}
2 {
1: 66
2 {
1: 3688188102
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/e590005f1b8bdbd812c~120x256.image"
}
23: ""
}
3: 13
}
2 {
1: 38
2 {
1: 75972230499
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/173b400272ba1269fb7d8~120x256.image"
}
23: ""
}
3: 14
}
2 {
1: 20
2 {
1: 654947037492940
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/2e549000299b4f464f99f~120x256.image"
}
23: ""
}
3: 15
}
2 {
1: 17
2 {
1: 6896749077
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/5046000873dbc5a8f31f~120x256.image"
}
23: ""
}
3: 16
}
2 {
1: 14
2 {
1: 50569473736
9 {
1: "http://p3-xg.bytecdn.cn/thumb/5d4b0002a7134afffa47"
2: "5d4b0002a7134afffa47"
}
23: ""
}
3: 17
}
2 {
1: 14
2 {
1: 2581241782866604
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/51c85ec9c5754938b89504217ae5bbbc~120x256.image"
}
23: ""
}
3: 18
}
2 {
1: 13
2 {
1: 50651928991
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/f81fee15e94a4405acc921916bfaff09~120x256.image"
}
23: ""
}
3: 19
}
2 {
1: 11
2 {
1: 106001804992
9 {
1: "http://sf6-ttcdn-tos.pstatp.com/img/mosaic-legacy/fe5f000080632ba520f5~120x256.image"
}
23: ""
}
3: 20
}
3: 15094
4: "132\344\270\207\344\272\272\346\260\224"
6: 1329944
}
}
1 {
1: "WebcastChatMessage"
2 {
1 {
1: "WebcastChatMessage"
2: 6776965784796482315
3: 6776895930592398094
4: 1577885306078
6: 1
}
2 {
1: 52120728008
3: "\346\234\250\345\255\2202910"
4: 1
9 {
1: "http://p1.pstatp.com/thumb/ef6000df19086df2853"
2: "ef6000df19086df2853"
}
21 {
1: "http://p3-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_3.png~tplv-obj.png"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_3.png~tplv-obj.png"
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_3.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_3.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&__live_platform__=webcast&type=popup&gravity=bottom&height=400&radius=8"
}
22 {
1: 65
2: 16
}
23 {
6: 3
19 {
1: "http://p3-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_3.png~tplv-obj.png"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_3.png~tplv-obj.png"
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_paygrade_level_3.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_3.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&__live_platform__=webcast&type=popup&gravity=bottom&height=400&radius=8"
}
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAD4OSjJ5hRbYDzZI0GJT_usTlLPEBYFrtPEYzBwLiIzQ"
50 {
1 {
3: 1008
4: 1125
}
3 {
3: 105
4: 111
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fnoble%2Fnoble_privilege_intro%2Findex.html%3Fforbid_right_back%3D1&type=fullscreen&hide_nav_bar=1&status_bar_color=white&status_bar_bg_color=%2300000000&noble_intercept=1&__live_platform__=webcast"
}
4: "\346\231\256\351\200\232\347\224\250\346\210\267"
6 {
3: 366
4: 615
}
7 {
3: 60
4: 108
}
8 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
1: "http://p3-webcast-ttcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/noble_boarder.png~tplv-obj.image"
2: "webcast/noble_boarder.png"
3: 64
4: 64
}
}
}
3: "\350\277\231\346\230\257\345\267\247\345\205\213\345\212\233\345\270\275\345\255\220\357\274\237"
}
}
1 {
1: "WebcastMemberMessage"
2 {
1 {
1: "WebcastMemberMessage"
2: 6776965784520887054
3: 6776895930592398094
6: 1
8 {
1: "live_room_enter_toast"
2: "{0:user} \346\235\245\344\272\206{1:string}"
3 {
1: "#de000000"
4: 400
}
4 {
1: 11
2 {
1: "#61000000"
4: 400
}
21 {
1 {
1: 71581494772
3: "\345\217\253\346\210\221\350\221\211\345\220\214\345\255\246"
4: 1
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/3792/5112637127~120x256.image"
}
22 {
1: 6
}
23 {
19: ""
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAfgxQATVlN1REs0ezLccSYBNp34sVcfh3EZHMu5Fi8uE"
}
}
}
}
}
2 {
1: 71581494772
3: "\345\217\253\346\210\221\350\221\211\345\220\214\345\255\246"
4: 1
9 {
1: "http://sf3-ttcdn-tos.pstatp.com/img/mosaic-legacy/3792/5112637127~120x256.image"
}
22 {
1: 6
}
23 {
19: ""
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAfgxQATVlN1REs0ezLccSYBNp34sVcfh3EZHMu5Fi8uE"
}
3: 15103
10: 1
14: "132\344\270\207\344\272\272\346\260\224"
}
}
1 {
1: "WebcastMemberMessage"
2 {
1 {
1: "WebcastMemberMessage"
2: 6776965785094048520
3: 6776895930592398094
6: 1
8 {
1: "live_room_enter_toast"
2: "{0:user} \346\235\245\344\272\206{1:string}"
3 {
1: "#de000000"
4: 400
}
4 {
1: 11
2 {
1: "#61000000"
4: 400
}
21 {
1 {
1: 6205145196
3: "\346\210\221\344\270\215\346\230\257\350\200\201\351\211\204"
4: 1
9 {
1: "http://p1-xg.bytecdn.cn/thumb/249a001395445a62671d"
2: "249a001395445a62671d"
}
21 {
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_8.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
6: 7
8 {
1: "\345\270\203\344\270\200\347\217\255"
2: "#FFFFFF"
3: 14
}
}
22 {
1: 15
2: 54
}
23 {
6: 8
19 {
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_8.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
}
24 {
1 {
1: "\345\270\203\344\270\200\347\217\255"
2: 14
3: 1
4 {
1 {
1: 2
2 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
3: 48
4: 150
}
}
2: "\345\270\203\344\270\200\347\217\255"
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAGMn5pO7qE_ZZu6ETuJmfSW8KLhLOtRkLnr3IiLE2e6A"
}
}
}
}
}
2 {
1: 6205145196
3: "\346\210\221\344\270\215\346\230\257\350\200\201\351\211\204"
4: 1
9 {
1: "http://p1-xg.bytecdn.cn/thumb/249a001395445a62671d"
2: "249a001395445a62671d"
}
21 {
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_8.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
21 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
6: 7
8 {
1: "\345\270\203\344\270\200\347\217\255"
2: "#FFFFFF"
3: 14
}
}
22 {
1: 15
2: 54
}
23 {
6: 8
19 {
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/xigua_paygrade_level_8.png~tplv-obj.png"
2: "webcast/xigua_paygrade_level_8.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2FhonorLevel%2Findex.html&type=popup&gravity=bottom&height=400&radius=8&__live_platform__=webcast"
}
}
24 {
1 {
1: "\345\270\203\344\270\200\347\217\255"
2: 14
3: 1
4 {
1 {
1: 2
2 {
1: "http://p9-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
1: "http://p6-webcast-xgcdn.byteimg.com/img/webcast/xigua_fansclub_medal_14.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_14.png"
3: 48
4: 150
}
}
2: "\345\270\203\344\270\200\347\217\255"
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAGMn5pO7qE_ZZu6ETuJmfSW8KLhLOtRkLnr3IiLE2e6A"
}
3: 15103
10: 1
14: "132\344\270\207\344\272\272\346\260\224"
}
}
1 {
1: "WebcastFansclubStatisticsMessage"
2 {
1 {
1: "WebcastFansclubStatisticsMessage"
2: 6776950071441869579
3: 6776895930592398094
4: 1577885306430
6: 1
}
2: "\345\270\203\344\270\200\347\217\255"
3: 19325
}
}
1 {
1: "WebcastFansclubMessage"
2 {
1 {
1: "WebcastFansclubMessage"
2: 6776950071441885963
3: 6776895930592398094
4: 1577885306441
6: 1
}
2: 2
3: "\346\201\255\345\226\234 \347\210\261\345\220\203\351\261\274\347\232\204\347\213\256\345\255\220\351\270\255 \346\210\220\344\270\272\347\254\25419325\345\220\215\347\262\211\344\270\235\345\233\242\346\210\220\345\221\230"
4 {
1: 109556646111
3: "\347\210\261\345\220\203\351\261\274\347\232\204\347\213\256\345\255\220\351\270\255"
9 {
1: "http://sf1-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/66d462f176c841a0a4939ad355fe8c00~120x256.image"
}
24 {
1 {
1: "\345\270\203\344\270\200\347\217\255"
2: 1
3: 1
4 {
1 {
1: 2
2 {
1: "https://p1.pstatp.com/obj/webcast/xigua_fansclub_1.png"
2: "webcast/xigua_fansclub_1.png"
3: 48
4: 150
}
}
2: "\345\270\203\344\270\200\347\217\255"
}
}
}
}
}
}
2: "6776950071441885963_1577885306619_6776965731513060100_1"
3: 1000
4: 1577885306619
5: "fetch_time:1577885306619|start_time:1577885302380|fetch_id:6776965761064883715|flag:0|seq:387"

1036
Demo/v926.txt Normal file

File diff suppressed because it is too large Load Diff

256
Demo/v926_fg.txt Normal file
View File

@ -0,0 +1,256 @@
1 {
1: "WebcastChatMessage"
2 {
1 {
1: "WebcastChatMessage"
2: 6902669212519992068
3: 6902629276546566925
6: 1
8 {
1: "webcast_chat_display_text"
2: "{0:user}{1:string}"
3 {
1: "#ff36c0cf"
4: 400
}
4 {
1: 11
2 {
1: "#60000000"
4: 400
}
21 {
1 {
1: 5518138898
3: "\345\247\232\345\247\232\347\220\263\347\232\2042\345\247\220\345\244\253"
4: 1
9 {
1: "https://p1-dy.bytexservice.com/img/user-avatar/deb96a5e7e07f60a613531670a570736~300x300.image"
}
21 {
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
2: "webcast/xigua_admin_badge_v2.png"
3: 16
4: 28
6: 3
}
21 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
2: "webcast/25_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast&type=fullscreen"
}
21 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_15.png"
6: 7
8 {
1: "\345\247\232\345\247\232\347\220\263"
2: "#FFFFFF"
3: 15
}
}
22 {
1: 13
2: 86
3: 2
}
23 {
6: 25
19 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
2: "webcast/25_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast&type=fullscreen"
}
}
24 {
1 {
1: "\345\247\232\345\247\232\347\220\263"
2: 15
3: 1
4 {
1: "\010\002\022\342\001\nZhttp://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image\nZhttp://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image\022#webcast/xigua_fansclub_medal_15.png\0300 \226\001"
2: "\345\247\232\345\247\232\347\220\263"
}
6: 61788610240
}
}
32 {
2: 1
}
38: "0"
46: "MS4wLjABAAAAKkWCgUKAN3GtNdQ0jqr8zAt3KtIc9kAc1GaJ32VcH3E"
54: 3
61 {
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
2: "webcast/xigua_admin_badge_v2.png"
3: 16
4: 28
6: 3
}
61 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
2: "webcast/25_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast&type=fullscreen"
}
61 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_15.png"
6: 7
8 {
1: "\345\247\232\345\247\232\347\220\263"
2: "#FFFFFF"
3: 15
}
}
}
2: 1
}
}
4 {
1: 1
11: "@\345\247\232\345\256\266\344\272\214\345\247\221\345\207\211 \346\210\221\345\211\215\345\244\251\346\235\245\346\267\261\345\234\263\344\272\206"
}
}
11: 31003
}
2 {
1: 5518138898
3: "\345\247\232\345\247\232\347\220\263\347\232\2042\345\247\220\345\244\253"
4: 1
9 {
1: "https://p1-dy.bytexservice.com/img/user-avatar/deb96a5e7e07f60a613531670a570736~300x300.image"
}
21 {
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
2: "webcast/xigua_admin_badge_v2.png"
3: 16
4: 28
6: 3
}
21 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
2: "webcast/25_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast&type=fullscreen"
}
21 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_15.png"
6: 7
8 {
1: "\345\247\232\345\247\232\347\220\263"
2: "#FFFFFF"
3: 15
}
}
22 {
1: 13
2: 86
3: 2
}
23 {
6: 25
19 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
2: "webcast/25_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast&type=fullscreen"
}
}
24 {
1 {
1: "\345\247\232\345\247\232\347\220\263"
2: 15
3: 1
4 {
1 {
1: 2
2 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_15.png"
3: 48
4: 150
}
}
2: "\345\247\232\345\247\232\347\220\263"
}
6: 61788610240
}
}
32 {
2: 1
}
38: "0"
46: "MS4wLjABAAAAKkWCgUKAN3GtNdQ0jqr8zAt3KtIc9kAc1GaJ32VcH3E"
54: 3
61 {
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_admin_badge_v2.png~tplv-obj.image"
2: "webcast/xigua_admin_badge_v2.png"
3: 16
4: 28
6: 3
}
61 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
1: "http://p9-webcast-ttcdn.byteimg.com/img/webcast/25_xigua_honor_level.png~tplv-obj.png"
2: "webcast/25_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast&type=fullscreen"
}
61 {
1: "http://p1-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/xigua_fansclub_medal_15.png~tplv-obj.image"
2: "webcast/xigua_fansclub_medal_15.png"
6: 7
8 {
1: "\345\247\232\345\247\232\347\220\263"
2: "#FFFFFF"
3: 15
}
}
}
3: "@\345\247\232\345\256\266\344\272\214\345\247\221\345\207\211 \346\210\221\345\211\215\345\244\251\346\235\245\346\267\261\345\234\263\344\272\206"
9 {
1 {
1: "http://p3-webcast-ttcdn.byteimg.com/img/webcast/userlabel_regular_chat.png~tplv-obj.image"
1: "http://p6-webcast-ttcdn.byteimg.com/img/webcast/userlabel_regular_chat.png~tplv-obj.image"
2: "webcast/userlabel_regular_chat.png"
5: "#E0BCD4"
}
2: 11
}
}
3: 6902669212519992068
}
2: "1607153101490_6902670004165030044_6902669995575083008_1"
3: 1000
4: 1607153101490
5: "fetch_time:1607153101490|start_time:0|fetch_id:6902670004165030042|flag:0|seq:2080|next_cursor:1607153101490_6902670004165030044_6902669995575083008_1"

364
Demo/v926_leave.txt Normal file
View File

@ -0,0 +1,364 @@
1 {
1: "WebcastControlMessage"
2 {
1 {
1: "WebcastControlMessage"
2: 6902672961476774663
3: 6902629276546566925
4: 1607153789195
6: 1
}
2: 3
}
3: 6902672961476774663
}
1 {
1: "WebcastMemberMessage"
2 {
1 {
1: "WebcastMemberMessage"
2: 6902672961728662285
3: 6902629276546566925
6: 1
8 {
1: "live_room_enter_toast"
2: "{0:user} \346\235\245\344\272\206{1:string}"
3 {
1: "#de000000"
4: 400
}
4 {
1: 11
2 {
1: "#61000000"
4: 400
}
21 {
1 {
1: 2638466963214383
2: 1520817
3: "\350\213\261\345\256\207girl"
9 {
1: "https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/a15266741ef770c810e18e5e6d073da9~300x300.image"
}
21 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
2: "webcast/3_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&type=fullscreen&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast"
}
22 {
1: 60
2: 120
}
23 {
6: 3
19 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
2: "webcast/3_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&type=fullscreen&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast"
}
}
24 {
1 {
4 {
1: "\010\000\022\000"
}
}
}
32: ""
38: "1520817"
46: "MS4wLjABAAAATNQnQSVI6ePiovK48LHJHvefLO_4RAmla1Hkn0GYTWc8oE5u0a0VZnmPM3VKnaSh"
54: 3
61 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
2: "webcast/3_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&type=fullscreen&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast"
}
}
}
}
}
9: 1
10: 1
11: 42000
}
2 {
1: 2638466963214383
2: 1520817
3: "\350\213\261\345\256\207girl"
9 {
1: "https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/a15266741ef770c810e18e5e6d073da9~300x300.image"
}
21 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
2: "webcast/3_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&type=fullscreen&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast"
}
22 {
1: 60
2: 120
}
23 {
6: 3
19 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
2: "webcast/3_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&type=fullscreen&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast"
}
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "1520817"
46: "MS4wLjABAAAATNQnQSVI6ePiovK48LHJHvefLO_4RAmla1Hkn0GYTWc8oE5u0a0VZnmPM3VKnaSh"
54: 3
61 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
2: "webcast/3_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&type=fullscreen&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast"
}
}
3: 31
10: 1
14: "0\344\272\272"
18 {
1: "live_room_enter_toast"
2: "{0:user} \346\235\245\344\272\206{1:string}"
3 {
1: "#de000000"
4: 400
}
4 {
1: 11
2 {
1: "#61000000"
4: 400
}
21 {
1 {
1: 2638466963214383
2: 1520817
3: "\350\213\261\345\256\207girl"
9 {
1: "https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/a15266741ef770c810e18e5e6d073da9~300x300.image"
}
21 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
2: "webcast/3_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&type=fullscreen&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast"
}
22 {
1: 60
2: 120
}
23 {
6: 3
19 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
2: "webcast/3_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&type=fullscreen&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast"
}
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "1520817"
46: "MS4wLjABAAAATNQnQSVI6ePiovK48LHJHvefLO_4RAmla1Hkn0GYTWc8oE5u0a0VZnmPM3VKnaSh"
54: 3
61 {
1: "http://p1-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
1: "http://p3-webcast-xgcdn.byteimg.com/img/webcast/3_xigua_honor_level.png~tplv-obj.png"
2: "webcast/3_xigua_honor_level.png"
3: 16
4: 30
6: 1
7: "sslocal://webcast_webview?url=https%3A%2F%2Fwebcast.ixigua.com%2Ffalcon%2Fwebcast_xigua%2Fpage%2Fhonor_level%2Fuser%2Findex.html&type=fullscreen&hide_nav_bar=1&hide_status_bar=0&__live_platform__=webcast"
}
}
}
}
}
}
3: 6902672961728662285
}
1 {
1: "WebcastMemberMessage"
2 {
1 {
1: "WebcastMemberMessage"
2: 6902672961866681091
3: 6902629276546566925
6: 1
8 {
1: "live_room_enter_toast"
2: "{0:user} \346\235\245\344\272\206{1:string}"
3 {
1: "#de000000"
4: 400
}
4 {
1: 11
2 {
1: "#61000000"
4: 400
}
21 {
1 {
1: 1015537608169303
3: "\347\224\250\346\210\267525366763846"
9 {
1: "https://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
22 {
1: 31
}
23 {
19: ""
}
24 {
1 {
4 {
1: "\010\000\022\000"
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAXDp4yUHFF_sA3Uf9T4OPkW0dk-9SUYxbFNFrs7CcyhAcjYzdsYFYE5vuUdaHbo9R"
54: 3
}
}
}
}
9: 1
10: 1
11: 42000
}
2 {
1: 1015537608169303
3: "\347\224\250\346\210\267525366763846"
9 {
1: "https://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
22 {
1: 31
}
23 {
19: ""
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAXDp4yUHFF_sA3Uf9T4OPkW0dk-9SUYxbFNFrs7CcyhAcjYzdsYFYE5vuUdaHbo9R"
54: 3
}
10: 1
14: "0\344\272\272"
18 {
1: "live_room_enter_toast"
2: "{0:user} \346\235\245\344\272\206{1:string}"
3 {
1: "#de000000"
4: 400
}
4 {
1: 11
2 {
1: "#61000000"
4: 400
}
21 {
1 {
1: 1015537608169303
3: "\347\224\250\346\210\267525366763846"
9 {
1: "https://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3791/5070639578~120x256.image"
}
22 {
1: 31
}
23 {
19: ""
}
24 {
1 {
4 {
1 {
1: 0
2: ""
}
}
}
}
32: ""
38: "0"
46: "MS4wLjABAAAAXDp4yUHFF_sA3Uf9T4OPkW0dk-9SUYxbFNFrs7CcyhAcjYzdsYFYE5vuUdaHbo9R"
54: 3
}
}
}
}
}
3: 6902672961866681091
}
2: "1607153789923_6902672963397497753_6902669995575083008_1"
3: 1000
4: 1607153789923
5: "fetch_time:1607153789923|start_time:0|fetch_id:6902672959102530453|flag:0|seq:2684|next_cursor:1607153789923_6902672963397497753_6902669995575083008_1"

54
Gift.py
View File

@ -1,54 +0,0 @@
import requests
from User import User
class Gift:
ID:int = 0
count:int = 0
roomID:int = 0
giftList:dict = {}
amount:int = 0
user:User = None
def __init__(self, json=None):
if json:
self.parse(json)
def parse(self, json):
self.user = User(json)
if "common" in json and json["common"] is not None:
if Gift.roomID != int(json["common"]["room_id"]):
Gift.roomID = int(json["common"]["room_id"])
self.update()
if "extra" in json and json["extra"] is not None:
if "present_info" in json["extra"] and json["extra"]['present_info'] is not None:
self.ID = int(json["extra"]['present_info']['id'])
self.count = json["extra"]['present_info']['repeat_count']
elif "present_end_info" in json["extra"] and json["extra"]['present_end_info'] is not None:
self.ID = int(json["extra"]['present_end_info']['id'])
self.count = json["extra"]['present_end_info']['count']
if self.ID != 0 and self.ID in self.giftList:
self.amount = self.giftList[self.ID]["Price"] * self.count
else:
self.update()
def update(self):
p = requests.get("https://i.snssdk.com/videolive/gift/get_gift_list?room_id={roomID}"
"&version_code=730&device_platform=android".format(roomID = self.roomID))
d = p.json()
if "gift_info" not in d:
print("错误:礼物更新失败")
else:
for i in d["gift_info"]:
_id = int(i["id"])
Gift.giftList[_id] = {"Name": i["name"], "Price": i["diamond_count"]}
def __str__(self):
if self.ID in self.giftList:
giftN = self.giftList[self.ID]["Name"]
else:
giftN = "未知礼物[{}]".format(self.ID)
return "{user} 送出的 {count}{name}".format(user= self.user, count= self.count, name= giftN)
def __unicode__(self):
return self.__str__()

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@ -1,16 +1,31 @@
# XiguaLiveDanmakuHelper
### 西瓜直播弹幕助手--控制台版
界面版:[q792602257/XiguaDanmakuHelperGUI](https://github.com/q792602257/XiguaDanmakuHelperGUI "C# ver")
## 现在西瓜视频搜索接口无法使用建议开发者自己找到自己的用户ID写死加载即可
### 计划更新:
+ Digg消息点亮了喜欢实例化
+ √ ~~使用android app协议~~
### 因西瓜直播弹幕接口换成了ProtoBuf已经尝试解析出了部分proto
已使用
除从用户ID获取roomID外其他均改为Android Api
### 从安卓9.4版本后 *(大概是)* 发现需要连接Websocket才能获取弹幕且又是魔改protobuf搞不懂手动断开Websocket后才会轮询请求
+ √ ~~闲的无聊的时候看一看有没有好用的GUI轮子可以用用~~
### ~~西瓜直播弹幕助手--界面版~~
已完成
已基于BiliLive_dm制作出初代西瓜直播弹幕姬api未跟进
> 界面版:[q792602257/XiguaDanmakuHelperGUI](https://github.com/q792602257/XiguaDanmakuHelperGUI "C# ver")
> #### 该项目已经荒废,除非你知道如何开发,否则不建议使用
### 西瓜直播弹幕接口```api.py```
> - 基于安卓9.6.6(96615)
### 西瓜直播弹幕助手--礼物端```WinMain.py```
### 西瓜直播弹幕助手--录播端```WebMain.py```
> - 能够自动进行ffmpeg转码
> - 转码后自动上传至B站
> - 顺便还能自己清理录播的文件移动到一个位置执行shell命令上传百度云
> - 把录像文件分一定大小保存B站有限制但是不知道是多少
> - 少部分错误包容机制
> - 有一个简单的WEB页面及简单的控制接口
### ~~计划更新~~
### 随缘更新

40
Struct/Chat.py Normal file
View File

@ -0,0 +1,40 @@
from .User import User
from .Lottery import Lottery
from XiguaMessage_pb2 import ChatMessage
class Chat:
content = ""
user = None
filterString = ["", ]
isFiltered = False
def __init__(self, json=None, lottery: Lottery = None):
if lottery:
self.filterString.append(lottery.content)
if json:
if type(json) == bytes:
self.parsePb(json)
else:
self.parse(json)
def parsePb(self, raw):
_message = ChatMessage()
_message.ParseFromString(raw)
self.user = User(_message.user)
self.content = _message.content
if self.content in self.filterString:
self.isFiltered = True
def parse(self, json):
self.user = User(json)
if "extra" in json:
if "content" in json["extra"]:
self.content = json["extra"]['content']
if self.content in self.filterString:
self.isFiltered = True
def __str__(self):
return "{} : {}".format(self.user, self.content)
def __unicode__(self):
return self.__str__()

73
Struct/Gift.py Normal file
View File

@ -0,0 +1,73 @@
import requests
from .User import User
from XiguaMessage_pb2 import GiftMessage
class Gift:
giftList = {}
def __init__(self, json=None):
self.ID = 0
self.count = 0
self.user = None
self.isFinished = False
self.backupName = None
if json:
if type(json) == bytes:
self.parsePb(json)
else:
self.parse(json)
def parsePb(self, raw):
_message = GiftMessage()
_message.ParseFromString(raw)
self.user = User(_message.user)
self.ID = _message.giftId
self.count = _message.repeated
self.isFinished = _message.isFinished
self.backupName = _message.commonInfo.displayText.params.gifts.gift.name
def parse(self, json):
self.user = User(json)
if "extra" in json and json["extra"] is not None:
if "present_info" in json["extra"] and json["extra"]['present_info'] is not None:
self.ID = int(json["extra"]['present_info']['id'])
self.count = json["extra"]['present_info']['repeat_count']
elif "present_end_info" in json["extra"] and json["extra"]['present_end_info'] is not None:
self.ID = int(json["extra"]['present_end_info']['id'])
self.count = json["extra"]['present_end_info']['count']
def isAnimate(self):
if self.ID != 0 and self.ID in self.giftList:
if 'combo' in self.giftList[self.ID]:
return self.giftList[self.ID]["combo"] == False
elif 'meta' in self.giftList[self.ID] and 'combo' in self.giftList[self.ID]['meta']:
return self.giftList[self.ID]['meta']["combo"] == False
elif 'type' in self.giftList[self.ID]:
return self.giftList[self.ID]["type"] == 2
return False
@property
def name(self):
if self.ID in self.giftList:
return self.giftList[self.ID]["name"]
elif self.backupName is not None:
return self.backupName
else:
return "未知礼物[{}]".format(self.ID)
def __str__(self):
return "{user} 送出的 {count}{name}".format(user=self.user, count=self.count, name=self.name)
def __unicode__(self):
return self.__str__()
def __repr__(self):
return "西瓜礼物【{}(ID:{})】".format(self.name, self.ID)
@classmethod
def addGift(cls, _gift):
if 'id' not in _gift:
return
_id = int(_gift["id"])
cls.giftList[_id] = _gift

View File

@ -1,17 +1,18 @@
# coding=utf-8
import requests
import time
from LuckyUser import LuckyUser
from .LuckyUser import LuckyUser
class Lottery:
ID: int = 0
ID = 0
isActive = False
content = ""
isFinished = False
luckyUsers = []
joinedUserCount = 0
prizeName = ""
finish:int = 0
finish = 0
def __init__(self, json=None):
if json:
@ -54,8 +55,7 @@ class Lottery:
self.isFinished = int(d["lottery_info"]["status"]) == 2
self.joinedUserCount = int(d["lottery_info"]["candidate_num"])
if self.isFinished:
for i in d["lottery_info"]["lucky_users"]:
self.luckyUsers.append(LuckyUser(i))
self.luckyUsers = [ LuckyUser(i) for i in d["lottery_info"]["lucky_users"] ]
def __str__(self):
if self.isFinished:

View File

@ -1,4 +1,4 @@
from User import User
from .User import User
class LuckyUser:

View File

@ -1,10 +1,10 @@
from User import User
from .User import User
class MemberMsg:
type:int = 0
content:str = ""
user:User = None
type = 0
content = ""
user = None
def __init__(self, json=None):
if json:

View File

@ -1,15 +1,33 @@
class User:
ID: int = 0
name: str = ""
brand: str = ""
level: int = 0
type: int = 0
block: bool = False
mute: bool = False
from XiguaUser_pb2 import User as UserPb
class User:
def __init__(self, json=None):
self.ID = 0
self.name = ""
self.brand = ""
self.level = 0
self.type = 0
self.block = False
self.mute = False
if json:
self.parse(json)
if type(json) == bytes:
self.parsePb(json)
elif type(json) == UserPb:
self.parseUserPb(json)
else:
self.parse(json)
def parseUserPb(self, _user):
self.ID = _user.id
self.name = _user.nickname
self.brand = _user.fansClub.fansClub.title
self.level = _user.fansClub.fansClub.level
def parsePb(self, raw):
_user = UserPb()
_user.ParseFromString(raw)
self.parseUserPb(_user)
def parse(self, json):
if "extra" in json:
@ -23,14 +41,17 @@ class User:
self.type = json["extra"]["user_room_auth_status"]["user_type"]
self.block = json["extra"]["user_room_auth_status"]["is_block"]
self.mute = json["extra"]["user_room_auth_status"]["is_silence"]
elif "room" in json and json["room"] is not None:
if "user_info" in json["room"] and json["room"]["user_info"] is not None:
self.ID = json["room"]['user_info']['user_id']
self.name = json["room"]['user_info']['name']
elif "anchor" in json and json["anchor"] is not None:
if "user_info" in json and json["user_info"] is not None:
self.ID = json['user_info']['user_id']
self.name = json['user_info']['name']
if "anchor" in json and json["anchor"] is not None:
if "user_info" in json["anchor"] and json["anchor"]['user_info'] is not None:
self.ID = json["anchor"]['user_info']['user_id']
self.name = json["anchor"]['user_info']['name']
if "user_id" in json:
self.ID = json["user_id"]
if "user_name" in json:
self.name = json["user_name"]
if self.type is None:
self.type = 0
if isinstance(self.level, str):
@ -47,8 +68,10 @@ class User:
else:
if self.type != 0:
return "[{}{}]{}".format(self.brand, self.level, self.name)
return "<{}{}>{}".format(self.brand,self.level,self.name)
return "<{}{}>{}".format(self.brand, self.level, self.name)
def __unicode__(self):
return self.__str__()
def __repr__(self):
return "西瓜用户【{}(ID:{})】".format(self.name, self.ID)

198
WebMain.py Normal file
View File

@ -0,0 +1,198 @@
import os
from glob import glob
from time import sleep
from flask_cors import CORS
from flask import Flask, jsonify, request, render_template, Response, send_file
import Common
import threading
from liveDownloader import run as RUN
app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
CORS(app, supports_credentials=True)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/config", methods=["GET"])
def readConfig():
config = Common.config.copy()
return jsonify(config)
@app.route("/config", methods=["POST"])
def writeConfig():
# TODO : 完善
Common.appendOperation("更新配置")
Common.reloadConfig()
return jsonify({"message": "ok", "code": 200, "status": 0, "data": request.form})
@app.route("/force/not/upload", methods=["POST"])
def toggleForceNotUpload():
Common.forceNotUpload = not Common.forceNotUpload
Common.appendOperation("将强制不上传的值改为:{}".format(Common.forceNotUpload))
return jsonify({"message": "ok", "code": 200, "status": 0, "data": {
"forceNotUpload": Common.forceNotUpload,
}})
@app.route("/force/not/encode", methods=["POST"])
def toggleForceNotEncode():
Common.forceNotEncode = not Common.forceNotEncode
Common.appendOperation("将强制不编码的值改为:{}".format(Common.forceNotEncode))
return jsonify({"message": "ok", "code": 200, "status": 0, "data": {
"forceNotEncode": Common.forceNotEncode,
}})
@app.route("/force/not/download", methods=["POST"])
def toggleForceNotDownload():
Common.forceNotDownload = not Common.forceNotDownload
Common.appendOperation("将强制不下载的值改为:{}".format(Common.forceNotDownload))
return jsonify({"message": "ok", "code": 200, "status": 0, "data": {
"forceNotDownload": Common.forceNotDownload,
}})
@app.route("/force/not/broadcast", methods=["POST"])
def toggleForceNotBroadcast():
Common.forceNotBroadcasting = not Common.forceNotBroadcasting
return jsonify({"message": "ok", "code": 200, "status": 0, "data": {
"forceNotBroadcasting": Common.forceNotBroadcasting,
}})
@app.route("/force/start/encode", methods=["POST"])
def toggleForceStartEncodeThread():
Common.forceStartEncodeThread = True
Common.appendOperation("强制运行编码线程")
return jsonify({"message": "ok", "code": 200, "status": 0, "data": {
}})
@app.route("/force/start/upload", methods=["POST"])
def toggleForceStartUploadThread():
Common.forceStartUploadThread = True
Common.appendOperation("强制运行上传线程")
return jsonify({"message": "ok", "code": 200, "status": 0, "data": {
}})
@app.route("/force/start/clean", methods=["POST"])
def startForceCleanDisk():
Common.doClean(True)
Common.appendOperation("强制执行清理程序")
return jsonify({"message": "ok", "code": 200, "status": 0, "data": {
}})
@app.route("/encode/insert", methods=["POST"])
def insertEncode():
if "filename" in request.form and os.path.exists(request.form["filename"]):
Common.appendOperation("添加编码文件:{}".format(request.form["filename"]))
Common.encodeQueue.put(request.form["filename"])
return jsonify({"message": "ok", "code": 200, "status": 0})
else:
return jsonify({"message": "no filename specific", "code": 400, "status": 1})
@app.route("/upload/insert", methods=["POST"])
def insertUpload():
if "filename" in request.form and os.path.exists(request.form["filename"]):
Common.appendOperation("添加上传文件:{}".format(request.form["filename"]))
Common.uploadQueue.put(request.form["filename"])
return jsonify({"message": "ok", "code": 200, "status": 0})
else:
return jsonify({"message": "no filename specific", "code": 400, "status": 1})
@app.route("/upload/discard", methods=["POST"])
def discardUpload():
Common.uploadQueue.empty()
Common.b.clear()
return jsonify({"message": "ok", "code": 200, "status": 0})
@app.route("/upload/finish", methods=["POST"])
def finishUpload():
Common.appendOperation("设置当前已完成上传")
Common.uploadQueue.put(True)
return jsonify({"message": "ok", "code": 200, "status": 0})
@app.route("/stats", methods=["GET"])
def getAllStats():
return jsonify({"message": "ok", "code": 200, "status": 0, "data": Common.collectInfomation()})
@app.route("/stats/device", methods=["GET"])
def getDeviceStatus():
return jsonify({"message": "ok", "code": 200, "status": 0, "data": {
"status": Common.getCurrentStatus(),
}})
@app.route("/stats/config", methods=["GET"])
def getConfigStats():
return jsonify({"message": "ok", "code": 200, "status": 0, "data": {
"config": {
"forceNotBroadcasting": Common.forceNotBroadcasting,
"forceNotDownload": Common.forceNotDownload,
"forceNotUpload": Common.forceNotUpload,
"forceNotEncode": Common.forceNotEncode,
"downloadOnly": Common.config['dlO'],
}
}})
@app.route("/account/reLogin", methods=["POST"])
def accountRelogin():
res = Common.loginBilibili(True)
return jsonify({"message": "ok", "code": 200, "status": 0, "data": {"result": res}})
@app.route("/files/", methods=["GET"])
def fileIndex():
a = []
for i in (glob("*.mp4") + glob("*.flv")):
a.append({
"name": i,
"size": Common.parseSize(os.path.getsize(i))
})
return render_template("files.html", files=a)
@app.route("/files/download/<path>", methods=["GET"])
def fileDownload(path):
if not (".mp4" in path or ".flv" in path):
return Response(status=404)
if os.path.exists(path):
return send_file(path, as_attachment=True)
else:
return Response(status=404)
def SubThread():
t = threading.Thread(target=RUN, args=())
t.setDaemon(True)
t.start()
while True:
if t.is_alive():
sleep(240)
else:
t = threading.Thread(target=RUN, args=())
t.setDaemon(True)
t.start()
if not app.debug:
p = threading.Thread(target=SubThread)
p.setDaemon(True)
p.start()
if __name__ == "__main__":
app.run()

View File

@ -4,24 +4,26 @@ import time
import requests
from Gift import Gift
from Lottery import Lottery
from MemberMsg import MemberMsg
from User import User
from Chat import Chat
from Struct.MemberMsg import MemberMsg
from Struct.User import User
from Struct.Gift import Gift
from Struct.Chat import Chat
from Struct.Lottery import Lottery
from api import XiGuaLiveApi as Api
from api import public_hello
import msvcrt
import ctypes
SHOW_ALL = False
def readInput(caption, default, timeout: int = 5):
start_time = time.time()
print('{}({})\r\n>'.format(caption, default), end="")
input = ''
while True:
if msvcrt.kbhit():
chr = msvcrt.getche()
chr = msvcrt.getwche()
if ord(chr) == 13: # enter_key
break
elif ord(chr) == 27:
@ -30,13 +32,15 @@ def readInput(caption, default, timeout: int = 5):
if input != "":
input = input[:-1]
msvcrt.putch(b" ")
msvcrt.putch(b" ")
msvcrt.putch(b"\b")
msvcrt.putch(b"\b")
if len(input) == 0:
start_time = time.time()
elif 32 > ord(chr) or 255 > ord(chr) > 126: # space_char
continue
else:
input += chr.decode("utf8")
input += chr
if len(input) == 0 and (time.time() - start_time) > timeout:
break
@ -74,8 +78,9 @@ FOREGROUND_YELLOW = 0x0e # yellow.
FOREGROUND_WHITE = 0x0f # white.
# Windows CMD命令行 背景颜色定义 background colors
BACKGROUND_BLUE = 0x10 # dark blue.
BACKGROUND_GREEN = 0x20 # dark green.
BACKGROUND_BLACK = 0x00 # dark blue.
BACKGROUND_DARKBLUE = 0x10 # dark blue.
BACKGROUND_DARKGREEN = 0x20 # dark green.
BACKGROUND_DARKSKYBLUE = 0x30 # dark skyblue.
BACKGROUND_DARKRED = 0x40 # dark red.
BACKGROUND_DARKPINK = 0x50 # dark pink.
@ -97,7 +102,7 @@ def set_cmd_text_color(color, handle=std_out_handle):
def resetColor():
set_cmd_text_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
set_cmd_text_color(BACKGROUND_BLACK | FOREGROUND_WHITE)
class WinMain(Api):
@ -107,8 +112,8 @@ class WinMain(Api):
self._tmp += 1
if self._tmp > 10:
self._tmp = 0
if self._tmp < 5 :
return "{} 的直播间 --弹幕助手 by JerryYan".format(self.roomLiver)
if self._tmp < 5:
return "{} 的直播间 --弹幕助手 by JerryYan".format(self.broadcaster)
else:
if self.roomPopularity == 0:
self._tmp = 0
@ -117,54 +122,64 @@ class WinMain(Api):
return "人气:{} --弹幕助手 by JerryYan".format(self.roomPopularity)
def onMessage(self, msg: str):
set_cmd_text_color(FOREGROUND_DARKGRAY)
print("消息 : ", msg)
resetColor()
if SHOW_ALL:
set_cmd_text_color(BACKGROUND_BLACK | FOREGROUND_DARKGRAY)
print("消息 : ", msg, end="")
resetColor()
print()
def onJoin(self, user: User):
set_cmd_text_color(BACKGROUND_WHITE | FOREGROUND_BLACK)
print("欢迎", user, "加入了粉丝团")
print("欢迎", user, "加入了粉丝团", end="")
resetColor()
print()
def onSubscribe(self, user: User):
if SHOW_ALL:
set_cmd_text_color(FOREGROUND_DARKGRAY)
print("用户", user, "关注了主播")
set_cmd_text_color(BACKGROUND_BLACK | FOREGROUND_DARKGRAY)
print("用户", user, "关注了主播", end="")
resetColor()
print()
def onEnter(self, msg:MemberMsg):
if SHOW_ALL:
set_cmd_text_color(FOREGROUND_DARKGRAY)
print("提示 :", msg)
set_cmd_text_color(BACKGROUND_BLACK | FOREGROUND_DARKGRAY)
print("提示 :", msg, end="")
resetColor()
print()
def onChat(self, chat: Chat):
if SHOW_ALL:
resetColor()
set_cmd_text_color(BACKGROUND_BLACK | FOREGROUND_WHITE)
if not chat.isFiltered:
print(chat)
print(chat, end="")
resetColor()
print()
def onLottery(self, i:Lottery):
set_cmd_text_color(FOREGROUND_WHITE | BACKGROUND_DARKGRAY)
print(i)
print(i, end="")
resetColor()
print()
def onPresent(self, gift: Gift):
if SHOW_ALL:
set_cmd_text_color(FOREGROUND_DARKGRAY)
set_cmd_text_color(BACKGROUND_BLACK | FOREGROUND_DARKGRAY)
print("连击 :", gift)
resetColor()
def onPresentEnd(self, gift: Gift):
set_cmd_text_color(BACKGROUND_WHITE | FOREGROUND_BLACK)
print("感谢", gift)
print("感谢", gift, end="")
resetColor()
print()
def onLike(self, user: User):
if SHOW_ALL:
set_cmd_text_color(FOREGROUND_DARKGRAY)
print("用户", user, "点了喜欢")
set_cmd_text_color(BACKGROUND_BLACK | FOREGROUND_DARKGRAY)
print("用户", user, "点了喜欢", end="")
resetColor()
print()
def onLeave(self, json: any):
return
@ -175,19 +190,32 @@ def warning(*args):
if __name__ == "__main__":
name = "永恒de草薙"
resetColor()
print("西瓜直播弹幕助手 by JerryYan")
if len(sys.argv) > 1:
name = "97621754276"
if len(sys.argv) > 2:
if sys.argv[-1] == "a":
SHOW_ALL = True
name = sys.argv[1]
else:
name = readInput("请输入主播用户名(请用拼音字母),默认为", name, 3)
resetColor()
public_hello()
print("搜索【", name, "", end="\t", flush=True)
api = WinMain(name)
print("进入", api.roomLiver, "的直播间")
if not api.isValidRoom:
input("房间不存在")
if not api.isValidUser:
input("用户不存在")
sys.exit()
print("OK")
print(api.broadcaster.__repr__())
print("更新房间信息,请稍后", end="\t", flush=True)
os.system("title {}".format(api.getTitle()))
if api.updRoomInfo(True):
print("OK")
else:
print("FAIL")
print("更新房间礼物信息", end="\t", flush=True)
__res = api.updGiftInfo()
if __res < 0:
print("FAIL")
else:
print('OK\n礼物种数:', __res)
print("=" * 30)
while True:
if api.isLive:
@ -205,4 +233,4 @@ if __name__ == "__main__":
print("主播未开播等待1分钟后重试")
resetColor()
time.sleep(60)
api.updRoomInfo()
api.updRoomInfo(True)

33
WinMain.spec Normal file
View File

@ -0,0 +1,33 @@
# -*- mode: python -*-
block_cipher = None
a = Analysis(['WinMain.py'],
pathex=['E:\\XiGuaLiveDanmakuHelper',r'C:\\Program Files (x86)\\Windows Kits\\10\\Redist\\10.0.17763.0\\ucrt\\DLLs\\x86'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=["xml", "_tkinter", "pydoc", "lib2to3"],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='西瓜直播礼物助手',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
runtime_tmpdir=None,
console=True,
icon='./ico.ico' )

122
XiguaGift_pb2.py Normal file
View File

@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: XiguaGift.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='XiguaGift.proto',
package='',
syntax='proto2',
serialized_options=None,
serialized_pb=b'\n\x0fXiguaGift.proto\" \n\x04Gift\x12\n\n\x02id\x18\x01 \x02(\t\x12\x0c\n\x04name\x18\x02 \x02(\t\"+\n\x08GiftPack\x12\n\n\x02id\x18\x01 \x02(\x05\x12\x13\n\x04gift\x18\x02 \x02(\x0b\x32\x05.Gift'
)
_GIFT = _descriptor.Descriptor(
name='Gift',
full_name='Gift',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='id', full_name='Gift.id', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='name', full_name='Gift.name', index=1,
number=2, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=19,
serialized_end=51,
)
_GIFTPACK = _descriptor.Descriptor(
name='GiftPack',
full_name='GiftPack',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='id', full_name='GiftPack.id', index=0,
number=1, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='gift', full_name='GiftPack.gift', index=1,
number=2, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=53,
serialized_end=96,
)
_GIFTPACK.fields_by_name['gift'].message_type = _GIFT
DESCRIPTOR.message_types_by_name['Gift'] = _GIFT
DESCRIPTOR.message_types_by_name['GiftPack'] = _GIFTPACK
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
Gift = _reflection.GeneratedProtocolMessageType('Gift', (_message.Message,), {
'DESCRIPTOR' : _GIFT,
'__module__' : 'XiguaGift_pb2'
# @@protoc_insertion_point(class_scope:Gift)
})
_sym_db.RegisterMessage(Gift)
GiftPack = _reflection.GeneratedProtocolMessageType('GiftPack', (_message.Message,), {
'DESCRIPTOR' : _GIFTPACK,
'__module__' : 'XiguaGift_pb2'
# @@protoc_insertion_point(class_scope:GiftPack)
})
_sym_db.RegisterMessage(GiftPack)
# @@protoc_insertion_point(module_scope)

797
XiguaMessage_pb2.py Normal file
View File

@ -0,0 +1,797 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: XiguaMessage.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
import XiguaUser_pb2 as XiguaUser__pb2
import XiguaGift_pb2 as XiguaGift__pb2
DESCRIPTOR = _descriptor.FileDescriptor(
name='XiguaMessage.proto',
package='',
syntax='proto2',
serialized_options=None,
serialized_pb=b'\n\x12XiguaMessage.proto\x1a\x0fXiguaUser.proto\x1a\x0fXiguaGift.proto\"*\n\x07Message\x12\x1f\n\ncommonInfo\x18\x01 \x02(\x0b\x32\x0b.CommonInfo\"f\n\x0f\x46\x61nsClubMessage\x12\x1f\n\ncommonInfo\x18\x01 \x02(\x0b\x32\x0b.CommonInfo\x12\x0c\n\x04type\x18\x02 \x02(\x05\x12\x0f\n\x07\x63ontent\x18\x03 \x02(\t\x12\x13\n\x04user\x18\x04 \x02(\x0b\x32\x05.User\"U\n\x14\x46\x61nsClubStatsMessage\x12\x1f\n\ncommonInfo\x18\x01 \x02(\x0b\x32\x0b.CommonInfo\x12\r\n\x05title\x18\x02 \x02(\t\x12\r\n\x05\x63ount\x18\x03 \x02(\x05\"]\n\x0eUserSeqMessage\x12\x1f\n\ncommonInfo\x18\x01 \x02(\x0b\x32\x0b.CommonInfo\x12\x16\n\x0epopularityText\x18\x04 \x02(\t\x12\x12\n\npopularity\x18\x06 \x02(\x05\"D\n\x10\x44\x61ilyRankMessage\x12\x1f\n\ncommonInfo\x18\x01 \x02(\x0b\x32\x0b.CommonInfo\x12\x0f\n\x07ranking\x18\n \x02(\x05\"T\n\x0b\x43hatMessage\x12\x1f\n\ncommonInfo\x18\x01 \x02(\x0b\x32\x0b.CommonInfo\x12\x13\n\x04user\x18\x02 \x02(\x0b\x32\x05.User\x12\x0f\n\x07\x63ontent\x18\x03 \x02(\t\"]\n\rMemberMessage\x12\x1f\n\ncommonInfo\x18\x01 \x02(\x0b\x32\x0b.CommonInfo\x12\x13\n\x04user\x18\x02 \x02(\x0b\x32\x05.User\x12\x16\n\x0epopularityText\x18\x0e \x02(\t\"\xa1\x01\n\x0bGiftMessage\x12\x1f\n\ncommonInfo\x18\x01 \x02(\x0b\x32\x0b.CommonInfo\x12\x0e\n\x06giftId\x18\x02 \x02(\x05\x12\x10\n\x08\x63ontent4\x18\x04 \x02(\x05\x12\x10\n\x08repeated\x18\x05 \x02(\x05\x12\r\n\x05\x63ombo\x18\x06 \x02(\x05\x12\x13\n\x04user\x18\x07 \x01(\x0b\x32\x05.User\x12\x19\n\nisFinished\x18\t \x01(\x08:\x05\x66\x61lse\"f\n\rSocialMessage\x12\x1f\n\ncommonInfo\x18\x01 \x02(\x0b\x32\x0b.CommonInfo\x12\x13\n\x04user\x18\x02 \x02(\x0b\x32\x05.User\x12\x0c\n\x04int4\x18\x04 \x02(\x05\x12\x11\n\tfansCount\x18\x06 \x02(\x05\"*\n\x05Style\x12\r\n\x05\x63olor\x18\x01 \x01(\t\x12\x12\n\nfontWeight\x18\x04 \x01(\x05\"q\n\x06Params\x12\x0c\n\x04type\x18\x01 \x02(\x05\x12\x15\n\x05style\x18\x02 \x01(\x0b\x32\x06.Style\x12\x0e\n\x06string\x18\x0b \x01(\t\x12\x18\n\x05users\x18\x15 \x01(\x0b\x32\t.UserPack\x12\x18\n\x05gifts\x18\x16 \x01(\x0b\x32\t.GiftPack\"_\n\x0b\x44isplayText\x12\x0e\n\x06method\x18\x01 \x02(\t\x12\x0e\n\x06\x66ormat\x18\x02 \x02(\t\x12\x17\n\x07\x62gStyle\x18\x03 \x01(\x0b\x32\x06.Style\x12\x17\n\x06params\x18\x04 \x02(\x0b\x32\x07.Params\"\x87\x01\n\nCommonInfo\x12\x0e\n\x06method\x18\x01 \x02(\t\x12\x0e\n\x06msg_id\x18\x02 \x02(\x05\x12\x0f\n\x07room_id\x18\x03 \x02(\x05\x12\x13\n\x0b\x63reate_time\x18\x04 \x02(\x05\x12\x10\n\x08someEnum\x18\x06 \x01(\x05\x12!\n\x0b\x64isplayText\x18\x08 \x01(\x0b\x32\x0c.DisplayText'
,
dependencies=[XiguaUser__pb2.DESCRIPTOR,XiguaGift__pb2.DESCRIPTOR,])
_MESSAGE = _descriptor.Descriptor(
name='Message',
full_name='Message',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='commonInfo', full_name='Message.commonInfo', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=56,
serialized_end=98,
)
_FANSCLUBMESSAGE = _descriptor.Descriptor(
name='FansClubMessage',
full_name='FansClubMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='commonInfo', full_name='FansClubMessage.commonInfo', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='type', full_name='FansClubMessage.type', index=1,
number=2, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='content', full_name='FansClubMessage.content', index=2,
number=3, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='user', full_name='FansClubMessage.user', index=3,
number=4, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=100,
serialized_end=202,
)
_FANSCLUBSTATSMESSAGE = _descriptor.Descriptor(
name='FansClubStatsMessage',
full_name='FansClubStatsMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='commonInfo', full_name='FansClubStatsMessage.commonInfo', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='title', full_name='FansClubStatsMessage.title', index=1,
number=2, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='count', full_name='FansClubStatsMessage.count', index=2,
number=3, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=204,
serialized_end=289,
)
_USERSEQMESSAGE = _descriptor.Descriptor(
name='UserSeqMessage',
full_name='UserSeqMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='commonInfo', full_name='UserSeqMessage.commonInfo', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='popularityText', full_name='UserSeqMessage.popularityText', index=1,
number=4, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='popularity', full_name='UserSeqMessage.popularity', index=2,
number=6, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=291,
serialized_end=384,
)
_DAILYRANKMESSAGE = _descriptor.Descriptor(
name='DailyRankMessage',
full_name='DailyRankMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='commonInfo', full_name='DailyRankMessage.commonInfo', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='ranking', full_name='DailyRankMessage.ranking', index=1,
number=10, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=386,
serialized_end=454,
)
_CHATMESSAGE = _descriptor.Descriptor(
name='ChatMessage',
full_name='ChatMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='commonInfo', full_name='ChatMessage.commonInfo', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='user', full_name='ChatMessage.user', index=1,
number=2, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='content', full_name='ChatMessage.content', index=2,
number=3, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=456,
serialized_end=540,
)
_MEMBERMESSAGE = _descriptor.Descriptor(
name='MemberMessage',
full_name='MemberMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='commonInfo', full_name='MemberMessage.commonInfo', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='user', full_name='MemberMessage.user', index=1,
number=2, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='popularityText', full_name='MemberMessage.popularityText', index=2,
number=14, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=542,
serialized_end=635,
)
_GIFTMESSAGE = _descriptor.Descriptor(
name='GiftMessage',
full_name='GiftMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='commonInfo', full_name='GiftMessage.commonInfo', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='giftId', full_name='GiftMessage.giftId', index=1,
number=2, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='content4', full_name='GiftMessage.content4', index=2,
number=4, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='repeated', full_name='GiftMessage.repeated', index=3,
number=5, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='combo', full_name='GiftMessage.combo', index=4,
number=6, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='user', full_name='GiftMessage.user', index=5,
number=7, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='isFinished', full_name='GiftMessage.isFinished', index=6,
number=9, type=8, cpp_type=7, label=1,
has_default_value=True, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=638,
serialized_end=799,
)
_SOCIALMESSAGE = _descriptor.Descriptor(
name='SocialMessage',
full_name='SocialMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='commonInfo', full_name='SocialMessage.commonInfo', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='user', full_name='SocialMessage.user', index=1,
number=2, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='int4', full_name='SocialMessage.int4', index=2,
number=4, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fansCount', full_name='SocialMessage.fansCount', index=3,
number=6, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=801,
serialized_end=903,
)
_STYLE = _descriptor.Descriptor(
name='Style',
full_name='Style',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='color', full_name='Style.color', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fontWeight', full_name='Style.fontWeight', index=1,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=905,
serialized_end=947,
)
_PARAMS = _descriptor.Descriptor(
name='Params',
full_name='Params',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='type', full_name='Params.type', index=0,
number=1, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='style', full_name='Params.style', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='string', full_name='Params.string', index=2,
number=11, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='users', full_name='Params.users', index=3,
number=21, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='gifts', full_name='Params.gifts', index=4,
number=22, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=949,
serialized_end=1062,
)
_DISPLAYTEXT = _descriptor.Descriptor(
name='DisplayText',
full_name='DisplayText',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='method', full_name='DisplayText.method', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='format', full_name='DisplayText.format', index=1,
number=2, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='bgStyle', full_name='DisplayText.bgStyle', index=2,
number=3, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='params', full_name='DisplayText.params', index=3,
number=4, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=1064,
serialized_end=1159,
)
_COMMONINFO = _descriptor.Descriptor(
name='CommonInfo',
full_name='CommonInfo',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='method', full_name='CommonInfo.method', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='msg_id', full_name='CommonInfo.msg_id', index=1,
number=2, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='room_id', full_name='CommonInfo.room_id', index=2,
number=3, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='create_time', full_name='CommonInfo.create_time', index=3,
number=4, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='someEnum', full_name='CommonInfo.someEnum', index=4,
number=6, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='displayText', full_name='CommonInfo.displayText', index=5,
number=8, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=1162,
serialized_end=1297,
)
_MESSAGE.fields_by_name['commonInfo'].message_type = _COMMONINFO
_FANSCLUBMESSAGE.fields_by_name['commonInfo'].message_type = _COMMONINFO
_FANSCLUBMESSAGE.fields_by_name['user'].message_type = XiguaUser__pb2._USER
_FANSCLUBSTATSMESSAGE.fields_by_name['commonInfo'].message_type = _COMMONINFO
_USERSEQMESSAGE.fields_by_name['commonInfo'].message_type = _COMMONINFO
_DAILYRANKMESSAGE.fields_by_name['commonInfo'].message_type = _COMMONINFO
_CHATMESSAGE.fields_by_name['commonInfo'].message_type = _COMMONINFO
_CHATMESSAGE.fields_by_name['user'].message_type = XiguaUser__pb2._USER
_MEMBERMESSAGE.fields_by_name['commonInfo'].message_type = _COMMONINFO
_MEMBERMESSAGE.fields_by_name['user'].message_type = XiguaUser__pb2._USER
_GIFTMESSAGE.fields_by_name['commonInfo'].message_type = _COMMONINFO
_GIFTMESSAGE.fields_by_name['user'].message_type = XiguaUser__pb2._USER
_SOCIALMESSAGE.fields_by_name['commonInfo'].message_type = _COMMONINFO
_SOCIALMESSAGE.fields_by_name['user'].message_type = XiguaUser__pb2._USER
_PARAMS.fields_by_name['style'].message_type = _STYLE
_PARAMS.fields_by_name['users'].message_type = XiguaUser__pb2._USERPACK
_PARAMS.fields_by_name['gifts'].message_type = XiguaGift__pb2._GIFTPACK
_DISPLAYTEXT.fields_by_name['bgStyle'].message_type = _STYLE
_DISPLAYTEXT.fields_by_name['params'].message_type = _PARAMS
_COMMONINFO.fields_by_name['displayText'].message_type = _DISPLAYTEXT
DESCRIPTOR.message_types_by_name['Message'] = _MESSAGE
DESCRIPTOR.message_types_by_name['FansClubMessage'] = _FANSCLUBMESSAGE
DESCRIPTOR.message_types_by_name['FansClubStatsMessage'] = _FANSCLUBSTATSMESSAGE
DESCRIPTOR.message_types_by_name['UserSeqMessage'] = _USERSEQMESSAGE
DESCRIPTOR.message_types_by_name['DailyRankMessage'] = _DAILYRANKMESSAGE
DESCRIPTOR.message_types_by_name['ChatMessage'] = _CHATMESSAGE
DESCRIPTOR.message_types_by_name['MemberMessage'] = _MEMBERMESSAGE
DESCRIPTOR.message_types_by_name['GiftMessage'] = _GIFTMESSAGE
DESCRIPTOR.message_types_by_name['SocialMessage'] = _SOCIALMESSAGE
DESCRIPTOR.message_types_by_name['Style'] = _STYLE
DESCRIPTOR.message_types_by_name['Params'] = _PARAMS
DESCRIPTOR.message_types_by_name['DisplayText'] = _DISPLAYTEXT
DESCRIPTOR.message_types_by_name['CommonInfo'] = _COMMONINFO
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
Message = _reflection.GeneratedProtocolMessageType('Message', (_message.Message,), {
'DESCRIPTOR' : _MESSAGE,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:Message)
})
_sym_db.RegisterMessage(Message)
FansClubMessage = _reflection.GeneratedProtocolMessageType('FansClubMessage', (_message.Message,), {
'DESCRIPTOR' : _FANSCLUBMESSAGE,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:FansClubMessage)
})
_sym_db.RegisterMessage(FansClubMessage)
FansClubStatsMessage = _reflection.GeneratedProtocolMessageType('FansClubStatsMessage', (_message.Message,), {
'DESCRIPTOR' : _FANSCLUBSTATSMESSAGE,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:FansClubStatsMessage)
})
_sym_db.RegisterMessage(FansClubStatsMessage)
UserSeqMessage = _reflection.GeneratedProtocolMessageType('UserSeqMessage', (_message.Message,), {
'DESCRIPTOR' : _USERSEQMESSAGE,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:UserSeqMessage)
})
_sym_db.RegisterMessage(UserSeqMessage)
DailyRankMessage = _reflection.GeneratedProtocolMessageType('DailyRankMessage', (_message.Message,), {
'DESCRIPTOR' : _DAILYRANKMESSAGE,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:DailyRankMessage)
})
_sym_db.RegisterMessage(DailyRankMessage)
ChatMessage = _reflection.GeneratedProtocolMessageType('ChatMessage', (_message.Message,), {
'DESCRIPTOR' : _CHATMESSAGE,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:ChatMessage)
})
_sym_db.RegisterMessage(ChatMessage)
MemberMessage = _reflection.GeneratedProtocolMessageType('MemberMessage', (_message.Message,), {
'DESCRIPTOR' : _MEMBERMESSAGE,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:MemberMessage)
})
_sym_db.RegisterMessage(MemberMessage)
GiftMessage = _reflection.GeneratedProtocolMessageType('GiftMessage', (_message.Message,), {
'DESCRIPTOR' : _GIFTMESSAGE,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:GiftMessage)
})
_sym_db.RegisterMessage(GiftMessage)
SocialMessage = _reflection.GeneratedProtocolMessageType('SocialMessage', (_message.Message,), {
'DESCRIPTOR' : _SOCIALMESSAGE,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:SocialMessage)
})
_sym_db.RegisterMessage(SocialMessage)
Style = _reflection.GeneratedProtocolMessageType('Style', (_message.Message,), {
'DESCRIPTOR' : _STYLE,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:Style)
})
_sym_db.RegisterMessage(Style)
Params = _reflection.GeneratedProtocolMessageType('Params', (_message.Message,), {
'DESCRIPTOR' : _PARAMS,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:Params)
})
_sym_db.RegisterMessage(Params)
DisplayText = _reflection.GeneratedProtocolMessageType('DisplayText', (_message.Message,), {
'DESCRIPTOR' : _DISPLAYTEXT,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:DisplayText)
})
_sym_db.RegisterMessage(DisplayText)
CommonInfo = _reflection.GeneratedProtocolMessageType('CommonInfo', (_message.Message,), {
'DESCRIPTOR' : _COMMONINFO,
'__module__' : 'XiguaMessage_pb2'
# @@protoc_insertion_point(class_scope:CommonInfo)
})
_sym_db.RegisterMessage(CommonInfo)
# @@protoc_insertion_point(module_scope)

727
XiguaUser_pb2.py Normal file
View File

@ -0,0 +1,727 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: XiguaUser.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='XiguaUser.proto',
package='',
syntax='proto2',
serialized_options=None,
serialized_pb=b'\n\x0fXiguaUser.proto\"\x1f\n\x08UserPack\x12\x13\n\x04user\x18\x01 \x02(\x0b\x32\x05.User\"\xb6\x01\n\x05\x42\x61\x64ge\x12\x0b\n\x03url\x18\x01 \x03(\t\x12\x0e\n\x06height\x18\x03 \x01(\x05\x12\r\n\x05width\x18\x04 \x01(\x05\x12\x0c\n\x04type\x18\x06 \x01(\x05\x12\x0f\n\x07\x63lickTo\x18\x07 \x01(\t\x12\'\n\x0b\x66\x61nClubText\x18\x08 \x01(\x0b\x32\x12.Badge.FanClubText\x1a\x39\n\x0b\x46\x61nClubText\x12\x0c\n\x04text\x18\x01 \x02(\t\x12\r\n\x05\x63olor\x18\x02 \x01(\t\x12\r\n\x05level\x18\x03 \x02(\x05\"y\n\x0c\x46\x61nsClubPack\x12(\n\x08\x66\x61nsClub\x18\x01 \x02(\x0b\x32\x16.FansClubPack.FansClub\x1a?\n\x08\x46\x61nsClub\x12\x0f\n\x05title\x18\x01 \x02(\t:\x00\x12\x10\n\x05level\x18\x02 \x02(\x05:\x01\x30\x12\x10\n\x08someEnum\x18\x03 \x01(\x05\"\xd8\x05\n\x04User\x12\n\n\x02id\x18\x01 \x02(\x03\x12\x10\n\x08nickname\x18\x03 \x02(\t\x12\x0e\n\x06gender\x18\x04 \x02(\x05\x12!\n\x0b\x61vatarThumb\x18\t \x02(\x0b\x32\x0c.User.Avatar\x12\"\n\x0c\x61vatarMedium\x18\n \x01(\x0b\x32\x0c.User.Avatar\x12!\n\x0b\x61vatarLarge\x18\x0b \x01(\x0b\x32\x0c.User.Avatar\x12\x15\n\x05\x62\x61\x64ge\x18\x15 \x03(\x0b\x32\x06.Badge\x12\x1c\n\x06\x66ollow\x18\x16 \x01(\x0b\x32\x0c.User.Follow\x12 \n\x08payGrade\x18\x17 \x02(\x0b\x32\x0e.User.PayGrade\x12\x1f\n\x08\x66\x61nsClub\x18\x18 \x02(\x0b\x32\r.FansClubPack\x12\x11\n\ttotalPaid\x18\" \x02(\x05\x1a!\n\x06\x41vatar\x12\x0b\n\x03url\x18\x01 \x02(\t\x12\n\n\x02id\x18\x02 \x01(\t\x1a\x33\n\x06\x46ollow\x12\x14\n\tfollowing\x18\x01 \x01(\x05:\x01\x30\x12\x13\n\x08\x66ollower\x18\x02 \x01(\x05:\x01\x30\x1a\x9c\x01\n\x08PayGrade\x12\x0f\n\x07\x63urrent\x18\x01 \x02(\x05\x12\r\n\x05level\x18\x06 \x02(\x05\x12\x18\n\x10\x63urrentLevelNeed\x18\n \x01(\x05\x12\x15\n\rnextLevelNeed\x18\x0b \x01(\x05\x12\x0f\n\x07\x63ontent\x18\r \x01(\t\x12\x15\n\x05\x62\x61\x64ge\x18\x13 \x02(\x0b\x32\x06.Badge\x12\x17\n\x0ftoNextLevelNeed\x18\x15 \x01(\x05\x1a#\n\nHonorLevel\x12\x15\n\x05\x62\x61\x64ge\x18\x13 \x02(\x0b\x32\x06.Badge\x1a\x90\x01\n\x05Noble\x12\x0f\n\x07\x63ontent\x18\x04 \x02(\t\x12)\n\x07\x62oarder\x18\x08 \x01(\x0b\x32\x18.User.Noble.NobleBoarder\x1aK\n\x0cNobleBoarder\x12\x0f\n\x07urlList\x18\x01 \x03(\t\x12\x0b\n\x03uri\x18\x02 \x02(\t\x12\x0e\n\x06height\x18\x03 \x01(\x05\x12\r\n\x05width\x18\x04 \x01(\x05'
)
_USERPACK = _descriptor.Descriptor(
name='UserPack',
full_name='UserPack',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='user', full_name='UserPack.user', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=19,
serialized_end=50,
)
_BADGE_FANCLUBTEXT = _descriptor.Descriptor(
name='FanClubText',
full_name='Badge.FanClubText',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='text', full_name='Badge.FanClubText.text', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='color', full_name='Badge.FanClubText.color', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='level', full_name='Badge.FanClubText.level', index=2,
number=3, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=178,
serialized_end=235,
)
_BADGE = _descriptor.Descriptor(
name='Badge',
full_name='Badge',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='url', full_name='Badge.url', index=0,
number=1, type=9, cpp_type=9, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='height', full_name='Badge.height', index=1,
number=3, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='width', full_name='Badge.width', index=2,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='type', full_name='Badge.type', index=3,
number=6, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='clickTo', full_name='Badge.clickTo', index=4,
number=7, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fanClubText', full_name='Badge.fanClubText', index=5,
number=8, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[_BADGE_FANCLUBTEXT, ],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=53,
serialized_end=235,
)
_FANSCLUBPACK_FANSCLUB = _descriptor.Descriptor(
name='FansClub',
full_name='FansClubPack.FansClub',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='title', full_name='FansClubPack.FansClub.title', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=True, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='level', full_name='FansClubPack.FansClub.level', index=1,
number=2, type=5, cpp_type=1, label=2,
has_default_value=True, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='someEnum', full_name='FansClubPack.FansClub.someEnum', index=2,
number=3, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=295,
serialized_end=358,
)
_FANSCLUBPACK = _descriptor.Descriptor(
name='FansClubPack',
full_name='FansClubPack',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='fansClub', full_name='FansClubPack.fansClub', index=0,
number=1, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[_FANSCLUBPACK_FANSCLUB, ],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=237,
serialized_end=358,
)
_USER_AVATAR = _descriptor.Descriptor(
name='Avatar',
full_name='User.Avatar',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='url', full_name='User.Avatar.url', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='id', full_name='User.Avatar.id', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=660,
serialized_end=693,
)
_USER_FOLLOW = _descriptor.Descriptor(
name='Follow',
full_name='User.Follow',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='following', full_name='User.Follow.following', index=0,
number=1, type=5, cpp_type=1, label=1,
has_default_value=True, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='follower', full_name='User.Follow.follower', index=1,
number=2, type=5, cpp_type=1, label=1,
has_default_value=True, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=695,
serialized_end=746,
)
_USER_PAYGRADE = _descriptor.Descriptor(
name='PayGrade',
full_name='User.PayGrade',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='current', full_name='User.PayGrade.current', index=0,
number=1, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='level', full_name='User.PayGrade.level', index=1,
number=6, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='currentLevelNeed', full_name='User.PayGrade.currentLevelNeed', index=2,
number=10, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='nextLevelNeed', full_name='User.PayGrade.nextLevelNeed', index=3,
number=11, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='content', full_name='User.PayGrade.content', index=4,
number=13, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='badge', full_name='User.PayGrade.badge', index=5,
number=19, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='toNextLevelNeed', full_name='User.PayGrade.toNextLevelNeed', index=6,
number=21, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=749,
serialized_end=905,
)
_USER_HONORLEVEL = _descriptor.Descriptor(
name='HonorLevel',
full_name='User.HonorLevel',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='badge', full_name='User.HonorLevel.badge', index=0,
number=19, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=907,
serialized_end=942,
)
_USER_NOBLE_NOBLEBOARDER = _descriptor.Descriptor(
name='NobleBoarder',
full_name='User.Noble.NobleBoarder',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='urlList', full_name='User.Noble.NobleBoarder.urlList', index=0,
number=1, type=9, cpp_type=9, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='uri', full_name='User.Noble.NobleBoarder.uri', index=1,
number=2, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='height', full_name='User.Noble.NobleBoarder.height', index=2,
number=3, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='width', full_name='User.Noble.NobleBoarder.width', index=3,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=1014,
serialized_end=1089,
)
_USER_NOBLE = _descriptor.Descriptor(
name='Noble',
full_name='User.Noble',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='content', full_name='User.Noble.content', index=0,
number=4, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='boarder', full_name='User.Noble.boarder', index=1,
number=8, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[_USER_NOBLE_NOBLEBOARDER, ],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=945,
serialized_end=1089,
)
_USER = _descriptor.Descriptor(
name='User',
full_name='User',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='id', full_name='User.id', index=0,
number=1, type=3, cpp_type=2, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='nickname', full_name='User.nickname', index=1,
number=3, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='gender', full_name='User.gender', index=2,
number=4, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='avatarThumb', full_name='User.avatarThumb', index=3,
number=9, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='avatarMedium', full_name='User.avatarMedium', index=4,
number=10, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='avatarLarge', full_name='User.avatarLarge', index=5,
number=11, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='badge', full_name='User.badge', index=6,
number=21, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='follow', full_name='User.follow', index=7,
number=22, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='payGrade', full_name='User.payGrade', index=8,
number=23, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fansClub', full_name='User.fansClub', index=9,
number=24, type=11, cpp_type=10, label=2,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='totalPaid', full_name='User.totalPaid', index=10,
number=34, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[_USER_AVATAR, _USER_FOLLOW, _USER_PAYGRADE, _USER_HONORLEVEL, _USER_NOBLE, ],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=361,
serialized_end=1089,
)
_USERPACK.fields_by_name['user'].message_type = _USER
_BADGE_FANCLUBTEXT.containing_type = _BADGE
_BADGE.fields_by_name['fanClubText'].message_type = _BADGE_FANCLUBTEXT
_FANSCLUBPACK_FANSCLUB.containing_type = _FANSCLUBPACK
_FANSCLUBPACK.fields_by_name['fansClub'].message_type = _FANSCLUBPACK_FANSCLUB
_USER_AVATAR.containing_type = _USER
_USER_FOLLOW.containing_type = _USER
_USER_PAYGRADE.fields_by_name['badge'].message_type = _BADGE
_USER_PAYGRADE.containing_type = _USER
_USER_HONORLEVEL.fields_by_name['badge'].message_type = _BADGE
_USER_HONORLEVEL.containing_type = _USER
_USER_NOBLE_NOBLEBOARDER.containing_type = _USER_NOBLE
_USER_NOBLE.fields_by_name['boarder'].message_type = _USER_NOBLE_NOBLEBOARDER
_USER_NOBLE.containing_type = _USER
_USER.fields_by_name['avatarThumb'].message_type = _USER_AVATAR
_USER.fields_by_name['avatarMedium'].message_type = _USER_AVATAR
_USER.fields_by_name['avatarLarge'].message_type = _USER_AVATAR
_USER.fields_by_name['badge'].message_type = _BADGE
_USER.fields_by_name['follow'].message_type = _USER_FOLLOW
_USER.fields_by_name['payGrade'].message_type = _USER_PAYGRADE
_USER.fields_by_name['fansClub'].message_type = _FANSCLUBPACK
DESCRIPTOR.message_types_by_name['UserPack'] = _USERPACK
DESCRIPTOR.message_types_by_name['Badge'] = _BADGE
DESCRIPTOR.message_types_by_name['FansClubPack'] = _FANSCLUBPACK
DESCRIPTOR.message_types_by_name['User'] = _USER
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
UserPack = _reflection.GeneratedProtocolMessageType('UserPack', (_message.Message,), {
'DESCRIPTOR' : _USERPACK,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:UserPack)
})
_sym_db.RegisterMessage(UserPack)
Badge = _reflection.GeneratedProtocolMessageType('Badge', (_message.Message,), {
'FanClubText' : _reflection.GeneratedProtocolMessageType('FanClubText', (_message.Message,), {
'DESCRIPTOR' : _BADGE_FANCLUBTEXT,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:Badge.FanClubText)
})
,
'DESCRIPTOR' : _BADGE,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:Badge)
})
_sym_db.RegisterMessage(Badge)
_sym_db.RegisterMessage(Badge.FanClubText)
FansClubPack = _reflection.GeneratedProtocolMessageType('FansClubPack', (_message.Message,), {
'FansClub' : _reflection.GeneratedProtocolMessageType('FansClub', (_message.Message,), {
'DESCRIPTOR' : _FANSCLUBPACK_FANSCLUB,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:FansClubPack.FansClub)
})
,
'DESCRIPTOR' : _FANSCLUBPACK,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:FansClubPack)
})
_sym_db.RegisterMessage(FansClubPack)
_sym_db.RegisterMessage(FansClubPack.FansClub)
User = _reflection.GeneratedProtocolMessageType('User', (_message.Message,), {
'Avatar' : _reflection.GeneratedProtocolMessageType('Avatar', (_message.Message,), {
'DESCRIPTOR' : _USER_AVATAR,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:User.Avatar)
})
,
'Follow' : _reflection.GeneratedProtocolMessageType('Follow', (_message.Message,), {
'DESCRIPTOR' : _USER_FOLLOW,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:User.Follow)
})
,
'PayGrade' : _reflection.GeneratedProtocolMessageType('PayGrade', (_message.Message,), {
'DESCRIPTOR' : _USER_PAYGRADE,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:User.PayGrade)
})
,
'HonorLevel' : _reflection.GeneratedProtocolMessageType('HonorLevel', (_message.Message,), {
'DESCRIPTOR' : _USER_HONORLEVEL,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:User.HonorLevel)
})
,
'Noble' : _reflection.GeneratedProtocolMessageType('Noble', (_message.Message,), {
'NobleBoarder' : _reflection.GeneratedProtocolMessageType('NobleBoarder', (_message.Message,), {
'DESCRIPTOR' : _USER_NOBLE_NOBLEBOARDER,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:User.Noble.NobleBoarder)
})
,
'DESCRIPTOR' : _USER_NOBLE,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:User.Noble)
})
,
'DESCRIPTOR' : _USER,
'__module__' : 'XiguaUser_pb2'
# @@protoc_insertion_point(class_scope:User)
})
_sym_db.RegisterMessage(User)
_sym_db.RegisterMessage(User.Avatar)
_sym_db.RegisterMessage(User.Follow)
_sym_db.RegisterMessage(User.PayGrade)
_sym_db.RegisterMessage(User.HonorLevel)
_sym_db.RegisterMessage(User.Noble)
_sym_db.RegisterMessage(User.Noble.NobleBoarder)
# @@protoc_insertion_point(module_scope)

143
Xigua_pb2.py Normal file
View File

@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: Xigua.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='Xigua.proto',
package='',
syntax='proto2',
serialized_options=None,
serialized_pb=b'\n\x0bXigua.proto\"\x9a\x01\n\tXiguaLive\x12\x1d\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x0f.XiguaLive.Data\x12\x0e\n\x06\x63ursor\x18\x02 \x02(\t\x12\x16\n\x0e\x66\x65tch_interval\x18\x03 \x01(\x05\x12\x0b\n\x03now\x18\x04 \x01(\x05\x12\x14\n\x0cinternal_ext\x18\x05 \x02(\t\x1a#\n\x04\x44\x61ta\x12\x0e\n\x06method\x18\x01 \x02(\t\x12\x0b\n\x03raw\x18\x02 \x02(\x0c'
)
_XIGUALIVE_DATA = _descriptor.Descriptor(
name='Data',
full_name='XiguaLive.Data',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='method', full_name='XiguaLive.Data.method', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='raw', full_name='XiguaLive.Data.raw', index=1,
number=2, type=12, cpp_type=9, label=2,
has_default_value=False, default_value=b"",
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=135,
serialized_end=170,
)
_XIGUALIVE = _descriptor.Descriptor(
name='XiguaLive',
full_name='XiguaLive',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='data', full_name='XiguaLive.data', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='cursor', full_name='XiguaLive.cursor', index=1,
number=2, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fetch_interval', full_name='XiguaLive.fetch_interval', index=2,
number=3, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='now', full_name='XiguaLive.now', index=3,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='internal_ext', full_name='XiguaLive.internal_ext', index=4,
number=5, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[_XIGUALIVE_DATA, ],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=16,
serialized_end=170,
)
_XIGUALIVE_DATA.containing_type = _XIGUALIVE
_XIGUALIVE.fields_by_name['data'].message_type = _XIGUALIVE_DATA
DESCRIPTOR.message_types_by_name['XiguaLive'] = _XIGUALIVE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
XiguaLive = _reflection.GeneratedProtocolMessageType('XiguaLive', (_message.Message,), {
'Data' : _reflection.GeneratedProtocolMessageType('Data', (_message.Message,), {
'DESCRIPTOR' : _XIGUALIVE_DATA,
'__module__' : 'Xigua_pb2'
# @@protoc_insertion_point(class_scope:XiguaLive.Data)
})
,
'DESCRIPTOR' : _XIGUALIVE,
'__module__' : 'Xigua_pb2'
# @@protoc_insertion_point(class_scope:XiguaLive)
})
_sym_db.RegisterMessage(XiguaLive)
_sym_db.RegisterMessage(XiguaLive.Data)
# @@protoc_insertion_point(module_scope)

0
access_token Normal file
View File

601
api.py
View File

@ -1,206 +1,481 @@
# coding=utf-8
import sys
from MemberMsg import MemberMsg
from User import User
from Gift import Gift
from Chat import Chat
from Lottery import Lottery
from Struct.MemberMsg import MemberMsg
from Struct.User import User
from Struct.Gift import Gift
from Struct.Chat import Chat
import requests
import time
from datetime import datetime, timedelta
from Xigua_pb2 import XiguaLive
from XiguaMessage_pb2 import FansClubMessage, SocialMessage
s = requests.Session()
DEBUG: bool = False
DEBUG = False
# 自己抓的自己设备的参数,建议开发者自己抓一个长期使用
# 如果有大佬破解初次激活设备时的数据也行,可以自己生成一堆用
CUSTOM_INFO = {
'iid': "3993882704224472",
'device_id': "71008241150",
'cdid': "f93b3708-3fec-498f-9080-723a5679f4c0",
'openudid': "4aeb1e2b627697be",
# 'aid': "32", # 是一个不变的值
'channel': "xiaomi",
'device_brand': "Xiaomi",
'device_type': "MI+9",
'os_api': "29",
'os_version': "10",
'abi': "armeabi-v7a",
'dpi': "480",
'resolution': "1080*2217",
'rom_version': "miui_V12_V12.0.6.0.QFACNXM",
}
VERSION_INFO = {
'app_name': "video_article",
'version_code': "966",
'version_code_full': "96615",
'version_name': "9.6.6",
'ab_version': "668851,2678488,668858,2678385,668859,2678471,668856,2678470,668855,2678439,668854,994679,"
"2678460,2713070,2738381,2744004,668853,2678466,668852,2678435,2625016",
'manifest_version_code': "566",
'tma_jssdk_version': "2010000",
'oaid': "693ea85657ef38ca",
}
COMMON_GET_PARAM = (
"&iid={iid}&device_id={device_id}&ac=wifi&channel={channel}&aid=32&app_name={app_name}&version_code={version_code}&"
"version_name={version_name}&device_platform=android&ab_version={ab_version}&ssmix=a&device_type={device_type}&"
"device_brand={device_brand}&language=zh&os_api={os_api}&os_version={os_version}&openudid={openudid}&"
"manifest_version_code={manifest_version_code}&resolution={resolution}&dpi={dpi}&"
"update_version_code={version_code_full}&_rticket={{TIMESTAMP:.0f}}&"
"cdid_ts={{TIMESTAMP:.0f}}&host_abi={abi}&tma_jssdk_version={tma_jssdk_version}&"
"rom_version={rom_version}&cdid={cdid}&oaid={oaid}").format_map({**VERSION_INFO, **CUSTOM_INFO})
WEBCAST_GET_PARAMS = "webcast_sdk_version=1990&webcast_language=zh&webcast_locale=zh_CN&webcast_gps_access=1"
ROOM_ENTER_POST_PARAMS = (
"room_id={roomId}&hold_living_room=1&is_login=0&enter_from_uid_by_shared=0&video_id=0&"
"scenario=0&enter_type=click&enter_source=click_pgc_WITHIN_pgc-head_portrait&live_room_mode=0")
SEARCH_USER_API = (
"https://search5-search-lq.ixigua.com/video/app/search/live/?format=json&keyword_type=search_subtab_switch"
"&fss=search_subtab_switch&target_channel=video_search&keyword_type=search_subtab_switch&offset=0&count=10"
"&search_sug=1&forum=1&is_native_req=0&m_tab=video&pd=user&tab=user&_s_tma=SEARCH_STANDARD.list.fe_get_data"
'&_s_page_sub_route=/&_s_ec={{"filterDataType":[],"reserveFilterBar":true}}&__use_xigua_native_bridge_fetch__=1'
'&ab_param={{"is_show_filter_feature": 1, "is_hit_new_ui": 1}}'
"&search_start_time={TIMESTAMP:.0f}&from=live&en_qc=1&pd=xigua_live&ssmix=a{COMMON}&keyword={keyword}")
USER_INFO_API = "https://ib-lq.snssdk.com/video/app/user/userhome/v8/?to_user_id={userId}{COMMON}"
ROOM_INFO_API = "https://webcast5-normal-c-lq.ixigua.com/webcast/room/enter/?{WEBCAST}{COMMON}"
DANMAKU_GET_API = "https://webcast5-normal-c-lq.ixigua.com/webcast/im/fetch/?{WEBCAST}{COMMON}"
GIFT_DATA_API = ("https://webcast5-normal-c-hl.ixigua.com/webcast/gift/list/?room_id={roomId}&to_room_id={roomId}&"
"gift_scene=1&fetch_giftlist_from=2&current_network_quality_info={{}}&"
"{WEBCAST}{COMMON}")
COMMON_HEADERS = {
"x-vc-bdturing-sdk-version": "2.0.1",
"sdk-version": '2',
"passport-sdk-version": "21",
"User-Agent": "Dalvik/2.1.0 (Linux; U; Android 10; MI 9 MIUI/V12.0.6.0.QFACNXM) VideoArticle/9.6.6 "
"cronet/TTNetVersion:4b936afe 2021-01-13 QuicVersion:47946d2a 2020-10-14",
"X-SS-STUB": "74103A7F40FDC66E0675705DCA2C3A77",
"X-SS-DP": "32",
"Accept-Encoding": "gzip, deflate"
}
class XiGuaLiveApi:
isLive: bool = False
isValidRoom: bool = False
_rawRoomInfo = {}
name: str = ""
roomID: int = 0
roomTitle: str = ""
roomLiver: User = None
roomPopularity: int = 0
_cursor:str = "0"
_updRoomCount:int = 0
lottery:Lottery = None
def __init__(self, name: str = "永恒de草薙"):
self.name = name
def __init__(self, name=None):
"""
Api类
Init Function
:param name: class:str|User: 主播名
"""
if name is None:
name = "永恒de草薙"
self.broadcaster = None
self.isValidUser = False
self.name = str(name)
if type(name) == User:
self.broadcaster = name
self.name = name.name
elif str(name).isdigit():
self.broadcaster = User()
self.isValidUser = True
self.broadcaster.ID = int(name)
else:
self.name = str(name)
self.isLive = False
self._rawRoomInfo = {}
self.roomID = 0
self.roomPopularity = 0
self.s = requests.session()
self.s.headers.update(COMMON_HEADERS)
self._updRoomAt = datetime.fromtimestamp(0)
self.updRoomInfo()
self._ext = ""
self._cursor = "0"
def _updateRoomInfo(self, json):
if "extra" in json:
if "member_count" in json["extra"] and json["extra"]["member_count"] > 0:
self.roomPopularity = json["extra"]["member_count"]
elif "data" in json:
if "popularity" in json["data"]:
self.roomPopularity = json["data"]["popularity"]
def _updateRoomPopularity(self, _data):
"""
更新房间人气的方法
Update Room Popularity
:param _data: Received Message
"""
if "extra" in _data:
if "member_count" in _data["extra"] and _data["extra"]["member_count"] > 0:
self.roomPopularity = _data["extra"]["member_count"]
if "data" in _data:
if "popularity" in _data["data"]:
self.roomPopularity = _data["data"]["popularity"]
def apiChangedError(self, msg: str, *args):
def getJson(self, url, **kwargs):
if "timeout" not in kwargs:
kwargs["timeout"] = 10
try:
p = self.s.get(url, **kwargs)
except Exception as e:
print("网络请求失败")
if DEBUG:
print("GET")
print("URL", url)
print("ERR ", e.__str__())
return None
try:
return p.json()
except Exception as e:
print("解析请求失败")
if DEBUG:
print("GET JSON")
print("URL", url)
print("CNT", p.text)
print("ERR ", e.__str__())
return None
def postJson(self, url, data, **kwargs):
if "timeout" not in kwargs:
kwargs["timeout"] = 10
try:
p = self.s.post(url, data=data, **kwargs)
except Exception as e:
print("网络请求失败")
if DEBUG:
print("POST")
print("URL", url)
print("DATA", data)
print("ERR ", e.__str__())
return None
try:
return p.json()
except Exception as e:
print("解析请求失败")
if DEBUG:
print("POST JSON")
print("URL", url)
print("DATA", data)
print("CNT", p.text)
print("HDR", p.headers)
print("ERR ", e.__str__())
return None
@staticmethod
def apiChangedError(msg: str, *args):
"""
API发生更改时的提示
Warning while Detected Api has Changed
:param msg: 提示信息
:param args: DEBUG模式下显示更多信息
"""
print(msg)
print(*args)
if DEBUG:
print(*args)
def onPresent(self, gift: Gift):
"""
礼物连击中的消息
Message On Sending Presents
:param gift: Struct of Gift Message
"""
print("礼物连击 :", gift)
def onPresentEnd(self, gift: Gift):
"""
礼物送完了的提示信息
Message On Finished Send Present
:param gift: Struct of Gift Message
"""
print("感谢", gift)
def onAd(self, i):
"""
全局广播
All Channel Broadcasting Message( Just An Ad )
:param i: JSON DATA if you wanna using it
"""
# print(i)
pass
def onChat(self, chat: Chat):
"""
聊天信息
On Chatting
:param chat: Struct of Chat Message
"""
if not chat.isFiltered:
print(chat)
def onEnter(self, msg: MemberMsg):
"""
进入房间消息
On Entering Room
:param msg: Struct of Member Message
"""
print("提示 :", msg)
def onSubscribe(self, user: User):
"""
关注主播时的消息
On Subscribe
:param user: Struct of User Message
"""
print("消息 :", user, "关注了主播")
def onJoin(self, user: User):
"""
加入粉丝团消息
:param user:
"""
print("欢迎", user, "加入了粉丝团")
def onMessage(self, msg: str):
"""
系统消息
:param msg:
"""
print("消息 :", msg)
def onLike(self, user: User):
"""
点击喜欢的消息
On Like
:param user:
"""
print("用户", user, "点了喜欢")
def onLeave(self, json: any):
"""
下播消息
On Liver Leave
:param json:
"""
print("消息 :", "主播离开了")
self.updRoomInfo()
def onLottery(self, i:Lottery):
print("中奖消息 :", i)
def _checkUsernameIsMatched(self, compare=None):
"""
验证主播名字是自己想要的那个
Check name matched
:return: bool: 是否匹配
"""
if compare is None:
compare = self.broadcaster
if self.name is None or compare is None:
return False
return self.name == compare.__str__() or compare.__repr__() in self.name or self.name in compare.__repr__()
def updRoomInfo(self):
if self.isLive:
p = s.post("https://i.snssdk.com/videolive/room/enter?version_code=730"
"&device_platform=android",
data="room_id={roomID}&version_code=730"
"&device_platform=android".format(roomID=self.roomID),
headers={"Content-Type":"application/x-www-form-urlencoded"})
d = p.json()
self.isValidRoom = d["base_resp"]["status_code"] == 0
if d["base_resp"]["status_code"] != 0:
return False
if "room" not in d and d["room"] is None:
self.apiChangedError("Api发生改变请及时联系我")
return False
self._rawRoomInfo = d["room"]
self.isLive = d["room"]["status"] == 2
self.roomLiver = User(d)
self.roomTitle = d["room"]["title"]
self.roomPopularity = d["room"]["user_count"]
l = Lottery(d)
if l.isActive:
self.lottery = l
return True
else:
p = s.get("https://security.snssdk.com/video/app/search/live/?version_code=730&device_platform=android"
"&format=json&keyword={}".format(self.name))
d = p.json()
if "data" in d and d["data"] is not None:
for i in d["data"]:
if i["block_type"] != 0:
continue
if len(i["cells"]) == 0:
return
self.isValidRoom = True
self.isLive = i["cells"][0]["anchor"]["user_info"]["is_living"]
self.roomID = int(i["cells"][0]["anchor"]["room_id"])
self.roomLiver = User(i["cells"][0])
if self.isLive:
return self.updRoomInfo()
else:
return False
@staticmethod
def findRoomByUserId(userId:int):
p = s.get("https://live.ixigua.com/api/room?anchorId={room}".format(room=userId))
if DEBUG:
print(p.text)
d = p.json()
if "data" not in d or "title" not in d["data"] or "id" not in d["data"]:
XiGuaLiveApi.apiChangedError("无法获取RoomID请与我联系")
return XiGuaLiveApi()
return XiGuaLiveApi(d["data"]["id"])
@staticmethod
def searchLive(keyword):
ret = []
p = s.get("https://security.snssdk.com/video/app/search/live/?version_code=730&device_platform=android"
"&format=json&keyword={}".format(keyword))
d = p.json()
if "data" in d:
def _forceSearchUser(self):
"""
搜索主播名
:return:
"""
_formatData = {"TIMESTAMP": time.time() * 1000, "keyword": self.name}
_COMMON = COMMON_GET_PARAM.format_map(_formatData)
_formatData['COMMON'] = _COMMON
_url = SEARCH_USER_API.format_map(_formatData)
d = self.getJson(_url)
if d is None:
print("搜索接口请求失败")
return False
self.broadcaster = None
self.isValidUser = False
self.isLive = False
if "data" in d and d["data"] is not None:
for i in d["data"]:
if i["block_type"] != 0:
if self.broadcaster is not None:
break
if i["card_type"] != 3:
continue
for _i in i["cells"]:
ret.append(_i["room"])
return ret
if "search_data" not in i or len(i["search_data"]) == 0:
break
for _j in i["search_data"]:
if "room" in _j:
_user = User(_j["room"])
self.roomID = _j["room"]["room_id"]
self.isLive = _j["room"]["is_living"]
if self._checkUsernameIsMatched(_user):
self.isValidUser = True
self.broadcaster = _user
break
self._updRoomAt = datetime.now()
return self._updateUserInfo()
def _updateUserInfo(self):
"""
获取用户信息
:return:
"""
if self.broadcaster is None:
self.isValidUser = False
return False
self.isLive = False
_formatData = {"TIMESTAMP": time.time() * 1000, "userId": self.broadcaster.ID}
_COMMON = COMMON_GET_PARAM.format_map(_formatData)
_formatData['COMMON'] = _COMMON
_url = USER_INFO_API.format_map(_formatData)
d = self.getJson(_url)
if d is None:
print("获取用户信息失败")
return False
self.isValidUser = d["status"] == 0
_d = d.get('data', {})
if "user_home_info" not in _d and _d['user_home_info']['user_info'] is None:
self.apiChangedError("Api发生改变请及时联系我", d)
return False
self._updRoomAt = datetime.now()
self.broadcaster = User(_d['user_home_info'])
if not self._checkUsernameIsMatched():
self.isLive = False
return False
self.isLive = 'user_live_info_list' in _d
if self.isLive and len(_d['user_live_info_list']) != 0:
# 既然有长度,默认个0应该没事
self._rawRoomInfo = _d['user_live_info_list'][0]['live_info']
else:
self.isLive = False
if self.isLive:
self.roomID = self._rawRoomInfo['room_id']
return self._getRoomInfo(True)
return self.isLive
def _getRoomInfo(self, force=False):
if self.roomID == 0 or not self.roomID:
self.isLive = False
return False
if (self._updRoomAt + timedelta(minutes=3) > datetime.now()) and not force:
return self.isLive
_formatData = {"TIMESTAMP": time.time() * 1000}
_COMMON = COMMON_GET_PARAM.format_map(_formatData)
_formatData['COMMON'] = _COMMON
_formatData['WEBCAST'] = WEBCAST_GET_PARAMS
_url = ROOM_INFO_API.format_map(_formatData)
_postData = ROOM_ENTER_POST_PARAMS.format_map({'roomId': self.roomID})
_headers = {"response-format": "json",
'Connection': "keep-alive",
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Content-Length': str(len(_postData)),
**COMMON_HEADERS,
}
d = self.postJson(_url, _postData, headers=_headers)
self.isLive = False
if d is None:
print("获取房间信息接口请求失败")
return False
if d["status_code"] != 0:
print("接口提示:【{}".format(d["data"]["message"]))
return False
self._rawRoomInfo = d["data"]
self.isLive = self._rawRoomInfo["status"] == 2
self._updRoomAt = datetime.now()
self._updateRoomPopularity(d)
return self.isLive
def updRoomInfo(self, force=False):
"""
更新房间信息
:return:
"""
if not force and (self._updRoomAt + timedelta(minutes=2) > datetime.now()):
return self.isLive
if not self.isValidUser:
return self._forceSearchUser()
elif not self.isLive:
return self._updateUserInfo()
else:
return self._getRoomInfo(force)
def updGiftInfo(self):
self.updRoomInfo()
_formatData = {"TIMESTAMP": time.time() * 1000, "roomId": self.roomID}
_COMMON = COMMON_GET_PARAM.format_map(_formatData)
_formatData['COMMON'] = _COMMON
_formatData['WEBCAST'] = WEBCAST_GET_PARAMS
_url = GIFT_DATA_API.format_map(_formatData)
d = self.getJson(_url)
if d is None or d["status_code"] != 0:
return "异常"
elif 'pages' in d["data"]:
for _page in d["data"]['pages']:
if 'gifts' in _page:
for _gift in _page['gifts']:
Gift.addGift(_gift)
return len(Gift.giftList)
def getDanmaku(self):
if not self.isValidRoom:
self.updRoomInfo()
"""
获取弹幕
"""
self.updRoomInfo()
if not self.isLive:
return
p = s.get("https://i.snssdk.com/videolive/im/get_msg?cursor={cursor}&room_id={roomID}"
"&version_code=730&device_platform=android".format(
roomID=self.roomID,
cursor=self._cursor
))
d = p.json()
if "data" not in d or "extra" not in d or "cursor" not in d["extra"]:
if DEBUG:
print(d)
self.apiChangedError("数据结构改变,请与我联系")
_formatData = {"TIMESTAMP": time.time() * 1000, "roomId": self.roomID}
_COMMON = COMMON_GET_PARAM.format_map(_formatData)
_formatData['COMMON'] = _COMMON
_formatData['WEBCAST'] = WEBCAST_GET_PARAMS
_url = DANMAKU_GET_API.format_map(_formatData)
p = self.s.post(_url, data="room_id={roomId}&fetch_rule=0&cursor={cursor}&"
"resp_content_type=protobuf&live_id=3&user_id=0&identity=audience&"
"last_rtt=85&internal_ext={ext}"
.format_map({"roomId":self.roomID, "cursor": self._cursor, "ext": self._ext}),
headers={"Content-Type": "application/x-www-form-urlencoded"})
if p.status_code != 200:
return
else:
self._cursor = d["extra"]["cursor"]
if DEBUG:
print("Cursor", self._cursor)
for i in d['data']:
if DEBUG:
print(i)
if "common" not in i and "method" not in i["common"]:
continue
if i["common"]['method'] == "VideoLivePresentMessage":
self.onPresent(Gift(i))
elif i["common"]['method'] == "VideoLivePresentEndTipMessage":
self.onPresentEnd(Gift(i))
elif i["common"]['method'] == "VideoLiveRoomAdMessage":
self.onAd(i)
elif i["common"]['method'] == "VideoLiveChatMessage":
self.onChat(Chat(i, self.lottery))
elif i["common"]['method'] == "VideoLiveMemberMessage":
self._updateRoomInfo(i)
self.onEnter(MemberMsg(i))
elif i["common"]['method'] == "VideoLiveSocialMessage":
self.onSubscribe(User(i))
elif i["common"]['method'] == "VideoLiveJoinDiscipulusMessage":
self.onJoin(User(i))
elif i["common"]['method'] == "VideoLiveControlMessage":
print("消息:", "主播离开一小会")
elif i["common"]['method'] == "VideoLiveDiggMessage":
self.onLike(User(i))
data = XiguaLive()
data.ParseFromString(p.content)
self._cursor = data.cursor
self._ext = data.internal_ext
for _each in data.data:
if _each.method == "WebcastGiftMessage":
_gift = Gift(_each.raw)
if _gift.isAnimate() or _gift.isFinished:
self.onPresentEnd(_gift)
else:
self.onPresent(_gift)
elif _each.method == "WebcastChatMessage":
_chat = Chat(_each.raw)
self.onChat(_chat)
elif _each.method == "WebcastControlMessage":
# 下播的时候会有个这个
self.onLeave(None)
elif _each.method == "WebcastSocialMessage":
_socialMessage = SocialMessage()
_socialMessage.ParseFromString(_each.raw)
_user = User(_socialMessage.user)
self.onSubscribe(_user)
elif _each.method == "WebcastFansclubMessage":
_fansClubMessage = FansClubMessage()
_fansClubMessage.ParseFromString(_each.raw)
# 升级是1加入是2
if _fansClubMessage.type == 2:
_user = User(_fansClubMessage.user)
self.onJoin(_user)
else:
self.onMessage(_fansClubMessage.content)
else:
pass
if self.lottery is None or self.lottery.ID == 0:
self.lottery = Lottery(i)
self._updRoomCount += 1
if self.lottery is not None and self.lottery.ID != 0:
self.lottery.update()
if self.lottery.isFinished:
self.onLottery(self.lottery)
self.lottery = None
if self._updRoomCount > 120 or len(d['data']) == 0:
self.updRoomInfo()
self._updRoomCount = 0
return
@property
def updateAt(self):
return self._updRoomAt
def public_hello():
print("西瓜直播弹幕助手 by JerryYan")
print("接口版本:{version_name}({version_code_full})".format_map(VERSION_INFO))
if __name__ == "__main__":
@ -209,25 +484,37 @@ if __name__ == "__main__":
if sys.argv[-1] == "d":
DEBUG = True
name = sys.argv[1]
print("西瓜直播弹幕助手 by JerryYan")
public_hello()
print("搜索【", name, "", end="\t", flush=True)
api = XiGuaLiveApi(name)
if not api.isValidRoom:
print(api.roomID)
input("房间不存在")
if not api.isValidUser:
input("用户不存在")
sys.exit()
print("进入", api.roomLiver, "的直播间")
print("OK")
print(api.broadcaster.__repr__())
print("更新房间信息,请稍后", end="\t", flush=True)
if api.updRoomInfo(True):
print("OK")
else:
print("FAIL")
print("更新房间礼物信息", end="\t", flush=True)
__res = api.updGiftInfo()
if __res < 0:
print("FAIL")
else:
print('OK\n礼物种数:', __res)
print("=" * 30)
while True:
if api.isLive:
try:
api.getDanmaku()
time.sleep(1)
except requests.exceptions.BaseHTTPError:
print("网络错误,请确认网络")
time.sleep(5)
except Exception as e:
print(e)
time.sleep(1)
# except Exception as e:
# print(e)
else:
print("主播未开播等待1分钟后重试")
time.sleep(60)
api.updRoomInfo()
api.updRoomInfo(True)

View File

@ -1,497 +1,121 @@
# coding=utf-8
import os
import re
import shutil
from datetime import datetime
import rsa
import math
import base64
import hashlib
import requests
from urllib import parse
from config import config
class VideoPart:
def __init__(self, path, title='', desc=''):
self.path = path
self.title = title
self.desc = desc
class Bilibili:
def __init__(self, cookie=None):
self.files = []
self.videos = []
self.session = requests.session()
if cookie:
self.session.headers["cookie"] = cookie
self.csrf = re.search('bili_jct=(.*?);', cookie).group(1)
self.mid = re.search('DedeUserID=(.*?);', cookie).group(1)
self.session.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
self.session.headers['Referer'] = 'https://space.bilibili.com/{mid}/#!/'.format(mid=self.mid)
# session.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36'
# session.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
def login(self, user, pwd):
"""
:param user: username
:type user: str
:param pwd: password
:type pwd: str
:return: if success return True
else return msg json
"""
APPKEY = '1d8b6e7d45233436'
ACTIONKEY = 'appkey'
BUILD = 520001
DEVICE = 'android'
MOBI_APP = 'android'
PLATFORM = 'android'
APPSECRET = '560c52ccd288fed045859ed18bffd973'
def md5(s):
h = hashlib.md5()
h.update(s.encode('utf-8'))
return h.hexdigest()
def sign(s):
"""
:return: return sign
"""
return md5(s + APPSECRET)
def signed_body(body):
"""
:return: body which be added sign
"""
if isinstance(body, str):
return body + '&sign=' + sign(body)
elif isinstance(body, dict):
ls = []
for k, v in body.items():
ls.append(k + '=' + v)
body['sign'] = sign('&'.join(ls))
return body
def getkey():
"""
:return: hash, key
"""
r = self.session.post(
'https://passport.bilibili.com/api/oauth2/getKey',
signed_body({'appkey': APPKEY}),
)
# {"ts":1544152439,"code":0,"data":{"hash":"99c7573759582e0b","key":"-----BEGIN PUBLIC----- -----END PUBLIC KEY-----\n"}}
json = r.json()
data = json['data']
return data['hash'], data['key']
def cnn_captcha(img):
url = "http://47.95.255.188:5000/code"
data = {"image": img}
r = requests.post(url, data=data)
return r.text
self.session.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
h, k = getkey()
pwd = base64.b64encode(
rsa.encrypt(
(h + pwd).encode('utf-8'),
rsa.PublicKey.load_pkcs1_openssl_pem(k.encode())
)
)
user = parse.quote_plus(user)
pwd = parse.quote_plus(pwd)
r = self.session.post(
'https://passport.bilibili.com/api/v2/oauth2/login',
signed_body('appkey={appkey}&password={password}&username={username}'
.format(appkey=APPKEY, username=user, password=pwd))
)
try:
json = r.json()
except:
return r.text
if json['code'] == -105:
# need captcha
self.session.headers['cookie'] = 'sid=xxxxxxxx'
r = self.session.get('https://passport.bilibili.com/captcha')
captcha = cnn_captcha(base64.b64encode(r.content))
r = self.session.post(
'https://passport.bilibili.com/api/v2/oauth2/login',
signed_body('actionKey={actionKey}&appkey={appkey}&build={build}&captcha={captcha}&device={device}'
'&mobi_app={mobi_app}&password={password}&platform={platform}&username={username}'
.format(actionKey=ACTIONKEY,
appkey=APPKEY,
build=BUILD,
captcha=captcha,
device=DEVICE,
mobi_app=MOBI_APP,
password=pwd,
platform=PLATFORM,
username=user)),
)
json = r.json()
if json['code'] is not 0:
return r.text
ls = []
for item in json['data']['cookie_info']['cookies']:
ls.append(item['name'] + '=' + item['value'])
cookie = '; '.join(ls)
self.session.headers["cookie"] = cookie
self.csrf = re.search('bili_jct=(.*?);', cookie).group(1)
self.mid = re.search('DedeUserID=(.*?);', cookie).group(1)
self.session.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
self.session.headers['Referer'] = 'https://space.bilibili.com/{mid}/#!/'.format(mid=self.mid)
return True
def upload(self,
parts,
title,
tid,
tag,
desc,
source='',
cover='',
no_reprint=1,
):
"""
:param parts: e.g. VideoPart('part path', 'part title', 'part desc'), or [VideoPart(...), VideoPart(...)]
:type parts: VideoPart or list<VideoPart>
:param title: video's title
:type title: str
:param tid: video type, see: https://member.bilibili.com/x/web/archive/pre
or https://github.com/uupers/BiliSpider/wiki/%E8%A7%86%E9%A2%91%E5%88%86%E5%8C%BA%E5%AF%B9%E5%BA%94%E8%A1%A8
:type tid: int
:param tag: video's tag
:type tag: list<str>
:param desc: video's description
:type desc: str
:param source: (optional) 转载地址
:type source: str
:param cover: (optional) cover's URL, use method *cover_up* to get
:type cover: str
:param no_reprint: (optional) 0=可以转载, 1=禁止转载(default)
:type no_reprint: int
"""
self.preUpload(parts)
self.finishUpload(title, tid, tag, desc, source, cover, no_reprint)
def preUpload(self, parts):
"""
:param parts: e.g. VideoPart('part path', 'part title', 'part desc'), or [VideoPart(...), VideoPart(...)]
:type parts: VideoPart or list<VideoPart>
"""
self.session.headers['Content-Type'] = 'application/json; charset=utf-8'
if not isinstance(parts, list):
parts = [parts]
for part in parts:
filepath = part.path
filename = os.path.basename(filepath)
filesize = os.path.getsize(filepath)
self.files.append(part)
r = self.session.get('https://member.bilibili.com/preupload?'
'os=upos&upcdn=ws&name={name}&size={size}&r=upos&profile=ugcupos%2Fyb&ssl=0'
.format(name=filename, size=filesize))
"""return example
{
"upos_uri": "upos://ugc/i181012ws18x52mti3gg0h33chn3tyhp.mp4",
"biz_id": 58993125,
"endpoint": "//upos-hz-upcdnws.acgvideo.com",
"endpoints": [
"//upos-hz-upcdnws.acgvideo.com",
"//upos-hz-upcdntx.acgvideo.com"
],
"chunk_retry_delay": 3,
"chunk_retry": 200,
"chunk_size": 4194304,
"threads": 2,
"timeout": 900,
"auth": "os=upos&cdn=upcdnws&uid=&net_state=4&device=&build=&os_version=&ak=×tamp=&sign=",
"OK": 1
}
"""
json = r.json()
upos_uri = json['upos_uri']
endpoint = json['endpoint']
auth = json['auth']
biz_id = json['biz_id']
chunk_size = json['chunk_size']
self.session.headers['X-Upos-Auth'] = auth # add auth header
r = self.session.post(
'https:{}/{}?uploads&output=json'.format(endpoint, upos_uri.replace('upos://', '')))
# {"upload_id":"72eb747b9650b8c7995fdb0efbdc2bb6","key":"\/i181012ws2wg1tb7tjzswk2voxrwlk1u.mp4","OK":1,"bucket":"ugc"}
json = r.json()
upload_id = json['upload_id']
with open(filepath, 'rb') as f:
chunks_num = math.ceil(filesize / chunk_size)
chunks_index = -1
while True:
chunks_data = f.read(chunk_size)
if not chunks_data:
break
chunks_index += 1 # start with 0
r = self.session.put('https:{endpoint}/{upos_uri}?'
'partNumber={part_number}&uploadId={upload_id}&chunk={chunk}&chunks={chunks}&size={size}&start={start}&end={end}&total={total}'
.format(endpoint=endpoint,
upos_uri=upos_uri.replace('upos://', ''),
part_number=chunks_index + 1, # starts with 1
upload_id=upload_id,
chunk=chunks_index,
chunks=chunks_num,
size=len(chunks_data),
start=chunks_index * chunk_size,
end=chunks_index * chunk_size + len(chunks_data),
total=filesize,
),
chunks_data,
)
print('{} : UPLOAD {}/{}'.format(datetime.strftime(datetime.now(), "%y%m%d %H%M"), chunks_index,
chunks_num), r.text)
# NOT DELETE! Refer to https://github.com/comwrg/bilibiliupload/issues/15#issuecomment-424379769
self.session.post('https:{endpoint}/{upos_uri}?'
'output=json&name={name}&profile=ugcupos%2Fyb&uploadId={upload_id}&biz_id={biz_id}'
.format(endpoint=endpoint,
upos_uri=upos_uri.replace('upos://', ''),
name=filename,
upload_id=upload_id,
biz_id=biz_id,
),
{"parts": [{"partNumber": i, "eTag": "etag"} for i in range(1, chunks_num + 1)]},
)
self.videos.append({'filename': upos_uri.replace('upos://ugc/', '').split('.')[0],
'title': part.title,
'desc': part.desc})
def finishUpload(self,
title,
tid,
tag,
desc,
source='',
cover='',
no_reprint=1,
):
"""
:param title: video's title
:type title: str
:param tid: video type, see: https://member.bilibili.com/x/web/archive/pre
or https://github.com/uupers/BiliSpider/wiki/%E8%A7%86%E9%A2%91%E5%88%86%E5%8C%BA%E5%AF%B9%E5%BA%94%E8%A1%A8
:type tid: int
:param tag: video's tag
:type tag: list<str>
:param desc: video's description
:type desc: str
:param source: (optional) 转载地址
:type source: str
:param cover: (optional) cover's URL, use method *cover_up* to get
:type cover: str
:param no_reprint: (optional) 0=可以转载, 1=禁止转载(default)
:type no_reprint: int
"""
self.session.headers['Content-Type'] = 'application/json; charset=utf-8'
copyright = 2 if source else 1
r = self.session.post('https://member.bilibili.com/x/vu/web/add?csrf=' + self.csrf,
json={
"copyright": copyright,
"source": source,
"title": title,
"tid": tid,
"tag": ','.join(tag),
"no_reprint": no_reprint,
"desc": desc,
"cover": cover,
"mission_id": 0,
"order_id": 0,
"videos": self.videos}
)
print(r.text)
if config["mv"]:
for _p in self.files:
shutil.move(_p.path, config["mtd"])
elif config["del"]:
for _p in self.files:
os.remove(_p.path)
def appendUpload(self,
aid,
parts,
title="",
tid="",
tag="",
desc="",
source='',
cover='',
no_reprint=1,
):
"""
:param aid: just aid
:type aid: int
:param parts: e.g. VideoPart('part path', 'part title', 'part desc'), or [VideoPart(...), VideoPart(...)]
:type parts: VideoPart or list<VideoPart>
:param title: video's title
:type title: str
:param tid: video type, see: https://member.bilibili.com/x/web/archive/pre
or https://github.com/uupers/BiliSpider/wiki/%E8%A7%86%E9%A2%91%E5%88%86%E5%8C%BA%E5%AF%B9%E5%BA%94%E8%A1%A8
:type tid: int
:param tag: video's tag
:type tag: list<str>
:param desc: video's description
:type desc: str
:param source: (optional) 转载地址
:type source: str
:param cover: (optional) cover's URL, use method *cover_up* to get
:type cover: str
:param no_reprint: (optional) 0=可以转载, 1=禁止转载(default)
:type no_reprint: int
"""
self.session.headers['Content-Type'] = 'application/json; charset=utf-8'
p = self.session.get("https://member.bilibili.com/x/web/archive/view?aid={}&history=".format(aid))
j = p.json()
if len(self.videos) == 0:
for i in j['data']['videos']:
self.videos.append({'filename': i['filename'],
'title': i["title"],
'desc': i["desc"]})
if (title == ""): title = j["data"]["archive"]['title']
if (tag == ""): tag = j["data"]["archive"]['tag']
if (no_reprint == ""): no_reprint = j["data"]["archive"]['no_reprint']
if (desc == ""): desc = j["data"]["archive"]['desc']
if (source == ""): source = j["data"]["archive"]['source']
if (tid == ""): tid = j["data"]["archive"]['tid']
self.preUpload(parts)
self.editUpload(aid, title, tid, tag, desc, source, cover, no_reprint)
def editUpload(self,
aid,
title,
tid,
tag,
desc,
source='',
cover='',
no_reprint=1,
):
"""
:param aid: just aid
:type aid: int
:param parts: e.g. VideoPart('part path', 'part title', 'part desc'), or [VideoPart(...), VideoPart(...)]
:type parts: VideoPart or list<VideoPart>
:param title: video's title
:type title: str
:param tid: video type, see: https://member.bilibili.com/x/web/archive/pre
or https://github.com/uupers/BiliSpider/wiki/%E8%A7%86%E9%A2%91%E5%88%86%E5%8C%BA%E5%AF%B9%E5%BA%94%E8%A1%A8
:type tid: int
:param tag: video's tag
:type tag: list<str>
:param desc: video's description
:type desc: str
:param source: (optional) 转载地址
:type source: str
:param cover: (optional) cover's URL, use method *cover_up* to get
:type cover: str
:param no_reprint: (optional) 0=可以转载, 1=禁止转载(default)
:type no_reprint: int
"""
copyright = 2 if source else 1
r = self.session.post('https://member.bilibili.com/x/vu/web/edit?csrf=' + self.csrf,
json={
"aid": aid,
"copyright": copyright,
"source": source,
"title": title,
"tid": tid,
"tag": ','.join(tag),
"no_reprint": no_reprint,
"desc": desc,
"cover": cover,
"mission_id": 0,
"order_id": 0,
"videos": self.videos}
)
print(r.text)
def addChannel(self, name, intro=''):
"""
:param name: channel's name
:type name: str
:param intro: channel's introduction
:type intro: str
"""
r = self.session.post(
url='https://space.bilibili.com/ajax/channel/addChannel',
data={
'name': name,
'intro': intro,
'aids': '',
'csrf': self.csrf,
},
# name=123&intro=123&aids=&csrf=565d7ed17cef2cc8ad054210c4e64324&_=1497077610768
)
# return
# {"status":true,"data":{"cid":"15812"}}
print(r.json())
def channel_addVideo(self, cid, aids):
"""
:param cid: channel's id
:type cid: int
:param aids: videos' id
:type aids: list<int>
"""
r = self.session.post(
url='https://space.bilibili.com/ajax/channel/addVideo',
data={
'aids': '%2C'.join(aids),
'cid': cid,
'csrf': self.csrf
}
# aids=9953555%2C9872953&cid=15814&csrf=565d7ed17cef2cc8ad054210c4e64324&_=1497079332679
)
print(r.json())
def cover_up(self, img):
"""
:param img: img path or stream
:type img: str or BufferedReader
:return: img URL
"""
if isinstance(img, str):
f = open(img, 'rb')
else:
f = img
r = self.session.post(
url='https://member.bilibili.com/x/vu/web/cover/up',
data={
'cover': b'data:image/jpeg;base64,' + (base64.b64encode(f.read())),
'csrf': self.csrf,
}
)
# print(r.text)
# {"code":0,"data":{"url":"http://i0.hdslb.com/bfs/archive/67db4a6eae398c309244e74f6e85ae8d813bd7c9.jpg"},"message":"","ttl":1}
return r.json()['data']['url']
from bilibiliuploader import core, VideoPart
class Bilibili:
def __init__(self):
self.access_token = ""
self.session_id = ""
self.user_id = ""
self.parts = []
def login(self):
from Common import appendOperation
with open("access_token", "r") as f:
self.access_token = f.read(64).strip()
self.session_id, self.user_id, expires = core.login_by_access_token(self.access_token)
appendOperation("B站登录UID【{}】,过期时间【{}".format(self.user_id, expires))
def upload(self,
parts,
title,
tid,
tag,
desc,
source='',
cover='',
no_reprint=1,
):
"""
:param parts: e.g. VideoPart('part path', 'part title', 'part desc'), or [VideoPart(...), VideoPart(...)]
:type parts: VideoPart or list<VideoPart>
:param title: video's title
:type title: str
:param tid: video type, see: https://member.bilibili.com/x/web/archive/pre
or https://github.com/uupers/BiliSpider/wiki/%E8%A7%86%E9%A2%91%E5%88%86%E5%8C%BA%E5%AF%B9%E5%BA%94%E8%A1%A8
:type tid: int
:param tag: video's tag
:type tag: list<str>
:param desc: video's description
:type desc: str
:param source: (optional) 转载地址
:type source: str
:param cover: (optional) cover's URL, use method *cover_up* to get
:type cover: str
:param no_reprint: (optional) 0=可以转载, 1=禁止转载(default)
:type no_reprint: int
"""
self.preUpload(parts)
self.finishUpload(title, tid, tag, desc, source, cover, no_reprint)
self.clear()
def preUpload(self, parts, max_retry=5):
"""
:param max_retry:
:param parts: e.g. VideoPart('part path', 'part title', 'part desc'), or [VideoPart(...), VideoPart(...)]
:type parts: VideoPart or list<VideoPart>
"""
from Common import appendUploadStatus, modifyLastUploadStatus, appendError
if not isinstance(parts, list):
parts = [parts]
def log_status(video_part: VideoPart, chunks_index: int, chunks_num: int):
modifyLastUploadStatus("Uploading >{}< @ {:.2f}%".format(video_part.path, 100.0 * chunks_index / chunks_num))
for part in parts:
appendUploadStatus("Start Uploading >{}<".format(part.path))
status = core.upload_video_part(self.access_token, self.session_id, self.user_id, part, max_retry, cb=log_status)
if status:
# 上传完毕
modifyLastUploadStatus("Upload >{}< Finished{}".format(part.path, part.server_file_name))
self.parts.append(part)
else:
modifyLastUploadStatus("Upload >{}< Failed".format(part.path))
def finishUpload(self,
title,
tid,
tag,
desc,
source='',
cover='',
no_reprint=1,
):
"""
:param title: video's title
:type title: str
:param tid: video type, see: https://member.bilibili.com/x/web/archive/pre
or https://github.com/uupers/BiliSpider/wiki/%E8%A7%86%E9%A2%91%E5%88%86%E5%8C%BA%E5%AF%B9%E5%BA%94%E8%A1%A8
:type tid: int
:param tag: video's tag
:type tag: list<str>
:param desc: video's description
:type desc: str
:param source: (optional) 转载地址
:type source: str
:param cover: (optional) cover's URL, use method *cover_up* to get
:type cover: str
:param no_reprint: (optional) 0=可以转载, 1=禁止转载(default)
:type no_reprint: int
:param copyright: (optional) 0=转载的, 1=自制的(default)
:type copyright: int
"""
from Common import appendUploadStatus, modifyLastUploadStatus, appendError
if len(self.parts) == 0:
return
appendUploadStatus("[{}]投稿中,请稍后".format(title))
copyright = 2 if source else 1
try:
avid, bvid = core.upload(self.access_token, self.session_id, self.user_id, self.parts, copyright,
title=title, tid=tid, tag=','.join(tag), desc=desc, source=source, cover=cover, no_reprint=no_reprint)
modifyLastUploadStatus("[{}]投稿成功AVID【{}BVID【{}".format(title, avid, bvid))
self.clear()
except Exception as e:
modifyLastUploadStatus("[{}]投稿失败".format(title))
appendError(e)
def reloadFromPrevious(self):
...
def clear(self):
self.parts = []

View File

@ -0,0 +1,4 @@
修改自
https://github.com/FortuneDayssss/BilibiliUploader/
LICENSEGPL

View File

@ -0,0 +1,4 @@
from .bilibiliuploader import BilibiliUploader
from .core import VideoPart
__version__ = '0.0.6'

View File

@ -0,0 +1,118 @@
import bilibiliuploader.core as core
from bilibiliuploader.util import cipher
import json
class BilibiliUploader():
def __init__(self):
self.access_token = None
self.refresh_token = None
self.sid = None
self.mid = None
def login(self, username, password):
code, self.access_token, self.refresh_token, self.sid, self.mid, _ = core.login(username, password)
if code != 0: # success
print("login fail, error code = {}".format(code))
def login_by_access_token(self, access_token, refresh_token=None):
self.access_token = access_token
self.refresh_token = refresh_token
self.sid, self.mid, _ = core.login_by_access_token(access_token)
def login_by_access_token_file(self, file_name):
with open(file_name, "r") as f:
login_data = json.loads(f.read())
self.access_token = login_data["access_token"]
self.refresh_token = login_data["refresh_token"]
self.sid, self.mid, _ = core.login_by_access_token(self.access_token)
def save_login_data(self, file_name=None):
login_data = json.dumps(
{
"access_token": self.access_token,
"refresh_token": self.refresh_token
}
)
try:
with open(file_name, "w+") as f:
f.write(login_data)
finally:
return login_data
def upload(self,
parts,
copyright: int,
title: str,
tid: int,
tag: str,
desc: str,
source: str = '',
cover: str = '',
no_reprint: int = 0,
open_elec: int = 1,
max_retry: int = 5,
thread_pool_workers: int = 1):
return core.upload(self.access_token,
self.sid,
self.mid,
parts,
copyright,
title,
tid,
tag,
desc,
source,
cover,
no_reprint,
open_elec,
max_retry,
thread_pool_workers)
def edit(self,
avid=None,
bvid=None,
parts=None,
insert_index=None,
copyright=None,
title=None,
tid=None,
tag=None,
desc=None,
source=None,
cover=None,
no_reprint=None,
open_elec=None,
max_retry: int = 5,
thread_pool_workers: int = 1):
if not avid and not bvid:
print("please provide avid or bvid")
return None, None
if not avid:
avid = cipher.bv2av(bvid)
if not isinstance(parts, list):
parts = [parts]
if type(avid) is str:
avid = int(avid)
core.edit_videos(
self.access_token,
self.sid,
self.mid,
avid,
bvid,
parts,
insert_index,
copyright,
title,
tid,
tag,
desc,
source,
cover,
no_reprint,
open_elec,
max_retry,
thread_pool_workers
)

790
bilibiliuploader/core.py Normal file
View File

@ -0,0 +1,790 @@
import requests
from datetime import datetime
from bilibiliuploader.util import cipher as cipher
from urllib import parse
import os
import math
import hashlib
from bilibiliuploader.util.retry import Retry
from concurrent.futures import ThreadPoolExecutor, as_completed
import base64
# From PC ugc_assisstant
# APPKEY = 'aae92bc66f3edfab'
# APPSECRET = 'af125a0d5279fd576c1b4418a3e8276d'
APPKEY = '1d8b6e7d45233436'
APPSECRET = '560c52ccd288fed045859ed18bffd973'
LOGIN_APPKEY = '783bbb7264451d82'
# upload chunk size = 2MB
CHUNK_SIZE = 2 * 1024 * 1024
# captcha
CAPTCHA_RECOGNIZE_URL = "NOT SUPPORT"
class VideoPart:
"""
Video Part of a post.
每个对象代表一个分P
Attributes:
path: file path in local file system.
title: title of the video part.
desc: description of the video part.
server_file_name: file name in bilibili server. generated by pre-upload API.
"""
def __init__(self, path, title='', desc='', server_file_name=None):
self.path = path
self.title = title
self.desc = desc
self.server_file_name = server_file_name
def __repr__(self):
return '<{clazz}, path: {path}, title: {title}, desc: {desc}, server_file_name:{server_file_name}>' \
.format(clazz=self.__class__.__name__,
path=self.path,
title=self.title,
desc=self.desc,
server_file_name=self.server_file_name)
def get_key_old(sid=None, jsessionid=None):
"""
get public key, hash and session id for login.
Args:
sid: session id. only for captcha login.
jsessionid: j-session id. only for captcha login.
Returns:
hash: salt for password encryption.
pubkey: rsa public key for password encryption.
sid: session id.
"""
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': "application/json, text/javascript, */*; q=0.01"
}
post_data = {
'appkey': APPKEY,
'platform': "pc",
'ts': str(int(datetime.now().timestamp()))
}
post_data['sign'] = cipher.sign_dict(post_data, APPSECRET)
cookie = {}
if sid:
cookie['sid'] = sid
if jsessionid:
cookie['JSESSIONID'] = jsessionid
r = requests.post(
# "https://passport.bilibili.com/api/oauth2/getKey",
"https://passport.bilibili.com/x/passport-login/web/key",
headers=headers,
data=post_data,
cookies=cookie
)
print(r.content.decode())
r_data = r.json()['data']
if sid:
return r_data['hash'], r_data['key'], sid
return r_data['hash'], r_data['key'], r.cookies['sid']
def get_key():
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': "application/json, text/javascript, */*; q=0.01"
}
params_data = {
'appkey': LOGIN_APPKEY,
# 'ts': str(int(datetime.now().timestamp()))
}
params_data['sign'] = cipher.login_sign_dict_bin(params_data)
r = requests.get(
"https://passport.bilibili.com/x/passport-login/web/key",
headers=headers,
params=params_data
)
r_data = r.json()['data']
return r_data['hash'], r_data['key'], ''
def get_capcha(sid):
headers = {
'User-Agent': '',
'Accept-Encoding': 'gzip,deflate',
}
params = {
'appkey': APPKEY,
'platform': 'pc',
'ts': str(int(datetime.now().timestamp()))
}
params['sign'] = cipher.sign_dict(params, APPSECRET)
r = requests.get(
"https://passport.bilibili.com/captcha",
headers=headers,
params=params,
cookies={
'sid': sid
}
)
print(r.status_code)
capcha_data = r.content
return r.cookies['JSESSIONID'], capcha_data
def recognize_captcha(img: bytes):
img_base64 = str(base64.b64encode(img), encoding='utf-8')
r = requests.post(
url=CAPTCHA_RECOGNIZE_URL,
data={'image': img_base64}
)
return r.content.decode()
def login(username, password):
"""
bilibili login.
Args:
username: plain text username for bilibili.
password: plain text password for bilibili.
Returns:
code: login response code (0: success, -105: captcha error, ...).
access_token: token for further operation.
refresh_token: token for refresh access_token.
sid: session id.
mid: member id.
expires_in: access token expire time (30 days)
"""
hash, pubkey, sid = get_key()
encrypted_password = cipher.encrypt_login_password(password, hash, pubkey)
url_encoded_username = parse.quote_plus(username)
url_encoded_password = parse.quote_plus(encrypted_password)
post_data = {
'appkey': LOGIN_APPKEY,
'password': url_encoded_password,
'ts': str(int(datetime.now().timestamp())),
'username': url_encoded_username
}
post_data['sign'] = cipher.login_sign_dict_bin(post_data)
# avoid multiple url parse
post_data['username'] = username
post_data['password'] = encrypted_password
headers = {
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent': '',
'Accept-Encoding': 'gzip,deflate',
}
r = requests.post(
# "https://passport.bilibili.com/api/v3/oauth2/login",
"https://passport.bilibili.com/x/passport-login/oauth2/login",
headers=headers,
data=post_data,
)
response = r.json()
response_code = response['code']
if response_code == 0:
login_data = response['data']['token_info']
return response_code, login_data['access_token'], login_data['refresh_token'], sid, login_data['mid'], \
login_data["expires_in"]
elif response_code == -105: # captcha error, retry=5
retry_cnt = 5
while response_code == -105 and retry_cnt > 0:
response_code, access_token, refresh_token, sid, mid, expire_in = login_captcha(username, password, sid)
if response_code == 0:
return response_code, access_token, refresh_token, sid, mid, expire_in
retry_cnt -= 1
# other error code
return response_code, None, None, sid, None, None
def login_captcha(username, password, sid):
"""
bilibili login with captcha.
depend on captcha recognize service, please do not use this as first choice.
Args:
username: plain text username for bilibili.
password: plain text password for bilibili.
sid: session id
Returns:
code: login response code (0: success, -105: captcha error, ...).
access_token: token for further operation.
refresh_token: token for refresh access_token.
sid: session id.
mid: member id.
expires_in: access token expire time (30 days)
"""
jsessionid, captcha_img = get_capcha(sid)
captcha_str = recognize_captcha(captcha_img)
hash, pubkey, sid = get_key(sid, jsessionid)
encrypted_password = cipher.encrypt_login_password(password, hash, pubkey)
url_encoded_username = parse.quote_plus(username)
url_encoded_password = parse.quote_plus(encrypted_password)
post_data = {
'appkey': APPKEY,
'captcha': captcha_str,
'password': url_encoded_password,
'platform': "pc",
'ts': str(int(datetime.now().timestamp())),
'username': url_encoded_username
}
post_data['sign'] = cipher.sign_dict(post_data, APPSECRET)
# avoid multiple url parse
post_data['username'] = username
post_data['password'] = encrypted_password
post_data['captcha'] = captcha_str
headers = {
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent': '',
'Accept-Encoding': 'gzip,deflate',
}
r = requests.post(
"https://passport.bilibili.com/api/oauth2/login",
headers=headers,
data=post_data,
cookies={
'JSESSIONID': jsessionid,
'sid': sid
}
)
response = r.json()
if response['code'] == 0:
login_data = response['data']
return response['code'], login_data['access_token'], login_data['refresh_token'], sid, login_data['mid'], \
login_data["expires_in"]
else:
return response['code'], None, None, sid, None, None
def login_by_access_token(access_token):
"""
bilibili access token login.
Args:
access_token: Bilibili access token got by previous username/password login.
Returns:
sid: session id.
mid: member id.
expires_in: access token expire time
"""
headers = {
'Connection': 'keep-alive',
'Accept-Encoding': 'gzip,deflate',
'Host': 'passport.bilibili.com',
'User-Agent': '',
}
login_params = {
'appkey': APPKEY,
'access_token': access_token,
'platform': "pc",
'ts': str(int(datetime.now().timestamp())),
}
login_params['sign'] = cipher.sign_dict(login_params, APPSECRET)
r = requests.get(
url="https://passport.bilibili.com/api/oauth2/info",
headers=headers,
params=login_params
)
login_data = r.json()['data']
return r.cookies['sid'], login_data['mid'], login_data["expires_in"]
def upload_cover(access_token, sid, cover_file_path):
with open(cover_file_path, "rb") as f:
cover_pic = f.read()
headers = {
'Connection': 'keep-alive',
'Host': 'member.bilibili.com',
'Accept-Encoding': 'gzip,deflate',
'User-Agent': '',
}
params = {
"access_key": access_token,
}
params["sign"] = cipher.sign_dict(params, APPSECRET)
files = {
'file': ("cover.png", cover_pic, "Content-Type: image/png"),
}
r = requests.post(
"http://member.bilibili.com/x/vu/client/cover/up",
headers=headers,
params=params,
files=files,
cookies={
'sid': sid
},
verify=False,
)
return r.json()["data"]["url"]
def upload_chunk(upload_url, server_file_name, local_file_name, chunk_data, chunk_size, chunk_id, chunk_total_num):
"""
upload video chunk.
Args:
upload_url: upload url by pre_upload api.
server_file_name: file name on server by pre_upload api.
local_file_name: video file name in local fs.
chunk_data: binary data of video chunk.
chunk_size: default of ugc_assisstant is 2M.
chunk_id: chunk number.
chunk_total_num: total chunk number.
Returns:
True: upload chunk success.
False: upload chunk fail.
"""
print("chunk{}/{}".format(chunk_id, chunk_total_num))
print("filename: {}".format(local_file_name))
files = {
'version': (None, '2.0.0.1054'),
'filesize': (None, chunk_size),
'chunk': (None, chunk_id),
'chunks': (None, chunk_total_num),
'md5': (None, cipher.md5_bytes(chunk_data)),
'file': (local_file_name, chunk_data, 'application/octet-stream')
}
r = requests.post(
url=upload_url,
files=files,
cookies={
'PHPSESSID': server_file_name
},
)
print(r.status_code)
print(r.content)
if r.status_code == 200 and r.json()['OK'] == 1:
return True
else:
return False
def upload_video_part(access_token, sid, mid, video_part: VideoPart, max_retry=5, cb=None):
"""
upload a video file.
Args:
access_token: access token generated by login api.
sid: session id.
mid: member id.
video_part: local video file data.
max_retry: max retry number for each chunk.
cb: 回调
Returns:
status: success or fail.
server_file_name: server file name by pre_upload api.
"""
if cb is None:
cb = lambda f, c, t: None
if not isinstance(video_part, VideoPart):
return False
if video_part.server_file_name is not None:
return True
headers = {
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent': '',
'Accept-Encoding': 'gzip,deflate',
}
r = requests.get(
"http://member.bilibili.com/preupload?access_key={}&mid={}&profile=ugcfr%2Fpc3".format(access_token, mid),
headers=headers,
cookies={
'sid': sid
},
verify=False,
)
pre_upload_data = r.json()
upload_url = pre_upload_data['url']
complete_upload_url = pre_upload_data['complete']
server_file_name = pre_upload_data['filename']
local_file_name = video_part.path
file_size = os.path.getsize(local_file_name)
chunk_total_num = int(math.ceil(file_size / CHUNK_SIZE))
file_hash = hashlib.md5()
with open(local_file_name, 'rb') as f:
for chunk_id in range(0, chunk_total_num):
chunk_data = f.read(CHUNK_SIZE)
cb(video_part, chunk_id, chunk_total_num)
status = Retry(max_retry=max_retry, success_return_value=True).run(
upload_chunk,
upload_url,
server_file_name,
os.path.basename(local_file_name),
chunk_data,
CHUNK_SIZE,
chunk_id,
chunk_total_num
)
if not status:
return False
file_hash.update(chunk_data)
print(file_hash.hexdigest())
# complete upload
post_data = {
'chunks': chunk_total_num,
'filesize': file_size,
'md5': file_hash.hexdigest(),
'name': os.path.basename(local_file_name),
'version': '2.0.0.1054',
}
r = requests.post(
url=complete_upload_url,
data=post_data,
headers=headers,
)
print(r.status_code)
print(r.content)
video_part.server_file_name = server_file_name
return True
def upload(access_token,
sid,
mid,
parts,
copyright: int,
title: str,
tid: int,
tag: str,
desc: str,
source: str = '',
cover: str = '',
no_reprint: int = 0,
open_elec: int = 1,
max_retry: int = 5,
thread_pool_workers: int = 1):
"""
upload video.
Args:
access_token: oauth2 access token.
sid: session id.
mid: member id.
parts: VideoPart list.
copyright: 原创/转载.
title: 投稿标题.
tid: 分区id.
tag: 标签.
desc: 投稿简介.
source: 转载地址.
cover: 封面图片文件路径.
no_reprint: 可否转载.
open_elec: 充电.
max_retry: max retry time for each chunk.
thread_pool_workers: max upload threads.
Returns:
(aid, bvid)
aid: av号
bvid: bv号
"""
if not isinstance(parts, list):
parts = [parts]
status = True
with ThreadPoolExecutor(max_workers=thread_pool_workers) as tpe:
t_list = []
for video_part in parts:
print("upload {} added in pool".format(video_part.title))
t_obj = tpe.submit(upload_video_part, access_token, sid, mid, video_part, max_retry)
t_obj.video_part = video_part
t_list.append(t_obj)
for t_obj in as_completed(t_list):
status = status and t_obj.result()
print("video part {} finished, status: {}".format(t_obj.video_part.title, t_obj.result()))
if not status:
print("upload failed")
return None, None
# cover
if os.path.isfile(cover):
try:
cover = upload_cover(access_token, sid, cover)
except:
cover = ''
else:
cover = ''
# submit
headers = {
'Connection': 'keep-alive',
'Content-Type': 'application/json',
'User-Agent': '',
}
post_data = {
'build': 1054,
'copyright': copyright,
'cover': cover,
'desc': desc,
'no_reprint': no_reprint,
'open_elec': open_elec,
'source': source,
'tag': tag,
'tid': tid,
'title': title,
'videos': []
}
for video_part in parts:
post_data['videos'].append({
"desc": video_part.desc,
"filename": video_part.server_file_name,
"title": video_part.title
})
params = {
'access_key': access_token,
}
params['sign'] = cipher.sign_dict(params, APPSECRET)
r = requests.post(
url="http://member.bilibili.com/x/vu/client/add",
params=params,
headers=headers,
verify=False,
cookies={
'sid': sid
},
json=post_data,
)
print("submit")
print(r.status_code)
print(r.content.decode())
data = r.json()["data"]
return data["aid"], data["bvid"]
def get_post_data(access_token, sid, avid):
headers = {
'Connection': 'keep-alive',
'Host': 'member.bilibili.com',
'Accept-Encoding': 'gzip,deflate',
'User-Agent': '',
}
params = {
"access_key": access_token,
"aid": avid,
"build": "1054"
}
params["sign"] = cipher.sign_dict(params, APPSECRET)
r = requests.get(
url="http://member.bilibili.com/x/client/archive/view",
headers=headers,
params=params,
cookies={
'sid': sid
}
)
return r.json()["data"]
def edit_videos(
access_token,
sid,
mid,
avid=None,
bvid=None,
parts=None,
insert_index=None,
copyright=None,
title=None,
tid=None,
tag=None,
desc=None,
source=None,
cover=None,
no_reprint=None,
open_elec=None,
max_retry: int = 5,
thread_pool_workers: int = 1):
"""
insert videos into existed post.
Args:
access_token: oauth2 access token.
sid: session id.
mid: member id.
avid: av number,
bvid: bv string,
parts: VideoPart list.
insert_index: new video index.
copyright: 原创/转载.
title: 投稿标题.
tid: 分区id.
tag: 标签.
desc: 投稿简介.
source: 转载地址.
cover: cover url.
no_reprint: 可否转载.
open_elec: 充电.
max_retry: max retry time for each chunk.
thread_pool_workers: max upload threads.
Returns:
(aid, bvid)
aid: av号
bvid: bv号
"""
if not avid and not bvid:
print("please provide avid or bvid")
return None, None
if not avid:
avid = cipher.bv2av(bvid)
if not isinstance(parts, list):
parts = [parts]
if type(avid) is str:
avid = int(avid)
post_video_data = get_post_data(access_token, sid, avid)
status = True
with ThreadPoolExecutor(max_workers=thread_pool_workers) as tpe:
t_list = []
for video_part in parts:
print("upload {} added in pool".format(video_part.title))
t_obj = tpe.submit(upload_video_part, access_token, sid, mid, video_part, max_retry)
t_obj.video_part = video_part
t_list.append(t_obj)
for t_obj in as_completed(t_list):
status = status and t_obj.result()
print("video part {} finished, status: {}".format(t_obj.video_part.title, t_obj.result()))
if not status:
print("upload failed")
return None, None
headers = {
'Connection': 'keep-alive',
'Content-Type': 'application/json',
'User-Agent': '',
}
submit_data = {
'aid': avid,
'build': 1054,
'copyright': post_video_data["archive"]["copyright"],
'cover': post_video_data["archive"]["cover"],
'desc': post_video_data["archive"]["desc"],
'no_reprint': post_video_data["archive"]["no_reprint"],
'open_elec': post_video_data["archive_elec"]["state"], # open_elec not tested
'source': post_video_data["archive"]["source"],
'tag': post_video_data["archive"]["tag"],
'tid': post_video_data["archive"]["tid"],
'title': post_video_data["archive"]["title"],
'videos': post_video_data["videos"]
}
# cover
if os.path.isfile(cover):
try:
cover = upload_cover(access_token, sid, cover)
except:
cover = ''
else:
cover = ''
# edit archive data
if copyright:
submit_data["copyright"] = copyright
if title:
submit_data["title"] = title
if tid:
submit_data["tid"] = tid
if tag:
submit_data["tag"] = tag
if desc:
submit_data["desc"] = desc
if source:
submit_data["source"] = source
if cover:
submit_data["cover"] = cover
if no_reprint:
submit_data["no_reprint"] = no_reprint
if open_elec:
submit_data["open_elec"] = open_elec
if type(insert_index) is int:
for i, video_part in enumerate(parts):
submit_data['videos'].insert(insert_index + i, {
"desc": video_part.desc,
"filename": video_part.server_file_name,
"title": video_part.title
})
elif insert_index is None:
for video_part in parts:
submit_data['videos'].append({
"desc": video_part.desc,
"filename": video_part.server_file_name,
"title": video_part.title
})
else:
print("wrong insert index")
return None, None
params = {
'access_key': access_token,
}
params['sign'] = cipher.sign_dict(params, APPSECRET)
r = requests.post(
url="http://member.bilibili.com/x/vu/client/edit",
params=params,
headers=headers,
verify=False,
cookies={
'sid': sid
},
json=submit_data,
)
print("edit submit")
print(r.status_code)
print(r.content.decode())
data = r.json()["data"]
return data["aid"], data["bvid"]

View File

@ -0,0 +1 @@
from .cipher import *

View File

@ -0,0 +1,119 @@
import hashlib
import rsa
import base64
import subprocess
import platform
import os.path
def md5(data: str):
"""
generate md5 hash of utf-8 encoded string.
"""
return hashlib.md5(data.encode("utf-8")).hexdigest()
def md5_bytes(data: bytes):
"""
generate md5 hash of binary.
"""
return hashlib.md5(data).hexdigest()
def sign_str(data: str, app_secret: str):
"""
sign a string of request parameters
Args:
data: string of request parameters, must be sorted by key before input.
app_secret: a secret string coupled with app_key.
Returns:
A hash string. len=32
"""
return md5(data + app_secret)
def sign_dict(data: dict, app_secret: str):
"""
sign a dictionary of request parameters
Args:
data: dictionary of request parameters.
app_secret: a secret string coupled with app_key.
Returns:
A hash string. len=32
"""
data_str = []
keys = list(data.keys())
keys.sort()
for key in keys:
data_str.append("{}={}".format(key, data[key]))
data_str = "&".join(data_str)
data_str = data_str + app_secret
return md5(data_str)
def login_sign_dict_bin(data: dict):
data_str = []
keys = list(data.keys())
keys.sort()
for key in keys:
data_str.append("{}={}".format(key, data[key]))
data_str = "&".join(data_str)
package_directory = os.path.dirname(os.path.abspath(__file__))
if platform.system().lower() == 'windows':
print(data_str)
print(subprocess.Popen([os.path.join(package_directory, "sign.exe"), data_str], stdout=subprocess.PIPE).communicate()[0].decode().strip())
return subprocess.Popen([os.path.join(package_directory, "sign.exe"), data_str], stdout=subprocess.PIPE).communicate()[0].decode().strip()
if platform.system().lower() == 'linux':
return subprocess.Popen([os.path.join(package_directory, "sign.out"), data_str], stdout=subprocess.PIPE).communicate()[0].decode().strip()
raise Exception("Operating System is not supported.")
def encrypt_login_password(password, hash, pubkey):
"""
encrypt password for login api.
Args:
password: plain text of user password.
hash: hash provided by /api/oauth2/getKey.
pubkey: public key provided by /api/oauth2/getKey.
Returns:
An encrypted cipher of password.
"""
return base64.b64encode(rsa.encrypt(
(hash + password).encode('utf-8'),
rsa.PublicKey.load_pkcs1_openssl_pem(pubkey.encode()),
))
def av2bv(av: int):
table = 'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF'
tr = {}
for i in range(58):
tr[table[i]] = i
s = [11, 10, 3, 8, 4, 6]
xor = 177451812
add = 8728348608
av = (av ^ xor) + add
r = list('BV1 4 1 7 ')
for i in range(6):
r[s[i]] = table[av // 58 ** i % 58]
return ''.join(r)
def bv2av(bv: str):
table = 'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF'
tr = {}
for i in range(58):
tr[table[i]] = i
s = [11, 10, 3, 8, 4, 6]
xor = 177451812
add = 8728348608
r = 0
for i in range(6):
r += tr[bv[s[i]]] * 58 ** i
return (r - add) ^ xor

View File

@ -0,0 +1,18 @@
class Retry:
def __init__(self, max_retry, success_return_value):
self.max_retry = max_retry
self.success_return_value = success_return_value
def run(self, func, *args, **kwargs):
status = False
for i in range(0, self.max_retry):
try:
return_value = func(*args, **kwargs)
except Exception:
return_value = not self.success_return_value
if return_value == self.success_return_value:
status = True
break
return status

Binary file not shown.

Binary file not shown.

BIN
ico.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,189 +1,153 @@
import sys
import time
from datetime import datetime
import m3u8
import queue
import threading
from config import config
from api import XiGuaLiveApi
from bilibili import *
import Common
import os
import requests
q = queue.Queue()
base_uri = ""
isUpload = False
uq = queue.Queue()
session = requests.session()
class downloader(XiGuaLiveApi):
files = []
playlist: str = None
def updRoomInfo(self):
super(downloader, self).updRoomInfo()
self.updPlayList()
def updPlayList(self):
if self.isLive:
if "stream_url" in self._rawRoomInfo:
if self.playlist is None:
self.apiChangedError("无法获取直播链接")
self.playlist = False
else:
self.playlist = self._rawRoomInfo["stream_url"]["alternate_pull_url"]
self.playlist = self.playlist.replace("_uhd","").replace("_sd","").replace("_ld","")
def download():
while Common.api.isLive and not Common.forceNotDownload:
if not Common.streamUrl:
Common.appendError("Download with No StreamUrl Specific")
break
path = datetime.strftime(datetime.now(), "%Y%m%d_%H%M.flv")
base_path = Common.config["path"]
if not os.path.isdir(base_path):
os.makedirs(base_path)
try:
p = session.get(Common.streamUrl, stream=True, timeout=3)
p.raise_for_status()
except Exception as e:
Common.appendError("Download >{}< with Exception [{}]".format(path,e.__str__()))
break
Common.api.initSave(os.path.join(base_path, path)+".xml")
Common.appendDownloadStatus("Download >{}< Start".format(path))
f = open(os.path.join(base_path, path), "wb")
_size = 0
try:
for T in p.iter_content(chunk_size=Common.config["c_s"]):
if Common.forceNotDownload:
Common.modifyLastDownloadStatus("Force Stop Download".format(path))
return
f.write(T)
_size += len(T)
Common.modifyLastDownloadStatus(
"Downloading >{}< @ {:.2f}%".format(path, 100.0 * _size / Common.config["p_s"]))
if _size > Common.config["p_s"] and not Common.config["dlO"]:
Common.modifyLastDownloadStatus("Download >{}< Exceed MaxSize".format(path))
break
Common.modifyLastDownloadStatus("Download >{}< Finished".format(path))
except Exception as e:
Common.appendError("Download >{}< With Exception {}".format(path, e.__str__()))
Common.api.updRoomInfo(True)
finally:
f.close()
if os.path.getsize(os.path.join(base_path, path)) < Common.config["i_s"]:
Common.modifyLastDownloadStatus("Downloaded File >{}< is too small, will ignore it".format(path))
else:
print("未开播,等待开播")
Common.encodeQueue.put(os.path.join(base_path, path))
Common.doUpdatePlaylist()
Common.api.updRoomInfo(True)
def onLike(self, user):
pass
def onAd(self, i):
pass
def encode():
Common.appendEncodeStatus("Encode Daemon Starting")
while True:
i = Common.encodeQueue.get()
Common.encodeVideo(i)
def onChat(self, chat):
pass
def onEnter(self, msg):
pass
def upload():
date = datetime.strftime(datetime.now(), Common.config["sdf"])
Common.appendUploadStatus("Upload Daemon Starting")
i = Common.uploadQueue.get()
while True:
if i is True:
Common.publishVideo(date)
break
try:
Common.uploadVideo(i)
except Exception as e:
Common.appendError(e.__str__())
continue
finally:
time.sleep(90)
i = Common.uploadQueue.get()
Common.appendUploadStatus("Upload Daemon Quiting")
def onJoin(self, user):
pass
def onLeave(self, json):
self.updRoomInfo()
t = threading.Thread(target=download, args=())
ut = threading.Thread(target=upload, args=())
et = threading.Thread(target=encode, args=())
def onMessage(self, msg):
pass
def onPresent(self, gift):
pass
def awakeEncode():
global et
if et.is_alive():
return True
et = threading.Thread(target=encode, args=())
et.setDaemon(True)
et.start()
return False
def onPresentEnd(self, gift):
pass
def onSubscribe(self, user):
pass
def awakeDownload():
global t
if t.is_alive():
return True
t = threading.Thread(target=download, args=())
t.setDaemon(True)
t.start()
Common.api.updRoomInfo()
return False
def preDownload(self):
global base_uri
if self.playlist:
def awakeUpload():
global ut
if ut.is_alive():
return True
ut = threading.Thread(target=upload, args=())
ut.setDaemon(True)
ut.start()
return False
def run():
Common.refreshDownloader()
if not Common.api.isValidUser:
Common.appendError("[{}]用户未找到".format(Common.api.name))
return
while True:
if Common.api.isLive and not Common.forceNotBroadcasting:
if not Common.forceNotDownload:
awakeDownload()
if not Common.forceNotUpload:
awakeUpload()
if not Common.forceNotEncode:
awakeEncode()
try:
p = m3u8.load(self.playlist)
except:
self.updRoomInfo()
return
base_uri = p.base_uri
for i in p.files:
if i not in self.files:
self.files.append(i)
print("{} : Add Sequence {}".format(datetime.strftime(datetime.now(), "%y%m%d %H%M"),
len(self.files)))
q.put(i)
Common.api.getDanmaku()
except Exception as e:
Common.appendError(e.__str__())
finally:
time.sleep(1)
else:
print("PlayList {}".format(self.playlist))
self.genNewName()
def genNewName(self):
if len(self.files) > 800:
q.put(True)
self.files.clear()
def download(path=datetime.strftime(datetime.now(), "%Y%m%d_%H%M.ts")):
global isUpload
print("{} : Download Daemon Starting".format(datetime.strftime(datetime.now(), "%y%m%d %H%M")))
n = False
isUpload = False
i = q.get()
while True:
if isinstance(i, bool):
print("{} : Download Daemon Receive Command {}".format(datetime.strftime(datetime.now(), "%y%m%d %H%M"), i))
break
print("{} : Download {}".format(datetime.strftime(datetime.now(), "%y%m%d %H%M"), i))
try:
_p = requests.get("{}{}".format(base_uri, i))
except:
continue
f = open(path, "ab")
f.write(_p.content)
f.close()
n = True
i = q.get()
if n:
isUpload = True
uq.put(path)
print("{} : Download Daemon Quiting".format(datetime.strftime(datetime.now(), "%y%m%d %H%M")))
def upload(date=datetime.strftime(datetime.now(), "%Y_%m_%d")):
print("{} : Upload Daemon Starting".format(datetime.strftime(datetime.now(), "%y%m%d %H%M")))
i = uq.get()
while True:
if isinstance(i, bool):
print("{} : Upload Daemon Receive Command {}"
.format(datetime.strftime(datetime.now(), "%y%m%d %H%M"), i))
if i is True:
print("自动投稿中,请稍后")
b.finishUpload(config["t_t"].format(date), 17, config["tag"], config["des"],
source=config["src"], no_reprint=0)
break
print("{} : Upload {}".format(datetime.strftime(datetime.now(), "%y%m%d %H%M"), i))
try:
b.preUpload(VideoPart(i, i))
except:
continue
i = uq.get()
print("{} : Upload Daemon Quiting".format(datetime.strftime(datetime.now(), "%y%m%d %H%M")))
b = Bilibili()
b.login(config["b_u"], config["b_p"])
if __name__ == "__main__":
name = "永恒de草薙"
# room = 75366565294
# room = 83940182312 #Dae
# room = 5947850784 #⑦
# room = 58649240617 #戏
if len(sys.argv) > 1:
name = sys.argv[1]
print("西瓜直播录播助手 by JerryYan")
api = downloader(name)
print("进入", api.roomLiver, "的直播间")
if not api.isValidRoom:
input("房间不存在")
sys.exit()
print("=" * 30)
d = datetime.strftime(datetime.now(), "%Y_%m_%d")
_preT = datetime.strftime(datetime.now(), "%Y%m%d_%H%M.ts")
t = threading.Thread(target=download, args=(_preT,))
ut = threading.Thread(target=upload, args=(d,))
while True:
if api.isLive:
if d is None:
d = datetime.strftime(datetime.now(), "%Y_%m_%d")
if not t.is_alive():
_preT = datetime.strftime(datetime.now(), "%Y%m%d_%H%M.ts")
t = threading.Thread(target=download, args=(_preT,))
t.setDaemon(True)
t.start()
if not ut.is_alive():
ut = threading.Thread(target=upload, args=(d,))
ut.setDaemon(True)
ut.start()
api.preDownload()
time.sleep(3)
else:
if d is not None:
q.put(False)
d = None
if isUpload:
uq.put(True)
isUpload = False
else:
del config
from config import config
# print("主播未开播等待1分钟后重试")
time.sleep(60)
api.updRoomInfo()
try:
Common.api.updRoomInfo()
except Exception as e:
Common.appendError(e.__str__())
Common.refreshDownloader()
if not Common.api.broadcaster:
Common.refreshDownloader()
if Common.forceStartEncodeThread:
awakeEncode()
Common.forceStartEncodeThread = False
if Common.forceStartUploadThread:
awakeUpload()
Common.forceStartUploadThread = False
if Common.doDelay():
Common.uploadQueue.put(True)
time.sleep(5)

12
requirements.txt Normal file
View File

@ -0,0 +1,12 @@
psutil>=5.9.0
certifi>=2020.4.5.1
chardet>=3.0.4
idna>=2.9
pyasn1>=0.4.8
requests>=2.23.0
rsa>=4.0
urllib3>=1.25.9
flask>=2.0.2
flask_cors>=3.0.10
protobuf>=3.19.3
python-dotenv>=0.19.2

25
static/device.js Normal file
View File

@ -0,0 +1,25 @@
function deviceUpdate(){
$.ajax(
"/stats/device",
{
success: function (res){
$("#memTotal").text(res.data.status.memTotal)
$("#memUsed").text(res.data.status.memUsed)
$("#memUsage").text(res.data.status.memUsage)
$("#diskTotal").text(res.data.status.diskTotal)
$("#diskUsed").text(res.data.status.diskUsed)
$("#diskUsage").text(res.data.status.diskUsage)
$("#cpu").text(res.data.status.cpu)
$("#memUsageP").val(res.data.status.memUsage)
$("#diskUsageP").val(res.data.status.diskUsage)
$("#cpuP").val(res.data.status.cpu)
$("#inSpeed").text(res.data.status.inSpeed)
$("#outSpeed").text(res.data.status.outSpeed)
$("#doCleanTime").text(res.data.status.doCleanTime)
}
}
)
}
deviceUpdate()
setInterval(deviceUpdate,2000)

59
static/index.js Normal file
View File

@ -0,0 +1,59 @@
function taskUpdate(){
$.ajax(
"/stats",
{
success: function (res){
$("#broadcaster").text(res.data.broadcast.broadcaster)
$("#isBroadcasting").text(res.data.broadcast.isBroadcasting)
$("#streamUrl").text(res.data.broadcast.streamUrl)
$("#delayTime").text(res.data.broadcast.delayTime)
$("#forceNotBroadcasting").text(res.data.config.forceNotBroadcasting)
$("#forceNotDownload").text(res.data.config.forceNotDownload)
$("#forceNotUpload").text(res.data.config.forceNotUpload)
$("#forceNotEncode").text(res.data.config.forceNotEncode)
$("#downloadOnly").text(res.data.config.downloadOnly)
$("#updateTime").text(res.data.broadcast.updateTime)
$("#encodeQueueSize").text(res.data.encodeQueueSize)
$("#uploadQueueSize").text(res.data.uploadQueueSize)
$("#download").html(function(){
var ret = ""
res.data.download.reverse().forEach(function(obj){
ret += "<tr><td class='time'>" + obj.datetime + "</td><td>" + obj.message + "</td></tr>"
})
return "<table>" + ret + "</table>"
})
$("#encode").html(function(){
var ret = ""
res.data.encode.reverse().forEach(function(obj){
ret += "<tr><td class='time'>" + obj.datetime + "</td><td>" + obj.message + "</td></tr>"
})
return "<table>" + ret + "</table>"
})
$("#upload").html(function(){
var ret = ""
res.data.upload.reverse().forEach(function(obj){
ret += "<tr><td class='time'>" + obj.datetime + "</td><td>" + obj.message + "</td></tr>"
})
return "<table>" + ret + "</table>"
})
$("#error").html(function(){
var ret = ""
res.data.error.reverse().forEach(function(obj){
ret += "<tr><td class='time'>" + obj.datetime + "</td><td>" + obj.message + "</td></tr>"
})
return "<table>" + ret + "</table>"
})
$("#operation").html(function(){
var ret = ""
res.data.operation.reverse().forEach(function(obj){
ret += "<tr><td class='time'>" + obj.datetime + "</td><td>" + obj.message + "</td></tr>"
})
return "<table>" + ret + "</table>"
})
}
}
)
}
taskUpdate()
setInterval(taskUpdate,8000)

30
templates/device.html Normal file
View File

@ -0,0 +1,30 @@
<h1>机器状态</h1>
<table>
<tr>
<td class='title'>CPU使用率</td>
<td><progress id="cpuP" max="100" value="0"></progress></td>
<td><span id="cpu"></span>%</td>
</tr>
<tr>
<td class='title'>内存使用率</td>
<td><progress id="memUsageP" max="100" value="0"></progress></td>
<td><span id="memUsed"></span>/<span id="memTotal"></span>(<span id="memUsage"></span>%)</td>
</tr>
<tr>
<td class='title'>磁盘使用率</td>
<td><progress id="diskUsageP" max="100" value="0"></progress></td>
<td><span id="diskUsed"></span>/<span id="diskTotal"></span>(<span id="diskUsage"></span>%)</td>
</tr>
<tr>
<td class='title'>网络速率</td>
<td><span id="inSpeed"></span>/s</td>
<td><span id="outSpeed"></span>/s</td>
</tr>
<tr>
<td class='title'>文件清理</td>
<td></td>
<td>@ <span id="doCleanTime"></span></td>
</tr>
</table>
<script src="/static/device.js"></script>

26
templates/files.html Normal file
View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="zh_CN">
<head>
<title>文件</title>
{% include 'head.html' %}
</head>
<body>
<div>
<h1>所有录像文件</h1>
<p>部分录像文件已转移至百度云,请在<a href="https://pan.baidu.com/s/1ECnwiHnsm-3dSXNJGWlR2g">这里</a>下载 提取码: ddxt</p>
<table>
<tr>
<td>文件名</td><td>文件大小</td><td>链接</td>
</tr>
{%for i in files %}
<tr>
<td>{{i.name}}</td><td>{{i.size}}</td><td><a href="/files/download/{{i.name}}">下载文件</a></td>
</tr>
{% endfor %}
</table>
<hr/>
<h3><a href="/">录播信息页</a></h3>
{% include 'device.html' %}
</div>
</body>
</html>

13
templates/head.html Normal file
View File

@ -0,0 +1,13 @@
<meta charset="UTF-8">
<script src="https://cdn.staticfile.org/jquery/3.3.1/jquery.min.js"></script>
<style>
td{
border: solid 1px lightgray;
}
.title{
width: 6em;
}
.time{
width: 10em;
}
</style>

86
templates/index.html Normal file
View File

@ -0,0 +1,86 @@
<!DOCTYPE html>
<html lang="zh_CN">
<head>
<title>录播</title>
{% include 'head.html' %}
</head>
<body>
<div>
<h1>基本信息</h1>
<table>
<tr>
<td>主播名</td>
<td><span id="broadcaster"></span></td>
</tr>
<tr>
<td>是否正在直播</td>
<td><span id="isBroadcasting"></span></td>
</tr>
<tr>
<td>直播视频流地址</td>
<td><span id="streamUrl"></span></td>
</tr>
<tr>
<td>信息更新时间</td>
<td><span id="updateTime"></span></td>
</tr>
<tr>
<td>延迟投稿时间</td>
<td><span id="delayTime"></span></td>
</tr>
</table>
<hr/>
<h1>特殊设置</h1>
<table>
<tr>
<td>是否设置强制认为不直播</td>
<td><span id="forceNotBroadcasting"></span></td>
</tr>
<tr>
<td>是否设置强制不下载</td>
<td><span id="forceNotDownload"></span></td>
</tr>
<tr>
<td>是否设置强制不上传</td>
<td><span id="forceNotUpload"></span></td>
</tr>
<tr>
<td>是否设置强制不转码</td>
<td><span id="forceNotEncode"></span></td>
</tr>
<tr>
<td>是否设置为仅下载(不上传不转码)</td>
<td><span id="downloadOnly"></span></td>
</tr>
</table>
<hr/>
<h1>当前状态</h1>
<table>
<tr>
<td class='title'>下载日志</td>
<td><span id="download"></span></td>
</tr>
<tr>
<td class='title'>转码日志<br>队列<span id="encodeQueueSize"></span></td>
<td><span id="encode"></span></td>
</tr>
<tr>
<td class='title'>上传日志<br>队列<span id="uploadQueueSize"></span></td>
<td><span id="upload"></span></td>
</tr>
<tr>
<td class='title'>错误日志</td>
<td><span id="error"></span></td>
</tr>
<tr>
<td class='title'>操作日志</td>
<td><span id="operation"></span></td>
</tr>
</table>
<hr/>
<h3><a href="/files/">所有录播文件</a></h3>
{% include 'device.html' %}
</div>
<script src="../static/index.js"></script>
</body>
</html>