@@ -787,143 +787,120 @@ <h3 class="settings-title">
787787 }
788788}
789789
790- /* ========== 自动更新功能 ========== */
791- let updateAvailable = null ;
790+ /* ========== 自动更新功能(GitHub API) ========== */
791+ const APP_VERSION = '1.0.0' ;
792+ const GITHUB_REPO = 'Yar1991-Translation/LoArchive' ;
793+ let latestRelease = null ;
792794
793795async function checkForUpdates ( silent = false ) {
794- const isTauri = window . __TAURI__ !== undefined || window . __TAURI_INTERNALS__ !== undefined ;
795- if ( ! isTauri ) {
796- if ( ! silent ) showNotification ( '浏览器模式不支持自动更新' , 'info' ) ;
797- return ;
798- }
799-
800796 try {
801797 if ( ! silent ) showNotification ( '正在检查更新...' , 'info' ) ;
802798
803- let updater ;
804- if ( window . __TAURI__ && window . __TAURI__ . updater ) {
805- updater = window . __TAURI__ . updater ;
806- } else {
807- updater = await import ( '@tauri-apps/plugin-updater' ) ;
799+ const res = await fetch ( `https://api.github.com/repos/${ GITHUB_REPO } /releases/latest` ) ;
800+ if ( ! res . ok ) {
801+ if ( res . status === 404 ) {
802+ if ( ! silent ) showNotification ( '暂无发布版本' , 'info' ) ;
803+ return ;
804+ }
805+ throw new Error ( 'GitHub API 请求失败' ) ;
808806 }
809807
810- const update = await updater . check ( ) ;
808+ const release = await res . json ( ) ;
809+ latestRelease = release ;
810+ const latestVersion = release . tag_name . replace ( / ^ v / , '' ) ;
811811
812- if ( update && update . available ) {
813- updateAvailable = update ;
814- showUpdateDialog ( update ) ;
812+ if ( isNewerVersion ( latestVersion , APP_VERSION ) ) {
813+ showUpdateDialog ( release , latestVersion ) ;
815814 } else {
816- if ( ! silent ) showNotification ( ' 当前已是最新版本 ✓' , 'success' ) ;
815+ if ( ! silent ) showNotification ( ` 当前已是最新版本 v ${ APP_VERSION } ✓` , 'success' ) ;
817816 }
818817 } catch ( e ) {
819818 console . error ( '检查更新失败:' , e ) ;
820- if ( ! silent ) showNotification ( '检查更新失败: ' + e . message , 'error' ) ;
819+ if ( ! silent ) showNotification ( '检查更新失败,请检查网络连接' , 'error' ) ;
820+ }
821+ }
822+
823+ function isNewerVersion ( latest , current ) {
824+ const l = latest . split ( '.' ) . map ( Number ) ;
825+ const c = current . split ( '.' ) . map ( Number ) ;
826+ for ( let i = 0 ; i < Math . max ( l . length , c . length ) ; i ++ ) {
827+ if ( ( l [ i ] || 0 ) > ( c [ i ] || 0 ) ) return true ;
828+ if ( ( l [ i ] || 0 ) < ( c [ i ] || 0 ) ) return false ;
821829 }
830+ return false ;
822831}
823832
824- function showUpdateDialog ( update ) {
825- // 创建更新弹窗
833+ function showUpdateDialog ( release , newVersion ) {
834+ const existing = document . getElementById ( 'update-overlay' ) ;
835+ if ( existing ) existing . remove ( ) ;
836+
826837 const overlay = document . createElement ( 'div' ) ;
827838 overlay . id = 'update-overlay' ;
828- overlay . style . cssText = `
829- position: fixed; inset: 0; background: rgba(0,0,0,0.6);
830- display: flex; align-items: center; justify-content: center ;
831- z-index: 20000; backdrop-filter: blur(4px );
832- ` ;
839+ overlay . style . cssText = `position:fixed;inset:0;background:rgba(0,0,0,0.6);display:flex;align-items:center;justify-content:center;z-index:20000;backdrop-filter:blur(4px);` ;
840+
841+ const msiAsset = release . assets . find ( a => a . name . endsWith ( '.msi' ) ) ;
842+ const exeAsset = release . assets . find ( a => a . name . endsWith ( '-setup.exe' ) ) ;
843+ const downloadUrl = msiAsset ?. browser_download_url || exeAsset ?. browser_download_url || release . html_url ;
833844
834845 const dialog = document . createElement ( 'div' ) ;
835- dialog . style . cssText = `
836- background: var(--bg-card); border-radius: 16px; padding: 32px;
837- max-width: 450px; width: 90%; box-shadow: 0 20px 60px rgba(0,0,0,0.3);
838- animation: slideUp 0.3s ease;
839- ` ;
846+ dialog . style . cssText = `background:var(--bg-card);border-radius:16px;padding:32px;max-width:500px;width:90%;box-shadow:0 20px 60px rgba(0,0,0,0.3);animation:slideUp 0.3s ease;` ;
847+
848+ const bodyHtml = release . body ? release . body
849+ . replace ( / ^ # # # ( .+ ) $ / gm, '<strong style="display:block;margin:8px 0 4px;">$1</strong>' )
850+ . replace ( / ^ # # ( .+ ) $ / gm, '<strong style="display:block;margin:12px 0 6px;">$1</strong>' )
851+ . replace ( / ^ - ( .+ ) $ / gm, '• $1<br>' )
852+ . replace ( / \* \* ( .+ ?) \* \* / g, '<strong>$1</strong>' )
853+ . replace ( / \n \n / g, '<br>' ) : '' ;
840854
841855 dialog . innerHTML = `
842856 <div style="text-align:center;margin-bottom:24px;">
843857 <div style="font-size:48px;margin-bottom:16px;">🎉</div>
844- <h2 style="margin:0 0 8px;font-size:20px;color:var(--text-primary);">发现新版本</h2>
845- <p style="margin:0;color:var(--text-muted);font-size:14px;">
846- ${ update . currentVersion || '当前版本' } → <strong style="color:var(--primary);">${ update . version || '新版本' } </strong>
847- </p>
858+ <h2 style="margin:0 0 8px;font-size:20px;color:var(--text-primary);">发现新版本!</h2>
859+ <p style="margin:0;color:var(--text-muted);font-size:14px;">v${ APP_VERSION } → <strong style="color:var(--primary);">v${ newVersion } </strong></p>
848860 </div>
849- ${ update . body ? `
850- <div style="background:var(--bg-secondary);border-radius:8px;padding:16px;margin-bottom:24px;max-height:200px;overflow-y:auto;">
851- <h4 style="margin:0 0 8px;font-size:14px;color:var(--text-primary);">📝 更新内容</h4>
852- <div style="font-size:13px;color:var(--text-secondary);line-height:1.6;white-space:pre-wrap;">${ update . body } </div>
861+ ${ bodyHtml ? `<div style="background:var(--bg-secondary);border-radius:8px;padding:16px;margin-bottom:24px;max-height:200px;overflow-y:auto;">
862+ <h4 style="margin:0 0 12px;font-size:14px;color:var(--text-primary);">📝 更新内容</h4>
863+ <div style="font-size:13px;color:var(--text-secondary);line-height:1.8;">${ bodyHtml } </div>
853864 </div>` : '' }
854- <div style="display:flex;gap:12px;">
855- <button id="update-later" style="
856- flex:1;padding:12px;border:1px solid var(--border);border-radius:8px;
857- background:transparent;color:var(--text-secondary);cursor:pointer;font-size:14px;
858- ">稍后更新</button>
859- <button id="update-now" style="
860- flex:1;padding:12px;border:none;border-radius:8px;
861- background:var(--primary);color:white;cursor:pointer;font-size:14px;font-weight:600;
862- ">立即更新</button>
863- </div>
864- ` ;
865+ <div style="display:flex;gap:12px;flex-wrap:wrap;">
866+ <button id="update-later" style="flex:1;min-width:100px;padding:12px;border:1px solid var(--border);border-radius:8px;background:transparent;color:var(--text-secondary);cursor:pointer;font-size:14px;">稍后提醒</button>
867+ <button id="update-github" style="flex:1;min-width:100px;padding:12px;border:none;border-radius:8px;background:var(--bg-secondary);color:var(--text-primary);cursor:pointer;font-size:14px;">📋 GitHub</button>
868+ <button id="update-download" style="flex:1;min-width:100px;padding:12px;border:none;border-radius:8px;background:var(--primary);color:white;cursor:pointer;font-size:14px;font-weight:600;">⬇️ 下载</button>
869+ </div>` ;
865870
866871 overlay . appendChild ( dialog ) ;
867872 document . body . appendChild ( overlay ) ;
868873
869- // 添加动画样式
870- const style = document . createElement ( 'style' ) ;
871- style . textContent = `@keyframes slideUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}` ;
872- document . head . appendChild ( style ) ;
874+ if ( ! document . getElementById ( 'update-anim-style' ) ) {
875+ const style = document . createElement ( 'style' ) ;
876+ style . id = 'update-anim-style' ;
877+ style . textContent = `@keyframes slideUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}` ;
878+ document . head . appendChild ( style ) ;
879+ }
873880
874- // 绑定事件
875881 document . getElementById ( 'update-later' ) . onclick = ( ) => {
876882 overlay . remove ( ) ;
877- style . remove ( ) ;
883+ localStorage . setItem ( 'loarchive_update_skip' , Date . now ( ) . toString ( ) ) ;
878884 } ;
879-
880- document . getElementById ( 'update-now' ) . onclick = async ( ) => {
881- const btn = document . getElementById ( 'update-now' ) ;
882- btn . textContent = '下载中...' ;
883- btn . disabled = true ;
884-
885- try {
886- await installUpdate ( ) ;
887- } catch ( e ) {
888- showNotification ( '更新失败: ' + e . message , 'error' ) ;
889- overlay . remove ( ) ;
890- style . remove ( ) ;
891- }
885+ document . getElementById ( 'update-github' ) . onclick = ( ) => window . open ( release . html_url , '_blank' ) ;
886+ document . getElementById ( 'update-download' ) . onclick = ( ) => {
887+ window . open ( downloadUrl , '_blank' ) ;
888+ showNotification ( '下载已开始,安装后请重启应用' , 'success' ) ;
889+ overlay . remove ( ) ;
892890 } ;
891+ overlay . onclick = ( e ) => { if ( e . target === overlay ) overlay . remove ( ) ; } ;
893892}
894893
895- async function installUpdate ( ) {
896- if ( ! updateAvailable ) return ;
897-
898- try {
899- showNotification ( '正在下载更新...' , 'info' ) ;
900-
901- // 下载并安装更新
902- await updateAvailable . downloadAndInstall ( ) ;
903-
904- showNotification ( '更新完成,正在重启应用...' , 'success' ) ;
905-
906- // 重启应用
907- let process ;
908- if ( window . __TAURI__ && window . __TAURI__ . process ) {
909- process = window . __TAURI__ . process ;
910- } else {
911- process = await import ( '@tauri-apps/plugin-process' ) ;
912- }
913- await process . relaunch ( ) ;
914- } catch ( e ) {
915- console . error ( '安装更新失败:' , e ) ;
916- throw e ;
917- }
918- }
919-
920- // 应用启动时静默检查更新
894+ // 应用启动时检查更新
921895setTimeout ( ( ) => {
922- checkForUpdates ( true ) ;
896+ const skipTime = localStorage . getItem ( 'loarchive_update_skip' ) ;
897+ if ( ! skipTime || ( Date . now ( ) - parseInt ( skipTime ) ) > 86400000 ) {
898+ checkForUpdates ( true ) ;
899+ }
923900} , 3000 ) ;
924901
925- // 暴露给全局使用
926902window . checkForUpdates = checkForUpdates ;
903+ window . APP_VERSION = APP_VERSION ;
927904 </ script >
928905</ body >
929906</ html >
0 commit comments