Add Douyin video downloader with auto-cookie feature

This commit is contained in:
2026-03-02 21:42:52 +08:00
commit 0f3dd8f287
50 changed files with 6471 additions and 0 deletions

197
Server/Server.py Normal file
View File

@@ -0,0 +1,197 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@Description:Server.py
@Date :2023/02/25 17:03:32
@Author :JohnserfSeed
@version :0.0.1
@License :MIT License
@Github :https://github.com/johnserf-seed
@Mail :johnserf-seed@foxmail.com
-------------------------------------------------
Change Log :
2023/02/25 17:03:32 - Create Flask Server XB Gen
2023/08/03 16:48:34 - Fix ttwid
-------------------------------------------------
'''
import time
import execjs
# import sqlite3
import requests
from flask import Flask
from flask import request
from flask import jsonify
# from flask import make_response
# from flask import render_template
from urllib.parse import urlencode
from urllib.parse import unquote
from urllib.parse import parse_qsl
class Server:
def __init__(self) -> None:
# 工厂模式
self.app = Flask(__name__)
self.app.config.from_mapping(
SECRET_KEY='douyin-xbogus'
)
self.app.config['JSON_AS_ASCII'] = False
with open("x-bogus.js", "r", encoding="utf-8") as fp:
self.xbogust_func = execjs.compile(fp.read())
with open("x-tt-params.js", "r", encoding="utf-8") as fp:
self.xttm_func = execjs.compile(fp.read())
self.ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
# 获取xg参数
def getXG(self, url_path, params):
xbogus = self.xbogust_func.call("getXB", url_path)
# 字典中添加xg
params["X-Bogus"] = xbogus
tips = {
"status_code": "200",
"time": {
"strftime": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
"timestamp": int(round(time.time() * 1000))
},
"result": [{
"params": params,
"paramsencode": urlencode(params, safe="="),
"user-agent": self.ua,
"X-Bogus": {
0: xbogus,
1: "X-Bogus=%s" % xbogus
}
}]
}
print(tips)
return jsonify(tips)
# 生成x-tt-params
def getxttparams(self, url_path):
xttp = self.xttm_func.call("getXTTP", url_path)
tips = {
"status_code": "200",
"time": {
"strftime": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
"timestamp": int(round(time.time() * 1000))
},
"result": [{
"headers": {
"user-agent": self.ua,
"x-tt-params": xttp
}
}]
}
print(tips)
return jsonify(tips)
def gen_ttwid(self) -> str:
"""生成请求必带的ttwid
param :None
return:ttwid
"""
url = 'https://ttwid.bytedance.com/ttwid/union/register/'
data = '{"region":"cn","aid":1768,"needFid":false,"service":"www.ixigua.com","migrate_info":{"ticket":"","source":"node"},"cbUrlProtocol":"https","union":true}'
response = requests.request("POST", url, data=data)
# j = ttwid k = 1%7CfPx9ZM.....
for j, k in response.cookies.items():
tips = {
"status_code": "200",
"time": {
"strftime": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
"timestamp": int(round(time.time() * 1000))
},
"result": [{
"headers": {
"user-agent": self.ua,
"cookie": "ttwid=%s;" % k
}
}]
}
print(tips)
return jsonify(tips)
if __name__ == "__main__":
server = Server()
# 首页
@server.app.route('/', methods=['GET', 'POST'])
def index():
tips = {
"status_code": "-1",
"time": {
"strftime": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
"timestamp": int(round(time.time() * 1000))
},
"path": {
0: "/xg/path/?url=",
2: "/x-tt-params/path"
}
}
print(tips)
return jsonify(tips)
# xg参数
@server.app.route('/xg/path/', methods=['GET', 'POST'])
def xgpath():
path = request.args.get('url', '')
# 如果str路径为空
if not path:
tips = {
"status_code": "-3",
"time": {
"strftime": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
"timestamp": int(round(time.time() * 1000))
},
"message": {
0: "The key url cannot be empty and the need for url encoding, The '&' sign needs to be escaped to '%26', Use urllib.parse.quote(url) to escape. Example:/xg/path/?url=aid=6383%26sec_user_id=xxx%26max_cursor=0%26count=10",
1: "url参数不能为空且需要注意传入值中的“&”需要转义成“%26”使用urllib.parse.quote(url)转义. 例如:/xg/path/?url=aid=6383%26sec_user_id=xxx%26max_cursor=0%26count=10"
}
}
print(tips)
return jsonify(tips)
else:
# url转字典
params = dict(parse_qsl(path))
# 字典转url
url_path = urlencode(params, safe="=")
return server.getXG(url_path, params)
# x-tt-params参数
@server.app.route('/x-tt-params/path', methods=['GET', 'POST'])
def xttppath():
try:
path = request.json
except:
pass
if not path:
tips = {
"status_code": "-5",
"time": {
"strftime": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
"timestamp": int(round(time.time() * 1000))
},
"message": {
0: "Body uses raw JSON format to pass dictionary parameters, such as %s" % '{"aid": 1988,"app_name": "tiktok_web","channel": "tiktok_web".........}',
1: "body中使用raw json格式传递字典参数%s" % '{"aid": 1988,"app_name": "tiktok_web","channel": "tiktok_web".........}'
}
}
print(tips)
return jsonify(tips)
else:
return server.getxttparams(path)
# ttwid
@server.app.route('/xg/ttwid', methods=['GET', 'POST'])
def ttwid():
return server.gen_ttwid()
server.app.run(host='0.0.0.0',port='8889')