1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::fmt;
use serde::{Deserialize, Serialize};
use crate::hex::encode_hex;
use crate::msg::elem::flash_image::FlashImage;
use crate::msg::{MessageChainBuilder, PushBuilder};
use crate::msg::{MessageElem, PushElem};
use crate::pb::msg;
use crate::pb::msg::CustomFace;
use crate::{push_builder_impl, to_elem_vec_impl};
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct GroupImage {
pub file_path: String,
pub file_id: i64,
pub size: u32,
pub width: u32,
pub height: u32,
pub md5: Vec<u8>,
pub orig_url: Option<String>,
pub image_type: i32,
pub signature: Vec<u8>,
pub server_ip: u32,
pub server_port: u32,
}
impl GroupImage {
pub fn flash(self) -> FlashImage {
FlashImage::from(self)
}
pub fn url(&self) -> String {
if let Some(orig_url) = &self.orig_url {
format!("https://gchat.qpic.cn{orig_url}")
} else {
format!(
"https://gchat.qpic.cn/gchatpic_new/0/0-0-{}/0?term=2",
encode_hex(&self.md5).to_uppercase()
)
}
}
}
impl From<GroupImage> for msg::CustomFace {
fn from(e: GroupImage) -> Self {
msg::CustomFace {
file_type: Some(66),
useful: Some(1),
biz_type: Some(5), width: Some(e.width),
height: Some(e.height),
file_id: Some(e.file_id as i32),
file_path: Some(e.file_path),
md5: Some(e.md5),
image_type: Some(e.image_type),
size: Some(e.size),
flag: Some(vec![0; 4]),
signature: Some(e.signature),
server_ip: Some(e.server_ip),
server_port: Some(e.server_port),
source: Some(200), origin: Some(0), show_len: Some(0), download_len: Some(0), ..Default::default()
}
}
}
impl PushElem for GroupImage {
fn push_to(elem: Self, vec: &mut Vec<MessageElem>) {
vec.push(MessageElem::CustomFace(elem.into()));
}
}
impl From<msg::CustomFace> for GroupImage {
fn from(custom_face: CustomFace) -> Self {
if custom_face.md5().is_empty() {
return Self::default();
}
return Self {
file_id: custom_face.file_id() as i64,
file_path: custom_face.file_path().to_owned(),
size: custom_face.size(),
width: custom_face.width(),
height: custom_face.height(),
orig_url: custom_face.orig_url,
md5: custom_face.md5.unwrap_or_default(),
image_type: custom_face.image_type.unwrap_or(1000),
signature: custom_face.signature.unwrap_or_default(),
server_ip: custom_face.server_ip.unwrap_or_default(),
server_port: custom_face.server_port.unwrap_or_default(),
};
}
}
fn to_uuid(md5: &str) -> String {
format!(
"{}-{}-{}-{}-{}",
&md5[0..8],
&md5[8..12],
&md5[12..16],
&md5[16..20],
&md5[20..32],
)
}
pub fn calculate_image_resource_id(md5: &[u8]) -> String {
format!("{{{}}}.png", to_uuid(&encode_hex(md5)))
}
impl fmt::Display for GroupImage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[GroupImage: {}]", self.url())
}
}
to_elem_vec_impl!(GroupImage);
push_builder_impl!(GroupImage);