lookatstudy-mobile 0.34.0 → 0.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/install-termux.sh +169 -25
- package/package.json +1 -1
- package/server.cjs +1796 -5809
- package/web/assets/{CanvasStage-CpZeMgwT.js → CanvasStage-F04y4zgY.js} +1 -1
- package/web/assets/{CommandPalette-BlRArZBr.js → CommandPalette-8EbP9nD8.js} +1 -1
- package/web/assets/{CompanionBotLab-Ch7CGv7f.js → CompanionBotLab-CpDmbEBy.js} +1 -1
- package/web/assets/{CourseSearchPanel-C7KIDdON.js → CourseSearchPanel-DBMdIlcw.js} +1 -1
- package/web/assets/{ExamView-8XI8Nw1H.js → ExamView-D9Cgt1bf.js} +1 -1
- package/web/assets/{ReviewPanel-CTzPBfgZ.js → ReviewPanel-DH3dhVt3.js} +1 -1
- package/web/assets/SettingsView-DOhBgfmD.js +20 -0
- package/web/assets/{VoicePanel-BhC8Hu-3.js → VoicePanel-CAud4bsL.js} +1 -1
- package/web/assets/{abnfDiagram-VCTEODGH-CTwnb_LX.js → abnfDiagram-VCTEODGH-CpzdURfK.js} +1 -1
- package/web/assets/{abnfDiagram-VCTEODGH-ODA7YWAP-C1dBUZ7b.js → abnfDiagram-VCTEODGH-ODA7YWAP-BwflFQl0.js} +1 -1
- package/web/assets/api-web-Dwfo27My.js +1 -0
- package/web/assets/{architectureDiagram-5GKGNRK7-C4PU3XN7-ChothZwf.js → architectureDiagram-5GKGNRK7-C4PU3XN7-D2fQalh8.js} +1 -1
- package/web/assets/{architectureDiagram-5GKGNRK7-DOTrgigK.js → architectureDiagram-5GKGNRK7-D9E1rxxz.js} +1 -1
- package/web/assets/{arrow-right-BQgpe45F.js → arrow-right-znl0Me0H.js} +1 -1
- package/web/assets/{blockDiagram-I7D4REHJ-DyYXGdPV.js → blockDiagram-I7D4REHJ-r15Lh1bi.js} +1 -1
- package/web/assets/{blockDiagram-NRAW4CY4-UMJ6PMQQ-DOFYspw-.js → blockDiagram-NRAW4CY4-UMJ6PMQQ-Q16ExT0e.js} +1 -1
- package/web/assets/{c4Diagram-7LVT6UL2-0AsslgW1.js → c4Diagram-7LVT6UL2-ODlC-C-l.js} +1 -1
- package/web/assets/{c4Diagram-UCG6FXSJ-75X3U2P3-B96ZJV69.js → c4Diagram-UCG6FXSJ-75X3U2P3-j7xMbgDN.js} +1 -1
- package/web/assets/channel-BhH3AJCa.js +1 -0
- package/web/assets/{chunk-2Q5K7J3B-YcEvx37Y.js → chunk-2Q5K7J3B-DIKZDPWd.js} +1 -1
- package/web/assets/{chunk-5VM5RSS4-BFI2AG6f.js → chunk-5VM5RSS4-D_d1aMiX.js} +1 -1
- package/web/assets/{chunk-7XDTSPCN-BjlU6ynD.js → chunk-7XDTSPCN-CDCDiD3k.js} +1 -1
- package/web/assets/{chunk-CTNIYPP6-LyWaVAeX.js → chunk-CTNIYPP6-BHWWkYo7.js} +1 -1
- package/web/assets/{chunk-CXNFBKHE-9OIQHuxw.js → chunk-CXNFBKHE-Ddv1ywyJ.js} +1 -1
- package/web/assets/{chunk-F27PBJKO-C1TvQsHt.js → chunk-F27PBJKO-Csh41uLz.js} +1 -1
- package/web/assets/{chunk-IMKFNOWR-B7G8Z_Ng.js → chunk-IMKFNOWR-CPE5ucO6.js} +1 -1
- package/web/assets/{chunk-ISA7TJRJ-BL4KA7xt.js → chunk-ISA7TJRJ-7TzBMXNZ.js} +1 -1
- package/web/assets/{chunk-JWPE2WC7-CH4FMDWX.js → chunk-JWPE2WC7-ZaRjjvWe.js} +1 -1
- package/web/assets/{chunk-LV3HUYFY-Ch9MhjBs.js → chunk-LV3HUYFY-CehBNNki.js} +1 -1
- package/web/assets/{chunk-M3IUQBOH-BcqMygxc.js → chunk-M3IUQBOH-BFEOlC3u.js} +1 -1
- package/web/assets/{chunk-NDIOYS4C-DE45Abjh.js → chunk-NDIOYS4C-EGU3EjM6.js} +1 -1
- package/web/assets/{chunk-POPQ4Y6H-D-SBQItu.js → chunk-POPQ4Y6H-6tlv39Ki.js} +1 -1
- package/web/assets/{chunk-RE4WF27V-C1subsXL.js → chunk-RE4WF27V-Bi2fqKq7.js} +1 -1
- package/web/assets/{chunk-SVP7TREG-cLlInCCA.js → chunk-SVP7TREG-B-ulnIuy.js} +1 -1
- package/web/assets/{chunk-TICWLB2K-DxNEFrwG.js → chunk-TICWLB2K-BjrX7t7Y.js} +1 -1
- package/web/assets/{chunk-VII2H2IX-ymoFJHrt.js → chunk-VII2H2IX-BMAB3iRM.js} +1 -1
- package/web/assets/{chunk-X5GNSKZ3-Cce97LK8.js → chunk-X5GNSKZ3-B7QFlx10.js} +1 -1
- package/web/assets/{chunk-XCWWM2C3-DDsEpbkx.js → chunk-XCWWM2C3-BjgcNQCf.js} +1 -1
- package/web/assets/{chunk-XXDRQBXY-BlitsaYT.js → chunk-XXDRQBXY-CKGs-9PK.js} +1 -1
- package/web/assets/classDiagram-DTDB5LWJ-LWRDKZ5K-B4iFPydy.js +1 -0
- package/web/assets/classDiagram-ZZMXUADV-CuaUIF7a.js +1 -0
- package/web/assets/classDiagram-v2-JRS7N3AN-2BZHGRP2-B4iFPydy.js +1 -0
- package/web/assets/classDiagram-v2-VYDZK3BY-CuaUIF7a.js +1 -0
- package/web/assets/{core-Cz8RF5Ss.js → core-BTS07XeK.js} +1 -1
- package/web/assets/{cose-bilkent-JH36ORCC-Z1v0LKQQ.js → cose-bilkent-JH36ORCC-Dz8-msXI.js} +1 -1
- package/web/assets/{cose-bilkent-JH36ORCC-OB24KH3T-CHMfylG8.js → cose-bilkent-JH36ORCC-OB24KH3T-AHcUGpPr.js} +1 -1
- package/web/assets/{cynefin-OW5HDTMX-B8B-PAKZ.js → cynefin-OW5HDTMX-CncUj8R6.js} +1 -1
- package/web/assets/{cynefin-OW5HDTMX-GVF3BKWE-B8BGNTw-.js → cynefin-OW5HDTMX-GVF3BKWE-DnbZYXxG.js} +1 -1
- package/web/assets/{cynefinDiagram-5FMLGOSQ-H3WIRU3N-BV3TRRUk.js → cynefinDiagram-5FMLGOSQ-H3WIRU3N-C0dZpAGS.js} +1 -1
- package/web/assets/{cynefinDiagram-5FMLGOSQ-Dx-FYIVc.js → cynefinDiagram-5FMLGOSQ-H9_ClqMv.js} +1 -1
- package/web/assets/{dagre-3AP2YEHR-DCERTXHT-US6ZPid6.js → dagre-3AP2YEHR-DCERTXHT-Dqjpb4H_.js} +1 -1
- package/web/assets/{dagre-GXQ25YYZ-DvgJpvrR.js → dagre-GXQ25YYZ-Bs6lG_oB.js} +1 -1
- package/web/assets/{diagram-S7CK7UJ4-IA_lpeJb.js → diagram-S7CK7UJ4-CoyM63cz.js} +1 -1
- package/web/assets/{diagram-S7CK7UJ4-MULGZGEL-9X64zpVt.js → diagram-S7CK7UJ4-MULGZGEL-Bk_UbBLt.js} +1 -1
- package/web/assets/{diagram-UQ7AKVKN-BI77k4Eg.js → diagram-UQ7AKVKN-Cbd8LIJZ.js} +1 -1
- package/web/assets/{diagram-UQ7AKVKN-YQBY353J-BSFLZLn0.js → diagram-UQ7AKVKN-YQBY353J-DvgMhn_1.js} +1 -1
- package/web/assets/{diagram-VSXAHHWV-qtk4pu7a.js → diagram-VSXAHHWV-BlOBRaa4.js} +1 -1
- package/web/assets/{diagram-VSXAHHWV-WLNH2ELY-BVJvpn3p.js → diagram-VSXAHHWV-WLNH2ELY-Bwvh2izi.js} +1 -1
- package/web/assets/{diagram-VX7I27RA-XW6YQV5G-c8XHmzOy.js → diagram-VX7I27RA-XW6YQV5G-DyII5dQK.js} +1 -1
- package/web/assets/{diagram-VX7I27RA-D1OUoA-L.js → diagram-VX7I27RA-XibYkEXv.js} +1 -1
- package/web/assets/{diagram-Z3DM3KII-A7_8IFdk.js → diagram-Z3DM3KII-Bzm2uV2N.js} +1 -1
- package/web/assets/{diagram-Z3DM3KII-HG7RF65D-Cw_b8aFx.js → diagram-Z3DM3KII-HG7RF65D-I0dD_VKh.js} +1 -1
- package/web/assets/{ebnfDiagram-PWID7BFC-s9w7t4t-.js → ebnfDiagram-PWID7BFC-BaCEN0aI.js} +1 -1
- package/web/assets/{ebnfDiagram-PWID7BFC-OKY4VHYD-DpM76Qo-.js → ebnfDiagram-PWID7BFC-OKY4VHYD-DBp9ntV_.js} +1 -1
- package/web/assets/{elk.bundled-B1HkkibK.js → elk.bundled-CE2zCVQp.js} +1 -1
- package/web/assets/{erDiagram-RLTQ6QDP-BqZVVONb.js → erDiagram-RLTQ6QDP-wXu0CF1e.js} +1 -1
- package/web/assets/{erDiagram-SSCWMZ5O-PIPKOIK7-mvBqIA0l.js → erDiagram-SSCWMZ5O-PIPKOIK7-DPE67Rb_.js} +1 -1
- package/web/assets/{flowDiagram-A5DVABFB-2Z4AVO5R-Y6pTj-b3.js → flowDiagram-A5DVABFB-2Z4AVO5R-5PgQxZH6.js} +1 -1
- package/web/assets/{flowDiagram-HODETNUW-Bd7fJP9N.js → flowDiagram-HODETNUW-eBCjgWhq.js} +1 -1
- package/web/assets/{ganttDiagram-EL5Y4UJY-Bu47S_cy.js → ganttDiagram-EL5Y4UJY-CLQ0R2N9.js} +1 -1
- package/web/assets/{ganttDiagram-EL5Y4UJY-JZNG7GOG-rP8k0IHr.js → ganttDiagram-EL5Y4UJY-JZNG7GOG-yvgn9AFs.js} +1 -1
- package/web/assets/{gitGraphDiagram-WWUBYQGX-6TDOHnoT.js → gitGraphDiagram-WWUBYQGX-Ch2LC_ZO.js} +1 -1
- package/web/assets/{gitGraphDiagram-WWUBYQGX-DMWMLL3G-B2RIK0rX.js → gitGraphDiagram-WWUBYQGX-DMWMLL3G-CdL6sKXD.js} +1 -1
- package/web/assets/{index-5Ng_lap_.js → index-CGVNDEoZ.js} +1 -1
- package/web/assets/{index-DqlC7JoQ.js → index-Cfos9l4N.js} +1 -1
- package/web/assets/{index-DqnX7_zV.js → index-D1-pMPvU.js} +4 -4
- package/web/assets/{index-DpPK19Iz.css → index-Q9eNSgJu.css} +1 -1
- package/web/assets/{infoDiagram-27XIBGKW-CNG9rO3x.js → infoDiagram-27XIBGKW-Dp9CZffC.js} +1 -1
- package/web/assets/{infoDiagram-RXCK75RN-HANS5KVC-BLQAuzZo.js → infoDiagram-RXCK75RN-HANS5KVC-CPk4LX77.js} +1 -1
- package/web/assets/{ishikawaDiagram-5VMMS53U-7GCIT7WU-cUZxo0qy.js → ishikawaDiagram-5VMMS53U-7GCIT7WU-CMGVPqEU.js} +1 -1
- package/web/assets/{ishikawaDiagram-5VMMS53U-O4xGKyXs.js → ishikawaDiagram-5VMMS53U-B-cMM-lu.js} +1 -1
- package/web/assets/{journeyDiagram-3NMN7TZE-CXvTN2XW.js → journeyDiagram-3NMN7TZE-jd0ulJL5.js} +1 -1
- package/web/assets/{journeyDiagram-EYS64GPL-OAPELBT7-DkfyTyBt.js → journeyDiagram-EYS64GPL-OAPELBT7-laqYJZSh.js} +1 -1
- package/web/assets/{kanban-definition-3QL26DDD-I7RKWQQY-CgdUNDmE.js → kanban-definition-3QL26DDD-I7RKWQQY-C2dlYmk5.js} +1 -1
- package/web/assets/{kanban-definition-UXKFOSKX-CXs9ROJB.js → kanban-definition-UXKFOSKX-C8FUqo2W.js} +1 -1
- package/web/assets/{katex-N6JRN4PM-BjAz2jJx.js → katex-N6JRN4PM-DpkGK9xr.js} +1 -1
- package/web/assets/{layout-Cp9w3JfL.js → layout-DAl5hPqz.js} +1 -1
- package/web/assets/{main-YTxb38yo.js → main-BgQ8DhpK.js} +108 -108
- package/web/assets/{mermaid-layout-elk.core-DUbLagu1.js → mermaid-layout-elk.core-DR1AiJQx.js} +2 -2
- package/web/assets/{mermaid.core-Czgmmu3m.js → mermaid.core-DGhTWg7e.js} +5 -5
- package/web/assets/{mindmap-definition-FBJOCRG2-KIYZG64Y-DTs3kC-2.js → mindmap-definition-FBJOCRG2-KIYZG64Y-CsijzG4P.js} +1 -1
- package/web/assets/{mindmap-definition-YA3MSWOX-8ZLAntKe.js → mindmap-definition-YA3MSWOX-0_EzROUF.js} +1 -1
- package/web/assets/{pegDiagram-XKGWAZYB-Ddy9tOBo.js → pegDiagram-XKGWAZYB-D0foGNNg.js} +1 -1
- package/web/assets/{pegDiagram-XKGWAZYB-OIP57N6J-CX1pDkyu.js → pegDiagram-XKGWAZYB-OIP57N6J-BGPwOePw.js} +1 -1
- package/web/assets/{pet-DCzJVVt6.js → pet-C5Roq2vO.js} +1 -1
- package/web/assets/{pieDiagram-E7YTZNPT-2UOTW327-CJbVQ7j0.js → pieDiagram-E7YTZNPT-2UOTW327-KJ0psy-0.js} +1 -1
- package/web/assets/{pieDiagram-E7YTZNPT-bhM8Af8W.js → pieDiagram-E7YTZNPT-DIjeGG-W.js} +1 -1
- package/web/assets/{quadrantDiagram-AXDQQJYC-BPNVp-tm.js → quadrantDiagram-AXDQQJYC-DUdT9pwG.js} +1 -1
- package/web/assets/{quadrantDiagram-AXDQQJYC-SN3ASJJK-JrUYqoH6.js → quadrantDiagram-AXDQQJYC-SN3ASJJK-B3eRvaAs.js} +1 -1
- package/web/assets/{railroadDiagram-O6MQD6OU-34742W6X-CNPl0cRd.js → railroadDiagram-O6MQD6OU-34742W6X-ckE1BJbz.js} +1 -1
- package/web/assets/{railroadDiagram-O6MQD6OU-Djl7WlNw.js → railroadDiagram-O6MQD6OU-CY8U1vkC.js} +1 -1
- package/web/assets/{render-O7CIS3YK-SgZRy1rl.js → render-O7CIS3YK-C5csyvRU.js} +7 -7
- package/web/assets/{requirementDiagram-BXWQKSXE-DvRiMfSd.js → requirementDiagram-BXWQKSXE-Bx_E3SzQ.js} +1 -1
- package/web/assets/{requirementDiagram-EFPCY7ZU-NGAFFSMB-CetNYmyR.js → requirementDiagram-EFPCY7ZU-NGAFFSMB-DEU_DtAn.js} +1 -1
- package/web/assets/{rotate-ccw-CmUerE0X.js → rotate-ccw-DTwPv1DZ.js} +1 -1
- package/web/assets/{sankeyDiagram-P5KCCOFB-3D3M4XPB-DTBggk4D.js → sankeyDiagram-P5KCCOFB-3D3M4XPB-EvJVJ1rl.js} +1 -1
- package/web/assets/{sankeyDiagram-P5KCCOFB-Chf73i3x.js → sankeyDiagram-P5KCCOFB-DT_jnEZ0.js} +1 -1
- package/web/assets/{sequenceDiagram-WJ2MYXX4-DH8S7n6r.js → sequenceDiagram-WJ2MYXX4-NXmk3r8f.js} +1 -1
- package/web/assets/{sequenceDiagram-WJ2MYXX4-Q2IOPB4R-BaqhVeKy.js → sequenceDiagram-WJ2MYXX4-Q2IOPB4R-ajUR8dxE.js} +1 -1
- package/web/assets/{sizeCapture-INFHLROL-DoWkN5kB.js → sizeCapture-INFHLROL-C4jFmWp9.js} +1 -1
- package/web/assets/{sizeCapture-X5ZJPWSS-PSGVOMYM-D1w8fJEe.js → sizeCapture-X5ZJPWSS-PSGVOMYM-BpuSUjAn.js} +1 -1
- package/web/assets/{stateDiagram-D77RDMKH-C2Bmxn5D.js → stateDiagram-D77RDMKH-BU70lxI5.js} +1 -1
- package/web/assets/{stateDiagram-HBIQ2CUA-4M2S6MAN-DmtO2hG4.js → stateDiagram-HBIQ2CUA-4M2S6MAN-NGpRbrT6.js} +1 -1
- package/web/assets/stateDiagram-v2-4QOOHH4V-LBBLA2WV-B5-idQ_e.js +1 -0
- package/web/assets/stateDiagram-v2-MP3YSRHH-6q18kRB6.js +1 -0
- package/web/assets/{swimlanes-42K2YHIH-CtCB4ffC.js → swimlanes-42K2YHIH-Im-eqjFe.js} +1 -1
- package/web/assets/{swimlanes-XN3QIQJK-N6N2CCQ6-C7V48a-4.js → swimlanes-XN3QIQJK-N6N2CCQ6-Dv2TRtEx.js} +1 -1
- package/web/assets/swimlanesDiagram-VK2B7HYN-E6N4H5SY-CG_jH3Yl.js +8 -0
- package/web/assets/swimlanesDiagram-VR7AAH4N-ylvx5aT5.js +8 -0
- package/web/assets/{timeline-definition-24CTP7MA-CGdYfJkN.js → timeline-definition-24CTP7MA-CGDK-783.js} +1 -1
- package/web/assets/{timeline-definition-24CTP7MA-KN7RSRVM-CPntDgZR.js → timeline-definition-24CTP7MA-KN7RSRVM-BnTGkjWL.js} +1 -1
- package/web/assets/{vennDiagram-4TSXK5OY-AKJ7LXAN-CGIdSvWW.js → vennDiagram-4TSXK5OY-AKJ7LXAN-B4F4yuzz.js} +1 -1
- package/web/assets/{vennDiagram-4TSXK5OY-BpWlDJtb.js → vennDiagram-4TSXK5OY-lOUVXJnN.js} +1 -1
- package/web/assets/{wardleyDiagram-VM6X3IG4-3B6A3BN5-DXGnwCFx.js → wardleyDiagram-VM6X3IG4-3B6A3BN5-BNvkWUde.js} +1 -1
- package/web/assets/{wardleyDiagram-VM6X3IG4-DqcLqOTM.js → wardleyDiagram-VM6X3IG4-CEmo8TwP.js} +1 -1
- package/web/assets/{xychartDiagram-S5SC5T6Z-VQI7mnX_.js → xychartDiagram-S5SC5T6Z-D3q4B-n3.js} +1 -1
- package/web/assets/{xychartDiagram-S5SC5T6Z-OBDNV6WG-DIO8oTNs.js → xychartDiagram-S5SC5T6Z-OBDNV6WG-MSCkooCe.js} +1 -1
- package/web/fouc.js +18 -0
- package/web/index.html +7 -23
- package/web/pet.html +4 -4
- package/web/assets/SettingsView-CoGqUXEr.js +0 -15
- package/web/assets/api-web-BZuBkYKX.js +0 -1
- package/web/assets/channel-CB0qYQAs.js +0 -1
- package/web/assets/classDiagram-DTDB5LWJ-LWRDKZ5K-gE6ypOty.js +0 -1
- package/web/assets/classDiagram-ZZMXUADV-6pfB_2-g.js +0 -1
- package/web/assets/classDiagram-v2-JRS7N3AN-2BZHGRP2-gE6ypOty.js +0 -1
- package/web/assets/classDiagram-v2-VYDZK3BY-6pfB_2-g.js +0 -1
- package/web/assets/stateDiagram-v2-4QOOHH4V-LBBLA2WV-BRoIf1d6.js +0 -1
- package/web/assets/stateDiagram-v2-MP3YSRHH-BVoQ569f.js +0 -1
- package/web/assets/swimlanesDiagram-VK2B7HYN-E6N4H5SY-B6zzyUKq.js +0 -8
- package/web/assets/swimlanesDiagram-VR7AAH4N-XUZui9QT.js +0 -8
- /package/web/assets/{index-DpUqsNSC.js → index-BwodmBiw.js} +0 -0
package/install-termux.sh
CHANGED
|
@@ -13,8 +13,9 @@ set -euo pipefail
|
|
|
13
13
|
PORT="${LOOKATSTUDY_PORT:-17890}"
|
|
14
14
|
APP_DIR="$HOME/lookatstudy"
|
|
15
15
|
DATA_DIR="$HOME/.lookatstudy"
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
GH_RELEASE="https://github.com/Kaiji-Z/LookatStudy/releases/latest/download"
|
|
17
|
+
GH_ASSET="${GH_RELEASE}/lookatstudy-mobile.zip"
|
|
18
|
+
GH_VOICE="${GH_RELEASE}/lookatstudy-termux-voice.tar.gz"
|
|
18
19
|
# 直连优先,失败再走代理前缀(镜像只做回退:KaijiBot 教训是镜像同步延迟会坏事,大头收益在 apt 的 TUNA)
|
|
19
20
|
DL_PREFIXES=("" "https://gh-proxy.com/" "https://ghproxy.net/" "https://ghfast.top/")
|
|
20
21
|
|
|
@@ -37,7 +38,9 @@ npm_tarball() {
|
|
|
37
38
|
return 0
|
|
38
39
|
fi
|
|
39
40
|
fi
|
|
40
|
-
printf '%s
|
|
41
|
+
printf '%s\n%s\n' \
|
|
42
|
+
"$(printf '%s' "$json" | sed -n 's/.*"tarball":"\([^"]*\)".*/\1/p')" \
|
|
43
|
+
"$(printf '%s' "$json" | sed -n 's/.*"integrity":"\([^"]*\)".*/\1/p')"
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
# npm 官方源(权威、零同步滞后):镜像未命中/滞后时的第一兜底,先于 GitHub 链。
|
|
@@ -45,7 +48,9 @@ npm_tarball() {
|
|
|
45
48
|
npm_tarball_official() {
|
|
46
49
|
local json
|
|
47
50
|
json=$(curl -sfL --connect-timeout 8 --max-time 20 "https://registry.npmjs.org/$1/latest" || true)
|
|
48
|
-
printf '%s
|
|
51
|
+
printf '%s\n%s\n' \
|
|
52
|
+
"$(printf '%s' "$json" | sed -n 's/.*"tarball":"\([^"]*\)".*/\1/p')" \
|
|
53
|
+
"$(printf '%s' "$json" | sed -n 's/.*"integrity":"\([^"]*\)".*/\1/p')"
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
# GitHub 最新 release 版本号(仅数字串;空=探测失败)。releases/latest/download 会 302 到
|
|
@@ -65,6 +70,64 @@ ver_ge() {
|
|
|
65
70
|
[ -n "$a" ] && [ -n "$b" ] && [ "$a" -ge "$b" 2>/dev/null ]
|
|
66
71
|
}
|
|
67
72
|
|
|
73
|
+
|
|
74
|
+
# ── 下载完整性(2026-09-13 审计后续)─────────────────────────
|
|
75
|
+
# npm tgz 走 registry dist.integrity(sha512,与 tarball 同一次元数据带回);
|
|
76
|
+
# GitHub 直连/代理资产走同 Release 的 <asset>.sha256 sidecar。校验不过/拿不到
|
|
77
|
+
# 期望值一律拒装;唯一逃逸口 LOOKATSTUDY_SKIP_VERIFY=1(用户显式自担风险)。
|
|
78
|
+
|
|
79
|
+
# 文件 sha256(小写 hex;失败空输出)
|
|
80
|
+
sha256_of() { sha256sum < "$1" 2>/dev/null | awk '{print $1}' || true; }
|
|
81
|
+
|
|
82
|
+
# npm tgz 强校验:期望值=registry 元数据 dist.integrity("sha512-<base64>")
|
|
83
|
+
verify_npm_tgz() { # <file> <integrity>
|
|
84
|
+
if [ "${LOOKATSTUDY_SKIP_VERIFY:-0}" = "1" ]; then
|
|
85
|
+
info "LOOKATSTUDY_SKIP_VERIFY=1:跳过 npm 包完整性校验(用户显式自担风险)"
|
|
86
|
+
return 0
|
|
87
|
+
fi
|
|
88
|
+
[ -n "$2" ] || { warn "registry 元数据缺 integrity,视为不可信"; return 1; }
|
|
89
|
+
local got
|
|
90
|
+
got=$(node -e "const c=require('crypto'),f=require('fs');process.stdout.write('sha512-'+c.createHash('sha512').update(f.readFileSync(process.argv[1])).digest('base64'))" "$1" 2>/dev/null || true)
|
|
91
|
+
if [ -n "$got" ] && [ "$got" = "$2" ]; then return 0; fi
|
|
92
|
+
warn "npm 包 sha512 完整性校验失败(下载损坏或镜像被篡改),换下一源"
|
|
93
|
+
return 1
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# GitHub Release 资产的期望 sha256(同 Release 的 .sha256 sidecar;直连优先代理兜底)
|
|
97
|
+
# 契约:恒 exit 0,空输出=校验源不可达。
|
|
98
|
+
gh_asset_sha256() { # <asset-filename>
|
|
99
|
+
local p raw sum
|
|
100
|
+
for p in "${DL_PREFIXES[@]}"; do
|
|
101
|
+
raw=$(curl -sfL --connect-timeout 8 --max-time 20 "${p}${GH_RELEASE}/$1.sha256" 2>/dev/null || true)
|
|
102
|
+
sum=$(printf '%s' "$raw" | tr -d ' \r\n' | tr 'A-F' 'a-f')
|
|
103
|
+
case "$sum" in
|
|
104
|
+
''|*[!0-9a-f]*) ;; # 空或非 hex:这一跳拿不到/坏,试下一跳
|
|
105
|
+
*) printf '%s' "$sum"; return 0 ;;
|
|
106
|
+
esac
|
|
107
|
+
done
|
|
108
|
+
return 0
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# GH 资产强校验:期望值拿不到或对不上都拒装(防代理篡改/下载损坏)
|
|
112
|
+
verify_gh_download() { # <file> <asset-filename> <label>
|
|
113
|
+
if [ "${LOOKATSTUDY_SKIP_VERIFY:-0}" = "1" ]; then
|
|
114
|
+
info "LOOKATSTUDY_SKIP_VERIFY=1:跳过 $3 完整性校验(用户显式自担风险)"
|
|
115
|
+
return 0
|
|
116
|
+
fi
|
|
117
|
+
local exp got
|
|
118
|
+
exp=$(gh_asset_sha256 "$2")
|
|
119
|
+
if [ -z "$exp" ]; then
|
|
120
|
+
warn "$3 的 sha256 校验源不可达(.sha256 sidecar 拿不到),拒装防篡改;稍后重跑,或自担风险:LOOKATSTUDY_SKIP_VERIFY=1 bash 本脚本"
|
|
121
|
+
return 1
|
|
122
|
+
fi
|
|
123
|
+
got=$(sha256_of "$1")
|
|
124
|
+
if [ "$got" != "$exp" ]; then
|
|
125
|
+
warn "$3 sha256 不匹配(期望 ${exp:0:12}…实际 ${got:0:12}…),已拒装(下载损坏或被篡改)"
|
|
126
|
+
return 1
|
|
127
|
+
fi
|
|
128
|
+
ok "$3 sha256 校验通过"
|
|
129
|
+
}
|
|
130
|
+
|
|
68
131
|
info() { printf '\033[1m[*]\033[0m %s\n' "$*"; }
|
|
69
132
|
ok() { printf '\033[38;2;0;229;204m[✓]\033[0m %s\n' "$*"; }
|
|
70
133
|
warn() { printf '\033[33m[!]\033[0m %s\n' "$*"; }
|
|
@@ -119,22 +182,31 @@ download_bundle() {
|
|
|
119
182
|
cd "$APP_DIR"
|
|
120
183
|
info "下载便携包(约 5MB)..."
|
|
121
184
|
# 主源:npm 镜像(npmmirror 同步 npm 发布,国内直连快;tgz 需剥 package/ 前缀)
|
|
122
|
-
|
|
123
|
-
tb
|
|
124
|
-
|
|
185
|
+
# meta 两行 = tarball URL + dist.integrity(sha512);下载后强校验,不过=换下一源
|
|
186
|
+
local meta tb itg
|
|
187
|
+
meta=$(npm_tarball lookatstudy-mobile)
|
|
188
|
+
tb=$(printf '%s' "$meta" | sed -n 1p)
|
|
189
|
+
itg=$(printf '%s' "$meta" | sed -n 2p)
|
|
190
|
+
if [ -n "$tb" ] && curl -fL --connect-timeout 10 --retry 2 -o mobile.tgz "$tb" \
|
|
191
|
+
&& verify_npm_tgz mobile.tgz "$itg"; then
|
|
125
192
|
tar -xzf mobile.tgz --strip-components=1
|
|
126
193
|
rm -f mobile.tgz
|
|
127
|
-
ok "便携包就位(npm
|
|
194
|
+
ok "便携包就位(npm 镜像,sha512 校验通过): $APP_DIR"
|
|
128
195
|
return 0
|
|
129
196
|
fi
|
|
197
|
+
rm -f mobile.tgz
|
|
130
198
|
# 次选:npm 官方源(权威零滞后,接住镜像同步窗口)
|
|
131
|
-
|
|
132
|
-
|
|
199
|
+
meta=$(npm_tarball_official lookatstudy-mobile)
|
|
200
|
+
tb=$(printf '%s' "$meta" | sed -n 1p)
|
|
201
|
+
itg=$(printf '%s' "$meta" | sed -n 2p)
|
|
202
|
+
if [ -n "$tb" ] && curl -fL --connect-timeout 10 --retry 2 -o mobile.tgz "$tb" \
|
|
203
|
+
&& verify_npm_tgz mobile.tgz "$itg"; then
|
|
133
204
|
tar -xzf mobile.tgz --strip-components=1
|
|
134
205
|
rm -f mobile.tgz
|
|
135
|
-
ok "便携包就位(npm
|
|
206
|
+
ok "便携包就位(npm 官方源,sha512 校验通过): $APP_DIR"
|
|
136
207
|
return 0
|
|
137
208
|
fi
|
|
209
|
+
rm -f mobile.tgz
|
|
138
210
|
info "npm 源未命中,回退 GitHub 直连+代理链..."
|
|
139
211
|
local dl_ok=0 p=""
|
|
140
212
|
for p in "${DL_PREFIXES[@]}"; do
|
|
@@ -148,6 +220,7 @@ download_bundle() {
|
|
|
148
220
|
echo "下载失败。请手动下载 $GH_ASSET 放到 $APP_DIR/ls.zip 后重跑本脚本。"
|
|
149
221
|
exit 1
|
|
150
222
|
fi
|
|
223
|
+
verify_gh_download ls.zip lookatstudy-mobile.zip "便携包" || { rm -f ls.zip; exit 1; }
|
|
151
224
|
unzip -o ls.zip
|
|
152
225
|
rm -f ls.zip
|
|
153
226
|
ok "便携包就位: $APP_DIR"
|
|
@@ -157,24 +230,32 @@ install_voice() {
|
|
|
157
230
|
mkdir -p "$APP_DIR/node_modules"
|
|
158
231
|
info "下载 Termux 语音引擎包(约 12MB)..."
|
|
159
232
|
# 主源:npm 镜像(tgz 剥 package/ 前缀,解出 sherpa-onnx-node/ 目录)
|
|
160
|
-
local tb
|
|
161
|
-
|
|
162
|
-
|
|
233
|
+
local meta tb itg
|
|
234
|
+
meta=$(npm_tarball lookatstudy-termux-voice)
|
|
235
|
+
tb=$(printf '%s' "$meta" | sed -n 1p)
|
|
236
|
+
itg=$(printf '%s' "$meta" | sed -n 2p)
|
|
237
|
+
if [ -n "$tb" ] && curl -fL --connect-timeout 10 --retry 2 -o voice.tgz "$tb" \
|
|
238
|
+
&& verify_npm_tgz voice.tgz "$itg"; then
|
|
163
239
|
tar -xzf voice.tgz --strip-components=1 -C "$APP_DIR/node_modules"
|
|
164
240
|
rm -f voice.tgz
|
|
165
|
-
ok "语音引擎就位(npm
|
|
241
|
+
ok "语音引擎就位(npm 镜像,sha512 校验通过): $APP_DIR/node_modules/sherpa-onnx-node"
|
|
166
242
|
info "语音模型在应用内按需下载(设置 → 语音能力):朗读本地档约 430MB;听写建议云档(Groq/Azure),本地 Whisper 约 360MB~1GB"
|
|
167
243
|
info "装完模型重启服务生效: bash ~/lookatstudy/start.sh"
|
|
168
244
|
return 0
|
|
169
245
|
fi
|
|
246
|
+
rm -f voice.tgz
|
|
170
247
|
# 次选:npm 官方源(权威零滞后,接住镜像同步窗口)
|
|
171
|
-
|
|
172
|
-
|
|
248
|
+
meta=$(npm_tarball_official lookatstudy-termux-voice)
|
|
249
|
+
tb=$(printf '%s' "$meta" | sed -n 1p)
|
|
250
|
+
itg=$(printf '%s' "$meta" | sed -n 2p)
|
|
251
|
+
if [ -n "$tb" ] && curl -fL --connect-timeout 10 --retry 2 -o voice.tgz "$tb" \
|
|
252
|
+
&& verify_npm_tgz voice.tgz "$itg"; then
|
|
173
253
|
tar -xzf voice.tgz --strip-components=1 -C "$APP_DIR/node_modules"
|
|
174
254
|
rm -f voice.tgz
|
|
175
|
-
ok "语音引擎就位(npm
|
|
255
|
+
ok "语音引擎就位(npm 官方源,sha512 校验通过): $APP_DIR/node_modules/sherpa-onnx-node"
|
|
176
256
|
return 0
|
|
177
257
|
fi
|
|
258
|
+
rm -f voice.tgz
|
|
178
259
|
info "npm 源未命中,回退 GitHub 直连+代理链..."
|
|
179
260
|
local dl_ok=0 p=""
|
|
180
261
|
for p in "${DL_PREFIXES[@]}"; do
|
|
@@ -189,6 +270,7 @@ install_voice() {
|
|
|
189
270
|
rm -f voice.tar.gz
|
|
190
271
|
return 1
|
|
191
272
|
fi
|
|
273
|
+
verify_gh_download voice.tar.gz lookatstudy-termux-voice.tar.gz "语音引擎包" || { rm -f voice.tar.gz; return 1; }
|
|
192
274
|
tar -xzf voice.tar.gz -C "$APP_DIR/node_modules"
|
|
193
275
|
rm -f voice.tar.gz
|
|
194
276
|
ok "语音引擎就位: $APP_DIR/node_modules/sherpa-onnx-node"
|
|
@@ -287,10 +369,59 @@ EOS
|
|
|
287
369
|
{
|
|
288
370
|
printf '#!/data/data/com.termux/files/usr/bin/bash\n'
|
|
289
371
|
printf 'set -euo pipefail\n'
|
|
290
|
-
printf 'APP_DIR=%q PORT=%q GH_ASSET=%q\n
|
|
372
|
+
printf 'APP_DIR=%q PORT=%q GH_ASSET=%q GH_RELEASE=%q\n' "$APP_DIR" "$PORT" "$GH_ASSET" "$GH_RELEASE"
|
|
373
|
+
printf 'DL_PREFIXES=("" "https://gh-proxy.com/" "https://ghproxy.net/" "https://ghfast.top/")\n\n'
|
|
291
374
|
cat <<'UPDATE_EOF'
|
|
292
375
|
# 更新便携包并重启(下载链与 install-termux.sh 同源:npmmirror+滞后守卫 → npm 官方 → GitHub 直连 → gh 代理)
|
|
293
376
|
info() { printf '\033[1m[*]\033[0m %s\n' "$*"; }
|
|
377
|
+
warn() { printf '\033[33m[!]\033[0m %s\n' "$*"; }
|
|
378
|
+
ok() { printf '\033[38;2;0,229,204m[✓]\033[0m %s\n' "$*"; }
|
|
379
|
+
|
|
380
|
+
# ↓↓ 完整性校验四件(与 install-termux.sh 逐字同源)↓↓
|
|
381
|
+
sha256_of() { sha256sum < "$1" 2>/dev/null | awk '{print $1}' || true; }
|
|
382
|
+
verify_npm_tgz() { # <file> <integrity>
|
|
383
|
+
if [ "${LOOKATSTUDY_SKIP_VERIFY:-0}" = "1" ]; then
|
|
384
|
+
info "LOOKATSTUDY_SKIP_VERIFY=1:跳过 npm 包完整性校验(用户显式自担风险)"
|
|
385
|
+
return 0
|
|
386
|
+
fi
|
|
387
|
+
[ -n "$2" ] || { warn "registry 元数据缺 integrity,视为不可信"; return 1; }
|
|
388
|
+
local got
|
|
389
|
+
got=$(node -e "const c=require('crypto'),f=require('fs');process.stdout.write('sha512-'+c.createHash('sha512').update(f.readFileSync(process.argv[1])).digest('base64'))" "$1" 2>/dev/null || true)
|
|
390
|
+
if [ -n "$got" ] && [ "$got" = "$2" ]; then return 0; fi
|
|
391
|
+
warn "npm 包 sha512 完整性校验失败(下载损坏或镜像被篡改),换下一源"
|
|
392
|
+
return 1
|
|
393
|
+
}
|
|
394
|
+
gh_asset_sha256() { # <asset-filename>
|
|
395
|
+
local p raw sum
|
|
396
|
+
for p in "${DL_PREFIXES[@]}"; do
|
|
397
|
+
raw=$(curl -sfL --connect-timeout 8 --max-time 20 "${p}${GH_RELEASE}/$1.sha256" 2>/dev/null || true)
|
|
398
|
+
sum=$(printf '%s' "$raw" | tr -d ' \r\n' | tr 'A-F' 'a-f')
|
|
399
|
+
case "$sum" in
|
|
400
|
+
''|*[!0-9a-f]*) ;;
|
|
401
|
+
*) printf '%s' "$sum"; return 0 ;;
|
|
402
|
+
esac
|
|
403
|
+
done
|
|
404
|
+
return 0
|
|
405
|
+
}
|
|
406
|
+
verify_gh_download() { # <file> <asset-filename> <label>
|
|
407
|
+
if [ "${LOOKATSTUDY_SKIP_VERIFY:-0}" = "1" ]; then
|
|
408
|
+
info "LOOKATSTUDY_SKIP_VERIFY=1:跳过 $3 完整性校验(用户显式自担风险)"
|
|
409
|
+
return 0
|
|
410
|
+
fi
|
|
411
|
+
local exp got
|
|
412
|
+
exp=$(gh_asset_sha256 "$2")
|
|
413
|
+
if [ -z "$exp" ]; then
|
|
414
|
+
warn "$3 的 sha256 校验源不可达(.sha256 sidecar 拿不到),拒装防篡改;稍后重跑,或自担风险:LOOKATSTUDY_SKIP_VERIFY=1 bash 本脚本"
|
|
415
|
+
return 1
|
|
416
|
+
fi
|
|
417
|
+
got=$(sha256_of "$1")
|
|
418
|
+
if [ "$got" != "$exp" ]; then
|
|
419
|
+
warn "$3 sha256 不匹配(期望 ${exp:0:12}…实际 ${got:0:12}…),已拒装(下载损坏或被篡改)"
|
|
420
|
+
return 1
|
|
421
|
+
fi
|
|
422
|
+
ok "$3 sha256 校验通过"
|
|
423
|
+
}
|
|
424
|
+
# ↑↑ 完整性校验四件结束 ↑↑
|
|
294
425
|
|
|
295
426
|
# ↓↓ 与 install-termux.sh 逐字同源的四个函数(契约:恒 exit 0,空输出=未命中)↓↓
|
|
296
427
|
npm_tarball() {
|
|
@@ -305,12 +436,16 @@ npm_tarball() {
|
|
|
305
436
|
return 0
|
|
306
437
|
fi
|
|
307
438
|
fi
|
|
308
|
-
printf '%s
|
|
439
|
+
printf '%s\n%s\n' \
|
|
440
|
+
"$(printf '%s' "$json" | sed -n 's/.*"tarball":"\([^"]*\)".*/\1/p')" \
|
|
441
|
+
"$(printf '%s' "$json" | sed -n 's/.*"integrity":"\([^"]*\)".*/\1/p')"
|
|
309
442
|
}
|
|
310
443
|
npm_tarball_official() {
|
|
311
444
|
local json
|
|
312
445
|
json=$(curl -sfL --connect-timeout 8 --max-time 20 "https://registry.npmjs.org/$1/latest" || true)
|
|
313
|
-
printf '%s
|
|
446
|
+
printf '%s\n%s\n' \
|
|
447
|
+
"$(printf '%s' "$json" | sed -n 's/.*"tarball":"\([^"]*\)".*/\1/p')" \
|
|
448
|
+
"$(printf '%s' "$json" | sed -n 's/.*"integrity":"\([^"]*\)".*/\1/p')"
|
|
314
449
|
}
|
|
315
450
|
gh_latest_version() {
|
|
316
451
|
local final
|
|
@@ -332,14 +467,22 @@ pkill -f "server.cjs --port $PORT" 2>/dev/null || true
|
|
|
332
467
|
sleep 1
|
|
333
468
|
echo "==> 下载最新便携包..."
|
|
334
469
|
src=""
|
|
335
|
-
|
|
336
|
-
|
|
470
|
+
meta=$(npm_tarball lookatstudy-mobile)
|
|
471
|
+
tb=$(printf '%s' "$meta" | sed -n 1p)
|
|
472
|
+
itg=$(printf '%s' "$meta" | sed -n 2p)
|
|
473
|
+
if [ -n "$tb" ] && curl -fL --connect-timeout 10 --retry 2 -o mobile.tgz "$tb" \
|
|
474
|
+
&& verify_npm_tgz mobile.tgz "$itg"; then
|
|
337
475
|
src="npm 镜像"
|
|
338
476
|
else
|
|
339
|
-
|
|
340
|
-
|
|
477
|
+
rm -f mobile.tgz
|
|
478
|
+
meta=$(npm_tarball_official lookatstudy-mobile)
|
|
479
|
+
tb=$(printf '%s' "$meta" | sed -n 1p)
|
|
480
|
+
itg=$(printf '%s' "$meta" | sed -n 2p)
|
|
481
|
+
if [ -n "$tb" ] && curl -fL --connect-timeout 10 --retry 2 -o mobile.tgz "$tb" \
|
|
482
|
+
&& verify_npm_tgz mobile.tgz "$itg"; then
|
|
341
483
|
src="npm 官方源"
|
|
342
484
|
fi
|
|
485
|
+
rm -f mobile.tgz
|
|
343
486
|
fi
|
|
344
487
|
if [ -n "$src" ]; then
|
|
345
488
|
tar -xzf mobile.tgz --strip-components=1 && rm -f mobile.tgz
|
|
@@ -351,6 +494,7 @@ else
|
|
|
351
494
|
echo " ${p:-GitHub 直连}失败,换下一个源..."
|
|
352
495
|
done
|
|
353
496
|
[ "$dl_ok" = 1 ] || { echo "下载失败,保持原版本。"; exit 1; }
|
|
497
|
+
verify_gh_download ls.zip lookatstudy-mobile.zip "便携包" || { rm -f ls.zip; echo "校验失败,保持原版本。"; exit 1; }
|
|
354
498
|
unzip -o ls.zip && rm -f ls.zip
|
|
355
499
|
fi
|
|
356
500
|
echo "==> 重启..."
|