14 个版本
新 0.0.18 | 2024 年 8 月 23 日 |
---|---|
0.0.17 | 2024 年 8 月 23 日 |
0.0.15 | 2024 年 6 月 21 日 |
0.0.6 | 2024 年 5 月 24 日 |
0.0.5 | 2024 年 1 月 6 日 |
#900 在 网络编程
2.5MB
47K SLoC
简介
一个 Rust 库。使用它可以从 TikTok LIVE 实时接收直播事件,如评论和礼物,无需凭据。
加入支持 discord 并访问 #rust-support
频道以提问、贡献和提出想法。请随意提交具有缺失/新功能、修复等内容的拉取请求
您更喜欢其他编程语言吗?
- Java TikTokLiveJava
- Node TikTok-Live-Connector by @zerodytrash
- Python TikTokLive by @isaackogan
- C# TikTokLiveSharp by @frankvHoof93
注意: 这不是官方 API。它是一个逆向工程项目。
概述
入门
依赖
[dependencies]
tiktoklive = "0.0.18"
tokio = { version = "1.35.1", features = ["full"] }
serde_json = "1.0"
log = "0.4"
env_logger = "0.10.1"
使用示例
use env_logger::{Builder, Env}; // Importing the logger builder and environment configuration
use log::LevelFilter; // Importing log level filter
use log::{error, warn};
use std::time::Duration; // Importing Duration for timeout settings
use tiktoklive::{
// Importing necessary modules and structs from tiktoklive crate
core::live_client::TikTokLiveClient,
data::live_common::{ClientData, StreamData, TikTokLiveSettings},
errors::LibError,
generated::events::TikTokLiveEvent,
TikTokLive,
};
use tokio::signal; // Importing signal handling from tokio
#[tokio::main] // Main function is asynchronous and uses tokio runtime
async fn main() {
init_logger("info"); // Initialize logger with "info" level
let user_name = "tragdate";
let client = create_client(user_name); // Create a client for the given username
// Spawn a new asynchronous task to connect the client
let handle = tokio::spawn(async move {
// Attempt to connect the client
if let Err(e) = client.connect().await {
match e {
// Match on the error type
LibError::LiveStatusFieldMissing => {
// Specific error case
warn!(
"Failed to get live status (probably needs authenticated client): {}",
e
);
let auth_client = create_client_with_cookies(user_name); // Create an authenticated client
if let Err(e) = auth_client.connect().await {
// Attempt to connect the authenticated client
error!("Error connecting to TikTok Live after retry: {}", e);
}
}
LibError::HeaderNotReceived => {
error!("Error connecting to TikTok Live: {}", e);
}
_ => {
// General error case
error!("Error connecting to TikTok Live: {}", e);
}
}
}
});
signal::ctrl_c().await.expect("Failed to listen for Ctrl+C"); // Wait for Ctrl+C signal to gracefully shut down
handle.await.expect("The spawned task has panicked"); // Await the spawned task to ensure it completes
}
fn handle_event(client: &TikTokLiveClient, event: &TikTokLiveEvent) {
match event {
TikTokLiveEvent::OnConnected(..) => {
// This is an EXPERIMENTAL and UNSTABLE feature
// Get room info from the client
let room_info = client.get_room_info();
// // Parse the room info
let client_data: ClientData = serde_json::from_str(room_info).unwrap();
// // Parse the stream data
let stream_data: StreamData = serde_json::from_str(
&client_data
.data
.stream_url
.live_core_sdk_data
.unwrap()
.pull_data
.stream_data,
)
.unwrap();
// Get the video URL for the low definition stream with fallback to the high definition stream in a flv format
let video_url = stream_data
.data
.ld
.map(|ld| ld.main.flv)
.or_else(|| stream_data.data.sd.map(|sd| sd.main.flv))
.or_else(|| stream_data.data.origin.map(|origin| origin.main.flv))
.expect("None of the stream types set");
println!("room info: {}", video_url);
}
// Match on the event type
TikTokLiveEvent::OnMember(join_event) => {
// Handle member join event
println!("user: {} joined", join_event.raw_data.user.nickname);
}
TikTokLiveEvent::OnChat(chat_event) => {
// Handle chat event
println!(
"user: {} -> {}",
chat_event.raw_data.user.nickname, chat_event.raw_data.content
);
}
TikTokLiveEvent::OnGift(gift_event) => {
// Handle gift event
let nick = &gift_event.raw_data.user.nickname;
let gift_name = &gift_event.raw_data.gift.name;
let gifts_amount = gift_event.raw_data.gift.combo;
println!(
"user: {} sends gift: {} x {}",
nick, gift_name, gifts_amount
);
}
TikTokLiveEvent::OnLike(like_event) => {
// Handle like event
let nick = &like_event.raw_data.user.nickname;
println!("user: {} likes", nick);
}
_ => {} // Ignore other events
}
}
// Function to initialize the logger with a default log level
fn init_logger(default_level: &str) {
let env = Env::default().filter_or("LOG_LEVEL", default_level); // Set default log level from environment or use provided level
Builder::from_env(env) // Build the logger from environment settings
.filter_module("tiktoklive", LevelFilter::Debug) // Set log level for tiktoklive module
.init(); // Initialize the logger
}
// Function to configure the TikTok live settings
fn configure(settings: &mut TikTokLiveSettings) {
settings.http_data.time_out = Duration::from_secs(12); // Set HTTP timeout to 12 seconds
}
// Function to configure the TikTok live settings with cookies for authentication
fn configure_with_cookies(settings: &mut TikTokLiveSettings) {
settings.http_data.time_out = Duration::from_secs(12); // Set HTTP timeout to 12 seconds
let contents = ""; // Placeholder for cookies
settings
.http_data
.headers
.insert("Cookie".to_string(), contents.to_string());
// Insert cookies into HTTP headers
}
// Function to create a TikTok live client for the given username
fn create_client(user_name: &str) -> TikTokLiveClient {
TikTokLive::new_client(user_name) // Create a new client
.configure(configure) // Configure the client
.on_event(handle_event) // Set the event handler
.build() // Build the client
}
// Function to create a TikTok live client with cookies for the given username
fn create_client_with_cookies(user_name: &str) -> TikTokLiveClient {
TikTokLive::new_client(user_name) // Create a new client
.configure(configure_with_cookies) // Configure the client with cookies
.on_event(handle_event) // Set the event handler
.build() // Build the client
}
库错误表
您可以在事件上捕获错误
use tiktoklive::LibError;
if let Err(e) = client.connect().await {
match e {
LibError::UserFieldMissing => {
println!("User field is missing");
}
_ => {
eprintln!("Error connecting to TikTok Live: {}", e);
}
}
}
错误类型 | 描述 |
---|---|
RoomIDFieldMissing | 缺少 Room ID 字段,请联系开发者 |
UserFieldMissing | 缺少 User 字段 |
UserDataFieldMissing | 缺少 User 数据字段 |
LiveDataFieldMissing | 实时数据字段缺失 |
Json解析错误 | 解析JSON错误 |
用户消息字段缺失 | 用户消息字段缺失 |
参数错误 | 参数错误 |
用户状态字段缺失 | 用户状态字段缺失 |
直播状态字段缺失 | 直播状态字段缺失 |
标题字段缺失 | 标题字段缺失 |
用户数量字段缺失 | 用户数量字段缺失 |
统计数据字段缺失 | 统计数据字段缺失 |
点赞数字段缺失 | 点赞数缺失 |
总用户字段缺失 | 总用户字段缺失 |
直播室字段缺失 | 直播室字段缺失 |
开始时间字段缺失 | 开始时间字段缺失 |
用户未找到 | 用户未找到 |
主播未在线 | 主播直播流未在线!当前状态为主播离线 |
无效主播 | WebSocket URL中的无效主播 |
WebSocket连接失败 | 连接WebSocket失败 |
推送帧解析错误 | 无法读取推送帧 |
网络直播响应解析错误 | 无法读取网络直播响应 |
确认包发送错误 | 无法发送确认包 |
HTTP请求失败 | HTTP请求失败 |
URL签名失败 | URL签名失败 |
未收到头部信息 | 未收到头部信息 |
字节解析错误 | 无法将字节解析为推送帧 |
贡献
贡献者
依赖
~27–42MB
~502K SLoC