mirror of
https://github.com/xuxiaobo-bobo/boda_jsEnv.git
synced 2025-04-21 11:10:15 +08:00
'0306'
This commit is contained in:
parent
abcc2e6a07
commit
c9c5b9815d
7
douyinlive/README.md
Normal file
7
douyinlive/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# 原git链接 https://github.com/Prince-cool/dy_protobuf/blob/main/main.py
|
||||
# dy_protobuf
|
||||
某音弹幕protobuf实战源码及工具
|
||||
# 修改web_url参数即可,稍微进行了一些修改
|
||||
|
||||
|
||||
|
BIN
douyinlive/__pycache__/new_pb2.cpython-38.pyc
Normal file
BIN
douyinlive/__pycache__/new_pb2.cpython-38.pyc
Normal file
Binary file not shown.
2817
douyinlive/get_handle.js
Normal file
2817
douyinlive/get_handle.js
Normal file
File diff suppressed because one or more lines are too long
410
douyinlive/main.js
Normal file
410
douyinlive/main.js
Normal 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
236
douyinlive/main.py
Normal 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
10219
douyinlive/new.proto
Normal file
File diff suppressed because it is too large
Load Diff
3055
douyinlive/new_pb2.py
Normal file
3055
douyinlive/new_pb2.py
Normal file
File diff suppressed because one or more lines are too long
3176
douyinlive/sign.js
Normal file
3176
douyinlive/sign.js
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user