This commit is contained in:
2026-08-08 00:48:05 +08:00
parent 1a645f9177
commit b56f3fa40a
7 changed files with 171 additions and 46 deletions
+1
View File
@@ -1,2 +1,3 @@
target/ target/
.idea/ .idea/
/cross-build.bat
+120 -15
View File
@@ -1,5 +1,6 @@
use crate::CONFIG; use crate::CONFIG;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Debug)] #[derive(Debug)]
@@ -19,6 +20,7 @@ impl Config {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct OptConfig { pub struct OptConfig {
pub proxy: Option<String>, pub proxy: Option<String>,
pub pjsk_proxy: Option<String>,
pub ghp: Option<String>, pub ghp: Option<String>,
pub log_level: Option<String>, pub log_level: Option<String>,
} }
@@ -27,6 +29,7 @@ impl OptConfig {
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
proxy: None, proxy: None,
pjsk_proxy: None,
ghp: None, ghp: None,
log_level: None, log_level: None,
} }
@@ -44,7 +47,6 @@ impl State {
serde_json::from_str(x).unwrap() serde_json::from_str(x).unwrap()
} }
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
git_hash: None, git_hash: None,
@@ -82,17 +84,6 @@ pub struct EventStory {
pub assetbundle_name: String, pub assetbundle_name: String,
} }
// 用这个找是因为这个文件小一点(((
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CardEpisode {
pub id: u64,
pub seq: u64,
#[serde(rename = "cardId")]
pub card_id: u64,
#[serde(rename = "assetbundleName")]
pub assetbundle_name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventCard { pub struct EventCard {
pub id: u64, pub id: u64,
@@ -102,6 +93,114 @@ pub struct EventCard {
pub event_id: u64, pub event_id: u64,
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Card {
pub id: u64,
#[serde(rename = "characterId")]
pub character_id: u64,
#[serde(rename = "cardRarityType")]
pub card_rarity_type: String,
pub attr: String,
#[serde(rename = "skillId")]
pub skill_id: u64,
pub prefix: String,
#[serde(rename = "assetbundleName")]
pub assetbundle_name: String,
}
impl PartialEq for Card {
fn eq(&self, other: &Self) -> bool {
self.id.eq(&other.id)
}
}
impl Eq for Card {}
impl PartialOrd for Card {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Card {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl Card {
pub fn rarity_short_text(&self) -> String {
match self.card_rarity_type.as_str() {
"rarity_1" => "".to_string(),
"rarity_2" => "⭐⭐".to_string(),
"rarity_3" => "⭐⭐⭐".to_string(),
"rarity_4" => "⭐⭐⭐⭐".to_string(),
"rarity_birthday" => "🎀".to_string(),
_ => self.card_rarity_type.clone(),
}
}
pub fn attr_short_text(&self) -> String {
match self.attr.as_str() {
"cute" => "粉花".to_string(),
"pure" => "绿草".to_string(),
"cool" => "蓝星".to_string(),
"mysterious" => "紫月".to_string(),
"happy" => "橙心".to_string(),
_ => self.attr.clone(),
}
}
pub fn skill_id_short(&self) -> Option<String> {
match self.skill_id {
1..=4 => Some("得分提高".to_string()),
5..=8 => Some("判定提升".to_string()),
9..=10 => Some("回复".to_string()),
11 => Some("P分".to_string()),
12 => Some("血分".to_string()),
13 => Some("P分(特殊)".to_string()),
14 => Some("回复P分(特殊)".to_string()),
15 => Some("LN团分".to_string()),
16 => Some("MMJ团分".to_string()),
17 => Some("VBS团分".to_string()),
18 => Some("WS团分".to_string()),
19 => Some("25团分".to_string()),
22 => Some("等级分(bfes)".to_string()),
23 => Some("队内抽分(bfes)".to_string()),
24 => Some("多团分".to_string()),
_ => None,
}
}
pub fn character_name(&self) -> String {
match self.character_id {
1 => "星乃一歌".to_string(),
2 => "天馬咲希".to_string(),
3 => "望月穂波".to_string(),
4 => "日野森志歩".to_string(),
5 => "花里みのり".to_string(),
6 => "桐谷遥".to_string(),
7 => "桃井愛莉".to_string(),
8 => "日野森雫".to_string(),
9 => "小豆沢こはね".to_string(),
10 => "白石杏".to_string(),
11 => "東雲彰人".to_string(),
12 => "青柳冬弥".to_string(),
13 => "天馬司".to_string(),
14 => "鳳えむ".to_string(),
15 => "草薙寧々".to_string(),
16 => "神代類".to_string(),
17 => "宵崎奏".to_string(),
18 => "朝比奈まふゆ".to_string(),
19 => "東雲絵名".to_string(),
20 => "暁山瑞希".to_string(),
21 => "初音ミク".to_string(),
22 => "鏡音リン".to_string(),
23 => "鏡音レン".to_string(),
24 => "巡音ルカ".to_string(),
25 => "MEIKO".to_string(),
26 => "KAITO".to_string(),
_ => "".to_string(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CurrentVersion { pub struct CurrentVersion {
pub app_hash: String, pub app_hash: String,
@@ -112,7 +211,13 @@ pub struct CurrentVersion {
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct FetchResult{ pub struct FetchResultCard {
pub event_id: u64, pub text: String,
pub card_paths: Vec<PathBuf>, pub path: Vec<PathBuf>,
}
#[derive(Debug, Clone, Serialize)]
pub struct FetchResult {
pub event_id: u64,
pub cards: Vec<FetchResultCard>,
} }
+5 -5
View File
@@ -14,11 +14,11 @@ impl Downloader {
pub async fn new() -> anyhow::Result<Downloader> { pub async fn new() -> anyhow::Result<Downloader> {
let master_data = get_master_data().await?; let master_data = get_master_data().await?;
let mut execution = ExecutionConfig::default(); let mut execution = ExecutionConfig::default();
// if let Ok(opt_conf) = &OPT_CONFIG.read() if let Ok(opt_conf) = &OPT_CONFIG.read()
// && let Some(proxy) = &opt_conf.proxy && let Some(proxy) = &opt_conf.pjsk_proxy
// { {
// execution.proxy = Some(proxy.to_string()); execution.proxy = Some(proxy.to_string());
// } }
let app_config = AppConfig { let app_config = AppConfig {
execution, execution,
tools: ToolsConfig{ tools: ToolsConfig{
+3 -3
View File
@@ -61,7 +61,7 @@ pub fn raw_url(path: &str) -> String {
pub async fn sync_data() -> anyhow::Result<()> { pub async fn sync_data() -> anyhow::Result<()> {
let client = http_client()?; let client = http_client()?;
let (events_cards, event_stories, card_episodes) = tokio::try_join!( let (events_cards, event_stories, cards) = tokio::try_join!(
client.get(raw_url("eventCards.json")).send().await?.text(), client.get(raw_url("eventCards.json")).send().await?.text(),
client client
.get(raw_url("eventStories.json")) .get(raw_url("eventStories.json"))
@@ -69,7 +69,7 @@ pub async fn sync_data() -> anyhow::Result<()> {
.await? .await?
.text(), .text(),
client client
.get(raw_url("cardEpisodes.json")) .get(raw_url("cards.json"))
.send() .send()
.await? .await?
.text() .text()
@@ -78,7 +78,7 @@ pub async fn sync_data() -> anyhow::Result<()> {
let mut store = STORE.write().map_err(|e| anyhow!("{}", e))?; let mut store = STORE.write().map_err(|e| anyhow!("{}", e))?;
store.set_event_cards(serde_json::from_str(&events_cards)?); store.set_event_cards(serde_json::from_str(&events_cards)?);
store.set_event_stories(serde_json::from_str(&event_stories)?); store.set_event_stories(serde_json::from_str(&event_stories)?);
store.set_card_episodes(serde_json::from_str(&card_episodes)?); store.set_cards(serde_json::from_str(&cards)?);
Ok(()) Ok(())
} }
+1
View File
@@ -78,6 +78,7 @@ macro_rules! def_opt_str_setter {
} }
def_opt_str_setter!(proxy); def_opt_str_setter!(proxy);
def_opt_str_setter!(pjsk_proxy);
def_opt_str_setter!(ghp); def_opt_str_setter!(ghp);
def_opt_str_setter!(log_level); def_opt_str_setter!(log_level);
+27 -9
View File
@@ -1,4 +1,4 @@
use crate::data::{FetchResult, State}; use crate::data::{FetchResult, FetchResultCard, State};
use crate::download::Downloader; use crate::download::Downloader;
use crate::github::{fetch_last_hash, sync_data}; use crate::github::{fetch_last_hash, sync_data};
use crate::{CONFIG, PROVIDE, STATE, STORE, ending_point}; use crate::{CONFIG, PROVIDE, STATE, STORE, ending_point};
@@ -70,7 +70,7 @@ pub async fn main() -> anyhow::Result<()> {
ending_point!(ok); ending_point!(ok);
debug!( debug!(
"Pulling card {} from bundle {}", "Pulling card {} from bundle {}",
card.card_id, card.assetbundle_name card.id, card.assetbundle_name
); );
let dir = downloader let dir = downloader
.pull(&format!("character/member/{}", card.assetbundle_name)) .pull(&format!("character/member/{}", card.assetbundle_name))
@@ -97,25 +97,43 @@ pub async fn main() -> anyhow::Result<()> {
} }
} }
fs::remove_dir_all(dir.0)?; fs::remove_dir_all(dir.0)?;
Ok::<_, anyhow::Error>((card.card_id, local_images)) Ok::<_, anyhow::Error>((card.clone(), local_images))
}); });
} }
let mut images = Vec::new(); let mut images = Vec::new();
while let Some(res) = futures.next().await { while let Some(res) = futures.next().await {
images.push(res?); images.push(res?);
} }
images.sort_by(|a, b| b.0.cmp(&a.0)); // 在前 images.sort_by(|a, b| a.0.id.cmp(&b.0.id)); // 在前
let images: Vec<_> = images.into_iter().flat_map(|(_, sub)| sub).collect(); let images: Vec<_> = images
.into_iter()
.map(|(card, path)| FetchResultCard {
text: format!(
"#{id} {attr}{rarity} {skill} [{prefix}]{name}",
id = card.id,
attr = card.attr_short_text(),
rarity = card.rarity_short_text(),
skill = card
.skill_id_short().map(|s| format!("({})", s))
.unwrap_or_default(),
prefix = card.prefix,
name = card.character_name()
),
path,
})
.collect();
info!( info!(
"In event {} collected {} images", "In event {} collected {} cards",
event.event_id, event.event_id,
images.len() images.len()
); );
*PROVIDE.write().map_err(|e| anyhow!("{}", e))? = Some(FetchResult { let result = FetchResult {
event_id: event.event_id, event_id: event.event_id,
card_paths: images, cards: images,
}); };
debug!("Providing result: {:?}", result);
*PROVIDE.write().map_err(|e| anyhow!("{}", e))? = Some(result);
let mut state = STATE.write().map_err(|e| anyhow!("{}", e))?; let mut state = STATE.write().map_err(|e| anyhow!("{}", e))?;
state.git_hash = Some(current_hash); state.git_hash = Some(current_hash);
state.event_id = Some(event.event_id); state.event_id = Some(event.event_id);
+14 -14
View File
@@ -1,5 +1,5 @@
use crate::CONFIG; use crate::CONFIG;
use crate::data::{CardEpisode, EventCard, EventStory}; use crate::data::{Card, EventCard, EventStory};
use serde::Serialize; use serde::Serialize;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::fs; use std::fs;
@@ -8,16 +8,16 @@ use std::path::PathBuf;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Store { pub struct Store {
pub event_stories: Vec<EventStory>, pub event_stories: Vec<EventStory>,
pub card_episodes: Vec<CardEpisode>,
pub event_cards: Vec<EventCard>, pub event_cards: Vec<EventCard>,
pub cards: Vec<Card>,
} }
impl Store { impl Store {
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
event_cards: Vec::new(), event_cards: Vec::new(),
card_episodes: Vec::new(),
event_stories: Vec::new(), event_stories: Vec::new(),
cards: Vec::new(),
} }
} }
@@ -31,8 +31,8 @@ impl Store {
Self { Self {
event_stories: Self::load_file(&cache_dir.join("event_stories.json")), event_stories: Self::load_file(&cache_dir.join("event_stories.json")),
card_episodes: Self::load_file(&cache_dir.join("card_episodes.json")),
event_cards: Self::load_file(&cache_dir.join("event_cards.json")), event_cards: Self::load_file(&cache_dir.join("event_cards.json")),
cards: Self::load_file(&cache_dir.join("cards.json")),
} }
} }
@@ -55,23 +55,23 @@ impl Store {
Self::save_file(&path, &self.event_stories); Self::save_file(&path, &self.event_stories);
} }
pub fn set_card_episodes(&mut self, data: Vec<CardEpisode>) {
self.card_episodes = data;
let path = CONFIG.get().unwrap().cache_dir().join("card_episodes.json");
Self::save_file(&path, &self.card_episodes);
}
pub fn set_event_cards(&mut self, data: Vec<EventCard>) { pub fn set_event_cards(&mut self, data: Vec<EventCard>) {
self.event_cards = data; self.event_cards = data;
let path = CONFIG.get().unwrap().cache_dir().join("event_cards.json"); let path = CONFIG.get().unwrap().cache_dir().join("event_cards.json");
Self::save_file(&path, &self.event_cards); Self::save_file(&path, &self.event_cards);
} }
pub fn set_cards(&mut self, data: Vec<Card>) {
self.cards = data;
let path = CONFIG.get().unwrap().cache_dir().join("cards.json");
Self::save_file(&path, &self.cards);
}
pub fn save_all(&self) { pub fn save_all(&self) {
let cache_dir = CONFIG.get().unwrap().cache_dir(); let cache_dir = CONFIG.get().unwrap().cache_dir();
Self::save_file(&cache_dir.join("event_stories.json"), &self.event_stories); Self::save_file(&cache_dir.join("event_stories.json"), &self.event_stories);
Self::save_file(&cache_dir.join("card_episodes.json"), &self.card_episodes);
Self::save_file(&cache_dir.join("event_cards.json"), &self.event_cards); Self::save_file(&cache_dir.join("event_cards.json"), &self.event_cards);
Self::save_file(&cache_dir.join("cards.json"), &self.cards);
} }
pub fn find_last_event(&self) -> Option<EventStory> { pub fn find_last_event(&self) -> Option<EventStory> {
@@ -81,15 +81,15 @@ impl Store {
.cloned() .cloned()
} }
pub fn find_cards_by_event(&self, event_id: u64) -> Vec<CardEpisode> { pub fn find_cards_by_event(&self, event_id: u64) -> Vec<Card> {
self.event_cards self.event_cards
.iter() .iter()
.filter(|e| e.event_id == event_id) .filter(|e| e.event_id == event_id)
.filter_map(|c| { .filter_map(|c| {
self.card_episodes self.cards
.iter() .iter()
.rev() .rev()
.find(|e| e.card_id == c.card_id) .find(|e| e.id == c.card_id)
}) })
.cloned() .cloned()
.collect() .collect()