Add Douyin video downloader with auto-cookie feature
This commit is contained in:
197
Server/Server.py
Normal file
197
Server/Server.py
Normal 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')
|
||||
Reference in New Issue
Block a user