1
Fork 0
mirror of https://github.com/thegeneralist01/twitter-openapi synced 2026-01-09 23:00:24 +01:00
twitter-openapi/tools/generater.py
ふぁ cd591c0377
Update openapi schemas
Signed-off-by: ふぁ <yuki@yuki0311.com>
2024-09-27 12:15:03 +09:00

130 lines
4.7 KiB
Python

# https://github.com/tsukumijima/KonomiTV/blob/master/server/misc/TwitterAPIQueryGenerator.py
# https://github.com/tsukumijima/KonomiTV/blob/master/License.txt
#!/usr/bin/env python3
# Usage: poetry run python -m misc.TwitterAPIQueryGenerator
import json
import re
import urllib.parse
from rich import print
from rich.rule import Rule
def main():
print(Rule(characters="="))
print(
"Chrome DevTools の Network タブで「表示されているものをすべてfetch としてコピー」したコードを`input.js`に貼り付けてください。"
)
print("Enter を押すと続行します。")
print(Rule(characters="="))
input()
with open("./tools/input.js", "r") as f:
fetch_code_raw = f.read()
print(Rule(characters="="))
splited = fetch_code_raw.split("\n")
fetch_code_list = []
code = ""
for line in splited:
if line.startswith("fetch("):
if code:
fetch_code_list.append(code)
code = line
else:
code += line + "\n"
fetch_code_list.append(code)
for fetch_code in fetch_code_list:
# query_idとendpointを抽出
query_id_match = re.search(r'/i/api/graphql/([^/]+)/([^"?]+)', fetch_code)
if not query_id_match:
print("query_id と endpoint の抽出に失敗しました。")
print(Rule(characters="="))
return
query_id = query_id_match.group(1)
endpoint = query_id_match.group(2)
# リクエストメソッドを判定
method_match = re.search(r'"method"\s*:\s*"(GET|POST)"', fetch_code)
if not method_match:
print("リクエストメソッドの判定に失敗しました。")
print(Rule(characters="="))
return
method = method_match.group(1)
if method == "POST":
# POST リクエストの場合、fetch() コードの第二引数にある {} で囲まれたオブジェクトを正規表現で抽出したものを JSON としてパース
body_match = re.search(r'"body"\s*:\s*"({.*})"', fetch_code, re.DOTALL)
if not body_match:
print("body の抽出に失敗しました。")
print(Rule(characters="="))
return
body_json_str = body_match.group(1).replace("\\", "")
body_json = json.loads(body_json_str)
features = body_json.get("features", None)
variables = body_json.get("variables", None)
else:
# GET リクエストの場合、まず URL を抽出
url_match = re.search(r'"(https?://[^"]+)"', fetch_code)
if not url_match:
print("URL の抽出に失敗しました。")
print(Rule(characters="="))
return
url = url_match.group(1)
# URL をパースして query string を取得
parsed_url = urllib.parse.urlparse(url)
query_string = parsed_url.query
# query string を dict 形式にパース
query_dict = urllib.parse.parse_qs(query_string)
# features を取得
features_json_str = query_dict.get("features", [None])[0]
if features_json_str is None:
features = None
variables = None
else:
try:
features = json.loads(features_json_str)
except json.JSONDecodeError:
print(
"features の JSON パースに失敗しました。features は None として続行します。"
)
features = None
variables = None
with open("./src/config/placeholder.json", "r") as f:
placeholder = json.load(f)
def check(a, b, msg):
if isinstance(a, dict) and isinstance(b, dict):
for k in {*a.keys(), *b.keys()}:
if k not in b:
print(f"{msg} key: {k} が存在しません。")
elif k not in a:
print(f"{msg} key: {k} が存在しません。")
else:
check(a[k], b[k], msg)
check(
variables,
placeholder.get(endpoint, {}).get("variables", {}),
f"{endpoint} の variables が不一致です。",
)
with open("./src/config/placeholder.json", "w") as f:
placeholder[endpoint] = placeholder.get(endpoint, {})
placeholder[endpoint]["queryId"] = query_id
if features:
placeholder[endpoint]["features"] = features
json.dump(placeholder, f, indent=4)
if __name__ == "__main__":
main()