refactor(app-frontend): move launcher update flow to AstralRinth helper and modal

This commit is contained in:
2026-06-18 02:03:20 +03:00
parent b88bd246f8
commit 9678770cba
10 changed files with 650 additions and 247 deletions
+57 -29
View File
@@ -85,7 +85,7 @@ import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
import { config } from '@/config'
import { check_reachable } from '@/helpers/auth.js'
import { get_user, get_version } from '@/helpers/cache.js'
import { command_listener, notification_listener, warning_listener, log_listener } from '@/helpers/events.js'
import { command_listener, notification_listener, warning_listener } from '@/helpers/events.js'
import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.ts'
import { create_profile_and_install_from_file } from '@/helpers/pack'
import { list } from '@/helpers/profile.js'
@@ -109,7 +109,7 @@ import { AppNotificationManager } from './providers/app-notifications'
import { AppPopupNotificationManager } from './providers/app-popup-notifications'
// This code line modified by AstralRinth
import { getRemote, updateState } from '@/helpers/update.js'
import { fetchRemote, isUpdateAvailable } from '@/helpers/astralrinth/update'
const themeStore = useTheming()
const router = useRouter()
@@ -119,23 +119,23 @@ const APP_SIDEBAR_WIDTH = 300
const INTERCOM_BUBBLE_DEFAULT_PADDING = 20
// This code line modified by AstralRinth
const filteredNewsPhrases = [
"LGBT",
"LGBTQ",
"LGBTQ+",
"LGBTQIA+",
"gay",
"lesbian",
"bisexual",
"pansexual",
"asexual",
"aromantic",
"transgender",
"nonbinary",
"intersex",
"homosexual",
"homosexuality",
"pride",
];
'LGBT',
'LGBTQ',
'LGBTQ+',
'LGBTQIA+',
'gay',
'lesbian',
'bisexual',
'pansexual',
'asexual',
'aromantic',
'transgender',
'nonbinary',
'intersex',
'homosexual',
'homosexuality',
'pride',
]
const credentials = ref()
const sidebarToggled = ref(true)
const unsubscribeSidebarToggle = themeStore.$subscribe(() => {
@@ -172,6 +172,8 @@ const popupNotificationManager = new AppPopupNotificationManager()
providePopupNotificationManager(popupNotificationManager)
const { addPopupNotification } = popupNotificationManager
const settingsModal = ref(null)
const appVersion = getVersion()
const tauriApiClient = new TauriModrinthClient({
userAgent: async () => `modrinth/theseus/${await appVersion} (support@modrinth.com)`,
@@ -281,7 +283,22 @@ const authUnreachable = computed(() => {
onMounted(async () => {
await useCheckDisableMouseover()
// This code line modified by AstralRinth
await getRemote(false)
await fetchRemote()
if (isUpdateAvailable.value) {
addPopupNotification({
title: formatMessage(messages.launcherUpdateAvailableTitle),
text: formatMessage(messages.launcherUpdateAvailableText),
type: 'info',
autoCloseMs: 12000,
buttons: [
{
label: formatMessage(messages.launcherUpdateAvailableAction),
action: () => settingsModal.value?.showUpdateModal?.(),
color: 'brand',
},
],
})
}
document.querySelector('body').addEventListener('click', handleClick)
document.querySelector('body').addEventListener('auxclick', handleAuxClick)
@@ -305,6 +322,18 @@ const messages = defineMessages({
defaultMessage:
'Minecraft authentication servers may be down right now. Check your internet connection and try again later.',
},
launcherUpdateAvailableTitle: {
id: 'astralrinth.app.launcher-update.available.title',
defaultMessage: 'Launcher update available',
},
launcherUpdateAvailableText: {
id: 'astralrinth.app.launcher-update.available.text',
defaultMessage: 'New version of AstralRinth is available for download.',
},
launcherUpdateAvailableAction: {
id: 'astralrinth.app.launcher-update.available.action',
defaultMessage: 'View update',
},
})
// This code line modified by AstralRinth
@@ -705,10 +734,7 @@ async function logOut() {
}
// This code line modified by AstralRinth
const hasPlus = computed(
() =>
!!credentials.value?.user,
)
const hasPlus = computed(() => !!credentials.value?.user)
async function fetchIntercomToken() {
const creds = await getCreds()
@@ -1121,18 +1147,20 @@ provideAppUpdateDownloadProgress(appUpdateDownload) // [AR Note] If delete this
</NavButton>
<div class="flex flex-grow"></div>
<!-- This code line modified by AstralRinth -->
<template v-if="updateState">
<template v-if="isUpdateAvailable">
<NavButton
class="neon-icon pulse"
v-tooltip.right="formatMessage(commonMessages.settingsLabel)"
:to="() => $refs.settingsModal.show()">
v-tooltip.right="formatMessage(commonMessages.settingsLabel)"
:to="() => $refs.settingsModal.show()"
>
<SettingsIcon />
</NavButton>
</template>
<template v-else>
<NavButton
v-tooltip.right="formatMessage(commonMessages.settingsLabel)"
:to="() => $refs.settingsModal.show()">
v-tooltip.right="formatMessage(commonMessages.settingsLabel)"
:to="() => $refs.settingsModal.show()"
>
<SettingsIcon />
</NavButton>
</template>
@@ -0,0 +1,253 @@
<script setup lang="ts">
import { Button, defineMessages, useVIntl } from '@modrinth/ui'
import { computed, ref } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import {
downloadLatestRelease,
isUpdateInstalling,
LAUNCHER_RELEASES_URL,
LAUNCHER_REPOSITORY_URL,
latestLauncherRelease,
} from '@/helpers/astralrinth/update'
type ModalHandle = {
hide: () => void
show: () => void
}
const props = defineProps<{
version: string
}>()
const { formatMessage } = useVIntl()
const updateModalView = ref<ModalHandle | null>(null)
const updateRequestFailView = ref<ModalHandle | null>(null)
const releaseTag = computed(() => latestLauncherRelease.value?.tag_name ?? '')
const releaseTitle = computed(() => latestLauncherRelease.value?.name ?? '')
const messages = defineMessages({
updateHeader: {
id: 'astralrinth.app.launcher-update-modal.update.header',
defaultMessage: 'AstralRinth launcher update',
},
updateTitle: {
id: 'astralrinth.app.launcher-update-modal.update.title',
defaultMessage: 'A new version of the AstralRinth launcher is available.',
},
updateDescription: {
id: 'astralrinth.app.launcher-update-modal.update.description',
defaultMessage:
'You are using an older version. We recommend updating now for the latest fixes and improvements.',
},
updateNoticeTitle: {
id: 'astralrinth.app.launcher-update-modal.update.notice-title',
defaultMessage: '⚠️ Before you continue',
},
updateNoticeLead: {
id: 'astralrinth.app.launcher-update-modal.update.notice-lead',
defaultMessage:
'Save your work, close all running launcher instances, and back up your launcher data before installing the update.',
},
updateNoticeWindows: {
id: 'astralrinth.app.launcher-update-modal.update.notice-windows',
defaultMessage: 'On Windows, important data may be stored in',
},
updateNoticeMacos: {
id: 'astralrinth.app.launcher-update-modal.update.notice-macos',
defaultMessage: 'On macOS, important data may be stored in',
},
updateNoticeOutro: {
id: 'astralrinth.app.launcher-update-modal.update.notice-outro',
defaultMessage: 'To avoid data loss, keep a backup copy in a safe place before continuing.',
},
latestReleaseTag: {
id: 'astralrinth.app.launcher-update-modal.update.latest-release-tag',
defaultMessage: '☁️ Latest release tag:',
},
latestReleaseTitle: {
id: 'astralrinth.app.launcher-update-modal.update.latest-release-title',
defaultMessage: '☁️ Latest release title:',
},
installedVersion: {
id: 'astralrinth.app.launcher-update-modal.update.installed-version',
defaultMessage: '💾 Installed & Running version:',
},
repositoryLink: {
id: 'astralrinth.app.launcher-update-modal.update.repository-link',
defaultMessage: 'Open the project repository',
},
cancelAction: {
id: 'astralrinth.app.launcher-update-modal.update.cancel-action',
defaultMessage: 'Cancel',
},
downloadAction: {
id: 'astralrinth.app.launcher-update-modal.update.download-action',
defaultMessage: 'Download update and close',
},
errorHeader: {
id: 'astralrinth.app.launcher-update-modal.error.header',
defaultMessage: 'Could not download the update',
},
errorTitle: {
id: 'astralrinth.app.launcher-update-modal.error.title',
defaultMessage: 'Download failed',
},
errorDescription: {
id: 'astralrinth.app.launcher-update-modal.error.description',
defaultMessage: 'AstralRinth could not download the update file from the server.',
},
errorHelpText: {
id: 'astralrinth.app.launcher-update-modal.error.help-text',
defaultMessage: 'You can try downloading it manually from',
},
errorHelpLink: {
id: 'astralrinth.app.launcher-update-modal.error.help-link',
defaultMessage: 'AstralRinth repository releases',
},
errorHelpSuffix: {
id: 'astralrinth.app.launcher-update-modal.error.help-suffix',
defaultMessage: 'if a newer release is available there.',
},
localVersion: {
id: 'astralrinth.app.launcher-update-modal.error.local-version',
defaultMessage: 'Local AstralRinth:',
},
closeAction: {
id: 'astralrinth.app.launcher-update-modal.error.close-action',
defaultMessage: 'Close',
},
})
async function show() {
updateModalView.value?.show()
}
async function initDownload() {
updateModalView.value?.hide()
const result = await downloadLatestRelease()
if (!result) {
updateRequestFailView.value?.show()
}
}
defineExpose({
show,
hide: () => updateModalView.value?.hide(),
})
</script>
<template>
<ModalWrapper
ref="updateModalView"
:has-to-type="false"
:header="formatMessage(messages.updateHeader)"
>
<div class="space-y-3 pb-16">
<div class="space-y-1 rounded-2xl border border-solid border-[rgba(255,255,255,0.12)] p-3">
<p class="m-0 text-base">
<strong>{{ formatMessage(messages.updateTitle) }}</strong>
</p>
<p class="m-0 text-secondary">{{ formatMessage(messages.updateDescription) }}</p>
</div>
<div
class="space-y-2 rounded-2xl border border-solid border-[rgba(255,255,255,0.12)] bg-[rgba(255,255,255,0.03)] p-3"
>
<div class="space-y-2">
<p class="m-0">
<strong class="neon-text">{{ formatMessage(messages.updateNoticeTitle) }}</strong>
</p>
<p class="m-0 text-secondary text-sm">{{ formatMessage(messages.updateNoticeLead) }}</p>
<p class="m-0 text-sm">
{{ formatMessage(messages.updateNoticeWindows) }}
<code class="neon-text">%appdata%\Roaming\AstralRinthApp</code>
</p>
<p class="m-0 text-sm">
{{ formatMessage(messages.updateNoticeMacos) }}
<code class="neon-text">~/Library/Application Support/AstralRinthApp</code>
</p>
<p class="m-0 text-sm">{{ formatMessage(messages.updateNoticeOutro) }}</p>
</div>
</div>
<div
class="space-y-2 rounded-2xl border border-solid border-[rgba(255,255,255,0.12)] p-3 text-sm text-secondary"
>
<p class="m-0">
<strong>{{ formatMessage(messages.latestReleaseTag) }}</strong>
<span class="neon-text">{{ releaseTag }}</span>
<br />
<strong>{{ formatMessage(messages.latestReleaseTitle) }}</strong>
<span class="neon-text">{{ releaseTitle }}</span>
<br />
<strong>{{ formatMessage(messages.installedVersion) }}</strong>
<span class="neon-text">v{{ props.version }}</span>
</p>
<a
class="inline-flex neon-text"
:href="LAUNCHER_REPOSITORY_URL"
target="_blank"
rel="noopener noreferrer"
>
{{ formatMessage(messages.repositoryLink) }}
</a>
</div>
<div class="absolute bottom-4 right-4 flex items-center gap-4 neon-button neon">
<Button class="bordered" @click="updateModalView?.hide()">
{{ formatMessage(messages.cancelAction) }}
</Button>
<Button class="bordered" :disabled="isUpdateInstalling" @click="initDownload()">
{{ formatMessage(messages.downloadAction) }}
</Button>
</div>
</div>
</ModalWrapper>
<ModalWrapper
ref="updateRequestFailView"
:has-to-type="false"
:header="formatMessage(messages.errorHeader)"
>
<div class="space-y-3 pb-16">
<div class="space-y-2 rounded-2xl border border-solid border-[rgba(255,255,255,0.12)] p-3">
<p><strong>{{ formatMessage(messages.errorTitle) }}</strong></p>
<p class="m-0 text-secondary">{{ formatMessage(messages.errorDescription) }}</p>
<p class="m-0 text-sm">
{{ formatMessage(messages.errorHelpText) }}
<a
class="neon-text"
:href="LAUNCHER_RELEASES_URL"
target="_blank"
rel="noopener noreferrer"
>
{{ formatMessage(messages.errorHelpLink) }}
</a>
{{ formatMessage(messages.errorHelpSuffix) }}
</p>
</div>
<div class="rounded-2xl border border-solid border-[rgba(255,255,255,0.12)] p-3 text-sm text-secondary">
<p class="m-0">
<strong>{{ formatMessage(messages.localVersion) }}</strong>
<span class="neon-text">v{{ props.version }}</span>
</p>
</div>
<div class="absolute bottom-4 right-4 flex items-center gap-4 neon-button neon">
<Button class="bordered" @click="updateRequestFailView?.hide()">
{{ formatMessage(messages.closeAction) }}
</Button>
</div>
</div>
</ModalWrapper>
</template>
<style lang="scss" scoped>
@import '../../../../../../packages/assets/styles/astralrinth/neon-button.scss';
@import '../../../../../../packages/assets/styles/astralrinth/neon-text.scss';
</style>
@@ -13,7 +13,6 @@ import {
ToggleRightIcon,
} from '@modrinth/assets'
import {
Button,
commonMessages,
commonSettingsMessages,
defineMessage,
@@ -26,7 +25,7 @@ import { getVersion } from '@tauri-apps/api/app'
import { platform as getOsPlatform, version as getOsVersion } from '@tauri-apps/plugin-os'
import { ref, watch } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import LauncherUpdateModal from '@/components/ui/astralrinth/LauncherUpdateModal.vue'
import AppearanceSettings from '@/components/ui/settings/AppearanceSettings.vue'
import DefaultInstanceSettings from '@/components/ui/settings/DefaultInstanceSettings.vue'
import FeatureFlagSettings from '@/components/ui/settings/FeatureFlagSettings.vue'
@@ -35,22 +34,16 @@ import LanguageSettings from '@/components/ui/settings/LanguageSettings.vue'
import PrivacySettings from '@/components/ui/settings/PrivacySettings.vue'
import ResourceManagementSettings from '@/components/ui/settings/ResourceManagementSettings.vue'
import { get, set } from '@/helpers/settings.ts'
import { getRemote, installState, updateState } from '@/helpers/update.js'
import { isUpdateInstalling, isUpdateAvailable } from '@/helpers/astralrinth/update'
import { injectAppUpdateDownloadProgress } from '@/providers/download-progress.ts'
import { useTheming } from '@/store/state'
type ModalHandle = {
hide: () => void
show: () => void
}
const themeStore = useTheming()
const { formatMessage } = useVIntl()
const devModeCounter = ref(0)
const modal = ref<InstanceType<typeof TabbedModal> | null>(null)
const updateModalView = ref<ModalHandle | null>(null)
const updateRequestFailView = ref<ModalHandle | null>(null)
const launcherUpdateModal = ref<InstanceType<typeof LauncherUpdateModal> | null>(null)
const developerModeEnabled = defineMessage({
id: 'app.settings.developer-mode-enabled',
@@ -120,20 +113,11 @@ function show() {
}
function showUpdateModal() {
updateModalView.value?.show()
void getRemote(false)
modal.value?.show()
void launcherUpdateModal.value?.show()
}
async function initDownload() {
updateModalView.value?.hide()
const result = await getRemote(true)
if (!result) {
updateRequestFailView.value?.show()
}
}
defineExpose({ show })
defineExpose({ show, showUpdateModal })
const { progress, version: downloadingVersion } = injectAppUpdateDownloadProgress()
@@ -168,6 +152,14 @@ const messages = defineMessages({
id: 'app.settings.downloading',
defaultMessage: 'Downloading v{version}',
},
updateInstalling: {
id: 'astralrinth.app.settings.update-installing',
defaultMessage: 'Installing update...',
},
viewUpdateInfo: {
id: 'astralrinth.app.settings.view-update-info',
defaultMessage: 'View update info',
},
})
</script>
@@ -211,19 +203,19 @@ const messages = defineMessages({
</p>
</div>
<div
v-if="updateState"
v-if="isUpdateAvailable"
class="w-8 h-8 cursor-pointer hover:brightness-75 neon-icon pulse shrink-0"
>
<template v-if="installState">
<template v-if="isUpdateInstalling">
<SpinnerIcon
class="size-6 animate-spin"
v-tooltip.bottom="'Installing in process...'"
v-tooltip.bottom="formatMessage(messages.updateInstalling)"
/>
</template>
<template v-else>
<DownloadIcon
class="size-6"
v-tooltip.bottom="'View update info'"
v-tooltip.bottom="formatMessage(messages.viewUpdateInfo)"
@click="showUpdateModal()"
/>
</template>
@@ -233,100 +225,9 @@ const messages = defineMessages({
</template>
</TabbedModal>
<ModalWrapper
ref="updateModalView"
:has-to-type="false"
header="Request to update the AstralRinth launcher"
>
<div class="space-y-4">
<div class="space-y-2">
<strong>The new version of the AstralRinth launcher is available!</strong>
<p>Your version is outdated. We recommend that you update to the latest version.</p>
<br />
<br />
<p><strong> Please, read this notice before initialize update process</strong></p>
<p>
Before updating, make sure that you have saved and closed all running instances and
made a backup copy of the launcher data such as
<code>%appdata%\Roaming\AstralRinthApp</code> on Windows or
<code>~/Library/Application Support/AstralRinthApp</code> on macOS. Remember that
the authors of the product are not responsible for the breakdown of your files, so
you should always make back up copies of them and keep them in a safe place.
</p>
</div>
<div class="text-sm text-secondary space-y-1">
<p>
<strong> Latest release tag:</strong>
<span id="releaseTag" class="neon-text"></span>
<br />
<strong> Latest release title:</strong>
<span id="releaseTitle" class="neon-text"></span>
<br />
<strong>💾 Installed & Running version:</strong>
<span class="neon-text">v{{ version }}</span>
</p>
</div>
<a
class="neon-text"
href="https://me.astralium.su/get/ar"
target="_blank"
rel="noopener noreferrer"
>
Checkout our git repository
</a>
<div class="absolute bottom-4 right-4 flex items-center gap-4 neon-button neon">
<Button class="bordered" @click="updateModalView?.hide()">Cancel</Button>
<Button class="bordered" @click="initDownload()">Download file</Button>
</div>
</div>
</ModalWrapper>
<ModalWrapper
ref="updateRequestFailView"
:has-to-type="false"
header="Failed to request a file from the server :("
>
<div class="space-y-4">
<div class="space-y-2">
<p><strong>Error occurred</strong></p>
<p>Unfortunately, the program was unable to download the file from our servers.</p>
<p>
Please try downloading it yourself from
<a
class="neon-text"
href="https://astralium.su/product/astralrinth/source"
target="_blank"
rel="noopener noreferrer"
>
AstralRinth repository
</a>
if there are any updates available.
</p>
</div>
<div class="text-sm text-secondary">
<p>
<strong>Local AstralRinth:</strong>
<span class="neon-text">v{{ version }}</span>
</p>
</div>
<div class="absolute bottom-4 right-4 flex items-center gap-4 neon-button neon">
<Button class="bordered" @click="updateRequestFailView?.hide()">Close</Button>
</div>
</div>
</ModalWrapper>
<LauncherUpdateModal ref="launcherUpdateModal" :version="version" />
</template>
<style lang="scss" scoped>
@import '../../../../../../packages/assets/styles/astralrinth/neon-icon.scss';
@import '../../../../../../packages/assets/styles/astralrinth/neon-button.scss';
@import '../../../../../../packages/assets/styles/astralrinth/neon-text.scss';
code {
background: linear-gradient(90deg, #005eff, #00cfff);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
}
</style>
@@ -0,0 +1,148 @@
import { getVersion } from '@tauri-apps/api/app'
import { ref } from 'vue'
import { getOS, initUpdateLauncher, isDev } from '@/helpers/utils.js'
export type LauncherReleaseAsset = {
name: string
browser_download_url: string
}
export type LauncherRelease = {
tag_name: string
name: string
assets: LauncherReleaseAsset[]
}
// import.meta.env uses `vite.config.ts`
// Environments can be configured in `packages/app-lib/` directory.
export const LAUNCHER_REPOSITORY_URL = `${import.meta.env.GIT_ASTRALIUM_URL}didirus/AstralRinth/`
export const LAUNCHER_RELEASES_URL = `${LAUNCHER_REPOSITORY_URL}releases`
const LAUNCHER_LATEST_RELEASE_API = `${import.meta.env.GIT_ASTRALIUM_API_URL}repos/didirus/AstralRinth/releases/latest`
export const isUpdateInstalling = ref(false)
export const isUpdateAvailable = ref(false)
export const latestLauncherRelease = ref<LauncherRelease | null>(null)
const currentOS = ref('')
const systems = ['macos', 'windows', 'linux'] as const
const osExtensions = {
"linux": ['.deb'],
"macos": ['.dmg', '.pkg', '.app'],
"windows": ['.exe', '.msi']
}
const isDeveloper = await isDev()
const blacklistBeginPrefixes = [
'dev',
'nightly',
'dirty',
'dirty-dev',
'dirty-nightly',
'dirty_dev',
'dirty_nightly',
]
export async function fetchRemote(): Promise<void> {
currentOS.value = (await getOS()).toLowerCase()
try {
const response = await fetch(LAUNCHER_LATEST_RELEASE_API)
if (!response.ok) {
throw new Error(String(response.status))
}
const remoteData = (await response.json()) as LauncherRelease
latestLauncherRelease.value = remoteData
if (systems.includes(currentOS.value as (typeof systems)[number])) {
const localVersion = normalizeVersion(await getVersion())
const remoteVersion = normalizeVersion(remoteData.tag_name)
isUpdateAvailable.value = remoteVersion !== localVersion
} else {
isUpdateAvailable.value = false
}
if (isDeveloper) {
console.debug('Update available state is', isUpdateAvailable.value)
console.debug('Remote version is', remoteData.tag_name)
console.debug('Remote title is', remoteData.name)
console.debug('Local version is', await getVersion())
console.debug('Operating System is', currentOS.value)
}
} catch (error) {
console.error('Failed to fetch remote releases:', error)
latestLauncherRelease.value = null
isUpdateAvailable.value = false
isUpdateInstalling.value = false
}
}
export async function downloadLatestRelease(): Promise<boolean> {
if (!latestLauncherRelease.value) {
return false
}
if (!currentOS.value) {
currentOS.value = (await getOS()).toLowerCase()
}
const installer = getInstaller(resolveOperationalSystemExtension(), latestLauncherRelease.value.assets)
if (isDeveloper) {
console.debug(installer)
}
if (!installer) {
isUpdateInstalling.value = false
return false
}
try {
isUpdateInstalling.value = true
return await initUpdateLauncher(
installer.browser_download_url,
installer.name,
currentOS.value,
true,
)
} finally {
isUpdateInstalling.value = false
}
}
function getInstaller(
osExtensions: string[],
builds: LauncherReleaseAsset[],
): LauncherReleaseAsset | null {
for (const build of builds) {
if (blacklistBeginPrefixes.some((prefix) => build.name.startsWith(prefix))) {
continue
}
if (osExtensions.some((extension) => build.name.endsWith(extension))) {
if (isDeveloper) {
console.debug(build.name, build.browser_download_url)
}
return build
}
}
return null
}
function resolveOperationalSystemExtension(): string[] {
if (currentOS.value === 'macos') {
return osExtensions["macos"]
}
if (currentOS.value === 'linux') {
return osExtensions["linux"]
}
return osExtensions["windows"]
}
function normalizeVersion(version: string): string {
return version.trim().replace(/^v/i, '')
}
-98
View File
@@ -1,98 +0,0 @@
import { getVersion } from '@tauri-apps/api/app'
import { ref } from 'vue'
import { getOS, initUpdateLauncher } from '@/helpers/utils.js'
export const allowState = ref(false)
export const installState = ref(false)
export const updateState = ref(false)
const currentOS = ref('')
const api = `https://git.astralium.su/api/v1/repos/didirus/AstralRinth/releases/latest`
const systems = ['macos', 'windows', 'linux']
const macosExtensions = ['.dmg', '.pkg', '.app']
const windowsExtensions = ['.exe', '.msi']
const blacklistBeginPrefixes = [
`dev`,
`nightly`,
`dirty`,
`dirty-dev`,
`dirty-nightly`,
`dirty_dev`,
`dirty_nightly`,
] // This is blacklisted builds for download. For example, file.startsWith('dev') is not allowed.
export async function getRemote(isDownloadState) {
var releaseTag = null;
var releaseTitle = null;
var result = false;
currentOS.value = await getOS();
try {
const response = await fetch(api);
if (!response.ok) {
throw new Error(response.status);
}
const remoteData = await response.json();
releaseTag = document.getElementById('releaseTag');
releaseTitle = document.getElementById('releaseTitle');
if (releaseTag && releaseTitle) {
releaseTag.textContent = remoteData.tag_name;
releaseTitle.textContent = remoteData.name;
}
if (systems.includes(currentOS.value.toLowerCase())) {
const localVersion = await getVersion();
const isUpdateAvailable = !remoteData.tag_name.includes(localVersion);
updateState.value = isUpdateAvailable;
allowState.value = isUpdateAvailable;
} else {
updateState.value = false;
allowState.value = false;
}
if (isDownloadState) {
try {
installState.value = true;
const builds = remoteData.assets;
const fileName = getInstaller(getExtension(), builds);
result = fileName ? await initUpdateLauncher(fileName[1], fileName[0], currentOS.value, true) : false;
installState.value = false;
} catch (err) {
installState.value = false;
}
}
console.log('Update available state is', updateState.value);
console.log('Remote version is', remoteData.tag_name);
console.log('Remote title is', remoteData.name);
console.log('Local version is', await getVersion());
console.log('Operating System is', currentOS.value);
return result;
} catch (error) {
console.error("Failed to fetch remote releases:", error);
if (!releaseTag) {
updateState.value = false;
allowState.value = false;
installState.value = false;
}
}
}
function getInstaller(osExtension, builds) {
console.log(osExtension, builds)
for (const build of builds) {
if (blacklistBeginPrefixes.some(prefix => build.name.startsWith(prefix))) {
continue;
}
if (osExtension.some(ext => build.name.endsWith(ext))) {
console.log(build.name, build.browser_download_url);
return [build.name, build.browser_download_url];
}
}
return null;
}
function getExtension() {
return systems.find(osName => osName === currentOS.value.toLowerCase())?.endsWith('macos')
? macosExtensions
: windowsExtensions;
}
@@ -119,6 +119,87 @@
"app.auth-servers.unreachable.header": {
"message": "Cannot reach authentication servers"
},
"astralrinth.app.launcher-update.available.action": {
"message": "View update"
},
"astralrinth.app.launcher-update.available.text": {
"message": "New version of AstralRinth is available for download."
},
"astralrinth.app.launcher-update.available.title": {
"message": "Launcher update available"
},
"astralrinth.app.settings.update-installing": {
"message": "Installing update..."
},
"astralrinth.app.settings.view-update-info": {
"message": "View update info"
},
"astralrinth.app.launcher-update-modal.error.close-action": {
"message": "Close"
},
"astralrinth.app.launcher-update-modal.error.description": {
"message": "AstralRinth could not download the update file from the server."
},
"astralrinth.app.launcher-update-modal.error.header": {
"message": "Could not download the update"
},
"astralrinth.app.launcher-update-modal.error.help-link": {
"message": "AstralRinth repository releases"
},
"astralrinth.app.launcher-update-modal.error.help-suffix": {
"message": "if a newer release is available there."
},
"astralrinth.app.launcher-update-modal.error.help-text": {
"message": "You can try downloading it manually from"
},
"astralrinth.app.launcher-update-modal.error.local-version": {
"message": "Local AstralRinth:"
},
"astralrinth.app.launcher-update-modal.error.title": {
"message": "Download failed"
},
"astralrinth.app.launcher-update-modal.update.cancel-action": {
"message": "Cancel"
},
"astralrinth.app.launcher-update-modal.update.description": {
"message": "You are using an older version. We recommend updating now for the latest fixes and improvements."
},
"astralrinth.app.launcher-update-modal.update.download-action": {
"message": "Download update and close"
},
"astralrinth.app.launcher-update-modal.update.header": {
"message": "AstralRinth launcher update"
},
"astralrinth.app.launcher-update-modal.update.installed-version": {
"message": "💾 Installed & Running version:"
},
"astralrinth.app.launcher-update-modal.update.latest-release-tag": {
"message": "☁️ Latest release tag:"
},
"astralrinth.app.launcher-update-modal.update.latest-release-title": {
"message": "☁️ Latest release title:"
},
"astralrinth.app.launcher-update-modal.update.notice-lead": {
"message": "Save your work, close all running launcher instances, and back up your launcher data before installing the update."
},
"astralrinth.app.launcher-update-modal.update.notice-macos": {
"message": "On macOS, important data may be stored in"
},
"astralrinth.app.launcher-update-modal.update.notice-outro": {
"message": "To avoid data loss, keep a backup copy in a safe place before continuing."
},
"astralrinth.app.launcher-update-modal.update.notice-windows": {
"message": "On Windows, important data may be stored in"
},
"astralrinth.app.launcher-update-modal.update.notice-title": {
"message": "⚠️ Before you continue"
},
"astralrinth.app.launcher-update-modal.update.repository-link": {
"message": "Open the project repository"
},
"astralrinth.app.launcher-update-modal.update.title": {
"message": "A new version of the AstralRinth launcher is available."
},
"astralrinth.app.minecraft-account.add-elyby-account": {
"message": "Add Ely.by account"
},
@@ -110,6 +110,87 @@
"app.auth-servers.unreachable.header": {
"message": "Нет связи с серверами аутентификации"
},
"astralrinth.app.launcher-update.available.action": {
"message": "Посмотреть обновление"
},
"astralrinth.app.launcher-update.available.text": {
"message": "Новая версия AstralRinth уже доступна для загрузки."
},
"astralrinth.app.launcher-update.available.title": {
"message": "Доступно обновление лаунчера"
},
"astralrinth.app.settings.update-installing": {
"message": "Установка обновления..."
},
"astralrinth.app.settings.view-update-info": {
"message": "Посмотреть информацию об обновлении"
},
"astralrinth.app.launcher-update-modal.error.close-action": {
"message": "Закрыть"
},
"astralrinth.app.launcher-update-modal.error.description": {
"message": "AstralRinth не удалось скачать файл обновления с сервера."
},
"astralrinth.app.launcher-update-modal.error.header": {
"message": "Не удалось скачать обновление"
},
"astralrinth.app.launcher-update-modal.error.help-link": {
"message": "релизы репозитория AstralRinth"
},
"astralrinth.app.launcher-update-modal.error.help-suffix": {
"message": "если там доступен более новый релиз."
},
"astralrinth.app.launcher-update-modal.error.help-text": {
"message": "Вы можете скачать его вручную из"
},
"astralrinth.app.launcher-update-modal.error.local-version": {
"message": "Локальная версия AstralRinth:"
},
"astralrinth.app.launcher-update-modal.error.title": {
"message": "Не удалось скачать файл"
},
"astralrinth.app.launcher-update-modal.update.cancel-action": {
"message": "Отмена"
},
"astralrinth.app.launcher-update-modal.update.description": {
"message": "Вы используете более старую версию. Рекомендуем обновиться сейчас, чтобы получить последние исправления и улучшения."
},
"astralrinth.app.launcher-update-modal.update.download-action": {
"message": "Скачать обновление и закрыть"
},
"astralrinth.app.launcher-update-modal.update.header": {
"message": "Обновление лаунчера AstralRinth"
},
"astralrinth.app.launcher-update-modal.update.installed-version": {
"message": "💾 Установленная и запущенная версия:"
},
"astralrinth.app.launcher-update-modal.update.latest-release-tag": {
"message": "☁️ Тег последнего релиза:"
},
"astralrinth.app.launcher-update-modal.update.latest-release-title": {
"message": "☁️ Название последнего релиза:"
},
"astralrinth.app.launcher-update-modal.update.notice-lead": {
"message": "Перед установкой обновления сохраните работу, закройте все запущенные экземпляры лаунчера и сделайте резервную копию его данных."
},
"astralrinth.app.launcher-update-modal.update.notice-macos": {
"message": "На macOS важные данные могут находиться в"
},
"astralrinth.app.launcher-update-modal.update.notice-outro": {
"message": "Чтобы избежать потери данных, сохраните резервную копию в безопасном месте перед продолжением."
},
"astralrinth.app.launcher-update-modal.update.notice-windows": {
"message": "На Windows важные данные могут находиться в"
},
"astralrinth.app.launcher-update-modal.update.notice-title": {
"message": "⚠️ Перед продолжением"
},
"astralrinth.app.launcher-update-modal.update.repository-link": {
"message": "Открыть репозиторий проекта"
},
"astralrinth.app.launcher-update-modal.update.title": {
"message": "Доступна новая версия лаунчера AstralRinth."
},
"astralrinth.app.minecraft-account.add-elyby-account": {
"message": "Добавить Ely.by аккаунт"
},
+1 -1
View File
@@ -101,7 +101,7 @@ export default defineConfig({
},
// to make use of `TAURI_ENV_DEBUG` and other env variables
// https://v2.tauri.app/reference/environment-variables/#tauri-cli-hook-commands
envPrefix: ['VITE_', 'TAURI_', 'MODRINTH_'],
envPrefix: ['VITE_', 'TAURI_', 'MODRINTH_', 'GIT_ASTRALIUM_'],
build: {
rolldownOptions: {
onwarn(warning, defaultHandler) {
+3 -1
View File
@@ -5,8 +5,10 @@ MODRINTH_API_URL=https://api.modrinth.com/v2/
MODRINTH_API_URL_V3=https://api.modrinth.com/v3/
MODRINTH_SOCKET_URL=wss://api.modrinth.com/
MODRINTH_LAUNCHER_META_URL=https://launcher-meta.modrinth.com/
GIT_ASTRALIUM_URL=https://git.astralium.su/
GIT_ASTRALIUM_API_URL=https://git.astralium.su/api/v1/
# SQLite database file used by sqlx for type checking. Uncomment this to a valid path
# in your system and run `cargo sqlx database setup` to generate an empty database that
# can be used for developing the app DB schema
#DATABASE_URL=sqlite:///tmp/Modrinth/code/packages/app-lib/.sqlx/generated/state.db
#DATABASE_URL=sqlite:///tmp/AstralRinth/code/packages/app-lib/.sqlx/generated/state.db
@@ -24,3 +24,10 @@
0 0 2px rgba(16, 250, 229, 0.4),
0 0 4px rgba(16, 250, 229, 0.25);
}
code {
background: linear-gradient(90deg, #005eff, #00cfff);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
}