Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
c4d023ed43 | |||
9b86af282e | |||
2e17e0ae75 | |||
edef5cc6dc |
15
CHANGELOG.md
15
CHANGELOG.md
@ -1,6 +1,19 @@
|
||||
## 0.19.1
|
||||
|
||||
- Fixed the update button enabling the package
|
||||
- Fixed deep URLs with rainycolor.org
|
||||
|
||||
## 0.19.0
|
||||
|
||||
- Added diagnostic exports
|
||||
|
||||
## 0.18.3
|
||||
|
||||
- Updated Rainycolor's domain・真
|
||||
|
||||
## 0.18.2
|
||||
|
||||
- Update Rainycolor's domain
|
||||
- Updated Rainycolor's domain
|
||||
|
||||
## 0.18.1
|
||||
|
||||
|
@ -125,12 +125,13 @@ pub async fn kill() -> Result<(), String> {
|
||||
pub async fn install_package(
|
||||
state: State<'_, tokio::sync::Mutex<AppData>>,
|
||||
key: PkgKey,
|
||||
force: bool
|
||||
force: bool,
|
||||
enable: bool
|
||||
) -> Result<InstallResult, String> {
|
||||
log::debug!("invoke: install_package({})", key);
|
||||
|
||||
let mut appd = state.lock().await;
|
||||
appd.pkgs.install_package(&key, force, true)
|
||||
appd.pkgs.install_package(&key, force, true, enable)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
@ -480,13 +481,18 @@ pub async fn create_shortcut(_app: AppHandle, profile_meta: ProfileMeta) -> Resu
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn export_profile(state: State<'_, Mutex<AppData>>, export_keychip: bool, files: Vec<String>) -> Result<(), String> {
|
||||
pub async fn export_profile(
|
||||
state: State<'_, Mutex<AppData>>,
|
||||
is_diagnostic: bool,
|
||||
export_keychip: bool,
|
||||
files: Vec<String>
|
||||
) -> Result<(), String> {
|
||||
log::debug!("invoke: export_profile({:?}, {:?} files)", export_keychip, files.len());
|
||||
|
||||
let appd = state.lock().await;
|
||||
match &appd.profile {
|
||||
Some(p) => {
|
||||
p.export(export_keychip, files)
|
||||
p.export(export_keychip, files, is_diagnostic)
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
None => {
|
||||
|
@ -17,6 +17,12 @@ pub struct DownloadTick {
|
||||
ratio: f32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct DownloadEndPayload {
|
||||
pub key: PkgKey,
|
||||
pub enable: bool
|
||||
}
|
||||
|
||||
impl DownloadHandler {
|
||||
pub fn new(app: AppHandle) -> DownloadHandler {
|
||||
DownloadHandler {
|
||||
@ -25,7 +31,7 @@ impl DownloadHandler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn download_zip(&mut self, zip_path: &PathBuf, pkg: &Package) -> Result<()> {
|
||||
pub fn download_zip(&mut self, zip_path: &PathBuf, pkg: &Package, enable: bool) -> Result<()> {
|
||||
let rmt = pkg.rmt.as_ref()
|
||||
.ok_or_else(|| anyhow!("Attempted to download a package without remote data"))?
|
||||
.clone();
|
||||
@ -34,12 +40,18 @@ impl DownloadHandler {
|
||||
} else {
|
||||
// TODO clear cache button should clear this
|
||||
self.paths.insert(zip_path.clone());
|
||||
tauri::async_runtime::spawn(Self::download_zip_proc(self.app.clone(), zip_path.clone(), pkg.key(), rmt));
|
||||
tauri::async_runtime::spawn(Self::download_zip_proc(self.app.clone(), zip_path.clone(), pkg.key(), rmt, enable));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn download_zip_proc(app: AppHandle, zip_path: PathBuf, pkg_key: PkgKey, rmt: Remote) -> Result<()> {
|
||||
async fn download_zip_proc(
|
||||
app: AppHandle,
|
||||
zip_path: PathBuf,
|
||||
pkg_key: PkgKey,
|
||||
rmt: Remote,
|
||||
enable: bool
|
||||
) -> Result<()> {
|
||||
use futures::StreamExt;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
@ -66,7 +78,10 @@ impl DownloadHandler {
|
||||
|
||||
log::debug!("downloaded to {:?}", zip_path);
|
||||
|
||||
app.emit("download-end", pkg_key)?;
|
||||
app.emit("download-end", DownloadEndPayload {
|
||||
key: pkg_key,
|
||||
enable
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -102,16 +102,23 @@ pub async fn run(_args: Vec<String>) {
|
||||
});
|
||||
|
||||
app.listen("download-end", closure!(clone apph, |ev| {
|
||||
let raw = ev.payload();
|
||||
log::debug!("download-end triggered: {}", raw);
|
||||
let key = PkgKey(raw[1..raw.len()-1].to_owned());
|
||||
let apph = apph.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let mutex = apph.state::<Mutex<AppData>>();
|
||||
let mut appd = mutex.lock().await;
|
||||
let res = appd.pkgs.install_package(&key, true, false).await;
|
||||
log::debug!("download-end install {:?}", res);
|
||||
});
|
||||
let payload = serde_json::from_str::<download_handler::DownloadEndPayload>(ev.payload());
|
||||
match payload {
|
||||
Ok(payload) => {
|
||||
log::debug!("download-end triggered: {:?}", payload);
|
||||
let key = payload.key;
|
||||
let apph = apph.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let mutex = apph.state::<Mutex<AppData>>();
|
||||
let mut appd = mutex.lock().await;
|
||||
let res = appd.pkgs.install_package(&key, true, false, payload.enable).await;
|
||||
log::debug!("download-end install {:?}", res);
|
||||
});
|
||||
},
|
||||
Err(err) => {
|
||||
log::error!("invalid download payload: {err}");
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
app.listen("launch-end", closure!(clone apph, |_| {
|
||||
@ -134,11 +141,13 @@ pub async fn run(_args: Vec<String>) {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let mutex = apph.state::<Mutex<AppData>>();
|
||||
let mut appd = mutex.lock().await;
|
||||
let res = appd.toggle_package(payload.pkg.clone(), ToggleAction::EnableSelf);
|
||||
log::debug!(
|
||||
"install-end-prelude toggle {:?}",
|
||||
res
|
||||
);
|
||||
if payload.enable == true {
|
||||
let res = appd.toggle_package(payload.pkg.clone(), ToggleAction::EnableSelf);
|
||||
log::debug!(
|
||||
"install-end-prelude toggle {:?}",
|
||||
res
|
||||
);
|
||||
}
|
||||
use tauri::Emitter;
|
||||
let res = apph.emit("install-end", payload);
|
||||
log::debug!("install-end {:?}", res);
|
||||
@ -261,7 +270,7 @@ fn deep_link(app: AppHandle, args: Vec<String>) {
|
||||
log::info!("deep link: {}", url);
|
||||
|
||||
let regex = regex::Regex::new(
|
||||
r"rainycolor://v1/install/rainy\.patafour\.zip/([^/]+)/([^/]+)/[0-9]+\.[0-9]+\.[0-9]+/"
|
||||
r"rainycolor://v1/install/www\.rainycolor\.org/([^/]+)/([^/]+)/[0-9]+\.[0-9]+\.[0-9]+/"
|
||||
).expect("Invalid regex");
|
||||
|
||||
if let Some(caps) = regex.captures(url) {
|
||||
@ -273,11 +282,13 @@ fn deep_link(app: AppHandle, args: Vec<String>) {
|
||||
let mut appd = mutex.lock().await;
|
||||
if appd.pkgs.is_offline() {
|
||||
log::warn!("Deep link installation failed: offline");
|
||||
} else if let Err(e) = appd.pkgs.install_package(&key, true, true).await {
|
||||
} else if let Err(e) = appd.pkgs.install_package(&key, true, true, true).await {
|
||||
log::warn!("Deep link installation failed: {}", e.to_string());
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
log::error!("No caps");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,10 @@ impl PatchFileVec {
|
||||
}
|
||||
|
||||
pub fn find_patches(&self, target: impl AsRef<Path>) -> Result<Vec<Patch>> {
|
||||
if !target.as_ref().exists() {
|
||||
log::warn!("invalid target path: {:?}", target.as_ref());
|
||||
anyhow::bail!("Unable to open {:?}. Make sure the game path is correct.", target.as_ref());
|
||||
}
|
||||
let checksum = try_digest(target.as_ref())?;
|
||||
|
||||
let mut res_patches = Vec::new();
|
||||
|
@ -109,7 +109,7 @@ impl Package {
|
||||
loc: None,
|
||||
rmt: Some(Remote {
|
||||
package_url: p.package_url,
|
||||
download_url: v.download_url,
|
||||
download_url: v.download_url.replace("https://rainy.patafour.zip/", "https://www.rainycolor.org/"),
|
||||
icon: v.icon,
|
||||
deprecated: p.is_deprecated,
|
||||
nsfw: p.has_nsfw_content,
|
||||
|
@ -23,7 +23,8 @@ pub struct PackageStore {
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct Payload {
|
||||
pub pkg: PkgKey
|
||||
pub pkg: PkgKey,
|
||||
pub enable: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||
@ -180,7 +181,13 @@ impl PackageStore {
|
||||
self.offline = false;
|
||||
}
|
||||
|
||||
pub async fn install_package(&mut self, key: &PkgKey, force: bool, install_deps: bool) -> Result<InstallResult> {
|
||||
pub async fn install_package(
|
||||
&mut self,
|
||||
key: &PkgKey,
|
||||
force: bool,
|
||||
install_deps: bool,
|
||||
enable: bool
|
||||
) -> Result<InstallResult> {
|
||||
log::info!("installation request: {}/{}/{}", key, force, install_deps);
|
||||
|
||||
let pkg = self.store.get(key)
|
||||
@ -193,7 +200,8 @@ impl PackageStore {
|
||||
}
|
||||
|
||||
self.app.emit("install-start", Payload {
|
||||
pkg: key.to_owned()
|
||||
pkg: key.to_owned(),
|
||||
enable
|
||||
})?;
|
||||
|
||||
let rmt = pkg.rmt.as_ref()
|
||||
@ -203,7 +211,7 @@ impl PackageStore {
|
||||
let mut set = HashSet::new();
|
||||
self.resolve_deps(rmt.clone(), &mut set)?;
|
||||
for dep in set {
|
||||
Box::pin(self.install_package(&dep, false, false)).await?;
|
||||
Box::pin(self.install_package(&dep, false, false, enable)).await?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,7 +222,7 @@ impl PackageStore {
|
||||
let part_path = zip_path.join(".part");
|
||||
|
||||
if !zip_path.exists() && !part_path.exists() {
|
||||
self.dlh.download_zip(&zip_path, &pkg)?;
|
||||
self.dlh.download_zip(&zip_path, &pkg, enable)?;
|
||||
log::debug!("deferring {}", key);
|
||||
return Ok(InstallResult::Deferred);
|
||||
}
|
||||
@ -230,7 +238,8 @@ impl PackageStore {
|
||||
self.reload_package(key.to_owned()).await;
|
||||
|
||||
self.app.emit("install-end-prelude", Payload {
|
||||
pkg: key.to_owned()
|
||||
pkg: key.to_owned(),
|
||||
enable
|
||||
})?;
|
||||
|
||||
log::info!("installed {}", key);
|
||||
@ -252,7 +261,8 @@ impl PackageStore {
|
||||
|
||||
if rv.is_ok() {
|
||||
self.app.emit("install-end-prelude", Payload {
|
||||
pkg: key.to_owned()
|
||||
pkg: key.to_owned(),
|
||||
enable: false
|
||||
})?;
|
||||
log::info!("deleted {}", key);
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ impl Profile {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn export(&self, export_keychip: bool, extra_files: Vec<String>) -> anyhow::Result<()> {
|
||||
pub fn export(&self, export_keychip: bool, extra_files: Vec<String>, is_diagnostic: bool) -> anyhow::Result<()> {
|
||||
let mut prf = self.clone();
|
||||
|
||||
let dir = util::config_dir().join("exports");
|
||||
@ -45,7 +45,7 @@ impl Profile {
|
||||
std::fs::create_dir(&dir)?;
|
||||
}
|
||||
|
||||
let path = dir.join(format!("{}-{}-template.zip", &self.meta.game, &self.meta.name));
|
||||
let path = dir.join(format!("{}-{}-{}.zip", &self.meta.game, &self.meta.name, if is_diagnostic { "diagnostic" } else { "template" } ));
|
||||
|
||||
{
|
||||
let sgt = &mut prf.data.sgt;
|
||||
@ -66,7 +66,7 @@ impl Profile {
|
||||
if network.local_path.is_absolute() {
|
||||
network.local_path = PathBuf::new();
|
||||
}
|
||||
if !export_keychip {
|
||||
if !export_keychip || is_diagnostic {
|
||||
network.keychip = String::new();
|
||||
}
|
||||
}
|
||||
@ -83,6 +83,29 @@ impl Profile {
|
||||
zip.write_all(&std::fs::read(self.config_dir().join(file))?)?;
|
||||
}
|
||||
|
||||
if is_diagnostic {
|
||||
let name = "mu3.exe.log";
|
||||
let path = self.data_dir().join(name);
|
||||
if path.exists() {
|
||||
zip.start_file(name, options)?;
|
||||
zip.write_all(&std::fs::read(path)?)?;
|
||||
}
|
||||
|
||||
let name = "chusanApp.exe.log";
|
||||
let path = self.data_dir().join(name);
|
||||
if path.exists() {
|
||||
zip.start_file(name, options)?;
|
||||
zip.write_all(&std::fs::read(path)?)?;
|
||||
}
|
||||
|
||||
let name = "amdaemon.exe.log";
|
||||
let path = self.data_dir().join(name);
|
||||
if path.exists() {
|
||||
zip.start_file(name, options)?;
|
||||
zip.write_all(&std::fs::read(path)?)?;
|
||||
}
|
||||
}
|
||||
|
||||
zip.finish()?;
|
||||
|
||||
Ok(())
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "STARTLINER",
|
||||
"version": "0.18.2",
|
||||
"version": "0.19.1",
|
||||
"identifier": "zip.patafour.startliner",
|
||||
"build": {
|
||||
"beforeDevCommand": "bun run dev",
|
||||
|
@ -295,7 +295,7 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
||||
pkg.hasAvailableUpdates
|
||||
"
|
||||
icon="pi pi-download"
|
||||
label="UPDATE ALL"
|
||||
:label="t('updateAll')"
|
||||
size="small"
|
||||
class="mr-4 m-2.5"
|
||||
@click="pkg.updateAll()"
|
||||
|
@ -53,6 +53,6 @@ const remove = async () => {
|
||||
class="self-center ml-4"
|
||||
style="width: 2rem; height: 2rem"
|
||||
:loading="pkg?.js.downloading"
|
||||
v-on:click="async () => await pkgs.install(pkg)"
|
||||
v-on:click="async () => await pkgs.install(pkg, true)"
|
||||
/>
|
||||
</template>
|
||||
|
@ -29,23 +29,34 @@ const files = new Set<string>();
|
||||
).includes('chunithm');
|
||||
})();
|
||||
|
||||
const fileList = {
|
||||
ongeki: ['aime.txt', 'inohara.cfg', 'mu3.ini', 'segatools-base.ini'],
|
||||
chunithm: ['aime.txt', 'saekawa.toml', 'segatools-base.ini'],
|
||||
};
|
||||
|
||||
const diagnosticList = {
|
||||
ongeki: ['mu3.ini', 'segatools-base.ini'],
|
||||
chunithm: ['segatools-base.ini'],
|
||||
};
|
||||
|
||||
const diagnostic = ref(false);
|
||||
|
||||
const exportTemplate = async () => {
|
||||
const fl = [...files.values()];
|
||||
exportVisible.value = false;
|
||||
await invoke('export_profile', {
|
||||
exportKeychip: exportKeychip.value,
|
||||
files: fl,
|
||||
isDiagnostic: diagnostic.value,
|
||||
files:
|
||||
diagnostic.value === true
|
||||
? diagnosticList[prf.current!.meta.game]
|
||||
: fl,
|
||||
});
|
||||
await invoke('open_file', {
|
||||
path: await path.join(await general.configDir, 'exports'),
|
||||
});
|
||||
};
|
||||
|
||||
const fileList = {
|
||||
ongeki: ['aime.txt', 'inohara.cfg', 'mu3.ini', 'segatools-base.ini'],
|
||||
chunithm: ['aime.txt', 'saekawa.toml', 'segatools-base.ini'],
|
||||
};
|
||||
|
||||
const fileListCurrent: Ref<string[]> = ref([]);
|
||||
|
||||
const recalcFileList = async () => {
|
||||
@ -91,16 +102,36 @@ const importPick = async () => {
|
||||
:visible="exportVisible"
|
||||
:closable="false /*this shit doesn't work */"
|
||||
:header="`${t('profile.export')} ${prf.current?.meta.name}`"
|
||||
:style="{ width: '300px', scale: client.scaleValue }"
|
||||
:style="{ width: '330px', scale: client.scaleValue }"
|
||||
>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col items-center">
|
||||
<SelectButton
|
||||
v-model="diagnostic"
|
||||
:options="[
|
||||
{
|
||||
title: t('profile.standardExport'),
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
title: t('profile.diagnostic'),
|
||||
value: true,
|
||||
},
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
>
|
||||
</SelectButton>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="grow">{{ t('profile.export') }} keychip</div>
|
||||
<ToggleSwitch v-model="exportKeychip" />
|
||||
<ToggleSwitch :disabled="diagnostic" v-model="exportKeychip" />
|
||||
</div>
|
||||
<div class="flex flex-row" v-for="f in fileListCurrent">
|
||||
<div class="grow">{{ t('profile.export') }} {{ f }}</div>
|
||||
<ToggleSwitch
|
||||
:disabled="diagnostic"
|
||||
:model-value="true"
|
||||
@update:model-value="
|
||||
(v) => {
|
||||
|
@ -17,6 +17,7 @@ const install = async () => {
|
||||
await invoke('install_package', {
|
||||
key: pkgKey(props.pkg),
|
||||
force: true,
|
||||
enable: false,
|
||||
});
|
||||
} catch (err) {
|
||||
if (props.pkg !== undefined) {
|
||||
|
@ -9,6 +9,7 @@ export default {
|
||||
skip: 'Skip',
|
||||
close: 'Close',
|
||||
by: 'by {namespace}',
|
||||
updateAll: 'UPDATE ALL',
|
||||
start: {
|
||||
failed: 'Start check failed',
|
||||
accept: 'Run anyway',
|
||||
@ -44,8 +45,10 @@ export default {
|
||||
reallyDelete: 'Are you sure you want to delete {profile}?',
|
||||
template: 'STARTLINER template',
|
||||
importTemplate: 'Import template',
|
||||
exportTemplate: 'Export template',
|
||||
exportTemplate: 'Export profile',
|
||||
export: 'Export',
|
||||
standardExport: 'Template',
|
||||
diagnostic: 'Diagnostic',
|
||||
},
|
||||
creator: {
|
||||
header: 'Package creator',
|
||||
|
@ -9,6 +9,7 @@ export default {
|
||||
skip: 'Pomiń',
|
||||
close: 'Zamknij',
|
||||
by: 'od {namespace}',
|
||||
updateAll: 'ZAKTUALIZUJ WSZYSTKO',
|
||||
start: {
|
||||
failed: 'Uruchomienie nie powiodło się',
|
||||
accept: 'Uruchom mimo to',
|
||||
@ -44,8 +45,10 @@ export default {
|
||||
reallyDelete: 'Czy na pewno chcesz usunąć {profile}?',
|
||||
template: 'Szablon',
|
||||
importTemplate: 'Importuj szablon',
|
||||
exportTemplate: 'Eksportuj szablon',
|
||||
exportTemplate: 'Eksportuj profil',
|
||||
export: 'Eksportuj',
|
||||
standardExport: 'Szablon',
|
||||
diagnostic: 'Diagnostyka',
|
||||
},
|
||||
creator: {
|
||||
header: 'Kreator pakietów',
|
||||
|
@ -189,7 +189,7 @@ export const usePkgStore = defineStore('pkg', {
|
||||
await this.reloadAll();
|
||||
},
|
||||
|
||||
async install(pkg: Package | undefined) {
|
||||
async install(pkg: Package | undefined, enable: boolean) {
|
||||
if (pkg === undefined) {
|
||||
return;
|
||||
}
|
||||
@ -198,6 +198,7 @@ export const usePkgStore = defineStore('pkg', {
|
||||
await invoke('install_package', {
|
||||
key: pkgKey(pkg),
|
||||
force: true,
|
||||
enable,
|
||||
});
|
||||
} catch (err) {
|
||||
if (pkg !== undefined) {
|
||||
@ -211,6 +212,7 @@ export const usePkgStore = defineStore('pkg', {
|
||||
await invoke('install_package', {
|
||||
key,
|
||||
force: true,
|
||||
enable: false,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@ -221,7 +223,7 @@ export const usePkgStore = defineStore('pkg', {
|
||||
const list = [];
|
||||
for (const pkg of this.allLocal) {
|
||||
if (pkg.rmt && pkg.rmt.version > pkg.loc!.version) {
|
||||
list.push(this.install(pkg));
|
||||
list.push(this.install(pkg, false));
|
||||
}
|
||||
}
|
||||
await Promise.all(list);
|
||||
|
Reference in New Issue
Block a user