├── README.md └── algorithm.py /README.md: -------------------------------------------------------------------------------- 1 | # TikTok-Algorithm 2 | Code for generating Tiktok X-Gorgon, X-Khronos and etc. parameters, also containing examples on how to use the TikTok API. 3 | 4 | This code was not written by me. 5 | 6 | This code was last tested and worked on Nov 20, 2021. 7 | -------------------------------------------------------------------------------- /algorithm.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | from urllib import request, parse 3 | import time 4 | from io import StringIO 5 | import gzip 6 | import ssl 7 | ssl._create_default_https_context = ssl._create_unverified_context 8 | 9 | byteTable1 = "D6 28 3B 71 70 76 BE 1B A4 FE 19 57 5E 6C BC 21 B2 14 37 7D 8C A2 FA 67 55 6A 95 E3 FA 67 78 ED 8E 55 33 89 A8 CE 36 B3 5C D6 B2 6F 96 C4 34 B9 6A EC 34 95 C4 FA 72 FF B8 42 8D FB EC 70 F0 85 46 D8 B2 A1 E0 CE AE 4B 7D AE A4 87 CE E3 AC 51 55 C4 36 AD FC C4 EA 97 70 6A 85 37 6A C8 68 FA FE B0 33 B9 67 7E CE E3 CC 86 D6 9F 76 74 89 E9 DA 9C 78 C5 95 AA B0 34 B3 F2 7D B2 A2 ED E0 B5 B6 88 95 D1 51 D6 9E 7D D1 C8 F9 B7 70 CC 9C B6 92 C5 FA DD 9F 28 DA C7 E0 CA 95 B2 DA 34 97 CE 74 FA 37 E9 7D C4 A2 37 FB FA F1 CF AA 89 7D 55 AE 87 BC F5 E9 6A C4 68 C7 FA 76 85 14 D0 D0 E5 CE FF 19 D6 E5 D6 CC F1 F4 6C E9 E7 89 B2 B7 AE 28 89 BE 5E DC 87 6C F7 51 F2 67 78 AE B3 4B A2 B3 21 3B 55 F8 B3 76 B2 CF B3 B3 FF B3 5E 71 7D FA FC FF A8 7D FE D8 9C 1B C4 6A F9 88 B5 E5" 10 | 11 | 12 | def getXGon(url, stub, cookies): 13 | NULL_MD5_STRING = "00000000000000000000000000000000" 14 | sb = "" 15 | if len(url) < 1: 16 | sb = NULL_MD5_STRING 17 | else: 18 | sb = encryption(url) 19 | if len(stub) < 1: 20 | sb += NULL_MD5_STRING 21 | else: 22 | sb += stub 23 | if len(cookies) < 1: 24 | sb += NULL_MD5_STRING 25 | else: 26 | sb += encryption(cookies) 27 | index = cookies.index("sessionid=") 28 | if index == -1: 29 | sb += NULL_MD5_STRING 30 | else: 31 | sessionid = cookies[index + 10:] 32 | if sessionid.__contains__(';'): 33 | endIndex = sessionid.index(';') 34 | sessionid = sessionid[:endIndex] 35 | sb += encryption(sessionid) 36 | return sb 37 | 38 | 39 | def encryption(url): 40 | obj = hashlib.md5() # 先创建一个md5的对象 41 | # 写入要加密的字节 42 | obj.update(url.encode("UTF-8")) 43 | # 获取密文 44 | secret = obj.hexdigest() 45 | return secret.lower() 46 | 47 | 48 | def initialize(data): 49 | myhex = 0 50 | byteTable2 = byteTable1.split(" ") 51 | for i in range(len(data)): 52 | hex1 = 0 53 | if i == 0: 54 | hex1 = int(byteTable2[int(byteTable2[0], 16) - 1], 16) 55 | byteTable2[i] = hex(hex1) 56 | # byteTable2[i] = Integer.toHexString(hex1); 57 | elif i == 1: 58 | temp = int("D6", 16) + int("28", 16) 59 | if temp > 256: 60 | temp -= 256 61 | hex1 = int(byteTable2[temp - 1], 16) 62 | myhex = temp 63 | byteTable2[i] = hex(hex1) 64 | else: 65 | temp = myhex + int(byteTable2[i], 16) 66 | if temp > 256: 67 | temp -= 256 68 | hex1 = int(byteTable2[temp - 1], 16) 69 | myhex = temp 70 | byteTable2[i] = hex(hex1) 71 | if hex1 * 2 > 256: 72 | hex1 = hex1 * 2 - 256 73 | else: 74 | hex1 = hex1 * 2 75 | hex2 = byteTable2[hex1 - 1] 76 | result = int(hex2, 16) ^ int(data[i], 16) 77 | data[i] = hex(result) 78 | for i in range(len(data)): 79 | data[i] = data[i].replace("0x", "") 80 | return data 81 | 82 | 83 | def handle(data): 84 | for i in range(len(data)): 85 | byte1 = data[i] 86 | if len(byte1) < 2: 87 | byte1 += '0' 88 | else: 89 | byte1 = data[i][1] + data[i][0] 90 | if i < len(data) - 1: 91 | byte1 = hex(int(byte1, 16) ^ int(data[i + 1], 16)).replace("0x", "") 92 | else: 93 | byte1 = hex(int(byte1, 16) ^ int(data[0], 16)).replace("0x", "") 94 | byte1 = byte1.replace("0x", "") 95 | a = (int(byte1, 16) & int("AA", 16)) / 2 96 | a = int(abs(a)) 97 | byte2 = ((int(byte1, 16) & int("55", 16)) * 2) | a 98 | byte2 = ((byte2 & int("33", 16)) * 4) | (int)((byte2 & int("cc", 16)) / 4) 99 | byte3 = hex(byte2).replace("0x", "") 100 | if len(byte3) > 1: 101 | byte3 = byte3[1] + byte3[0] 102 | else: 103 | byte3 += "0" 104 | byte4 = int(byte3, 16) ^ int("FF", 16); 105 | byte4 = byte4 ^ int("14", 16) 106 | data[i] = hex(byte4).replace("0x", "") 107 | return data 108 | 109 | 110 | def xGorgon(timeMillis, inputBytes): 111 | data1 = [] 112 | data1.append("3") 113 | data1.append("61") 114 | data1.append("41") 115 | data1.append("10") 116 | data1.append("80") 117 | data1.append("0") 118 | data2 = input(timeMillis, inputBytes) 119 | data2 = initialize(data2) 120 | data2 = handle(data2) 121 | for i in range(len(data2)): 122 | data1.append(data2[i]) 123 | 124 | xGorgonStr = "" 125 | for i in range(len(data1)): 126 | temp = data1[i] + "" 127 | if len(temp) > 1: 128 | xGorgonStr += temp 129 | else: 130 | xGorgonStr += "0" 131 | xGorgonStr += temp 132 | return xGorgonStr 133 | 134 | 135 | def input(timeMillis, inputBytes): 136 | result = [] 137 | for i in range(4): 138 | if inputBytes[i] < 0: 139 | temp = hex(inputBytes[i]) + '' 140 | temp = temp[6:] 141 | result.append(temp) 142 | else: 143 | temp = hex(inputBytes[i]) + '' 144 | result.append(temp) 145 | for i in range(4): 146 | result.append("0") 147 | for i in range(4): 148 | if inputBytes[i + 32] < 0: 149 | result.append(hex(inputBytes[i + 32]) + '')[6:] 150 | else: 151 | result.append(hex(inputBytes[i + 32]) + '') 152 | for i in range(4): 153 | result.append("0") 154 | tempByte = hex(int(timeMillis)) + "" 155 | tempByte = tempByte.replace("0x", "") 156 | for i in range(4): 157 | a = tempByte[i * 2:2 * i + 2] 158 | result.append(tempByte[i * 2:2 * i + 2]) 159 | for i in range(len(result)): 160 | result[i] = result[i].replace("0x", "") 161 | return result 162 | 163 | 164 | def strToByte(str): 165 | length = len(str) 166 | str2 = str 167 | bArr = [] 168 | i = 0 169 | while i < length: 170 | # bArr[i/2] = b'\xff\xff\xff'+(str2hex(str2[i]) << 4+str2hex(str2[i+1])).to_bytes(1, "big") 171 | a = str2[i] 172 | b = str2[1 + i] 173 | c = ((str2hex(a) << 4) + str2hex(b)) 174 | bArr.append(c) 175 | i += 2 176 | return bArr 177 | 178 | 179 | def str2hex(s): 180 | odata = 0; 181 | su = s.upper() 182 | for c in su: 183 | tmp = ord(c) 184 | if tmp <= ord('9'): 185 | odata = odata << 4 186 | odata += tmp - ord('0') 187 | elif ord('A') <= tmp <= ord('F'): 188 | odata = odata << 4 189 | odata += tmp - ord('A') + 10 190 | return odata 191 | 192 | 193 | def doGetGzip(url, headers, charset): 194 | req = request.Request(url) 195 | for key in headers: 196 | req.add_header(key, headers[key]) 197 | with request.urlopen(req, ) as f: 198 | data = f.read() 199 | return gzip.decompress(data).decode() 200 | 201 | 202 | def doPostGzip(url, headers, charset, params): 203 | data = parse.urlencode(params).encode(encoding='UTF8') 204 | req = request.Request(url) 205 | for key in headers: 206 | req.add_header(key, headers[key]) 207 | with request.urlopen(req, data=data) as f: 208 | data = f.read() 209 | return gzip.decompress(data).decode() 210 | 211 | 212 | def testVideo(): 213 | url = "https://api.amemv.com/aweme/v1/aweme/post/?min_cursor=0&max_cursor=0&user_id=3988636999116436&count=12&retry_type=no_retry&iid=109444326057&device_id=71287686249&ac=wifi&channel=wandoujia_aweme1&aid=1128&app_name=aweme&version_code=580&version_name=5.8.0&device_platform=android&ssmix=a&device_type=Redmi+7&device_brand=xiaomi&language=zh&os_api=28&os_version=9&uuid=869770206713501&openudid=fa23302a97ff78d8&manifest_version_code=580&resolution=720*1369&dpi=320&update_version_code=5800&_rticket=1586317529843&mcc_mnc=46000&ts=1586317529&js_sdk_version=1.13.10&as=a145e4573a697ec94c4388&cp=4d96e95ca9ca7095e1QiYm&mas=011e3edaa330cfa2b4aaad7ffd200ad3c91c1ccc2cc62c9cc6a6ec" 214 | cookies = "odin_tt=040efd2bf4c78c326ebea9cfef43c85c9fd71818c1187c4c4d9b0d1994358d2e26652a7ac37e10bc17dbb6d75b66d8f1581df65cc3b04fa8ec347c776bd32642; d_ticket=7061a2d71f0b7d7f808b8b5b387469b758fe5; sid_guard=5fd28ea88ca3a63af05149dc57643f6a%7C1585289794%7C5184000%7CTue%2C+26-May-2020+06%3A16%3A34+GMT; uid_tt=95140db49dc514a38e2d3f2e397a4801; sid_tt=5fd28ea88ca3a63af05149dc57643f6a; sessionid=5fd28ea88ca3a63af05149dc57643f6a; install_id=109444326057; ttreq=1$33d82222910d9c4ef2f61f17df2610ccf98061b3" 215 | ts = str(time.time()).split(".")[0] 216 | _rticket = str(time.time() * 1000).split(".")[0] 217 | params = url[url.index('?') + 1:] 218 | STUB = "" 219 | s = getXGon(params, STUB, cookies) 220 | gorgon = xGorgon(ts, strToByte(s)) 221 | print(gorgon) 222 | headers = { 223 | "X-Gorgon": gorgon, 224 | "X-SS-REQ-TICKET": "1585711173953", 225 | "X-Khronos": ts, 226 | "sdk-version": "1", 227 | "Accept-Encoding": "gzip", 228 | "X-SS-REQ-TICKET": _rticket, 229 | "User-Agent": "com.ss.android.ugc.aweme/580 (Linux; U; Android 9; zh_CN; Redmi 7; Build/PKQ1.181021.001; Cronet/58.0.2991.0)", 230 | "Host": "api.amemv.com", 231 | "Cookie": cookies, 232 | "Connection": "Keep-Alive", 233 | # "x-tt-token":"00080ab789c0bf0519740314c59de87d8ace96d49d8ab2afd7a0f09cba0911612f99baf92acae289860e0f84ffd97fc2c344" 234 | } 235 | result = doGetGzip(url, headers, "UTF-8") 236 | print(result) 237 | 238 | 239 | def search_item(): 240 | url = "https://api.amemv.com/aweme/v1/search/item/?manifest_version_code=700&_rticket=1588042256699&app_type=normal&iid=2049122346481144&channel=wandoujia_aweme1&device_type=Redmi%207&language=zh&resolution=720*1369&openudid=23ff9f6b93efea26&update_version_code=7002&os_api=28&dpi=320&ac=wifi&device_id=67765281791&mcc_mnc=46000&os_version=9&version_code=700&app_name=aweme&version_name=7.0.0&js_sdk_version=1.18.1.0&device_brand=xiaomi&ssmix=a&device_platform=android&aid=1128&ts=1588042250" 241 | params = "keyword=jjj&offset=0&count=10&source=video_search&is_pull_refresh=1&hot_search=0&search_id=&query_correct_type=1" 242 | params2 = { 243 | "keyword": "key", 244 | "offset": 0, 245 | "count": 10, 246 | "source": "video_search", 247 | "is_pull_refresh": 1, 248 | "hot_search": 0 249 | } 250 | cookies = "odin_tt=040efd2bf4c78c326ebea9cfef43c85c9fd71818c1187c4c4d9b0d1994358d2e26652a7ac37e10bc17dbb6d75b66d8f1581df65cc3b04fa8ec347c776bd32642; d_ticket=7061a2d71f0b7d7f808b8b5b387469b758fe5; sid_guard=5fd28ea88ca3a63af05149dc57643f6a%7C1585289794%7C5184000%7CTue%2C+26-May-2020+06%3A16%3A34+GMT; uid_tt=95140db49dc514a38e2d3f2e397a4801; sid_tt=5fd28ea88ca3a63af05149dc57643f6a; sessionid=5fd28ea88ca3a63af05149dc57643f6a; install_id=109444326057; ttreq=1$33d82222910d9c4ef2f61f17df2610ccf98061b3" 251 | ts = str(time.time()).split(".")[0] 252 | _rticket = str(time.time() * 1000).split(".")[0] 253 | STUB = "" 254 | s = getXGon(params, STUB, cookies) 255 | gorgon = xGorgon(ts, strToByte(s)) 256 | print(gorgon) 257 | headers = { 258 | "X-Gorgon": gorgon, 259 | "X-SS-REQ-TICKET": "1585711173953", 260 | "X-Khronos": ts, 261 | "sdk-version": "1", 262 | "Accept-Encoding": "gzip", 263 | "X-SS-REQ-TICKET": _rticket, 264 | "User-Agent": "com.ss.android.ugc.aweme/700 (Linux; U; Android 9; zh_CN; Redmi 7; Build/PKQ1.181021.001; Cronet/58.0.2991.0)", 265 | "Host": "aweme.snssdk.com", 266 | "Cookie": cookies, 267 | "Connection": "Keep-Alive", 268 | } 269 | # result =doGetGzip(url,headers,"UTF-8") 270 | result = doPostGzip(url, headers, "UTF-8", params2) 271 | print(result) 272 | 273 | 274 | def live_test(): 275 | url = "https://webcast3-normal-c-lq.amemv.com/webcast/room/info/?room_id=6824421323302046479&pack_level=3&webcast_sdk_version=1120&os_api=22&device_type=HUAWEI%20MLA-AL10&ssmix=a&manifest_version_code=721&dpi=320&js_sdk_version=1.19.2.0&uuid=863064010168948&app_name=aweme&version_name=7.2.1&ts=1588934410&app_type=normal&ac=wifi&update_version_code=7204&channel=tianzhuo_dy_sg4&_rticket=1588934410268&device_platform=android&iid=4494439458804173&version_code=721&openudid=a85e45a2f9735601&device_id=71048224768&resolution=900*1600&os_version=5.1.1&language=zh&device_brand=HUAWEI&aid=1128&mcc_mnc=46007" 276 | cookies = "install_id=4494439458804173; ttreq=1$ed7ac0d772116f6326f7d1b2a8636e6029233ee1; d_ticket=76fae73c318bb8721339f3af8799a71c49c70; odin_tt=9c30b37d6e8049a50632bdbd69de05df8d25a3cfce4b9019da8de5336f84d0321dcd6d06e23acc88a0809946a4ec91bba93d46b85f3ad6045bec92b2b6879c58; sid_guard=6cd51f77e2c2daa7cce28b9e6792d279%7C1588836447%7C5184000%7CMon%2C+06-Jul-2020+07%3A27%3A27+GMT; uid_tt=afd1ffc540e9cbd1934bed9566772427; uid_tt_ss=afd1ffc540e9cbd1934bed9566772427; sid_tt=6cd51f77e2c2daa7cce28b9e6792d279; sessionid=6cd51f77e2c2daa7cce28b9e6792d279; sessionid_ss=6cd51f77e2c2daa7cce28b9e6792d279; qh[360]=1" 277 | params = url[url.index('?') + 1:] 278 | ts = str(time.time()).split(".")[0] 279 | _rticket = str(time.time() * 1000).split(".")[0] 280 | STUB = "" 281 | s = getXGon(params, STUB, cookies) 282 | gorgon = xGorgon(ts, strToByte(s)) 283 | headers = { 284 | "X-Gorgon": gorgon, 285 | "X-SS-REQ-TICKET": "1585711173953", 286 | "X-Khronos": ts, 287 | "sdk-version": "1", 288 | "Accept-Encoding": "gzip", 289 | "X-SS-REQ-TICKET": _rticket, 290 | "User-Agent": "com.ss.android.ugc.aweme/721 (Linux; U; Android 5.1.1; zh_CN; HUAWEI MLA-AL10; Build/HUAWEIMLA-AL10; Cronet/58.0.2991.0)", 291 | "Host": "webcast3-normal-c-lq.amemv.com", 292 | "Cookie": cookies, 293 | "Connection": "Keep-Alive", 294 | "x-tt-token": "006cd51f77e2c2daa7cce28b9e6792d279ac380936bb11c43b53547e236d78cb08e7b964068edb33123054e653c7770d0f12" 295 | } 296 | result = doGetGzip(url, headers, "UTF-8") 297 | print(result) 298 | 299 | 300 | if __name__ == "__main__": 301 | # testVideo() 302 | # search_item() 303 | # live_test() 304 | url = "https://aweme.snssdk.com/aweme/v2/comment/list/?aweme_id=6810650141905669383&cursor=0&count=20&address_book_access=1&gps_access=1&forward_page_type=1&os_api=22&device_type=MI%205s&ssmix=a&manifest_version_code=920&dpi=192&uuid=869273222474044&app_name=aweme&version_name=9.2.0&ts=1585739874&app_type=normal&ac=wifi&update_version_code=9202&channel=aweGW&_rticket=1585739874633&device_platform=android&iid=110128576639&version_code=920&cdid=e7d2d302-0ff6-4774-8750-acec805feb67&openudid=f4c3dc16590ada36&device_id=69567395847&resolution=1280*720&os_version=5.1.1&language=zh&device_brand=Xiaomi&aid=1128&mcc_mnc=46000" 305 | ts = str(time.time()).split(".")[0] 306 | _rticket = str(time.time() * 1000).split(".")[0] 307 | cookies = "install_id=110128576639; ttreq=1$b3de35bd51c867f4a291a7f697bf4f5d3da252f4; passport_csrf_token=eae0cb8afd7ae83568ac9eb0d470b35d; d_ticket=f6d6d5c5aa2a95349b6fb01c0f8f029e1cf3b; odin_tt=ca86a870c665e2857ec3af1df759ee747bcadae223cd706f61e55ce4352bc4ed8d6af5bb42a78ecaa7714daccc9884639f2b2f36d4231ce5bab18051f91d9b11; sid_guard=080ab789c0bf0519740314c59de87d8a%7C1585711138%7C5184000%7CSun%2C+31-May-2020+03%3A18%3A58+GMT; uid_tt=f02935cf52727202351fb06c888f4a28; sid_tt=080ab789c0bf0519740314c59de87d8a; sessionid=080ab789c0bf0519740314c59de87d8a" 308 | params = url[url.index('?') + 1:] 309 | STUB = "" 310 | s = getXGon(params, STUB, cookies) 311 | gorgon = xGorgon(ts, strToByte(s)) 312 | headers = { 313 | "X-Gorgon": gorgon, 314 | "X-SS-REQ-TICKET": "1585711173953", 315 | "X-Khronos": ts, 316 | "sdk-version": "1", 317 | "Accept-Encoding": "gzip", 318 | "X-SS-REQ-TICKET": _rticket, 319 | "User-Agent": "ttnet okhttp/3.10.0.2", 320 | "Host": "aweme.snssdk.com", 321 | "Cookie": cookies, 322 | "Connection": "Keep-Alive", 323 | "x-tt-token": "00080ab789c0bf0519740314c59de87d8ace96d49d8ab2afd7a0f09cba0911612f99baf92acae289860e0f84ffd97fc2c344" 324 | } 325 | result = doGetGzip(url, headers, "UTF-8") 326 | print(result) 327 | --------------------------------------------------------------------------------