use std::fs::File;
use std::io::Read;
use std::path::Path;
use bytes::Bytes;
use serde::{Serialize, Deserialize};
use serde_json::{json, Value};
use crate::{session::SessionStore, LabradorResult, RequestBody, RequestType, WechatMpClient, WechatCommonResponse, WechatRequest, get_nonce_str, request};
use crate::wechat::mp::constants::MATERIAL_TYPE_NEWS;
use crate::wechat::mp::method::{MpMediaMethod, WechatMpMethod};
#[derive(Debug, Clone)]
pub struct WechatMpMedia<'a, T: SessionStore> {
client: &'a WechatMpClient<T>,
}
#[allow(unused)]
impl<'a, T: SessionStore> WechatMpMedia<'a, T> {
#[inline]
pub fn new(client: &WechatMpClient<T>) -> WechatMpMedia<T> {
WechatMpMedia {
client,
}
}
pub async fn upload_media(&self, media_type: &str, file_name: Option<&str>, data: Vec<u8>) -> LabradorResult<WechatMpMediaResponse> {
let default_file_name = format!("{}.png", get_nonce_str());
let req = WechatMpMediaRequest {
media_type: media_type.to_string(),
file_name: file_name.map(|v| v.to_string()).unwrap_or(default_file_name),
media_data: data
};
let v = self.client.execute::<WechatMpMediaRequest, String>(req).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMediaResponse>(v)
}
pub async fn upload_media_with_file(&self, media_type: &str, file_path: &str) -> LabradorResult<WechatMpMediaResponse> {
let path = Path::new(file_path);
let file_name = path.file_name().map(|v| v.to_str().unwrap_or_default()).unwrap_or_default();
let mut f = File::open(path)?;
let mut content: Vec<u8> = Vec::new();
let _ = f.read_to_end(&mut content)?;
self.upload_media(media_type, file_name.into(),content).await
}
pub async fn upload_media_with_url(&self, media_type: &str, url: &str) -> LabradorResult<WechatMpMediaResponse> {
let result = request(|client| client.get(url)).await?;
let content = result.bytes()?;
self.upload_media(media_type, None,content.to_vec()).await
}
pub async fn get_media(&self, media_id: &str) -> LabradorResult<Bytes> {
let response = self.client.post(WechatMpMethod::Media(MpMediaMethod::GetMedia), vec![("media_id".to_string(), media_id.to_string())], serde_json::Value::Null, RequestType::Json).await?;
response.bytes()
}
pub async fn get_media_jssdk(&self, media_id: &str) -> LabradorResult<Bytes> {
let response = self.client.post(WechatMpMethod::Media(MpMediaMethod::GetMediaJssdk), vec![("media_id".to_string(), media_id.to_string())], serde_json::Value::Null, RequestType::Json).await?;
response.bytes()
}
pub async fn upload_img_media(&self, file_name: &str, data: Vec<u8>) -> LabradorResult<WechatMpMediaResponse> {
let req = WechatMpImageRequest {
media_data: data,
file_name: file_name.to_string(),
};
let v = self.client.execute::<WechatMpImageRequest, String>(req).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMediaResponse>(v)
}
pub async fn upload_material(&self, req: WechatMpMaterialRequest) -> LabradorResult<WechatMpMediaResponse> {
let v = self.client.execute::<WechatMpMaterialRequest, String>(req).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMediaResponse>(v)
}
pub async fn get_material(&self, media_id: &str) -> LabradorResult<Bytes> {
let response = self.client.post(WechatMpMethod::Media(MpMediaMethod::GetMaterial), vec![("media_id".to_string(), media_id.to_string())], serde_json::Value::Null, RequestType::Json).await?;
response.bytes()
}
pub async fn get_material_video_info(&self, media_id: &str) -> LabradorResult<WechatMpMaterialVideoInfoResponse> {
let response = self.client.post(WechatMpMethod::Media(MpMediaMethod::GetMaterial), vec![("media_id".to_string(), media_id.to_string())], serde_json::Value::Null, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMaterialVideoInfoResponse>(response)
}
pub async fn get_material_news(&self, media_id: &str) -> LabradorResult<WechatMpMaterialNewsResponse> {
let response = self.client.post(WechatMpMethod::Media(MpMediaMethod::GetMaterial), vec![("media_id".to_string(), media_id.to_string())], serde_json::Value::Null, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMaterialNewsResponse>(response)
}
pub async fn delete_material(&self, media_id: &str) -> LabradorResult<WechatCommonResponse> {
self.client.post(WechatMpMethod::Media(MpMediaMethod::DeleteMaterial), vec![], json!({"media_id": media_id}), RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn get_material_count(&self) -> LabradorResult<WechatMpMaterialCountResponse> {
let v = self.client.post(WechatMpMethod::Media(MpMediaMethod::DeleteMaterial), vec![], Value::Null, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMaterialCountResponse>(v)
}
pub async fn get_material_news_batch(&self, offset: i32, count: i32) -> LabradorResult<WechatMpMaterialNewsBatchResponse> {
let v = self.client.post(WechatMpMethod::Media(MpMediaMethod::GetMaterialList), vec![], json!({
"type": MATERIAL_TYPE_NEWS,
"offset": offset,
"count": count
}), RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMaterialNewsBatchResponse>(v)
}
pub async fn get_material_batch(&self,material_type: &str, offset: i32, count: i32) -> LabradorResult<WechatMpMaterialBatchResponse> {
let v = self.client.post(WechatMpMethod::Media(MpMediaMethod::GetMaterialList), vec![], json!({
"type": material_type,
"offset": offset,
"count": count
}), RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMaterialBatchResponse>(v)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMediaRequest {
pub media_type: String,
pub file_name: String,
pub media_data: Vec<u8>
}
impl WechatRequest for WechatMpMediaRequest {
fn get_api_method_name(&self) -> String {
MpMediaMethod::UploadMedia(self.media_type.to_string()).get_method()
}
fn get_request_body<T: Serialize>(&self) -> RequestBody<T> {
let form = reqwest::multipart::Form::new().part("media", reqwest::multipart::Part::stream(self.media_data.to_owned()).file_name(self.file_name.to_string()));
form.into()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpImageRequest {
pub file_name: String,
pub media_data: Vec<u8>
}
impl WechatRequest for WechatMpImageRequest {
fn get_api_method_name(&self) -> String {
MpMediaMethod::UploadImage.get_method()
}
fn get_request_body<T: Serialize>(&self) -> RequestBody<T> {
let form = reqwest::multipart::Form::new().part("media", reqwest::multipart::Part::stream(self.media_data.to_vec()).file_name(self.file_name.to_string()));
form.into()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMediaResponse {
pub url: Option<String>,
pub media_id: Option<String>,
#[serde(rename="type")]
pub r#type: Option<String>,
pub thumb_media_id: Option<String>,
pub created_at: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMaterialRequest {
pub media_type: String,
pub filename: String,
pub name: Option<String>,
pub video_title: Option<String>,
pub video_introduction: Option<String>,
pub media_data: Vec<u8>
}
impl WechatRequest for WechatMpMaterialRequest {
fn get_api_method_name(&self) -> String {
MpMediaMethod::AddMaterial(self.media_type.to_string()).get_method()
}
fn get_request_body<T: Serialize>(&self) -> RequestBody<T> {
let mut form = reqwest::multipart::Form::new().part("media", reqwest::multipart::Part::stream(self.media_data.to_vec()).file_name(self.filename.to_string()));
if let Some(video_title) = &self.video_title {
form = form.text("title", video_title.to_string());
}
if let Some(video_introduction) = &self.video_introduction {
form = form.text("introduction", video_introduction.to_string());
}
form.into()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMaterialVideoInfoResponse {
pub title: Option<String>,
pub description: Option<String>,
pub down_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMaterialNewsResponse {
pub create_time: Option<String>,
pub update_time: Option<String>,
pub articles: Vec<WechatMpNewsArticle>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpNewsArticle {
pub thumb_media_id: String,
pub thumb_url: Option<String>,
pub author: Option<String>,
pub title: String,
pub content_source_url: Option<String>,
pub content: String,
pub digest: Option<String>,
pub show_cover_pic: bool,
pub url: Option<String>,
pub need_open_comment: Option<u8>,
pub only_fans_can_comment: Option<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMaterialCountResponse {
pub voice_count: Option<i32>,
pub video_count: Option<i32>,
pub image_count: Option<i32>,
pub news_count: Option<i32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMaterialNewsBatchResponse {
pub total_count: Option<i32>,
pub item_count: Option<i32>,
pub items: Option<Vec<WechatMpMaterialNewsBatchItem>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMaterialNewsBatchItem {
pub media_id: Option<String>,
pub update_time: Option<String>,
pub content: Option<WechatMpMaterialNewsResponse>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMaterialBatchResponse {
pub total_count: Option<i32>,
pub item_count: Option<i32>,
pub items: Option<Vec<WechatMpMaterialBatchItem>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMaterialBatchItem {
pub media_id: Option<String>,
pub update_time: Option<String>,
pub name: Option<String>,
pub url: Option<String>,
}