com.github.stormbit.tiktokapi.TikTokApi.kt Maven / Gradle / Ivy
package com.github.stormbit.tiktokapi
import com.google.gson.Gson
import com.google.gson.JsonObject
import net.dongliu.requests.Requests
import org.apache.http.NameValuePair
import org.apache.http.client.utils.URLEncodedUtils
import org.apache.http.message.BasicNameValuePair
import java.lang.Thread.sleep
import kotlin.random.Random
private const val BASE_URL = "https://m.tiktok.com/"
@Suppress("unused", "unused_variable", "MemberVisibilityCanBePrivate")
class TikTokApi(private val request_delay: Int = 0, executablePath: String, external_signer: String? = null) {
private var signerUrl: String? = null
private var userAgent: String = ""
private var referrer: String? = null
private var width = "1920"
private var height = "1080"
private val browserLanguage = ""
private val browserPlatform = ""
private val browserName = ""
private val browserVersion = ""
private val timezoneName = ""
private lateinit var browser: Browser
init {
if (external_signer == null) {
this.browser = Browser(executablePath = executablePath)
this.userAgent = browser.userAgent
this.referrer = browser.referrer
this.width = browser.width
this.height = browser.height
}
}
fun close() {
browser.close()
}
fun getTiktokById(id: String, params: HashMap): JsonObject {
val (region, language, proxy, maxCount, did) = processParams(params)
val query = listOf(
BasicNameValuePair("itemId", id),
BasicNameValuePair("language", language)
)
val apiUrl = "%sapi/item/detail/?%s&%s".format(BASE_URL, addNewParams(), URLEncodedUtils.format(query, "utf-8"))
val prms = hashMapOf("url" to apiUrl)
prms.putAll(params)
return getData(prms)
}
fun getTikTokByUrl(url: String, params: HashMap): JsonObject {
var postId = ""
if (url.contains("@") && url.contains("/video/")) {
postId = url.split("/video/")[1].split("?")[0]
}
return getTiktokById(postId, params)
}
fun getVideoURL(url: String, params: HashMap): String {
val tiktokSchema = getTikTokByUrl(url, params)
val download_url = tiktokSchema.get("itemInfo").asJsonObject.get("itemStruct").asJsonObject.get("video").asJsonObject.get("downloadAddr").asString
return download_url
}
fun getBytes(params: HashMap): ByteArray {
val (region, language, proxy, maxCount, did) = processParams(params)
params["custom_did"] = did
if (request_delay != 0) {
sleep(request_delay.toLong())
}
val verifyFp: String
val didd: String
val signature: String
val userAgent: String
val referrer: String
if (this.signerUrl == null) {
val args = this.browser.signUrl(params)
verifyFp = args[0]
didd = args[1]
signature = args[2]
userAgent = this.browser.userAgent
referrer = this.browser.referrer
} else {
val resp = externalSigner(params["url"].toString(), params.getOrDefault("custom_did", null).toString())
verifyFp = resp[0]
didd = resp[1]
signature = resp[2]
userAgent = resp[3]
referrer = resp[4]
}
val query = listOf(
BasicNameValuePair("verifyFp", verifyFp),
BasicNameValuePair("_signature", signature)
)
val url = "%s&%s".format(params["url"], URLEncodedUtils.format(query, "utf-8"))
val url2 = "https://v16-web.tiktok.com/video/tos/alisg/tos-alisg-pve-0037c001/d40364f8143c495fbb718a3dbf2641f4/?a=1988&br=924&bt=462&cr=0&cs=0&dr=0&ds=2&er=&expire=1605476212&l=2020111515363101018907414801124BE0&lr=tiktok_m&mime_type=video_mp4&policy=2&qs=0&rc=andndHJ2eGdoeDMzNjczM0ApOWQ6ODQ8OTtmNzRmOjMzZWdvbHFyXjIwY2tfLS0tMTRzcy42Yi9eNTVgYDQtNTU2MTU6Yw%3D%3D&signature=9a38cc496936df261c22db24447352d6&tk=tt_webid_v2&vl=&vr=&verifyFp=verify_khgp4f49_V12d4mRX_MdCO_4Wzt_Ar0k_z4RCQC9pUDpX&_signature=_02B4Z6wo00f01cUV0hgAAIBBz-Rqd-BUVYHFBNaAAC7357"
val headers = mapOf(
"Accept" to "*/*",
"Accept-Encoding" to "identity;q=1, *;q=0",
"Accept-Language" to "en-US;en;q=0.9",
"Cache-Control" to "no-cache",
"Connection" to "keep-alive",
"cookie" to "tt_webid_v2=$didd",
"Host" to url.split("/")[2],
"Pragma" to "no-cache",
"Range" to "bytes=0-",
"Referer" to referrer,
"User-Agent" to userAgent,
)
val bytes = Requests.get(url)
.headers(headers).send().readToBytes()
return bytes
}
fun getVideoBytesByURL(url: String, params: HashMap = HashMap()): ByteArray {
val (region, language, proxy, maxCount, did) = processParams(params)
params["custom_did"] = did
val downloadUrl = getVideoURL(url, params)
val prms = hashMapOf(
"url" to downloadUrl
)
prms.putAll(params)
return getBytes(prms)
}
private fun getData(params: HashMap = HashMap()): JsonObject {
val (region, language, proxy, maxCount, did) = processParams(params)
params["custom_did"] = did
if (request_delay != 0) {
sleep(request_delay.toLong())
}
val verifyFp: String
val didd: String
val signature: String
val userAgent: String
val referrer: String
if (this.signerUrl == null) {
val args = this.browser.signUrl(params)
verifyFp = args[0]
didd = args[1]
signature = args[2]
userAgent = this.browser.userAgent
referrer = this.browser.referrer
} else {
val resp = externalSigner(params["url"].toString(), params.getOrDefault("custom_did", null).toString())
verifyFp = resp[0]
didd = resp[1]
signature = resp[2]
userAgent = resp[3]
referrer = resp[4]
}
val query = listOf(
BasicNameValuePair("verifyFp", verifyFp),
BasicNameValuePair("did", didd),
BasicNameValuePair("_signature", signature)
)
val url = "%s&%s".format(params["url"], URLEncodedUtils.format(query, "utf-8"))
val headers = mapOf(
"authority" to "m.tiktok.com",
"method" to "GET",
"path" to url.split("tiktok.com")[1],
"scheme" to "https",
"accept" to "application/json, text/plain, */*",
"accept-encoding" to "gzip, deflate, br",
"accept-language" to "en-US,en;q=0.9",
"referer" to referrer,
"sec-fetch-dest" to "empty",
"sec-fetch-mode" to "cors",
"sec-fetch-site" to "same-site",
"user-agent" to userAgent,
"cookie" to "tt_webid_v2=$did"
)
val r = Requests.get(url)
.headers(headers).send().readToText()
return Gson().fromJson(r, JsonObject::class.java)
}
private fun externalSigner(url: String, custom_did: String? = null): List {
val query: List = if (custom_did != null) {
listOf(
BasicNameValuePair("url", url),
BasicNameValuePair("custom_did", custom_did)
)
} else {
listOf(
BasicNameValuePair("url", url)
)
}
val data = Requests.get("" + "?%s".format(URLEncodedUtils.format(query, "utf-8"))).send().readToText()
val parsedData = Gson().fromJson(data, JsonObject::class.java)
return listOf(parsedData["verifyFp"].asString, parsedData["did"].asString, parsedData["_signature"].asString, parsedData["userAgent"].asString, parsedData["referrer"].asString)
}
private fun processParams(params: HashMap): List {
val region = params.getOrDefault("region", "US").toString()
val language = params.getOrDefault("language", "en").toString()
val proxy = params.getOrDefault("proxy", null).toString()
val maxCount = params.getOrDefault("maxCount", "35").toString()
val did = params.getOrDefault("did", Random.nextInt(10000, 999999999).toString()).toString()
params["did"] = did
return listOf(region, language, proxy, maxCount, did)
}
private fun addNewParams(): String {
val query = listOf(
BasicNameValuePair("aid", "1988"),
BasicNameValuePair("app_name", "tiktok_web"),
BasicNameValuePair("device_platform", "web"),
BasicNameValuePair("referer", "https://www.tiktok.com/"),
BasicNameValuePair("user_agent", formatNewParams(this.userAgent)),
BasicNameValuePair("cookie_enabled", "true"),
BasicNameValuePair("screen_width", this.width),
BasicNameValuePair("screen_height", this.height),
BasicNameValuePair("browser_language", this.browserLanguage),
BasicNameValuePair("browser_platform", this.browserPlatform),
BasicNameValuePair("browser_name", this.browserName),
BasicNameValuePair("browser_version", this.browserVersion),
BasicNameValuePair("browser_online", "true"),
BasicNameValuePair("ac", "4g"),
BasicNameValuePair("timezone_name", this.timezoneName),
BasicNameValuePair("appId", "1233"),
BasicNameValuePair("appType", "m"),
BasicNameValuePair("isAndroid", "false"),
BasicNameValuePair("isMobile", "false"),
BasicNameValuePair("isIOS", "false"),
BasicNameValuePair("OS", "windows"),
BasicNameValuePair("page_referer", "https://www.tiktok.com/")
)
return URLEncodedUtils.format(query, "utf-8")
}
private fun formatNewParams(parm: String): String {
return parm.replace("/", "%2F").replace(" ", "+").replace(";", "%3B")
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy