Skip to content

Commit 769af62

Browse files
feat: add functions to get current blacklist content and sync blacklist profile from file
close #34
1 parent 99dc001 commit 769af62

File tree

5 files changed

+143
-2
lines changed

5 files changed

+143
-2
lines changed

resources/dist.rc

574 Bytes
Binary file not shown.

src/blacklist.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,50 @@ pub fn remove_mod_blacklist_profile(
211211

212212
Ok(())
213213
}
214+
215+
pub fn get_current_blacklist_content(game_path: &String) -> anyhow::Result<String> {
216+
let blacklist = Path::new(game_path).join("Mods").join("blacklist.txt");
217+
if blacklist.exists() {
218+
Ok(fs::read_to_string(blacklist)?)
219+
} else {
220+
Ok("".to_string())
221+
}
222+
}
223+
224+
pub fn sync_blacklist_profile_from_file(
225+
game_path: &String,
226+
profile_name: &String,
227+
) -> anyhow::Result<()> {
228+
let blacklist = Path::new(game_path).join("Mods").join("blacklist.txt");
229+
if !blacklist.exists() {
230+
return Ok(());
231+
}
232+
let data = fs::read_to_string(blacklist)?;
233+
let mods = get_installed_mods_sync(game_path.clone() + "/Mods");
234+
let profile = ModBlacklistProfile {
235+
name: profile_name.clone(),
236+
mods: data
237+
.lines()
238+
.map(|v| v.trim())
239+
.filter(|v| !v.starts_with('#') && !v.is_empty())
240+
.map(|v| ModBlacklist {
241+
name: {
242+
if let Some(mod_name) = mods.iter().find(|m| m.file == v) {
243+
mod_name.name.clone()
244+
} else {
245+
v.to_string()
246+
}
247+
},
248+
file: v.to_string(),
249+
})
250+
.collect(),
251+
};
252+
let blacklist_path = Path::new(game_path)
253+
.join("celemod_blacklist_profiles")
254+
.join(format!("{}.json", profile_name));
255+
fs::write(
256+
blacklist_path,
257+
serde_json::to_string_pretty(&profile).unwrap(),
258+
)?;
259+
Ok(())
260+
}

src/celemod-ui/src/index.scss

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,37 @@ input[type="checkbox"]:disabled {
301301
}
302302
}
303303
}
304+
305+
306+
.popup-content {
307+
background: $bg1;
308+
padding: 30px;
309+
border-radius: 10px;
310+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
311+
text-align: center;
312+
max-width: 400px;
313+
margin: 0 auto;
314+
border: 1px solid $bg2;
315+
316+
.title {
317+
font-size: 18px;
318+
font-weight: 500;
319+
margin-bottom: 15px;
320+
color: $fg;
321+
}
322+
323+
.content {
324+
margin-bottom: 25px;
325+
color: $fg1;
326+
line-height: 1.5;
327+
}
328+
329+
.buttons {
330+
display: flex;
331+
justify-content: center;
332+
gap: 10px;
333+
button {
334+
margin: 4px;
335+
}
336+
}
337+
}

src/celemod-ui/src/routes/Home.tsx

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import _i18n from 'src/i18n';
22
import { useI18N } from 'src/i18n';
33
import { h } from 'preact';
4-
import { useMemo, useState } from 'preact/hooks';
4+
import { useContext, useMemo, useState } from 'preact/hooks';
55
import { GameSelector } from '../components/GameSelector';
66
import { Icon } from '../components/Icon';
77
import { callRemote, selectGamePath, useBlockingMask } from '../utils';
88
// @ts-ignore
99
import strawberry from '../resources/Celemod.png';
1010
import {
11+
useAlwaysOnMods,
1112
useCurrentBlacklistProfile,
1213
useCurrentLang,
1314
useGamePath,
@@ -20,7 +21,7 @@ import { ModBlacklistProfile } from '../ipc/blacklist';
2021
import { useEffect } from 'react';
2122
import { Button } from '../components/Button';
2223
import './Home.scss';
23-
import { createPopup } from '../components/Popup';
24+
import { createPopup, PopupContext } from '../components/Popup';
2425
import { useEnableAcrylic } from 'src/context/theme';
2526
import { useGlobalContext } from 'src/App';
2627

@@ -77,6 +78,43 @@ export const Home = () => {
7778
);
7879
}, [currentProfileName, profiles]);
7980

81+
const [alwaysOnMods] = useAlwaysOnMods();
82+
83+
useEffect(() => {
84+
if (!currentProfile || !gamePath) return;
85+
const checkSync = () => {
86+
const content = callRemote('get_current_blacklist_content', gamePath);
87+
const disabledFiles = content.split('\n').map(v => v.trim()).filter(v => v && !v.startsWith('#')).sort();
88+
const expectedDisabledFiles = currentProfile.mods
89+
.filter(m => !alwaysOnMods.includes(m.name))
90+
.map(m => m.file)
91+
.sort();
92+
if (JSON.stringify(expectedDisabledFiles) !== JSON.stringify(disabledFiles)) {
93+
const popup = createPopup(() => {
94+
const { hide } = useContext(PopupContext);
95+
return (
96+
<div className="popup-content">
97+
<h2>{_i18n.t('同步黑名单 Mod 列表')}</h2>
98+
<p>{_i18n.t('当前的 blacklist.txt 与配置文件不同。您想要同步配置文件以匹配吗?')}</p>
99+
<p>{_i18n.t('注意,该功能不支持通配符等')}</p>
100+
<div className="buttons">
101+
<button onClick={() => {
102+
callRemote('sync_blacklist_profile_from_file', gamePath, currentProfileName);
103+
callRemote('get_blacklist_profiles', gamePath, (data: string) => {
104+
setProfiles(JSON.parse(data));
105+
});
106+
hide();
107+
}}>{_i18n.t('同步')}</button>
108+
<button onClick={() => hide()}>{_i18n.t('忽略')}</button>
109+
</div>
110+
</div>
111+
);
112+
});
113+
}
114+
};
115+
checkSync();
116+
}, [currentProfile, gamePath, alwaysOnMods, currentProfileName]);
117+
80118
const formatTime = (time: number) => {
81119
if (time === 0) return _i18n.t('未知');
82120
const now = Date.now();

src/main.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,26 @@ impl Handler {
653653
}
654654
}
655655

656+
fn get_current_blacklist_content(&self, game_path: String) -> String {
657+
let result = blacklist::get_current_blacklist_content(&game_path);
658+
if let Err(e) = result {
659+
eprintln!("Failed to get current blacklist content: {}", e);
660+
"".to_string()
661+
} else {
662+
result.unwrap()
663+
}
664+
}
665+
666+
fn sync_blacklist_profile_from_file(&self, game_path: String, profile_name: String) -> String {
667+
let result = blacklist::sync_blacklist_profile_from_file(&game_path, &profile_name);
668+
if let Err(e) = result {
669+
eprintln!("Failed to sync blacklist profile: {}", e);
670+
format!("Failed to sync blacklist profile: {}", e)
671+
} else {
672+
"Success".to_string()
673+
}
674+
}
675+
656676
fn open_url(&self, url: String) {
657677
if let Err(e) = open::that(url) {
658678
eprintln!("Failed to open url: {}", e);
@@ -843,6 +863,8 @@ impl sciter::EventHandler for Handler {
843863
fn verify_celeste_install(String);
844864
fn get_mod_latest_info(Value);
845865
fn show_log_window();
866+
fn get_current_blacklist_content(String);
867+
fn sync_blacklist_profile_from_file(String, String);
846868
}
847869
}
848870

0 commit comments

Comments
 (0)