diff --git a/core/amily2-updater.js b/core/amily2-updater.js new file mode 100644 index 0000000..acad5f6 --- /dev/null +++ b/core/amily2-updater.js @@ -0,0 +1,301 @@ +const GIT_REPO_OWNER = 'Wx-2025'; +const GIT_REPO_NAME = 'ST-Amily2-Chat-Optimisation'; +const EXTENSION_NAME = 'ST-Amily2-Chat-Optimisation'; +const EXTENSION_FOLDER_PATH = `scripts/extensions/third-party/${EXTENSION_NAME}`; + +class Amily2Updater { + constructor() { + this.currentVersion = '0.0.0'; + this.latestVersion = '0.0.0'; + this.changelogContent = ''; + this.isChecking = false; + } + + async fetchRawFileFromGitHub(filePath) { + const url = `https://raw.githubusercontent.com/${GIT_REPO_OWNER}/${GIT_REPO_NAME}/main/${filePath}`; + const response = await fetch(url, { cache: 'no-cache' }); + if (!response.ok) { + throw new Error(`获取文件失败 ${filePath}: ${response.statusText}`); + } + return response.text(); + } + + parseVersion(content) { + try { + return JSON.parse(content).version || '0.0.0'; + } catch (error) { + console.error(`[Amily2Updater] 版本解析失败:`, error); + return '0.0.0'; + } + } + + compareVersions(v1, v2) { + const parts1 = v1.split('.').map(Number); + const parts2 = v2.split('.').map(Number); + for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { + const p1 = parts1[i] || 0; + const p2 = parts2[i] || 0; + if (p1 > p2) return 1; + if (p1 < p2) return -1; + } + return 0; + } + + showToast(type, message) { + + if (typeof toastr !== 'undefined') { + toastr[type](message); + } else { + console.log(`[${type.toUpperCase()}] ${message}`); + } + } + + async performUpdate() { + const { getRequestHeaders } = SillyTavern.getContext().common; + const { extension_types } = SillyTavern.getContext().extensions; + + this.showToast('info', '正在更新 Amily2号优化助手...'); + + try { + const response = await fetch('/api/extensions/update', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + extensionName: EXTENSION_NAME, + global: extension_types[EXTENSION_NAME] === 'global', + }), + }); + + if (!response.ok) { + throw new Error(await response.text()); + } + + this.showToast('success', '更新成功!将在3秒后刷新页面应用更改。'); + setTimeout(() => location.reload(), 3000); + } catch (error) { + this.showToast('error', `更新失败: ${error.message}`); + throw error; + } + } + + async showUpdateLogDialog() { + const { POPUP_TYPE, callGenericPopup } = SillyTavern; + + try { + const updateInfoText = await this.fetchRawFileFromGitHub('amily2_update_info.json'); + const updateInfo = JSON.parse(updateInfoText); + + let logContent = `📋 Amily2号优化助手 - 更新日志\n\n`; + logContent += `当前版本: ${this.currentVersion}\n`; + logContent += `最新版本: ${this.latestVersion}\n\n`; + + if (updateInfo.changelog) { + logContent += updateInfo.changelog; + } else { + logContent += "暂无更新日志内容。"; + } + + const hasUpdate = this.compareVersions(this.latestVersion, this.currentVersion) > 0; + + if (hasUpdate) { + const confirmed = await callGenericPopup( + logContent, + POPUP_TYPE.CONFIRM, + { + okButton: '立即更新', + cancelButton: '稍后', + wide: true, + large: true, + } + ); + + if (confirmed) { + await this.performUpdate(); + } + } else { + await callGenericPopup( + logContent, + POPUP_TYPE.TEXT, + { + okButton: '知道了', + wide: true, + large: true, + } + ); + } + + } catch (error) { + console.error('[Amily2Updater] 获取更新日志失败:', error); + const basicContent = `📋 Amily2号优化助手 - 版本信息\n\n`; + basicContent += `当前版本: ${this.currentVersion}\n`; + basicContent += `最新版本: ${this.latestVersion}\n\n`; + basicContent += `无法获取详细更新日志: ${error.message}`; + + await callGenericPopup( + basicContent, + POPUP_TYPE.TEXT, + { + okButton: '知道了', + wide: true, + large: true, + } + ); + } + } + + async showUpdateConfirmDialog() { + const { POPUP_TYPE, callGenericPopup } = SillyTavern; + + try { + this.changelogContent = await this.fetchRawFileFromGitHub('CHANGELOG.md'); + } catch (error) { + this.changelogContent = `发现新版本 ${this.latestVersion}!\n\n您想现在更新吗?`; + } + + const confirmed = await callGenericPopup( + this.changelogContent, + POPUP_TYPE.CONFIRM, + { + okButton: '立即更新', + cancelButton: '稍后', + wide: true, + large: true, + } + ); + + if (confirmed) { + await this.performUpdate(); + } + } + + updateUI() { + this.updateVersionDisplay(); + + const $updateButton = $('#amily2_update_button'); + const $updateButtonNew = $('#amily2_update_button_new'); + const $updateIndicator = $('#amily2_update_indicator'); + + if (this.compareVersions(this.latestVersion, this.currentVersion) > 0) { + $updateIndicator.show(); + $updateButton.attr('title', `发现新版本 ${this.latestVersion}!点击查看详情`); + $updateButtonNew + .show() + .html(` 新版 ${this.latestVersion}`) + .off('click') + .on('click', () => this.showUpdateConfirmDialog()); + } else { + $updateIndicator.hide(); + $updateButton.attr('title', `当前版本 ${this.currentVersion}(已是最新)`); + $updateButtonNew.hide(); + } + } + + updateVersionDisplay() { + + const $currentVersion = $('#amily2_current_version'); + if ($currentVersion.length) { + $currentVersion.text(this.currentVersion || '未知'); + } + + const $latestVersion = $('#amily2_latest_version'); + const $latestContainer = $latestVersion.closest('.version-latest'); + + if ($latestVersion.length) { + $latestVersion.text(this.latestVersion || '获取失败'); + + if (this.compareVersions(this.latestVersion, this.currentVersion) > 0) { + $latestContainer.addClass('has-update'); + } else { + $latestContainer.removeClass('has-update'); + } + } + } + + async checkForUpdates(isManual = false) { + if (this.isChecking) return; + + this.isChecking = true; + const $updateButton = $('#amily2_update_button'); + const $latestVersion = $('#amily2_latest_version'); + + if ($latestVersion.length) { + $latestVersion.text('检查中...'); + } + + if (isManual) { + $updateButton.html('').prop('disabled', true); + } + + try { + const localManifestText = await ( + await fetch(`/${EXTENSION_FOLDER_PATH}/manifest.json?t=${Date.now()}`) + ).text(); + this.currentVersion = this.parseVersion(localManifestText); + + const $currentVersion = $('#amily2_current_version'); + if ($currentVersion.length) { + $currentVersion.text(this.currentVersion || '未知'); + } + + const remoteManifestText = await this.fetchRawFileFromGitHub('manifest.json'); + this.latestVersion = this.parseVersion(remoteManifestText); + + this.updateUI(); + + console.log(`[Amily2Updater] 版本检查完成 - 当前: ${this.currentVersion}, 最新: ${this.latestVersion}`); + + if (isManual) { + if (this.compareVersions(this.latestVersion, this.currentVersion) > 0) { + this.showToast('success', `发现新版本 ${this.latestVersion}!点击"更新"按钮进行升级。`); + } else { + this.showToast('info', '您当前已是最新版本。'); + } + } + } catch (error) { + console.error('[Amily2Updater] 检查更新失败:', error); + + if ($latestVersion.length) { + $latestVersion.text('获取失败'); + } + + if (isManual) { + this.showToast('error', `检查更新失败: ${error.message}`); + } + } finally { + this.isChecking = false; + if (isManual) { + $updateButton.html('').prop('disabled', false); + } + } + } + + initialize() { + const $updateButton = $('#amily2_update_button'); + const $updateButtonNew = $('#amily2_update_button_new'); + $updateButton.off('click').on('click', () => { + this.showUpdateLogDialog(); + }); + + this.checkForUpdates(false); + + setInterval(() => { + this.checkForUpdates(false); + }, 30 * 60 * 1000); + } + + async manualCheck() { + await this.checkForUpdates(true); + } + + getVersionInfo() { + return { + current: this.currentVersion, + latest: this.latestVersion, + hasUpdate: this.compareVersions(this.latestVersion, this.currentVersion) > 0 + }; + } +} + +window.amily2Updater = new Amily2Updater(); + +export default window.amily2Updater;