feat: simplify douyin room-adding (close #196)

This commit is contained in:
Xinrea
2025-10-26 22:03:04 +08:00
parent 64dec36773
commit 1f666d402d
3 changed files with 53 additions and 25 deletions

View File

@@ -3,6 +3,7 @@ use crate::errors::RecorderError;
use crate::utils::user_agent_generator;
use deno_core::JsRuntime;
use deno_core::RuntimeOptions;
use regex::Regex;
use reqwest::Client;
use uuid::Uuid;
@@ -332,6 +333,34 @@ pub async fn get_user_info(
})
}
pub async fn get_room_owner_sec_uid(
client: &Client,
room_id: i64,
) -> Result<String, RecorderError> {
let url = format!("https://live.douyin.com/{room_id}");
let mut headers = generate_user_agent_header();
headers.insert("Referer", "https://live.douyin.com/".parse().unwrap());
let resp = client.get(url).headers(headers).send().await?;
let status = resp.status();
let text = resp.text().await?;
if !status.is_success() {
return Err(RecorderError::ApiError {
error: format!("Failed to get room owner sec uid: {status} {text}"),
});
}
// match to get sec_uid from text like \"sec_uid\":\"MS4wLjABAAAAdFmmud36bynPjXOvoMjatb42856_zryHsGmlkpIECDA\"
let sec_uid = Regex::new(r#"\\"sec_uid\\":\\"(.*?)\\""#)
.unwrap()
.captures(&text)
.and_then(|c| c.get(1))
.ok_or_else(|| RecorderError::ApiError {
error: "Failed to find sec_uid in room page".to_string(),
})?
.as_str()
.to_string();
Ok(sec_uid)
}
/// Download file from url to path
pub async fn download_file(client: &Client, url: &str, path: &Path) -> Result<(), RecorderError> {
if !path.parent().unwrap().exists() {
@@ -344,3 +373,18 @@ pub async fn download_file(client: &Client, url: &str, path: &Path) -> Result<()
tokio::io::copy(&mut content, &mut file).await?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_get_room_owner_sec_uid() {
let client = Client::new();
let sec_uid = get_room_owner_sec_uid(&client, 200525029536).await.unwrap();
assert_eq!(
sec_uid,
"MS4wLjABAAAAdFmmud36bynPjXOvoMjatb42856_zryHsGmlkpIECDA"
);
}
}

View File

@@ -14,6 +14,7 @@ use crate::webhook::events;
use recorder::account::Account;
use recorder::danmu::DanmuEntry;
use recorder::platforms::bilibili;
use recorder::platforms::douyin;
use recorder::platforms::PlatformType;
use recorder::RecorderInfo;
@@ -33,7 +34,7 @@ pub async fn add_recorder(
state: state_type!(),
platform: String,
room_id: i64,
extra: String,
mut extra: String,
) -> Result<RecorderRow, String> {
log::info!("Add recorder: {platform} {room_id}");
let platform = PlatformType::from_str(&platform).unwrap();
@@ -47,6 +48,12 @@ pub async fn add_recorder(
}
}
PlatformType::Douyin => {
let client = reqwest::Client::new();
let sec_uid = douyin::api::get_room_owner_sec_uid(&client, room_id)
.await
.map_err(|e| e.to_string())?;
extra = sec_uid;
if let Ok(account) = state.db.get_account_by_platform("douyin").await {
Ok(account.to_account())
} else {

View File

@@ -104,7 +104,6 @@
let addModal = false;
let addRoom = "";
let addSecUserId = "";
let addValid = false;
let addErrorMsg = "";
let selectedPlatform = "bilibili";
@@ -337,7 +336,6 @@
.then(() => {
addModal = false;
addRoom = "";
addSecUserId = "";
})
.catch(async (e) => {
await message(e);
@@ -709,27 +707,6 @@
</div>
<div class="space-y-2">
{#if selectedPlatform === "douyin"}
<label
for="sec_user_id"
class="block text-sm font-medium text-gray-700 dark:text-gray-300"
>
主播 SEC_UID (
<a
href="https://bsr.xinrea.cn/usage/features/room.html#%E6%89%8B%E5%8A%A8%E6%B7%BB%E5%8A%A0%E7%9B%B4%E6%92%AD%E9%97%B4"
target="_blank"
class="text-blue-500">如何获取</a
>
)
</label>
<input
id="sec_user_id"
type="text"
bind:value={addSecUserId}
placeholder="请输入主播的 SEC_UID选填"
class="w-full px-3 py-2 bg-[#f5f5f7] dark:bg-[#1c1c1e] border-0 rounded-lg focus:ring-2 focus:ring-blue-500 text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400"
/>
{/if}
<label
for="room_id"
class="block text-sm font-medium text-gray-700 dark:text-gray-300"
@@ -778,7 +755,7 @@
class="px-4 py-2 bg-[#0A84FF] hover:bg-[#0A84FF]/90 text-white text-sm font-medium rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
disabled={!addValid}
on:click={() => {
addNewRecorder(Number(addRoom), selectedPlatform, addSecUserId);
addNewRecorder(Number(addRoom), selectedPlatform, "");
addModal = false;
addRoom = "";
}}