This commit is contained in:
xuxiaobo-bobo 2023-03-06 14:37:00 +08:00
parent abcc2e6a07
commit c9c5b9815d
8 changed files with 19920 additions and 0 deletions

7
douyinlive/README.md Normal file
View File

@ -0,0 +1,7 @@
# 原git链接 https://github.com/Prince-cool/dy_protobuf/blob/main/main.py
# dy_protobuf
某音弹幕protobuf实战源码及工具
# 修改web_url参数即可,稍微进行了一些修改

Binary file not shown.

2817
douyinlive/get_handle.js Normal file

File diff suppressed because one or more lines are too long

410
douyinlive/main.js Normal file
View File

@ -0,0 +1,410 @@
//babel库及文件模块导入
const fs = require('fs');
//babel库相关解析转换构建生产
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const types = require("@babel/types");
const generator = require("@babel/generator").default;
//读取文件
let encode_file = "./test.js", decode_file = "./decode_result.proto";
if (process.argv.length > 2) {
encode_file = process.argv[2];
}
if (process.argv.length > 3) {
decode_file = process.argv[3];
}
//some function code
//判断类型
function get_id_type(id_type) {
switch (id_type) {
case "readString":
id_type = "string";
break;
case "readDouble":
id_type = "double";
break;
case "readInt32":
id_type = "int32";
break;
case "readInt64":
id_type = "int64";
break;
case "readFloat":
id_type = "float";
break;
case "readBool":
id_type = "bool";
break;
case "readPackedInt32":
id_type = "int32";
break;
case "readBytes":
id_type = "bytes";
break;
case "readEnum":
id_type = "readEnum";
break;
case "readPackedEnum":
id_type = "readPackedEnum";
break;
case "readUint64String":
id_type = "uint64";
break;
case "readInt64String":
id_type = "int64";
break;
case "readUint32":
id_type = "uint32";
break;
case "readUint64":
id_type = "uint64";
break;
case "readPackedInt64String":
id_type ='int64';
break;
}
return id_type
}
//首字母大写,处理
function titleCase(str) {
newStr = str.slice(0, 1).toUpperCase() + str.slice(1).toLowerCase();
return newStr;
}
//读取文件
let jscode = fs.readFileSync(encode_file, {encoding: "utf-8"});
//转换为ast树
let ast = parser.parse(jscode);
// console.log(ast)
text = 'syntax = "proto3";\n'
//处理message插件
const visitor =
{
//TODO write your code here
AssignmentExpression(path, scope) {
// 外面大模型是没问题了,主要是里面细节
if (path.node.left.property) {
if (path.node.left.type == 'MemberExpression' &&
path.node.left.property.type == 'Identifier' &&
path.node.left.property.name == 'deserializeBinaryFromReader') {
//处理message名字
object_name = path.node.left.object.property.name
left_node = path.node.left
codename_list = generator(left_node).code.split('.');
codename_list.shift()
codename_list.pop()
object_name = codename_list.join('_');
// console.log(object_name);
text = text + 'message ' + object_name + '{\n'
//处理右边FunctionExpression语句
if (path.node.right.type == 'FunctionExpression') {
path.traverse({
//处理switch
SwitchStatement(path2) {
//case语句
cases_list = path2.node.cases
// console.log(generator(path2.node).code);
// try {
for (i = 0; i < path2.node.cases.length - 1; i++) {
location = cases_list[i].test.value
if (cases_list[i].consequent.length) {
if (cases_list[i].consequent[0].type == 'VariableDeclaration') {
//遇到new对象处理
if (cases_list[i].consequent[0].declarations[0].init.type == 'NewExpression') {
//获得type
node_code = cases_list[i].consequent[0].declarations[0].init
// console.log(generator(node_code).code)
node_code_list = generator(node_code).code.split('.')
node_code_list.shift()
id_type = node_code_list.join('_').replace('()', '')
// console.log(id_type);
//获得name这部分有点问题大家可以自行修改
try {
id_name = cases_list[i].consequent[1].expression.expressions[1].callee.property.name
} catch (e) {
id_name = cases_list[i].consequent[2].expression.callee.property.name
}
// console.log(id_name);
if (id_name.startsWith("set")) {
id_st = "";
} else if (id_name.startsWith("add")) {
id_st = "repeated";
} else {
// map类型因为案例中用不到所以这里省略
continue
}
id_name = id_name.substring(3, id_name.length).toLowerCase();
// console.log(id_name)
text = text + id_st + ' ' + id_type + ' ' + id_name + '=' + location + ';' + '\n'
}
//其他情况处理
else {
if (cases_list[i].consequent[0].declarations[0].init.callee)
id_type = cases_list[i].consequent[0].declarations[0].init.callee.property.name
if (cases_list[i].consequent[0].declarations[0].init.consequent || cases_list[i].consequent[0].declarations[0].init.alternate)
id_type = cases_list[i].consequent[0].declarations[0].init.consequent.callee.property.name
id_type = get_id_type(id_type)
// console.log(id_type);
if (cases_list[i].consequent[1].type == 'ForStatement')
id_name = cases_list[i].consequent[1].body.body[0].expression.callee.property.name
else if (cases_list[i].consequent[1].type == 'ExpressionStatement') {
if (cases_list[i].consequent[1].expression.expressions)
id_name = cases_list[i].consequent[1].expression.expressions[cases_list[i].consequent[1].expression.expressions.length - 1].callee.property.name
else
id_name = cases_list[i].consequent[1].expression.callee.property.name
}
if (id_name.startsWith("set")) {
id_st = "";
} else if (id_name.startsWith("add")) {
id_st = "repeated";
} else {
// map类型因为案例中用不到所以这里省略
continue
}
id_name = id_name.substring(3, id_name.length);
// console.log(id_name)
if (id_type == 'readEnum') {
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else if (id_type == 'readPackedEnum') {
id_st = 'repeated'
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else
text = text + id_st + ' ' + id_type + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
}
}
if (cases_list[i].consequent[0].type == 'ExpressionStatement') {
//一般处理
if (cases_list[i].consequent[0].expression.right.type == 'CallExpression') {
id_type = cases_list[i].consequent[0].expression.right.callee.property.name
// console.log(id_type)
id_type = get_id_type(id_type)
// console.log(id_type);
if (cases_list[i].consequent[1].type == 'ForStatement')
id_name = cases_list[i].consequent[1].body.body[0].expression.callee.property.name
else if (cases_list[i].consequent[1].type == 'ExpressionStatement') {
if (cases_list[i].consequent[1].expression.expressions)
id_name = cases_list[i].consequent[1].expression.expressions[cases_list[i].consequent[1].expression.expressions.length - 1].callee.property.name
else
id_name = cases_list[i].consequent[1].expression.callee.property.name
}
// console.log(id_name);
if (id_name.startsWith("set")) {
id_st = "";
} else if (id_name.startsWith("add")) {
id_st = "repeated";
} else {
// map类型因为案例中用不到所以这里省略
continue
}
id_name = id_name.substring(3, id_name.length).toLowerCase();
// console.log(id_name)
if (id_type == 'readEnum') {
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else if (id_type == 'readPackedEnum') {
id_st = 'repeated'
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else
text = text + id_st + ' ' + id_type + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
}
//遇到new对象处理
if (cases_list[i].consequent[0].expression.right.type == 'NewExpression') {
//转化成字符串对象处理
node_code = cases_list[i].consequent[0].expression.right.callee
node_code_list = generator(node_code).code.split('.')
node_code_list.shift()
id_type = node_code_list.join('_')
// console.log(id_type);
//获得name
id_name = cases_list[i].consequent[1].expression.expressions[1].callee.property.name
// console.log(id_name);
if (id_name.startsWith("set")) {
id_st = "";
} else if (id_name.startsWith("add")) {
id_st = "repeated";
} else {
// map类型因为案例中用不到所以这里省略
continue
}
id_name = id_name.substring(3, id_name.length).toLowerCase();
// console.log(id_name)
if (id_type == 'readEnum') {
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else if (id_type == 'readPackedEnum') {
id_st = 'repeated'
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else
text = text + id_st + ' ' + id_type + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
}
}
}
}
},
////某音有的结构,遇到其他网站可以注释
IfStatement(path3) {
location = path3.node.test.left.value
if (path3.node.consequent.type === 'BlockStatement') {
if (path3.node.consequent.body[0].type === 'VariableDeclaration') {
// console.log(generator(path3.node).code)
//遇到new对象处理
if (path3.node.consequent.body[0].declarations[0].init.type == 'NewExpression') {
//获得type
node_code = path3.node.consequent.body[0].declarations[0].init
// console.log(generator(node_code).code)
node_code_list = generator(node_code).code.split('.')
node_code_list.shift()
id_type = node_code_list.join('_').replace('()', '')
// console.log(id_type);
//获得name这部分有点问题大家可以自行修改
try {
id_name = path3.node.consequent.body[0].expression.callee.property.name
} catch (e) {
id_name = path3.node.consequent.body[1].expression.expressions[1].callee.property.name
}
// console.log(id_name);
if (id_name.startsWith("set")) {
id_st = "";
} else if (id_name.startsWith("add")) {
id_st = "repeated";
} else {
// map类型因为案例中用不到所以这里省略
}
id_name = id_name.substring(3, id_name.length).toLowerCase();
// console.log(id_name)
if (id_type == 'readEnum') {
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else if (id_type == 'readPackedEnum') {
id_st = 'repeated'
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else
text = text + id_st + ' ' + id_type + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else {
id_type = path3.node.consequent.body[0].declarations[0].init.callee.property.name
id_type = get_id_type(id_type)
id_name = path3.node.consequent.body[1].expression.callee.property.name
if (id_name.startsWith("set")) {
id_st = "";
} else if (id_name.startsWith("add")) {
id_st = "repeated";
} else {
// map类型因为案例中用不到所以这里省略
}
id_name = id_name.substring(3, id_name.length).toLowerCase();
// console.log(id_name)
if (id_type == 'readEnum') {
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else if (id_type == 'readPackedEnum') {
id_st = 'repeated'
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else
text = text + id_st + ' ' + id_type + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
}
}
}
if (path3.node.consequent.type === 'ForStatement') {
id_type = path3.node.consequent.init.declarations[0].init.consequent.callee.property.name
id_type = get_id_type(id_type)
id_name = path3.node.consequent.body.expression.callee.property.name
// console.log(id_name);
if (id_name.startsWith("set")) {
id_st = "";
} else if (id_name.startsWith("add")) {
id_st = "repeated";
} else {
// map类型因为案例中用不到所以这里省略
}
id_name = id_name.substring(3, id_name.length).toLowerCase();
// console.log(id_name)
if (id_type == 'readEnum') {
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else if (id_type == 'readPackedEnum') {
id_st = 'repeated'
text = text + 'enum ' + titleCase(id_name) + ' {\n' + id_name + '_0=0;\n}\n' + id_st + ' ' + titleCase(id_name) + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
} else
text = text + id_st + ' ' + id_type + ' ' + id_name.toLowerCase() + '=' + location + ';' + '\n'
}
}
}
)
}
text = text + '}\n'
}
}
}
}
//处理enum对象插件
const visitor2 = {
AssignmentExpression(path) {
if (path.node.right.type === 'ObjectExpression' && path.node.left.type === 'MemberExpression' && path.node.right.properties.length) {
left_node = path.node.left
left_code = generator(left_node).code.split('.')
word = left_code.shift()
if (word === 'proto') {
enum_name = left_code.join('_')
// console.log(enum_name)
right_object_list = path.node.right.properties
right_str = ''
for (i = 0; i < right_object_list.length; i++) {
// console.log(right_object_list[i].key.name)
objet_name = right_object_list[i].key.name
objet_value = right_object_list[i].value.value
right_str = right_str + enum_name + '_' + objet_name + '=' + objet_value + ';\n'
}
text = text + 'enum ' + enum_name + '{\n' + right_str + '}' + '\n'
// console.log(right_code)
}
}
// console.log(generator(path.node).code)
}
}
//调用插件,处理源代码
// traverse(ast, visitor2)
// console.log('enum部分完成')
// fs.writeFile('douyin_test_enum完成.proto', text, (err) => {});
traverse(ast, visitor);
console.log('message部分完成')
// // fs.writeFile('douyin_test_message完成.proto', text, (err) => {});
//
//
// // console.log(text);
//
fs.writeFile(decode_file, text, (err) => {
});

236
douyinlive/main.py Normal file
View File

@ -0,0 +1,236 @@
# from websocket import WebSocketApp
import json
import base64
import re
from urllib.parse import unquote_plus
import requests
import websocket
import new_pb2 as pb
import execjs
ctx=execjs.compile(open('get_handle.js','r').read())
ctx2=execjs.compile(open('sign.js','r').read())
pushproto_PushFrame = pb.pushproto_PushFrame()
pushproto_PushFrame.payloadtype = "hb"
ping_byte = pushproto_PushFrame.SerializeToString()
# print(ping_byte)
def getsignature(room_id):
encrypt_data={
"app_name": "douyin_web",
"version_code": "180800",
"webcast_sdk_version": "1.3.0",
"update_version_code": "1.3.0",
"compress": "gzip",
"internal_ext": "internal_src:dim|wss_push_room_id:7207278655167318816|wss_push_did:7207288815714141734|dim_log_id:20230306141514E5958EB8835D27B6FC01|fetch_time:1678083315093|seq:1|wss_info:0-1678083315093-0-0|wrds_kvs:WebcastRoomRankMessage-1678083188373199999_InputPanelComponentSyncData-1678075358394993109_HighlightContainerSyncData-5_WebcastRoomStatsMessage-1678083314333747395",
"cursor": "t-1678083315093_r-1_d-1_u-1_h-1",
"host": "https://live.douyin.com",
"aid": "6383",
"live_id": 1,
"did_rule": 3,
"debug": False,
"endpoint": "live_pc",
"support_wrds": 1,
"im_path": "/webcast/im/fetch/",
"user_unique_id": "7207288815714141734",
"device_platform": "web",
"cookie_enabled": True,
"screen_width": 1440,
"screen_height": 960,
"browser_language": "zh-CN",
"browser_platform": "Win32",
"browser_name": "Mozilla",
"browser_version": "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
"browser_online": True,
"tz_name": "Asia/Shanghai",
"identity": "audience",
"room_id": room_id,
"heartbeatDuration": "0"
}
signature = ctx2.call('get_sign', encrypt_data)
return signature
def fetch_live_room_info(url):
s=requests.session()
headers={
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
}
response = s.get(url, headers=headers)
cookies_dict = dict(response.cookies)
response = s.get(url, headers=headers, cookies=cookies_dict)
ttwid = dict(response.cookies).get('ttwid')
data_string = re.findall(r'<script id="RENDER_DATA" type="application/json">(.*?)</script>', response.text)[0]
data_dict = json.loads(unquote_plus(data_string))
room_id = data_dict['app']['initialState']['roomStore']['roomInfo']['roomId']
room_title = data_dict['app']['initialState']['roomStore']['roomInfo']["room"]['title']
room_user_count = data_dict['app']['initialState']['roomStore']['roomInfo']["room"]['user_count_str']
# print('data_dict',data_dict)
sign=getsignature(room_id)['X-Bogus']
# print(sign)
# "wss://webcast3-ws-web-lq.douyin.com/webcast/im/push/v2/?app_name=douyin_web&version_code=180800&webcast_sdk_version=1.3.0&update_version_code=1.3.0&compress=gzip&internal_ext=internal_src:dim|wss_push_room_id:7207278655167318816|wss_push_did:7207288815714141734|dim_log_id:20230306141143BD3CCC7F4DDB60EF17BD|fetch_time:1678083103647|seq:1|wss_info:0-1678083103647-0-0|wrds_kvs:WebcastRoomStatsMessage-1678083098314427540_WebcastRoomRankMessage-1678083050356881368_HighlightContainerSyncData-5_InputPanelComponentSyncData-1678075358394993109&cursor=h-1_t-1678083103647_r-1_d-1_u-1&host=https://live.douyin.com&aid=6383&live_id=1&did_rule=3&debug=false&endpoint=live_pc&support_wrds=1&im_path=/webcast/im/fetch/&user_unique_id=7207288815714141734&device_platform=web&cookie_enabled=true&screen_width=1440&screen_height=960&browser_language=zh-CN&browser_platform=Win32&browser_name=Mozilla&browser_version=5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36&browser_online=true&tz_name=Asia/Shanghai&identity=audience&room_id=7207278655167318816&heartbeatDuration=0&signature=R4/bsUQ+Ps82hF6J"
wss_url = f"wss://webcast3-ws-web-lq.douyin.com/webcast/im/push/v2/?app_name=douyin_web&version_code=180800&webcast_sdk_version=1.3.0&update_version_code=1.3.0&compress=gzip&internal_ext=internal_src:dim|wss_push_room_id:7207278655167318816|wss_push_did:7207288815714141734|dim_log_id:20230306141005A7E02173D68CBD5587C4|fetch_time:1678083005453|seq:1|wss_info:0-1678083005453-0-0|wrds_kvs:WebcastRoomStatsMessage-1678082996341225893_HighlightContainerSyncData-5_InputPanelComponentSyncData-1678075358394993109_WebcastRoomRankMessage-1678082666367325824&cursor=t-1678083005453_r-1_d-1_u-1_h-1&host=https://live.douyin.com&aid=6383&live_id=1&did_rule=3&debug=false&endpoint=live_pc&support_wrds=1&im_path=/webcast/im/fetch/&user_unique_id=7207288815714141734&device_platform=web&cookie_enabled=true&screen_width=1440&screen_height=960&browser_language=zh-CN&browser_platform=Win32&browser_name=Mozilla&browser_version=5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/110.0.0.0%20Safari/537.36&browser_online=true&tz_name=Asia/Shanghai&identity=audience&room_id={room_id}&heartbeatDuration=0&signature={sign}"
return room_id, room_title, room_user_count, wss_url, ttwid
def keymessage(ws,byte,logid,payloadtype):
# print('keymessage---',keymessage)
webcast_im_Response = pb.webcast_im_Response()
webcast_im_Response.ParseFromString(byte)
# print(webcast_im_Response)
for item in webcast_im_Response.messages:
# print(item.method)
if item.method == 'WebcastMemberMessage':
webcast_im_MemberMessage = pb.webcast_im_MemberMessage()
webcast_im_MemberMessage.ParseFromString(item.payload)
# print(webcast_im_MemberMessage)
try:
nickname = webcast_im_MemberMessage.user.nickname
text = webcast_im_MemberMessage.common.displaytext.defaultpattern.strip('{0:user} ').strip('{1:string}')
print(nickname+':'+text)
except:
pass
if item.method == 'WebcastChatMessage':
webcast_im_ChatMessage = pb.webcast_im_ChatMessage()
webcast_im_ChatMessage.ParseFromString(item.payload)
# print(webcast_im_ChatMessage)
try:
nickname = webcast_im_ChatMessage.user.nickname
# print(nickname)
content = webcast_im_ChatMessage.content
# print(content)
# print(nickname, ':', content)
except:
pass
if item.method == 'WebcastGiftMessage':
webcast_im_GiftMessage = pb.webcast_im_GiftMessage()
webcast_im_GiftMessage.ParseFromString(item.payload)
# print(webcast_im_GiftMessage)
print(webcast_im_GiftMessage.common.describe)
try:
user = webcast_im_GiftMessage.user.nickname
gift = webcast_im_GiftMessage.gift.name
# print(webcast_im_GiftMessage.common.describe)
except:
pass
if item.method == 'WebcastSocialMessage':
webcast_im_SocialMessage = pb.webcast_im_SocialMessage()
webcast_im_SocialMessage.ParseFromString(item.payload)
try:
user = webcast_im_SocialMessage.user.nickname
text = webcast_im_SocialMessage.common.displaytext.defaultpattern.strip('{0:user} ')
# print(webcast_im_SocialMessage)
# print(user,text)
except:
pass
if item.method == 'WebcastLikeMessage':
webcast_im_LikeMessage = pb.webcast_im_LikeMessage()
webcast_im_LikeMessage.ParseFromString(item.payload)
try:
user = webcast_im_LikeMessage.user.nickname
# print(user)
text = webcast_im_LikeMessage.common.displaytext.pieces[-1].stringvalue
# print(text)
# print(user,text)
except:
pass
# print(webcast_im_LikeMessage)
if item.method == 'WebcastRoomStatsMessage':
webcast_im_RoomStatsMessage = pb.webcast_im_RoomStatsMessage()
webcast_im_RoomStatsMessage.ParseFromString(item.payload)
print(webcast_im_RoomStatsMessage)
needack = webcast_im_Response.needack
# print(needack)
if needack:
internalext = webcast_im_Response.internalext
# print(webcast_im_Response.cursor)
ackpayload = ctx.call('get_ackpayload', internalext)
# print(ackpayload)
ackpayload = base64.b64decode(ackpayload)
# print(ackpayload)
pushproto_PushFrame2 = pb.pushproto_PushFrame()
pushproto_PushFrame2.payloadtype = 'ack'
pushproto_PushFrame2.payload = ackpayload
pushproto_PushFrame2.logid = logid
# print(pushproto_PushFrame2.SerializeToString())
ws.send(pushproto_PushFrame2.SerializeToString())
if payloadtype == 'close':
ws.close()
def on_open(ws):
print('连接成功!!!')
ws.send(ping_byte)
def on_message(ws, content):
print('已获得数据:')
pushproto_PushFrame.ParseFromString(content)
logid=pushproto_PushFrame.logid
payloadtype=pushproto_PushFrame.payloadtype
# print(pushproto_PushFrame.headers)
headers_list = {}
for item in pushproto_PushFrame.headers:
headers_list[item.key] = item.value
# print(headers_list)
if 'compress_type' in headers_list and headers_list['compress_type'] == 'gzip':
payload = pushproto_PushFrame.payload
payload = base64.b64encode(payload).decode()
string = ctx.call('handle', payload)
byte = base64.b64decode(string)
keymessage(ws,byte,logid,payloadtype)
else:
payload = pushproto_PushFrame.payload
keymessage(ws, payload, logid,payloadtype)
def on_ping(ws):
ws.send(ping_byte)
def on_error(ws,errormessag,**kwargs):
try:
pass
except:
pass
print("on_error:")
print(errormessag)
def on_close(ws, content,**kwargs):
print("连接已关闭!!!")
def run():
web_url = "https://live.douyin.com/911085801976"
room_id, room_title, room_user_count, wss_url, ttwid = fetch_live_room_info(web_url)
print(f'欢迎来到{room_title}直播间,直播间人数{room_user_count}')
cookie=f'ttwid={ttwid}'
ws = websocket.WebSocketApp(
url=wss_url,
header={
"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36'
},
cookie=cookie,
on_open=on_open,
on_message=on_message,
on_error=on_error,
on_close=on_close,
on_ping=on_ping
)
ws.run_forever(ping_interval=10)
if __name__ == '__main__':
run()

10219
douyinlive/new.proto Normal file

File diff suppressed because it is too large Load Diff

3055
douyinlive/new_pb2.py Normal file

File diff suppressed because one or more lines are too long

3176
douyinlive/sign.js Normal file

File diff suppressed because one or more lines are too long