feat: integrate creator hub douyin workflows

This commit is contained in:
2026-09-14 19:22:07 +08:00
parent 025fe62c37
commit 44a28954cf
42 changed files with 2850 additions and 880 deletions
+36 -42
View File
@@ -1,5 +1,6 @@
from __future__ import annotations
import base64
import io
import json
import socket
@@ -83,7 +84,6 @@ validate_create = gateway_module.validate_create
parse_proxy_exit = gateway_module.parse_proxy_exit
validate_proxy_exit = gateway_module.validate_proxy_exit
validate_proxy_restore = gateway_module.validate_proxy_restore
valid_cookies = gateway_module.valid_cookies
valid_douyin_generation = gateway_module.valid_douyin_generation
valid_account_key_query = gateway_module.valid_account_key_query
numeric_cursor = gateway_module.numeric_cursor
@@ -228,7 +228,8 @@ class GatewayValidationTests(unittest.TestCase):
handler._route("POST", "/v1/browsers/safe/start", {}, {})
handler._route("POST", "/v1/browsers/safe/stop", {}, {})
handler._route("POST", "/v1/browsers/safe/proxy", {}, {})
handler._route("POST", "/v1/browsers/safe/douyin/cookies", {}, {})
with self.assertRaises(RequestError):
handler._route("POST", "/v1/browsers/safe/douyin/cookies", {}, {})
handler._route("POST", "/v1/browsers/safe/douyin/get", {}, {})
handler._route("POST", "/v1/browsers/safe/douyin/identity", {}, {})
handler._route("POST", "/v1/browsers/safe/douyin/action", {}, {})
@@ -285,10 +286,6 @@ class GatewayValidationTests(unittest.TestCase):
)
with self.assertRaises(RequestError):
validate_proxy_exit(ProxyExit("http", "proxy", 0))
cookie = {"name": "sessionid", "value": "v", "domain": ".douyin.com"}
self.assertTrue(valid_cookies([cookie]))
self.assertFalse(valid_cookies([{**cookie, "domain": "evil.example"}]))
self.assertFalse(valid_cookies([{**cookie, "same_site": "bad"}]))
generation = {
"binding_version": 1,
"runtime_id": "a" * 64,
@@ -332,19 +329,6 @@ class GatewayValidationTests(unittest.TestCase):
load_config({"GATEWAY_TOKEN": "short"})
self.assertFalse(valid_douyin_url("http://www.douyin.com/video/1"))
self.assertFalse(valid_douyin_url("https://www.douyin.com/unknown"))
self.assertFalse(valid_cookies("not-a-list"))
self.assertFalse(
valid_cookies(
[
{
"name": "x",
"value": "v",
"domain": ".douyin.com",
"path": "relative",
}
]
)
)
with self.assertRaises(RequestError):
decode_generation(
{"binding_version": 1, "runtime_id": "a" * 64}, True, True
@@ -651,33 +635,36 @@ class BrowserTests(unittest.TestCase):
cast(Any, browser).connection = bound
def test_cookie_navigation_and_fetch(self) -> None:
cdp = BrowserCDP(
[{"origin": "https://www.douyin.com", "state": "complete"}, "{}"]
)
browser = DouyinBrowser()
self._with_connection(browser, cdp)
browser.set_cookies(
"safe", [{"name": "sessionid", "value": "v", "domain": ".douyin.com"}]
)
self.assertIn("Page.navigate", [method for method, _ in cdp.commands])
set_command = next(
params for method, params in cdp.commands if method == "Network.setCookies"
)
assert set_command is not None
self.assertEqual(set_command["cookies"][0]["domain"], ".douyin.com")
def test_browser_fetch_uses_manually_logged_session(self) -> None:
cdp = BrowserCDP(
[
"https://www.douyin.com",
{"status": 200, "body": "{}", "too_large": False},
]
)
browser = DouyinBrowser()
self._with_connection(browser, cdp)
response = browser.get(
"safe", "https://www.douyin.com/aweme/v1/web/user/profile/self/?aid=6383"
)
self.assertEqual(response.status, 200)
self.assertNotIn("Network.setCookies", [method for method, _ in cdp.commands])
def test_media_download_is_browser_mediated_and_bounded(self) -> None:
payload = base64.b64encode(b"video-bytes").decode("ascii")
cdp = BrowserCDP(
[
"complete",
{"status": 200, "content_type": "video/mp4", "body": payload},
]
)
browser = DouyinBrowser()
self._with_connection(browser, cdp)
response = browser.get_media("safe", "https://www.douyin.com/video/123")
self.assertEqual(response.status, 200)
self.assertEqual(response.content_type, "video/mp4")
self.assertEqual(base64.b64decode(response.body_base64), b"video-bytes")
self.assertIn("Page.navigate", [method for method, _ in cdp.commands])
def test_connect_identity_and_actions(self) -> None:
target = [
@@ -1768,13 +1755,6 @@ class AdditionalGatewayCoverageTests(unittest.TestCase):
browser.action("safe", "1", "follow", "2", confirm=True)
def test_gateway_and_proxy_validation_edges(self) -> None:
for value in (
None,
[],
[{"name": "bad"}],
[{"name": "sessionid", "value": "x", "domain": "evil.test"}],
):
self.assertFalse(valid_cookies(value))
self.assertEqual(
parse_proxy_exit({"protocol": "http", "host": "", "port": 80}).host, ""
)
@@ -2009,7 +1989,21 @@ class AdditionalGatewayCoverageTests(unittest.TestCase):
assert notice is not None
self.assertEqual(notice["event_type"], "dm")
self.assertEqual(notice["interactor_uid"], "456789")
self.assertEqual(notice["message_type"], "text")
self.assertEqual(notice["message_text"], "hello")
non_text = normalize_notice(
{
"dm": {
"message_id": "123457",
"from_user": {"uid": "456789"},
"message_type": "image",
"image_url": "https://example.invalid/image",
}
}
)
assert non_text is not None
self.assertEqual(non_text["message_type"], "image")
self.assertEqual(non_text["message_text"], "")
script = action_expression({"alias": "safe", "action": "follow", "target": "2"})
self.assertIn("POST_UNCERTAIN", script)
self.assertIn("BUSINESS_REJECTED", script)