shawenguan 2 лет назад
Родитель
Сommit
172758a673
27 измененных файлов с 8740 добавлено и 0 удалено
  1. 3003 0
      Scripts/box/chavy.boxjs.html
  2. 902 0
      Scripts/box/chavy.boxjs.js
  3. 688 0
      Scripts/box/chavy.boxjs.json
  4. 29 0
      Scripts/box/chavy.boxjs.test.json
  5. BIN
      Scripts/box/icons/BoxJs.png
  6. BIN
      Scripts/box/icons/BoxSetting.mini.png
  7. BIN
      Scripts/box/icons/BoxSetting.png
  8. BIN
      Scripts/box/icons/BoxSwitcher.mini.png
  9. BIN
      Scripts/box/icons/BoxSwitcher.png
  10. 2433 0
      Scripts/box/release/box.release.json
  11. 1371 0
      Scripts/box/release/box.release.tf.json
  12. 15 0
      Scripts/box/rewrite/boxjs.rewrite.loon.plugin
  13. 15 0
      Scripts/box/rewrite/boxjs.rewrite.loon.tf.plugin
  14. 3 0
      Scripts/box/rewrite/boxjs.rewrite.quanx.conf
  15. 3 0
      Scripts/box/rewrite/boxjs.rewrite.quanx.tf.conf
  16. 25 0
      Scripts/box/rewrite/boxjs.rewrite.stash.stoverride
  17. 25 0
      Scripts/box/rewrite/boxjs.rewrite.stash.tf.stoverride
  18. 11 0
      Scripts/box/rewrite/boxjs.rewrite.surge.sgmodule
  19. 11 0
      Scripts/box/rewrite/boxjs.rewrite.surge.tf.sgmodule
  20. 16 0
      Scripts/box/scripts/boxjs.revert.baks.js
  21. 32 0
      Scripts/box/scripts/boxjs.revert.boxjs.js
  22. 13 0
      Scripts/box/scripts/boxjs.revert.caches.js
  23. 14 0
      Scripts/box/scripts/boxjs.revert.usercfgs.favapps.js
  24. 14 0
      Scripts/box/scripts/boxjs.revert.usercfgs.httpbackend.js
  25. 11 0
      Scripts/box/scripts/boxjs.revert.usercfgs.js
  26. 13 0
      Scripts/box/scripts/boxjs.revert.usercfgs.sessions.js
  27. 93 0
      Scripts/box/switcher/box.switcher.js

+ 3003 - 0
Scripts/box/chavy.boxjs.html

@@ -0,0 +1,3003 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>BoxJs</title>
+    <meta charset="utf-8" />
+    <meta name="apple-mobile-web-app-capable" content="yes" />
+    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover" />
+    <link rel="Bookmark" href="https://raw.githubusercontent.com/chavyleung/scripts/master/BOXJS.png" />
+    <link rel="shortcut icon" href="https://raw.githubusercontent.com/chavyleung/scripts/master/BOXJS.png" />
+    <link rel="apple-touch-icon" href="https://raw.githubusercontent.com/chavyleung/scripts/master/BOXJS.png" />
+    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet" />
+    <link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet" />
+    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet" />
+    <script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
+    <style>
+      #BG {
+        position: fixed;
+        top: 0;
+        left: 0;
+        bottom: 0;
+        right: 0;
+        z-index: 0;
+        background-position: center;
+        background-size: cover;
+        background-repeat: no-repeat;
+        background-color: transparent;
+      }
+      @media (prefers-color-scheme: light) {
+        body {
+          background-color: #fff;
+        }
+      }
+      @media (prefers-color-scheme: dark) {
+        body {
+          background-color: #121212;
+        }
+      }
+      [v-cloak] {
+        display: none;
+      }
+      .v-navigation-drawer {
+        padding-top: constant(safe-area-inset-top) !important;
+        padding-top: env(safe-area-inset-top) !important;
+      }
+      .v-bottom-sheet.v-dialog--fullscreen {
+        padding-top: constant(safe-area-inset-top) !important;
+        padding-top: env(safe-area-inset-top) !important;
+      }
+      .v-app-bar.safe {
+        height: auto !important;
+        padding-top: constant(safe-area-inset-top) !important;
+        padding-top: env(safe-area-inset-top) !important;
+      }
+      .v-toolbar.safe {
+        height: auto !important;
+        padding-top: constant(safe-area-inset-top) !important;
+        padding-top: env(safe-area-inset-top) !important;
+      }
+      .v-toolbar__content {
+        padding-left: 12px !important;
+        padding-right: 12px !important;
+      }
+      .v-main {
+        margin-top: constant(safe-area-inset-top) !important;
+        margin-top: env(safe-area-inset-top) !important;
+        margin-bottom: constant(safe-area-inset-bottom) !important;
+        margin-bottom: env(safe-area-inset-bottom) !important;
+      }
+      .v-main .container {
+        height: 100%;
+      }
+      .v-bottom-navigation,
+      .v-bottom-sheet {
+        padding-bottom: constant(safe-area-inset-bottom);
+        padding-bottom: env(safe-area-inset-bottom);
+      }
+      .v-bottom-navigation {
+        box-sizing: content-box;
+      }
+      .v-bottom-navigation button {
+        box-sizing: border-box;
+      }
+      .v-bottom-navigation button.v-btn:before {
+        background-color: transparent;
+      }
+      .v-speed-dial {
+        margin-bottom: calc(48px + constant(safe-area-inset-bottom));
+        margin-bottom: calc(48px + env(safe-area-inset-bottom));
+      }
+      .container.container--fluid {
+        padding-bottom: 68px;
+      }
+      .appicon {
+        user-select: none;
+        -webkit-user-select: none;
+      }
+    </style>
+  </head>
+  <body>
+    <div id="BG"></div>
+    <div id="app" v-cloak>
+      <v-app v-if="box" :style="appViewStyle">
+        <v-app-bar
+          ref="appBar"
+          v-bind="appBarBind"
+          :class="!$refs.appBar || $refs.appBar.isActive ? 'safe' : undefined"
+          :value="!isHidedSearchBar"
+          v-touch="{ up: () => isHidedSearchBar = true }"
+        >
+          <!-- 搜索条 -->
+          <v-autocomplete v-bind="ui.searchBar" :label="title" @click="ui.searchDialog.show = true" hide-no-data hide-details solo>
+            <template #prepend-inner>
+              <!-- 容器切换 Surge、QuanX、Loon -->
+              <v-menu bottom left v-if="!isLoading && isMainView">
+                <template #activator="{ on }">
+                  <v-btn v-on="on" icon class="ml-n3">
+                    <v-avatar size="26"><img :src="env.icons[iconEnvThemeIdx]" /></v-avatar>
+                  </v-btn>
+                </template>
+                <v-list>
+                  <v-list-item dense v-for="(env, envIdx) in envs" :key="env.id" @click="switchEnv(env.id)">
+                    <v-list-item-avatar size="26"><v-img :src="env.icon" /></v-list-item-avatar>
+                    <v-list-item-title>{{env.id}}</v-list-item-title>
+                  </v-list-item>
+                </v-list>
+              </v-menu>
+              <!-- 返回按钮 -->
+              <v-btn icon class="ml-n3" @click="back" v-else-if="!isLoading && !isMainView">
+                <v-icon>mdi-chevron-left</v-icon>
+              </v-btn>
+              <v-btn icon class="ml-n3" v-show="isLoading" :loading="isLoading" color="primary"></v-btn>
+            </template>
+            <template #append>
+              <v-btn icon class="mr-n3" @click="ui.naviDrawer.show = true">
+                <v-avatar size="26"><v-icon>mdi-menu</v-icon></v-avatar>
+              </v-btn>
+            </template>
+          </v-autocomplete>
+        </v-app-bar>
+        <v-dialog v-model="ui.searchDialog.show" fullscreen scrollable>
+          <v-card class="align-self-start">
+            <v-card-subtitle class="pa-0">
+              <v-toolbar v-bind="searchBarBind" class="safe">
+                <v-btn icon dark @click="ui.searchDialog.show = false">
+                  <v-icon>mdi-chevron-left</v-icon>
+                </v-btn>
+                <v-text-field ref="search" v-model="ui.searchBar.input" :label="title" autofocus hide-details solo></v-text-field>
+                <v-btn icon @click="open(box.syscfgs.orz3.repo)">
+                  <v-avatar size="26"><img :src="box.syscfgs.orz3.icon" /></v-avatar>
+                </v-btn>
+              </v-toolbar>
+            </v-card-subtitle>
+            <v-card-text class="px-0">
+              <v-list nav>
+                <v-list-item
+                  v-for="(app, appIdx) in searchApps"
+                  :key="appIdx"
+                  @click="ui.searchDialog.show = false, switchAppView(app.id)"
+                  dense
+                >
+                  <v-list-item-avatar class="elevation-3"><img :src="app.icon" /></v-list-item-avatar>
+                  <v-list-item-content>
+                    <v-list-item-title>{{`${app.name} (${app.id})`}}</v-list-item-title>
+                    <v-list-item-subtitle>{{app.repo}}</v-list-item-subtitle>
+                    <v-list-item-subtitle>{{app.author}}</v-list-item-subtitle>
+                  </v-list-item-content>
+                  <v-list-item-action>
+                    <v-btn icon @click.stop="ui.searchDialog.show = false, favApp(app.id)">
+                      <v-icon :color="app.favIconColor" v-text="app.favIcon" />
+                    </v-btn>
+                  </v-list-item-action>
+                </v-list-item>
+              </v-list>
+            </v-card-text>
+          </v-card>
+        </v-dialog>
+        <!-- 侧栏 -->
+        <v-navigation-drawer app v-model="ui.naviDrawer.show" height="100%" temporary right disable-route-watcher>
+          <v-list dense nav>
+            <v-list-item dense>
+              <v-list-item-avatar @click="open(box.syscfgs.boxjs.repo)" class="elevation-3">
+                <v-img :src="box.syscfgs.boxjs.icon"></v-img>
+              </v-list-item-avatar>
+              <v-row justify="start" no-gutters>
+                <v-col v-for="(c, cIdx) in ui.collaborators" cols="4" :key="c.id">
+                  <a>
+                    <v-avatar size="40" @click="open(c.repo)" class="elevation-3">
+                      <img :src="c.icon" />
+                    </v-avatar>
+                  </a>
+                </v-col>
+              </v-row>
+            </v-list-item>
+            <v-divider></v-divider>
+            <v-list-item class="pt-1">
+              <v-progress-linear :active="isLoading" height="1" absolute top indeterminate></v-progress-linear>
+              <v-row justify="start" no-gutters>
+                <v-col v-for="(c, cIdx) in ui.contributors" cols="2" :key="c.id">
+                  <v-tooltip bottom>
+                    <template v-slot:activator="{ on, attrs }">
+                      <a>
+                        <v-avatar v-on="on" class="ma-1 elevation-3" size="26" @click="open(c.repo)">
+                          <v-img :src="c.icon"></v-img>
+                        </v-avatar>
+                      </a>
+                    </template>
+                    <span>{{c.login}}</span>
+                  </v-tooltip>
+                </v-col>
+              </v-row>
+            </v-list-item>
+            <v-divider></v-divider>
+            <v-list-item v-if="box.syscfgs.env === 'Surge'">
+              <v-list-item-content>
+                <v-select
+                  v-if="box.usercfgs.httpapis"
+                  hide-details
+                  v-model="box.usercfgs.httpapi"
+                  :items="box.usercfgs.httpapis.split(',')"
+                  @change="saveUserCfgs"
+                  label="HTTP-API (Surge)"
+                >
+                </v-select>
+                <v-text-field
+                  v-else
+                  label="HTTP-API (Surge)"
+                  v-model="box.usercfgs.httpapi"
+                  hint="Surge http-api 地址."
+                  placeholder="[email protected]:6166"
+                  persistent-hint
+                  @change="saveUserCfgs"
+                  :rules="[(val)=> /.*?@.*?:[0-9]+/.test(val) || '格式错误: [email protected]:6166']"
+                >
+                </v-text-field>
+              </v-list-item-content>
+            </v-list-item>
+            <v-list-item>
+              <v-list-item-content>
+                <v-select
+                  :items="[{text: 'English', value: 'en-US'}, {text: '简体中文', value: 'zh-CN'}]"
+                  hide-details
+                  label="Language"
+                  v-model="box.usercfgs.lang"
+                >
+                </v-select>
+              </v-list-item-content>
+            </v-list-item>
+            <v-list-item>
+              <v-list-item-content>
+                <v-select
+                  :items="[{text: $t('prefs.appearances.auto'), value: 'auto'}, {text: $t('prefs.appearances.dark'), value: 'dark'}, {text: $t('prefs.appearances.light'), value: 'light'}]"
+                  :label="$t('prefs.appearance')"
+                  hide-details
+                  v-model="box.usercfgs.theme"
+                >
+                </v-select>
+              </v-list-item-content>
+            </v-list-item>
+            <v-list-item class="mt-4" v-show="box.usercfgs.bgimgs">
+              <v-list-item-content>
+                <v-select
+                  :items="bgimgs"
+                  :label="$t('prefs.background')"
+                  @change="saveUserCfgs"
+                  hide-details
+                  item-text="name"
+                  item-value="url"
+                  v-model="box.usercfgs.bgimg"
+                >
+                </v-select>
+              </v-list-item-content>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hide-details="isDarkMode"
+                :hint="$t('prefs.iconDesc')"
+                :label="$t('prefs.icon')"
+                :persistent-hint="true"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                v-model="box.usercfgs.isTransparentIcons"
+              >
+              </v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text @click="open(box.syscfgs.orz3.repo)">
+                <v-avatar size="32"><img :src="box.syscfgs.orz3.icon" /></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.bgModeDesc')"
+                :label="$t('prefs.bgMode')"
+                :persistent-hint="true"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                v-model="isWallpaperMode"
+              >
+              </v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar size="32"><v-icon>mdi-image</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.hideTopBarDesc')"
+                :label="$t('prefs.hideTopBar')"
+                :persistent-hint="true"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                v-model="box.usercfgs.isHidedSearchBar"
+              >
+              </v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar size="32"><v-icon>mdi-dock-top</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.autoTopBarDesc')"
+                :label="$t('prefs.autoTopBar')"
+                :persistent-hint="true"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                v-model="isAutoSearchBar"
+              >
+              </v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar size="32"><v-icon>mdi-format-align-top</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.hideBottomBarDesc')"
+                :label="$t('prefs.hideBottomBar')"
+                :persistent-hint="true"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                v-model="box.usercfgs.isHidedNaviBottom"
+              >
+              </v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar size="32"><v-icon>mdi-dock-bottom</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.autoBottomBarDesc')"
+                :label="$t('prefs.autoBottomBar')"
+                :persistent-hint="true"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                v-model="isAutoNaviBottom"
+              >
+              </v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar size="32"><v-icon>mdi-format-align-bottom</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <!-- <v-list-item class="mt-4">
+              <v-switch
+                dense
+                class="mt-0"
+                label="透明主题"
+                v-model="box.usercfgs.isTransparent"
+                @change="saveUserCfgs"
+                :persistent-hint="true"
+                hint="使界面更多元素透明 (beta)"
+              >
+              </v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar size="32"><v-icon>mdi-invert-colors</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item> -->
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.muteModeDesc')"
+                :label="$t('prefs.muteMode')"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                persistent-hint
+                v-model="box.usercfgs.isMute"
+              ></v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar size="32"><v-icon>mdi-volume-off</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.hideHelpDesc')"
+                :label="$t('prefs.hideHelp')"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                persistent-hint
+                v-model="box.usercfgs.isHideHelp"
+              ></v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text @click="open(box.syscfgs.boxjs.repo)">
+                <v-avatar size="32"><v-icon>mdi-help</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.hideBoxJsDesc')"
+                :label="$t('prefs.hideBoxJs')"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                persistent-hint
+                v-model="box.usercfgs.isHideBoxIcon"
+              ></v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text @click="open(box.syscfgs.boxjs.repo)">
+                <v-avatar size="32">
+                  <img :src="box.syscfgs.boxjs.icons[iconThemeIdx]" />
+                </v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.hideProfileTitleDesc')"
+                :label="$t('prefs.hideProfileTitle')"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                persistent-hint
+                v-model="box.usercfgs.isHideMyTitle"
+              ></v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar v-if="box.usercfgs.icon" size="32">
+                  <img :src="box.usercfgs.icon" />
+                </v-avatar>
+                <v-icon v-else size="32">mdi-face-profile</v-icon>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.hideCoddingDesc')"
+                :label="$t('prefs.hideCodding')"
+                dense
+                class="mt-0"
+                persistent-hint
+                v-model="box.usercfgs.isHideCoding"
+                @change="saveUserCfgs"
+              ></v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar size="32"><v-icon>mdi-code-tags</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.hideReloadDesc')"
+                :label="$t('prefs.hideReload')"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                persistent-hint
+                v-model="box.usercfgs.isHideRefresh"
+              ></v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar size="32"><v-icon>mdi-refresh</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item class="mt-4">
+              <v-switch
+                :hint="$t('prefs.debugModeDesc')"
+                :label="$t('prefs.debugMode')"
+                @change="saveUserCfgs"
+                class="mt-0"
+                dense
+                persistent-hint
+                v-model="box.usercfgs.isDebugWeb"
+              ></v-switch>
+              <v-spacer></v-spacer>
+              <v-btn fab small text>
+                <v-avatar size="32"><v-icon>mdi-language-html5</v-icon></v-avatar>
+              </v-btn>
+            </v-list-item>
+            <v-list-item v-if="box.usercfgs.isDebugWeb">
+              <v-list-item-content>
+                <v-text-field
+                  :hint="$t('prefs.debugPageDesc')"
+                  :label="$t('prefs.debugPage')"
+                  @change="saveUserCfgs"
+                  clearable
+                  persistent-hint
+                  placeholder="http://ip:port/boxjs.html"
+                  v-model="box.usercfgs.debugger_web"
+                >
+                </v-text-field>
+              </v-list-item-content>
+            </v-list-item>
+            <v-list-item class="mt-4"></v-list-item>
+          </v-list>
+        </v-navigation-drawer>
+        <!-- 主页 -->
+        <v-main class="appBarBind.app ? 'safe' : ''" v-scroll="onScroll">
+          <v-snackbar top app v-model="ui.snackbar.show" v-bind="ui.snackbar">{{ui.snackbar.msg}}</v-snackbar>
+          <!-- 主页 -->
+          <v-container
+            fluid
+            v-show="view === ''"
+            v-touch="{
+              up: () => {
+                if (isWallpaperMode) {
+                  clearWallpaper()
+                  setWallpaper()
+                }
+              },
+              down: () => {
+                if (isWallpaperMode) {
+                  isWallpaperMode = !isWallpaperMode
+                  changeWallpaper()
+                }
+              }
+            }"
+          >
+            <v-row no-gutters v-show="!isHidedAppIcons" class="align-self-start" id="appList">
+              <v-col cols="3" md="2" v-for="(app, appIdx) in favApps" :key="app.id" class="d-flex justify-space-around">
+                <div class="ma-2 appicon" @click="switchAppView(app.id)">
+                  <v-card v-if="isDarkMode" style="border-radius: 12px">
+                    <v-img style="border-radius: 12px" :aspect-ratio="1" width="54" height="54" contain v-ripple :src="app.icon"></v-img>
+                  </v-card>
+                  <v-img
+                    v-else
+                    style="border-radius: 12px"
+                    :aspect-ratio="1"
+                    width="54"
+                    height="54"
+                    contain
+                    v-ripple
+                    class="elevation-3"
+                    :src="app.icon"
+                  ></v-img>
+                  <p class="text-center ma-0">
+                    <span class="d-inline-block text-truncate font-weight-bold" :style="appIconFontStyle"> {{app.name}} </span>
+                  </p>
+                </div>
+              </v-col>
+            </v-row>
+          </v-container>
+          <!-- 应用列表 -->
+          <v-container fluid v-show="view === 'app' && !curapp">
+            <!-- 收藏应用 -->
+            <v-expansion-panels multiple class="mb-4" v-if="favApps.length > 0" v-model="box.usercfgs.favapppanel">
+              <v-expansion-panel>
+                <v-expansion-panel-header> {{ $t('apps.fav') }} ({{favApps.length}}) </v-expansion-panel-header>
+                <v-expansion-panel-content>
+                  <v-list dense nav class="ma-n4">
+                    <template v-for="(app, appIdx) in favApps">
+                      <v-list-item dense @click="switchAppView(app.id)" :key="app.id">
+                        <v-list-item-avatar class="elevation-3"><v-img :src="app.icon" /></v-list-item-avatar>
+                        <v-list-item-content>
+                          <v-list-item-title>{{app.name}} ({{app.id}})</v-list-item-title>
+                          <v-list-item-subtitle>{{app.repo}}</v-list-item-subtitle>
+                          <v-list-item-subtitle>{{app.author}}</v-list-item-subtitle>
+                        </v-list-item-content>
+                        <v-list-item-action>
+                          <v-menu bottom left>
+                            <template #activator="{ on }">
+                              <v-btn icon v-on="on"><v-icon>mdi-dots-vertical</v-icon></v-btn>
+                            </template>
+                            <v-list>
+                              <v-list-item dense v-if="appIdx > 0" @click="moveFav(appIdx, -1)">
+                                <v-list-item-title>{{ $t('base.sort.up') }}</v-list-item-title>
+                              </v-list-item>
+                              <v-list-item dense v-if="appIdx + 1 < favApps.length" @click="moveFav(appIdx, 1)">
+                                <v-list-item-title>{{ $t('base.sort.dn') }}</v-list-item-title>
+                              </v-list-item>
+                              <v-divider v-if="favApps.length > 1"></v-divider>
+                              <v-list-item dense @click="favApp(app.id)">
+                                <v-list-item-title>{{ $t('apps.unStar') }}</v-list-item-title>
+                              </v-list-item>
+                            </v-list>
+                          </v-menu>
+                        </v-list-item-action>
+                      </v-list-item>
+                      <!-- <v-divider inset v-if="favApps.length !== appIdx + 1"></v-divider> -->
+                    </template>
+                  </v-list>
+                </v-expansion-panel-content>
+              </v-expansion-panel>
+            </v-expansion-panels>
+            <!-- 订阅应用 -->
+            <v-expansion-panels multiple class="mb-4" v-if="appSubs.length > 0" v-model="box.usercfgs.subapppanel">
+              <v-expansion-panel v-for="(sub, subIdx) in appSubs" :key="sub.id" v-if="!sub.isErr">
+                <v-expansion-panel-header> {{sub.name}} ({{sub.apps.length}}) </v-expansion-panel-header>
+                <v-expansion-panel-content>
+                  <v-list dense nav class="ma-n4">
+                    <template v-for="(app, appIdx) in sub.apps">
+                      <v-list-item dense @click="switchAppView(app.id)" :key="app.id">
+                        <v-list-item-avatar class="elevation-3"><v-img :src="app.icon" /></v-list-item-avatar>
+                        <v-list-item-content>
+                          <v-list-item-title>{{app.name}} ({{app.id}})</v-list-item-title>
+                          <v-list-item-subtitle>{{app.repo}}</v-list-item-subtitle>
+                          <v-list-item-subtitle>{{app.author}}</v-list-item-subtitle>
+                        </v-list-item-content>
+                        <v-list-item-action>
+                          <v-btn icon @click.stop="favApp(app.id)">
+                            <v-icon :color="app.favIconColor" v-text="app.favIcon" />
+                          </v-btn>
+                        </v-list-item-action>
+                      </v-list-item>
+                      <!-- <v-divider inset v-if="sub.apps.length !== appIdx + 1"></v-divider> -->
+                    </template>
+                  </v-list>
+                </v-expansion-panel-content>
+              </v-expansion-panel>
+            </v-expansion-panels>
+            <!-- 内置应用 -->
+            <v-expansion-panels multiplev-if="sysApps.length > 0" v-model="box.usercfgs.sysapppanel">
+              <v-expansion-panel>
+                <v-expansion-panel-header> {{ $t('apps.sysApps') }} ({{sysApps.length}}) </v-expansion-panel-header>
+                <v-expansion-panel-content>
+                  <v-list dense nav class="ma-n4">
+                    <template v-for="(app, appIdx) in sysApps">
+                      <v-list-item dense @click="switchAppView(app.id)" :key="app.id">
+                        <v-list-item-avatar class="elevation-3"><v-img :src="app.icon" /></v-list-item-avatar>
+                        <v-list-item-content>
+                          <v-list-item-title>{{app.name}} ({{app.id}})</v-list-item-title>
+                          <v-list-item-subtitle>{{app.repo}}</v-list-item-subtitle>
+                          <v-list-item-subtitle>{{app.author}}</v-list-item-subtitle>
+                        </v-list-item-content>
+                        <v-list-item-action>
+                          <v-btn icon @click.stop="favApp(app.id)">
+                            <v-icon :color="app.favIconColor" v-text="app.favIcon" />
+                          </v-btn>
+                        </v-list-item-action>
+                      </v-list-item>
+                      <!-- <v-divider inset v-if="sysApps.length !== appIdx + 1"></v-divider> -->
+                    </template>
+                  </v-list>
+                </v-expansion-panel-content>
+              </v-expansion-panel>
+            </v-expansion-panels>
+          </v-container>
+          <!-- 订阅列表 -->
+          <v-container fluid v-show="view === 'sub'">
+            <template v-if="appSubs.length === 0">
+              <v-btn block class="primary" @click="addAppSubDialog = true">{{ $t('subs.add') }}</v-btn>
+              <v-btn block class="primary" @click="open('https://chavyleung.gitbook.io/boxjs/awesome/subscriptions')">
+                <v-icon class="mr-2">mdi-cloud</v-icon>{{ $t('subs.moreSubs') }}
+              </v-btn>
+            </template>
+            <v-card v-else>
+              <v-list dense nav>
+                <v-subheader inset dense>
+                  {{ $t('subs.appSubs') }} ({{appSubs.length}})
+                  <v-spacer></v-spacer>
+                  <v-btn icon @click="open('https://chavyleung.gitbook.io/boxjs/awesome/subscriptions')">
+                    <v-icon>mdi-cloud-circle</v-icon>
+                  </v-btn>
+                  <v-btn icon @click="reloadAppSub()">
+                    <v-icon>mdi-refresh-circle</v-icon>
+                  </v-btn>
+                  <v-btn icon>
+                    <v-icon color="primary" @click="addAppSubDialog = true">mdi-plus-circle</v-icon>
+                  </v-btn>
+                </v-subheader>
+                <template v-for="(sub, subIdx) in appSubs">
+                  <v-list-item dense two-line @click="reloadAppSub(sub)" :key="sub.id">
+                    <v-list-item-avatar v-if="sub.icon"><v-img :src="sub.icon" /></v-list-item-avatar>
+                    <v-list-item-avatar v-else color="primary"><v-icon dark>mdi-account</v-icon></v-list-item-avatar>
+                    <v-list-item-content>
+                      <v-list-item-title>
+                        {{sub.name}} ({{sub.apps.length}})
+                        <v-chip v-if="sub.isErr" color="pink" dark x-small class="ml-1 mb-1">{{ $t('subs.errData') }}</v-chip>
+                      </v-list-item-title>
+                      <v-list-item-subtitle>{{sub.repo ? sub.repo : sub.url}}</v-list-item-subtitle>
+                      <v-list-item-subtitle>{{sub.author ? sub.author : '@anonymous'}}</v-list-item-subtitle>
+                      <v-list-item-subtitle>
+                        {{ $t('subs.updated') }}: {{ timeago.format(sub.updateTime, timeagoLang.replace('-', '_')) }}
+                      </v-list-item-subtitle>
+                    </v-list-item-content>
+                    <v-list-item-action>
+                      <v-menu bottom left>
+                        <template #activator="{ on }">
+                          <v-btn icon v-on="on"><v-icon>mdi-dots-vertical</v-icon></v-btn>
+                        </template>
+                        <v-list dense>
+                          <template v-if="sub.onInstall">
+                            <v-list-item @click="openInstall(sub.raw.id)">
+                              <v-list-item-title>{{ $t('subs.install') }}</v-list-item-title>
+                            </v-list-item>
+                            <v-divider></v-divider>
+                          </template>
+                          <v-list-item @click="open(sub.repo)">
+                            <v-list-item-title>{{ $t('subs.repo') }}</v-list-item-title>
+                          </v-list-item>
+                          <v-list-item @click="copy(sub.url)">
+                            <v-list-item-title>{{ $t('base.cmd.cp') }}</v-list-item-title>
+                          </v-list-item>
+                          <v-list-item @click="share(sub.url)">
+                            <v-list-item-title>{{ $t('base.cmd.share') }}</v-list-item-title>
+                          </v-list-item>
+                          <v-divider></v-divider>
+                          <v-list-item v-if="subIdx > 0" @click="moveSub(subIdx, -1)">
+                            <v-list-item-title>{{ $t('base.sort.up') }}</v-list-item-title>
+                          </v-list-item>
+                          <v-list-item v-if="subIdx + 1 < appSubs.length" @click="moveSub(subIdx, 1)">
+                            <v-list-item-title>{{ $t('base.sort.dn') }}</v-list-item-title>
+                          </v-list-item>
+                          <v-divider></v-divider>
+                          <v-list-item @click="delSub(subIdx)">
+                            <v-list-item-title class="text-uppercase red--text">{{ $t('base.cmd.del') }}</v-list-item-title>
+                          </v-list-item>
+                        </v-list>
+                      </v-menu>
+                    </v-list-item-action>
+                  </v-list-item>
+                  <!-- <v-divider inset v-if="appSubs.length !== subIdx + 1"></v-divider> -->
+                </template>
+              </v-list>
+            </v-card>
+            <v-dialog v-model="addAppSubDialog" scrollable>
+              <v-card>
+                <v-card-title>{{ $t('subs.addDialog.title') }}</v-card-title>
+                <v-divider></v-divider>
+                <v-card-text>
+                  <v-textarea
+                    :label="$t('subs.addDialog.url')"
+                    :hint="$t('subs.addDialog.urlDesc')"
+                    autofocus
+                    clearable
+                    persistent-hint
+                    rows="3"
+                    v-model="ui.addAppSubDialog.url"
+                  ></v-textarea>
+                </v-card-text>
+                <v-divider></v-divider>
+                <v-card-actions>
+                  <v-spacer></v-spacer>
+                  <v-btn text small color="grey" @click="addAppSubDialog = false"> {{$t('base.dialog.close')}} </v-btn>
+                  <v-btn text small color="primary" @click="addAppSub(ui.addAppSubDialog.url)" :loading="isLoading">
+                    {{$t('base.dialog.save')}}
+                  </v-btn>
+                </v-card-actions>
+              </v-card>
+            </v-dialog>
+            <v-dialog persistent v-model="ui.installConfirmDialog.show">
+              <v-card>
+                <v-card-title>{{ ui.installConfirmDialog.title }}</v-card-title>
+                <v-card-text> {{ ui.installConfirmDialog.message }}</v-card-text>
+                <v-card-actions>
+                  <v-spacer></v-spacer>
+                  <v-btn text small color="grey" @click="ui.installConfirmDialog.show = false"> {{$t('base.dialog.close')}} </v-btn>
+                  <v-btn text small color="primary" @click="install(ui.installConfirmDialog.url)" :loading="isLoading">
+                    {{$t('base.dialog.ok')}}
+                  </v-btn>
+                </v-card-actions>
+              </v-card>
+            </v-dialog>
+          </v-container>
+          <!-- 我的 -->
+          <v-container fluid v-show="view === 'my'">
+            <v-card class="mx-auto">
+              <v-card-title class="headline">
+                {{box.usercfgs.name ? box.usercfgs.name : $t('profile.leaveName')}}
+                <v-spacer></v-spacer>
+                <v-dialog v-model="ui.editProfileDialog.show">
+                  <template #activator="{ on }">
+                    <v-btn icon v-on="on"><v-icon>mdi-cog-outline</v-icon></v-btn>
+                  </template>
+                  <v-card>
+                    <v-card-title>{{ $t('profile.editor.title') }}</v-card-title>
+                    <v-divider></v-divider>
+                    <v-card-text>
+                      <v-text-field
+                        :hint="$t('profile.editor.nameDesc')"
+                        :label="$t('profile.editor.name')"
+                        v-model="box.usercfgs.name"
+                      ></v-text-field>
+                      <v-text-field
+                        :hint="$t('profile.editor.avatarDesc')"
+                        :label="$t('profile.editor.avatar')"
+                        v-model="box.usercfgs.icon"
+                      ></v-text-field>
+                    </v-card-text>
+                    <v-divider></v-divider>
+                    <v-card-actions>
+                      <v-spacer></v-spacer>
+                      <v-btn text small color="grey" @click="ui.editProfileDialog.show = false">{{ $t('base.dialog.close') }}</v-btn>
+                      <v-btn text small color="primary" @click="ui.editProfileDialog.show = false" :loading="isLoading">
+                        {{ $t('base.dialog.save') }}
+                      </v-btn>
+                    </v-card-actions>
+                  </v-card>
+                </v-dialog>
+              </v-card-title>
+              <v-divider class="mx-4"></v-divider>
+              <v-card-text>
+                <span class="subheading">{{ $t('profile.datas') }}</span>
+                <v-chip-group>
+                  <v-chip small>{{ $t('profile.apps') }}: {{this.apps.length}}</v-chip>
+                  <v-chip small>{{ $t('profile.subs') }}: {{this.appSubs.length}}</v-chip>
+                  <v-chip small>{{ $t('profile.sessions') }}: {{this.sessions.length}}</v-chip>
+                </v-chip-group>
+              </v-card-text>
+              <v-card-actions>
+                <v-spacer></v-spacer>
+                <v-btn small class="mr-2" @click="switchView('viewer')"> {{ $t('profile.dataviewer')}} </v-btn>
+                <v-dialog v-model="ui.impGlobalBakDialog.show">
+                  <template #activator="{ on }">
+                    <v-btn small v-on="on">{{ $t('profile.imp') }}</v-btn>
+                  </template>
+                  <v-card>
+                    <v-card-title> {{ $t('profile.impDialog.title') }} </v-card-title>
+                    <v-divider></v-divider>
+                    <v-card-text>
+                      <v-textarea
+                        :hint="$t('profile.impDialog.impDataDesc')"
+                        :label="$t('profile.impDialog.impData')"
+                        autofocus
+                        clearable
+                        rows="3"
+                        v-model="ui.impGlobalBakDialog.impval"
+                      ></v-textarea>
+                    </v-card-text>
+                    <v-divider></v-divider>
+                    <v-card-actions>
+                      <v-spacer></v-spacer>
+                      <v-btn text small color="grey" text @click="ui.impGlobalBakDialog.show = false">{{ $t('base.dialog.close') }}</v-btn>
+                      <v-btn text small color="primary" text @click="impGlobalBak" :loading="isLoading">{{ $t('profile.imp') }}</v-btn>
+                    </v-card-actions>
+                  </v-card>
+                </v-dialog>
+                <v-btn small @click="saveGlobalBak">{{ $t('profile.bak') }}</v-btn>
+              </v-card-actions>
+            </v-card>
+            <v-card class="mt-4" v-if="box.globalbaks">
+              <template v-for="(bak, bakIdx) in box.globalbaks">
+                <v-divider v-if="bakIdx>0"></v-divider>
+                <v-list-item dense @click="switchBakView(bak.id)">
+                  <v-list-item-content>
+                    <v-list-item-title>{{bak.name}}</v-list-item-title>
+                    <v-list-item-subtitle>{{dayjs(bak.createTime).format('YYYY-MM-DD HH:mm:ss')}}</v-list-item-subtitle>
+                    <v-list-item-subtitle>
+                      <v-chip x-small class="mr-2" v-for="(tag, tagIdx) in bak.tags" :key="tagIdx">{{tag}}</v-chip>
+                    </v-list-item-subtitle>
+                  </v-list-item-content>
+                  <v-list-item-action>
+                    <v-btn icon><v-icon>mdi-chevron-right</v-icon></v-btn>
+                  </v-list-item-action>
+                </v-list-item>
+              </template>
+            </v-card>
+          </v-container>
+          <!-- 数据查看 -->
+          <v-container fluid v-show="view === 'viewer'">
+            <v-card class="mb-4">
+              <v-subheader>
+                {{ $t('viewer.dataViewer') }}
+                <v-spacer></v-spacer>
+                <v-btn color="primary" small @click="copy(ui.viewer.key)"> {{ $t('base.cmd.cp') }} </v-btn>
+              </v-subheader>
+              <v-card-text>
+                <v-text-field
+                  :hint="$t('viewer.dataKeyDesc')"
+                  :label="$t('viewer.dataKey')"
+                  persistent-hint
+                  placeholder="boxjs_host"
+                  v-model="ui.viewer.key"
+                >
+                </v-text-field>
+              </v-card-text>
+              <v-divider></v-divider>
+              <v-card-actions>
+                <!-- TODO 列出最近查询过的 key -->
+                <v-spacer></v-spacer>
+                <v-btn small text color="primary" @click="queryData">{{ $t('base.dialog.view') }}</v-btn>
+              </v-card-actions>
+            </v-card>
+            <v-card class="mb-4">
+              <v-subheader>
+                {{ $t('viewer.dataEditor') }}
+                <v-spacer></v-spacer>
+                <v-btn color="primary" small @click="copy(ui.viewer.val)"> {{ $t('base.cmd.cp') }} </v-btn>
+              </v-subheader>
+              <v-card-text>
+                <v-textarea v-model="ui.viewer.val" :row="3" :label="$t('viewer.dataVal')"> </v-textarea>
+              </v-card-text>
+              <v-divider></v-divider>
+              <v-card-actions>
+                <v-spacer></v-spacer>
+                <v-btn small text color="primary" @click="saveData">{{ $t('base.dialog.save') }}</v-btn>
+              </v-card-actions>
+            </v-card>
+          </v-container>
+          <!-- 代码编辑 -->
+          <v-container fluid v-show="view === 'coding'">
+            <v-card rounded="0" flat style="width: inherit">
+              <v-subheader>
+                <h2>{{ $t('codding.title') }}</h2>
+                <v-spacer></v-spacer>
+                <v-btn icon @click="runTxtScript" :loading="isLoading">
+                  <v-icon color="primary">mdi-play-circle</v-icon>
+                </v-btn>
+              </v-subheader>
+            </v-card>
+            <div class="pa-0" id="container" style="width: inherit; height: inherit"></div>
+          </v-container>
+          <!-- 应用详情 -->
+          <v-container fluid v-if="view === 'app' && !!curapp">
+            <v-subheader>
+              <h2 :style="appTitleStyle">{{curapp.name}}</h2>
+              <v-spacer></v-spacer>
+              <v-btn v-if="curapp.script" icon :loading="isLoading" @click="runRemoteScript(curapp.script, curapp.script_timeout)">
+                <v-icon color="primary">mdi-play-circle</v-icon>
+              </v-btn>
+            </v-subheader>
+            <v-card class="mb-4" v-if="curapp.desc || curapp.descs || curapp.desc_html || curapp.descs_html">
+              <v-card-subtitle>
+                <p v-if="curapp.desc" v-text="curapp.desc" class="text-pre-wrap"></p>
+                <p
+                  v-for="(desc, descIdx) in curapp.descs"
+                  v-text="desc"
+                  :class="curapp.descs.length === descIdx + 1 ? 'text-pre-wrap' : 'mb-0 text-pre-wrap'"
+                ></p>
+                <p v-if="curapp.desc_html" v-html="curapp.desc_html"></p>
+                <div v-for="(desc_html, desc_htmlIdx) in curapp.descs_html" v-html="desc_html"></div>
+              </v-card-subtitle>
+            </v-card>
+            <v-card class="mb-4">
+              <template v-if="curapp.scripts">
+                <v-subheader> {{ $t('appDetail.scripts') }} ({{curapp.scripts.length}}) </v-subheader>
+                <v-list dense>
+                  <v-list-item v-for="(script, scriptIdx) in curapp.scripts" :key="scriptIdx">
+                    <v-list-item-title> {{scriptIdx + 1}}. {{script.name}} </v-list-item-title>
+                    <v-btn icon :loading="isLoading" @click.stop="runRemoteScript(script.script, script.script_timeout)">
+                      <v-icon>mdi-play-circle</v-icon>
+                    </v-btn>
+                  </v-list-item>
+                </v-list>
+              </template>
+            </v-card>
+            <v-card class="mb-4">
+              <template v-if="curapp.settings">
+                <v-subheader> {{ $t('appDetail.settings') }} ({{curapp.settings.length}}) </v-subheader>
+                <v-form class="pl-4 pr-4 pb-4">
+                  <template v-for="(setting, settingIdx) in curapp.settings">
+                    <v-slider
+                      v-model="setting.val"
+                      v-bind="setting"
+                      class="mt-4"
+                      dense
+                      persistent-hint
+                      :label="setting.name"
+                      :hint="setting.desc"
+                      thumb-label="always"
+                      v-if="setting.type === 'slider'"
+                    ></v-slider>
+                    <v-switch
+                      v-model="setting.val"
+                      class="mt-2"
+                      persistent-hint
+                      dense
+                      :label="setting.name"
+                      :hint="setting.desc"
+                      v-else-if="setting.type === 'boolean'"
+                    ></v-switch>
+                    <v-textarea
+                      v-model="setting.val"
+                      v-bind="setting"
+                      class="mt-4"
+                      :row="3"
+                      :label="setting.name"
+                      :hint="setting.desc"
+                      v-else-if="setting.type === 'textarea'"
+                    ></v-textarea>
+                    <v-radio-group
+                      v-model="setting.val"
+                      v-bind="setting"
+                      persistent-hint
+                      class="mt-0"
+                      :hint="setting.desc"
+                      v-else-if="setting.type === 'radios'"
+                    >
+                      <v-subheader class="mb-n4 pa-0">{{setting.name}}</v-subheader>
+                      <v-radio
+                        :class="itemIdx === 0 ? 'mt-2' : ''"
+                        v-for="(item, itemIdx) in setting.items"
+                        :label="item.label"
+                        :value="item.key"
+                        :key="item.key"
+                      ></v-radio>
+                    </v-radio-group>
+                    <template v-else-if="setting.type === 'checkboxes'">
+                      <v-subheader class="mb-n8 pa-0">{{setting.name}}</v-subheader>
+                      <v-item-group class="mt-4 pt-1">
+                        <v-checkbox
+                          v-model="setting.val"
+                          class="mt-0"
+                          persistent-hint
+                          :hide-details="itemIdx + 1 !== setting.items.length"
+                          :hint="setting.desc"
+                          :label="item.label"
+                          :value="item.key"
+                          v-for="(item, itemIdx) in setting.items"
+                          :key="item.key"
+                          multiple
+                        ></v-checkbox>
+                      </v-item-group>
+                    </template>
+                    <template v-else-if="setting.type === 'colorpicker'">
+                      <v-subheader class="mb-n2 pa-0">{{setting.name}}</v-subheader>
+                      <v-color-picker
+                        v-model="setting.val"
+                        v-bind="setting"
+                        class="mt-2 mb-4"
+                        persistent-hint
+                        :hint="setting.desc"
+                        :hide-canvas="!setting.canvas"
+                        :dot-size="30"
+                        mode="hexa"
+                        light
+                      ></v-color-picker>
+                    </template>
+                    <div class="mt-4" v-else-if="setting.type === 'number'">
+                      <v-text-field
+                        v-model="setting.val"
+                        v-bind="setting"
+                        type="number"
+                        :label="setting.name"
+                        :hint="setting.desc"
+                      ></v-text-field>
+                    </div>
+                    <div class="mt-4" v-else-if="setting.type === 'selects'">
+                      <v-select
+                        v-model="setting.val"
+                        v-bind="setting"
+                        persistent-hint
+                        type="number"
+                        item-text="label"
+                        item-value="key"
+                        :items="setting.items"
+                        :label="setting.name"
+                        :hint="setting.desc"
+                      ></v-select>
+                    </div>
+                    <div class="mt-4" v-else>
+                      <v-text-field v-model="setting.val" v-bind="setting" :label="setting.name" :hint="setting.desc"></v-text-field>
+                    </div>
+                  </template>
+                </v-form>
+                <v-divider></v-divider>
+                <v-card-actions>
+                  <v-spacer></v-spacer>
+                  <v-btn small text color="primary" @click="saveAppSettings">{{ $t('base.dialog.save') }}</v-btn>
+                </v-card-actions>
+              </template>
+            </v-card>
+            <v-card class="mx-auto" v-if="curapp.datas && curapp.datas.length > 0">
+              <v-subheader>
+                {{ $t('appDetail.curSession') }}
+                <a class="ml-2">{{curapp.curSession ? curapp.curSession.name : ''}}</a>
+                <v-spacer></v-spacer>
+                <v-menu bottom left>
+                  <template #activator="{ on }">
+                    <v-btn icon v-on="on"><v-icon>mdi-dots-vertical</v-icon></v-btn>
+                  </template>
+                  <v-list dense>
+                    <v-list-item @click="copy(JSON.stringify(curapp))">
+                      <v-list-item-title>{{ $t('base.cmd.cp') }}</v-list-item-title>
+                    </v-list-item>
+                    <v-dialog v-model="ui.impAppDatasDialog.show">
+                      <template #activator="{ on }">
+                        <v-list-item v-on="on">
+                          <v-list-item-title>{{ $t('base.cmd.imp') }}</v-list-item-title>
+                        </v-list-item>
+                      </template>
+                      <v-card>
+                        <v-card-title> {{ $t('appDetail.impDialog.title') }} </v-card-title>
+                        <v-divider></v-divider>
+                        <v-card-text>
+                          <v-textarea
+                            v-model="ui.impAppDatasDialog.impval"
+                            rows="3"
+                            clearable
+                            autofocus
+                            :label="$t('appDetail.impDialog.data')"
+                            :hint="$t('appDetail.impDialog.dataDesc')"
+                          ></v-textarea>
+                        </v-card-text>
+                        <v-divider></v-divider>
+                        <v-card-actions>
+                          <v-spacer></v-spacer>
+                          <v-btn text small color="grey" text @click="ui.impAppDatasDialog.show = false">
+                            {{ $t('base.dialog.close') }}
+                          </v-btn>
+                          <v-btn text small color="primary" text @click="impAppDatas()" :loading="isLoading">
+                            {{ $t('base.cmd.imp') }}
+                          </v-btn>
+                        </v-card-actions>
+                      </v-card>
+                    </v-dialog>
+                    <v-list-item @click="copyData(curapp)">
+                      <v-list-item-title>{{ $t('appDetail.copyDatas') }}</v-list-item-title>
+                    </v-list-item>
+                    <v-divider></v-divider>
+                    <v-list-item @click="clearAppDatas()">
+                      <v-list-item-title class="text-uppercase red--text">{{ $t('appDetail.clearDatas') }}</v-list-item-title>
+                    </v-list-item>
+                  </v-list>
+                </v-menu>
+              </v-subheader>
+              <v-list-item two-line dense v-for="(data, dataIdx) in curapp.datas" :key="dataIdx">
+                <v-list-item-content>
+                  <v-list-item-title>{{data.key}}</v-list-item-title>
+                  <v-list-item-subtitle>{{data.val ? data.val : $t('appDetail.noDatas')}}</v-list-item-subtitle>
+                </v-list-item-content>
+                <v-list-item-action>
+                  <v-btn icon @click.stop="clearAppDatas(data.key)">
+                    <v-icon color="grey">mdi-close</v-icon>
+                  </v-btn>
+                </v-list-item-action>
+              </v-list-item>
+              <v-divider></v-divider>
+              <v-card-actions>
+                <v-spacer></v-spacer>
+                <v-btn small text color="primary" @click="saveAppSession">{{ $t('base.cmd.duplicate') }}</v-btn>
+              </v-card-actions>
+            </v-card>
+            <v-card :id="session.id" class="ml-10 mt-4" v-for="(session, sessionIdx) in curapp.sessions" :key="session.id">
+              <v-subheader>
+                <a v-if="curapp.curSession && curapp.curSession.id === session.id">#{{sessionIdx + 1}} {{session.name}}</a>
+                <template v-else>#{{sessionIdx + 1}} {{session.name}}</template>
+                <v-spacer></v-spacer>
+                <v-menu bottom left>
+                  <template #activator="{ on }">
+                    <v-btn icon v-on="on"><v-icon>mdi-dots-vertical</v-icon></v-btn>
+                  </template>
+                  <v-list dense>
+                    <v-dialog v-model="ui.modSessionDialog.show">
+                      <template #activator="{ on }">
+                        <v-list-item v-on="on">
+                          <v-list-item-title>{{ $t('base.cmd.mod') }}</v-list-item-title>
+                        </v-list-item>
+                      </template>
+                      <v-card>
+                        <v-card-title>{{ $t('appDetail.sessionEditor.title') }}</v-card-title>
+                        <v-divider></v-divider>
+                        <v-card-text>
+                          <v-text-field class="mt-4" :label="$t('appDetail.sessionEditor.name')" v-model="session.name"></v-text-field>
+                          <v-text-field
+                            v-for="(data, dataIdx) in session.datas"
+                            :key="dataIdx"
+                            v-model="data.val"
+                            :label="data.key"
+                          ></v-text-field>
+                        </v-card-text>
+                        <v-divider></v-divider>
+                        <v-card-actions>
+                          <v-spacer></v-spacer>
+                          <v-btn text small color="grey" text @click="ui.modSessionDialog.show = false"
+                            >{{ $t('base.dialog.close') }}</v-btn
+                          >
+                          <v-btn text small color="primary" text @click="updateAppSession(session)" :loading="isLoading"
+                            >{{ $t('base.dialog.save') }}</v-btn
+                          >
+                        </v-card-actions>
+                      </v-card>
+                    </v-dialog>
+                    <v-divider></v-divider>
+                    <v-list-item @click="delAppSession(session.id)">
+                      <v-list-item-title>{{ $t('base.cmd.del') }}</v-list-item-title>
+                    </v-list-item>
+                  </v-list>
+                </v-menu>
+              </v-subheader>
+              <v-list-item two-line dense v-for="(data, dataIdx) in session.datas" :key="dataIdx">
+                <v-list-item-content>
+                  <v-list-item-title>{{data.key}}</v-list-item-title>
+                  <v-list-item-subtitle>{{data.val ? data.val : $t('appDetail.noDatas')}}</v-list-item-subtitle>
+                </v-list-item-content>
+              </v-list-item>
+              <v-divider></v-divider>
+              <v-card-actions>
+                <v-btn small text color="grey">{{dayjs(session.createTime).format('YYYY-MM-DD HH:mm:ss')}}</v-btn>
+                <v-spacer></v-spacer>
+                <v-btn small text color="primary" @click="useAppSession(session.id)">{{ $t('base.dialog.apply') }}</v-btn>
+              </v-card-actions>
+            </v-card>
+          </v-container>
+          <!-- 备份详情 -->
+          <v-container fluid v-else-if="view === 'bak' && !!curbak">
+            <v-subheader>
+              <h2 :style="appTitleStyle">{{curbak.name}}</h2>
+              <v-spacer></v-spacer>
+              <v-btn color="primary" small @click="revertGlobalBak"> {{ $t('base.cmd.recovery') }} </v-btn>
+            </v-subheader>
+            <v-card class="mb-4">
+              <v-subheader> {{ $t('bakDetail.title') }} </v-subheader>
+              <v-card-text>
+                <v-text-field :label="$t('bakDetail.id')" v-model="curbak.id" readonly> </v-text-field>
+                <v-text-field :label="$t('bakDetail.name')" v-model="curbak.name" @change="updateGlobalBak"> </v-text-field>
+              </v-card-text>
+              <v-divider></v-divider>
+              <v-card-actions>
+                <v-spacer></v-spacer>
+                <v-btn small text color="error" @click="delGlobalBak">{{ $t('base.cmd.del') }}</v-btn>
+              </v-card-actions>
+            </v-card>
+            <v-card class="mb-4">
+              <v-subheader>
+                {{ $t('bakDetail.dataTitle') }}
+                <v-spacer></v-spacer>
+                <v-btn color="primary" small @click="copy(JSON.stringify(curbak.bak))"> {{ $t('base.cmd.cp') }} </v-btn>
+              </v-subheader>
+            </v-card>
+          </v-container>
+          <!-- 计算器 -->
+          <v-container fluid v-else-if="view === 'calculator'">
+            <h3>Surge 费用计算器(open AI 编写)</h3>
+            <div class="text-body-2 grey--text text--darken-2">仅供参考,最终价格以实际为准</div>
+            <div class="mt-4">
+              <v-text-field v-model="purchaseDate" label="购买日期" type="date"></v-text-field>
+              <v-select v-model="licenseType" :items="licenseTypes" label="设备授权数"></v-select>
+              <v-btn @click="calculateCost">计算费用</v-btn>
+              <p class="mt-2">费用:{{ cost.toFixed(2) }}</p>
+            </div>       
+          </v-container>
+        </v-main>
+        <!-- 底部 -->
+        <v-bottom-navigation ref="naviBar" v-bind="naviBarBind" v-touch="{ down: () => isHidedNaviBottom = true }">
+          <v-progress-linear :active="isLoading" height="2" absolute top indeterminate></v-progress-linear>
+          <v-btn @click="switchView('')" value="">{{ $t('menus.home') }}<v-icon>mdi-home</v-icon></v-btn>
+          <v-btn @click="switchView('app')" value="app">{{ $t('menus.apps') }}<v-icon>mdi-application</v-icon></v-btn>
+          <v-btn @click="switchView('sub')" value="sub">{{ $t('menus.subs') }}<v-icon>mdi-database</v-icon></v-btn>
+          <v-btn @click="switchView('my')" value="my">
+            <template v-if="myIcon">
+              <span v-if="!isHideMyTitle">{{ $t('menus.profile') }}</span>
+              <v-avatar :size="isHideMyTitle ? 36 : 24"><v-img :src="myIcon" /></v-avatar>
+            </template>
+            <template v-else>
+              <span v-if="!isHideMyTitle">{{ $t('menus.profile') }}</span>
+              <v-icon :size="isHideMyTitle ? 36 : 24">mdi-face-profile</v-icon>
+            </template>
+          </v-btn>
+        </v-bottom-navigation>
+        <v-fab-transition>
+          <v-speed-dial
+            v-show="!box.usercfgs.isHideBoxIcon && !isWallpaperMode"
+            direction="top"
+            fixed
+            fab
+            bottom
+            :left="box.usercfgs.isLeftBoxIcon"
+            :right="!box.usercfgs.isLeftBoxIcon === true"
+          >
+            <template #activator>
+              <v-btn
+                fab
+                text
+                @dblclick="reload()"
+                v-touch="{
+                  left: () => box.usercfgs.isLeftBoxIcon = true,
+                  right: () => box.usercfgs.isLeftBoxIcon = false,
+                  up: () => {
+                    clearWallpaper()
+                    setWallpaper()
+                  },
+                  down: () => {
+                    isWallpaperMode = !!!isWallpaperMode
+                    changeWallpaper()
+                  }
+                }"
+              >
+                <v-avatar><img :src="box.syscfgs.boxjs.icons[iconThemeIdx]" /></v-avatar>
+              </v-btn>
+            </template>
+            <v-btn dark v-if="!box.usercfgs.isHideHelp" fab small color="grey" @click="open('https://chavyleung.gitbook.io/boxjs')">
+              <v-icon>mdi-help</v-icon>
+            </v-btn>
+            <v-btn dark v-if="!box.usercfgs.isHideHelp" fab small color="purple" @click="ui.versionSheet.show = true">
+              <v-icon>mdi-new-box</v-icon>
+            </v-btn>
+            <v-btn dark v-if="!box.usercfgs.isCalculator" fab small color="yellow" @click="switchView('calculator')">
+              <v-icon>mdi-calculator-variant-outline</v-icon>
+            </v-btn>
+            <v-btn dark fab small color="pink" @click="box.usercfgs.isLeftBoxIcon = !box.usercfgs.isLeftBoxIcon">
+              <v-icon> {{box.usercfgs.isLeftBoxIcon ? 'mdi-format-horizontal-align-right' : 'mdi-format-horizontal-align-left'}} </v-icon>
+            </v-btn>
+            <v-btn dark v-if="!box.usercfgs.isHideRefresh" fab small color="orange" @click="reload()">
+              <v-icon>mdi-refresh</v-icon>
+            </v-btn>
+            <v-btn dark v-if="!box.usercfgs.isHideCoding" fab small @click="switchView('coding')">
+              <v-icon>mdi-code-tags</v-icon>
+            </v-btn>
+            <v-btn dark v-if="!box.usercfgs.isHidedSearch" fab small color="green" @click="ui.searchDialog.show = true">
+              <v-icon>mdi-magnify</v-icon>
+            </v-btn>
+          </v-speed-dial>
+        </v-fab-transition>
+        <v-bottom-sheet v-model="ui.versionSheet.show" scrollable fullscreen>
+          <v-card v-if="box.versions">
+            <v-subheader v-touch="{ down: () => ui.versionSheet.show = false }">
+              <v-btn icon small @click="open('https://chavyleung.gitbook.io/boxjs/base/upgrade')">
+                <v-icon>mdi-help-circle</v-icon>
+              </v-btn>
+              <v-spacer></v-spacer>
+              <template v-if="hasNewVersion">
+                <v-btn text small v-if="env.id === 'Loon'" @click="update('loon://update?sub=all')"
+                  >{{ $t('versionSheet.updateButton') }}</v-btn
+                >
+                <v-btn
+                  text
+                  small
+                  v-else-if="env.id === 'QuanX'"
+                  @click="update('quantumult-x:///add-resource?remote-resource=%7B%22rewrite_remote%22%3A%5B%22https%3A%2F%2Fgithub.com%2Fchavyleung%2Fscripts%2Fraw%2Fmaster%2Fbox%2Frewrite%2Fboxjs.rewrite.quanx.conf%2Ctag%3Dboxjs%22%5D%7D')"
+                  >{{ $t('versionSheet.updateButton') }}</v-btn
+                >
+              </template>
+              <template v-else>
+                <v-btn text small>{{ $t('versionSheet.versionButton') }}</v-btn>
+              </template>
+              <v-spacer></v-spacer>
+              <v-btn icon small @click="ui.versionSheet.show = false">
+                <v-icon>mdi-chevron-double-down</v-icon>
+              </v-btn>
+            </v-subheader>
+            <v-divider></v-divider>
+            <v-card-text style="height: 80%">
+              <div class="mt-6" v-for="(ver, verIdx) in box.versions">
+                <h2 :class="version === ver.version ? 'primary--text' : undefined">v{{ver.version}}</h2>
+                <div class="pl-4 pt-2" v-for="(note, noteIdx) in ver.notes">
+                  <strong>{{note.name}}</strong>
+                  <ul>
+                    <li v-for="(desc, descIdx) in note.descs">{{desc}}</li>
+                  </ul>
+                </div>
+              </div>
+            </v-card-text>
+            <v-dialog persistent v-model="ui.reloadDialog.show">
+              <v-card>
+                <v-card-title>{{ $t('reloadDialog.title') }}</v-card-title>
+                <v-card-text>{{ $t('reloadDialog.text') }}</v-card-text>
+                <v-card-actions>
+                  <v-spacer></v-spacer>
+                  <v-btn text small color="grey" @click="ui.reloadDialog.show = false">{{ $t('base.dialog.close') }}</v-btn>
+                  <v-btn text small color="primary" @click="reload()" :loading="isLoading">{{ $t('reloadDialog.reload') }}</v-btn>
+                </v-card-actions>
+              </v-card>
+            </v-dialog>
+          </v-card>
+        </v-bottom-sheet>
+        <v-bottom-sheet v-model="ui.exeScriptSheet.show" scrollable fullscreen>
+          <v-card>
+            <v-card-title v-touch="{ down: () => ui.exeScriptSheet.show = false }">
+              执行结果
+              <v-spacer></v-spacer>
+              <v-btn icon @click="ui.exeScriptSheet.show = false">
+                <v-icon>mdi-chevron-double-down</v-icon>
+              </v-btn>
+            </v-card-title>
+            <v-divider></v-divider>
+            <v-card-text style="height: 80%">
+              <div class="mt-4" v-if="ui.exeScriptSheet.resp">
+                <p class="text-pre-wrap" v-if="ui.exeScriptSheet.resp.exception" v-text="ui.exeScriptSheet.resp.exception"></p>
+                <p class="text-pre-wrap" v-else-if="ui.exeScriptSheet.resp.output" v-text="ui.exeScriptSheet.resp.output"></p>
+                <p v-else v-text="JSON.stringify(ui.exeScriptSheet.resp)"></p>
+              </div>
+            </v-card-text>
+          </v-card>
+        </v-bottom-sheet>
+      </v-app>
+    </div>
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-i18n.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/dayjs.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/timeago.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/uuidv4.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-clipboard.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/min/vs/loader.js"></script>
+    <script>
+      Vue.prototype.timeago = timeago
+      Vue.prototype.dayjs = dayjs
+      new Vue({
+        el: '#app',
+        vuetify: new Vuetify(),
+        i18n: new VueI18n({
+          locale: 'zh-CN',
+          messages: {
+            'en-US': {
+              base: {
+                dialog: {
+                  apply: 'Apply',
+                  save: 'Save',
+                  view: 'View',
+                  close: 'Close',
+                  ok: 'OK'
+                },
+                sort: {
+                  up: 'Up',
+                  dn: 'Down'
+                },
+                cmd: {
+                  cp: 'Copy',
+                  del: 'Delete',
+                  imp: 'Import',
+                  exp: 'Export',
+                  mod: 'Modify',
+                  share: 'Share',
+                  recovery: 'Recovery',
+                  duplicate: 'Duplicate'
+                }
+              },
+              menus: {
+                home: 'Home',
+                apps: 'Applications',
+                subs: 'Subscriptions',
+                profile: 'Profile'
+              },
+              apps: {
+                fav: 'Favorites',
+                unStar: 'Unstar',
+                sysApps: 'System Applications'
+              },
+              appDetail: {
+                scripts: 'Scripts',
+                settings: 'Settings',
+                curSession: 'Current Session',
+                copyDatas: 'Copy Datas',
+                clearDatas: 'Clear Datas',
+                noDatas: 'No datas',
+                impDialog: {
+                  title: 'Import Session',
+                  data: 'Session Data (JSON)',
+                  dataDesc: 'You can get session data via `Current Session` more > Copy'
+                }
+              },
+              subs: {
+                addDialog: {
+                  title: 'Add Subscription',
+                  name: 'Session Name',
+                  url: 'Subscription url',
+                  urlDesc: 'https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.json'
+                },
+
+                sessionEditor: {
+                  title: 'Modify Session',
+                  name: 'Name',
+                  nameDesc: 'Leave your name',
+                  avatar: 'Avatar (Optional)',
+                  avatarDesc: 'Your avatar link'
+                },
+                install: 'Install',
+                add: 'Add Subscription',
+                subs: 'More Subscriptions',
+                appSubs: 'App Subscriptions',
+                errData: 'Error Data',
+                updated: 'Updated',
+                repo: 'Repository'
+              },
+              prefs: {
+                appearance: 'Appearance',
+                appearances: {
+                  auto: 'Auto',
+                  dark: 'Dark',
+                  light: 'Light'
+                },
+                background: 'Background',
+                icon: 'Dark icon',
+                iconDesc: 'Available in dark mode',
+                bgMode: 'Backgroud Mode',
+                bgModeDesc: 'Hides bars & icons',
+                hideTopBar: 'Hide TopBar',
+                hideTopBarDesc: 'Restore via sidebar',
+                autoTopBar: 'Auto TopBar',
+                autoTopBarDesc: 'Hides when scrolling',
+                hideBottomBar: 'Hide BottomBar',
+                hideBottomBarDesc: 'Restore via sidebar',
+                autoBottomBar: 'Auto BottomBar',
+                autoBottomBarDesc: 'Hides when scrolling',
+                muteMode: 'Do Not Disturb',
+                muteModeDesc: 'Disable notifications',
+                hideHelp: 'Hide Help',
+                hideHelpDesc: 'Hides help button',
+                hideBoxJs: 'Hide BoxJs',
+                hideBoxJsDesc: 'Hides BoxJs button',
+                hideProfileTitle: 'Hide Profile Title',
+                hideProfileTitleDesc: 'Show avatar only',
+                hideCodding: 'Hide Codding',
+                hideCoddingDesc: 'Hides codding button',
+                hideReload: 'Hide Reload',
+                hideReloadDesc: 'Reload by double tap BoxJs',
+                debugMode: 'Debug Mode',
+                debugModeDesc: 'No page caches',
+                debugPage: 'Debug Page Addr',
+                debugPageDesc: 'Load page from...'
+              },
+              profile: {
+                leaveName: 'Leave a name',
+                dataviewer: 'Data Viewer',
+                editor: {
+                  title: 'Profile',
+                  name: 'Name',
+                  nameDesc: 'Leave your name',
+                  avatar: 'Avatar (Optional)',
+                  avatarDesc: 'Your avatar link'
+                },
+                impDialog: {
+                  title: 'Import Backup',
+                  impData: 'Backup Data',
+                  impDataDesc: ''
+                },
+                datas: 'Datas',
+                apps: 'Apps',
+                subs: 'Subs',
+                sessions: 'Sessions',
+                imp: 'Import',
+                bak: 'Backup',
+                bakName: 'Global Backup'
+              },
+              bakDetail: {
+                note: 'Note: ',
+                id: 'Backup Index',
+                name: 'Backup Name',
+                title: 'Backup Informations',
+                dataTitle: 'Backup Datas'
+              },
+              codding: {
+                title: 'Script Editor'
+              },
+              viewer: {
+                dataViewer: 'Data Viewer',
+                dataKey: 'Data Key',
+                dataKeyDesc: 'Input the data key',
+                dataEditor: 'Data Editor',
+                dataVal: 'Data Value'
+              },
+              reloadDialog: {
+                title: 'Next',
+                text: 'Reload page?',
+                reload: 'GO'
+              },
+              versionSheet: {
+                updateButton: 'UPDATE NOW',
+                versionButton: 'NEW VERSION'
+              }
+            },
+            'zh-CN': {
+              base: {
+                dialog: {
+                  apply: '应用',
+                  save: '保存',
+                  close: '关闭',
+                  ok: '好'
+                },
+                sort: {
+                  up: '上移',
+                  dn: '下移'
+                },
+                cmd: {
+                  cp: '复制',
+                  del: '删除',
+                  imp: '导入',
+                  mod: '修改',
+                  share: '分享',
+                  recovery: '恢复',
+                  duplicate: '克隆'
+                }
+              },
+              menus: {
+                home: '主页',
+                apps: '应用',
+                subs: '订阅',
+                profile: '我的'
+              },
+              apps: {
+                fav: '收藏应用',
+                unStar: '取消收藏',
+                sysApps: '内置应用'
+              },
+              appDetail: {
+                scripts: '应用脚本',
+                settings: '应用设置',
+                curSession: '当前会话',
+                copyDatas: '复制数据',
+                clearDatas: '清除数据',
+                noDatas: '无数据',
+                impDialog: {
+                  title: '导入会话',
+                  data: '会话数据 (JSON)',
+                  dataDesc: '你可通过 `当前会话` 更多 > 复制 来获得会话数据'
+                }
+              },
+              subs: {
+                addDialog: {
+                  title: '添加订阅',
+                  name: 'Session Name',
+                  url: '订阅地址',
+                  urlDesc: 'https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.json'
+                },
+
+                sessionEditor: {
+                  title: '修改会话',
+                  name: '会话名称'
+                },
+                install: '安装',
+                add: '添加订阅',
+                moreSubs: '更多订阅',
+                appSubs: '应用订阅',
+                errData: '格式错误',
+                updated: '更新于',
+                repo: '仓库'
+              },
+              prefs: {
+                appearance: '外观',
+                appearances: {
+                  auto: '自动',
+                  dark: '暗黑',
+                  light: '明亮'
+                },
+                background: '背景图标',
+                icon: '透明图标',
+                iconDesc: '明亮主题下强制使用彩色图标',
+                bgMode: '壁纸模式',
+                bgModeDesc: '同时隐藏顶栏、底栏、图标',
+                hideTopBar: '隐藏顶栏',
+                hideTopBarDesc: '通过侧栏恢复',
+                autoTopBar: '自动顶栏',
+                autoTopBarDesc: '滚动时自动隐藏',
+                hideBottomBar: '隐藏底栏',
+                hideBottomBarDesc: '通过侧栏恢复',
+                autoBottomBar: '自动底栏',
+                autoBottomBarDesc: '滚动时自动隐藏',
+                muteMode: '勿扰模式',
+                muteModeDesc: '不发出通知 (仍记日志)',
+                hideHelp: '隐藏帮助按钮',
+                hideHelpDesc: '隐藏帮助按钮',
+                hideBoxJs: '隐藏悬浮按钮',
+                hideBoxJsDesc: '隐藏右下角 BoxJs 悬浮按钮',
+                hideProfileTitle: '隐藏我的标题',
+                hideProfileTitleDesc: '只显示头像',
+                hideCodding: '隐藏编码按钮',
+                hideCoddingDesc: 'Hides script editor entrance',
+                hideReload: '隐藏刷新按钮',
+                hideReloadDesc: '仍可双击悬浮按钮刷新页面',
+                debugMode: '调试模式',
+                debugModeDesc: '每次请求都获取最新的页面',
+                debugPage: '调试页面地址',
+                debugPageDesc: '页面源码的获取地址'
+              },
+              profile: {
+                leaveName: '大侠, 请留名!',
+                dataviewer: '数据查看器',
+                editor: {
+                  title: '个人资源',
+                  name: '昵称',
+                  nameDesc: '大侠, 请留名!',
+                  avatar: '头像 (可选)',
+                  avatarDesc: '头像链接, 建议从 Github 获取'
+                },
+                impDialog: {
+                  title: 'Import Backup',
+                  impData: 'Backup Data',
+                  impDataDesc: ''
+                },
+                datas: '我的数据',
+                apps: '应用',
+                subs: '订阅',
+                sessions: '会话',
+                imp: '导入',
+                bak: '备份',
+                bakName: '全局备份'
+              },
+              bakDetail: {
+                id: '备份索引',
+                name: '备份名称',
+                title: '备份信息',
+                dataTitle: '备份数据'
+              },
+              codding: {
+                title: '脚本编辑器'
+              },
+              viewer: {
+                dataViewer: '数据查看器',
+                dataKey: '数据键 (Key)',
+                dataKeyDesc: '输入要查询的数据键, 如: boxjs_host',
+                dataEditor: '数据编辑器',
+                dataVal: '数据内容'
+              },
+              reloadDialog: {
+                title: '接下来',
+                text: '更新完成, 需要刷新页面吗?',
+                reload: '马上刷新'
+              },
+              versionSheet: {
+                updateButton: ' 立即更新',
+                versionButton: '新版本'
+              }
+            }
+          }
+        }),
+        data() {
+          return {
+            ui: {
+              // 请求类
+              isCors: false, // 是否需要发起跨域请求
+              // 路径类
+              path: null,
+              bfpath: null,
+              view: null,
+              bfview: null,
+              subview: null,
+              bfsubview: null,
+              // 数据类
+              collaborators: [],
+              contributors: [],
+              isSaveUserCfgs: false,
+              // 界面类
+              scrollY: {}, //记录每个界面的滚动值
+              overlay: { show: false, val: 60 },
+              snackbar: { show: false, color: 'primary', msg: '' },
+              searchBar: {
+                isActive: true,
+                color: 'primary',
+                class: 'rounded-xl',
+                readonly: true,
+                input: '',
+                hideNoData: true,
+                hideDetails: true,
+                solo: true
+              },
+              viewer: {
+                key: '',
+                val: ''
+              },
+              searchDialog: { show: false },
+              versionSheet: { show: false },
+              updatesheet: { show: false },
+              exeScriptSheet: { show: false, resp: null },
+              naviDrawer: { show: false },
+              reloadDialog: { show: false },
+              modSessionDialog: { show: false },
+              editProfileDialog: { show: false },
+              impGlobalBakDialog: { show: false, impval: '' },
+              impAppDatasDialog: { show: false, impval: '' },
+              addAppSubDialog: { show: false, url: '' },
+              installConfirmDialog: { show: false, title: '安装确认', message: '是否自动安装外部资源?' },
+              defaultIcons: [
+                'https://raw.githubusercontent.com/Orz-3/mini/master/appstore.png',
+                'https://raw.githubusercontent.com/Orz-3/task/master/appstore.png'
+              ]
+            },
+            boxServerData: null,
+            box: null,
+            purchaseDate: null,
+            cost: 0,
+            licenseTypes: ["1 Device License", "3 Devices License", "5 Devices License"],
+            licenseType: ''
+          }
+        },
+        computed: {
+          // 获取当前版本
+          version() {
+            return this.box.syscfgs.version
+          },
+          // 标题
+          title() {
+            const isDebugWeb = this.box.usercfgs.isDebugWeb
+            const debugger_web = this.box.usercfgs.debugger_web
+            const isDebugMode = this.box.syscfgs.isDebugMode
+            return `BoxJs - v${this.version}${isDebugMode ? ` - ${debugger_web}` : ''}`
+          },
+          // 判断是否有新版本
+          hasNewVersion() {
+            const curver = this.box.syscfgs.version
+            const vers = this.box.versions
+            if (curver && vers && vers.length > 0) {
+              const lastestVer = vers[0].version
+              return this.compareVersion(lastestVer, curver) > 0
+            }
+          },
+          timeagoLang() {
+            const lang = this.box.usercfgs.lang
+            return lang ? lang.replace('-', '_') : 'zh_CN'
+          },
+          // 判断是否需要跨域请求
+          isCors() {
+            return this.ui.isCors
+          },
+          // 是否加载中
+          isLoading: {
+            set(val) {
+              this.ui.overlay.show = val
+            },
+            get() {
+              return this.ui.overlay.show
+            }
+          },
+          // 判断当前是否`WebApp`
+          isWebApp() {
+            return window.navigator.standalone
+          },
+          // 是否壁纸模式
+          isWallpaperMode: {
+            get() {
+              return this.box.usercfgs.isWallpaperMode
+            },
+            set(val) {
+              this.box.usercfgs.isWallpaperMode = val === true
+            }
+          },
+          // 切换壁纸
+          changeWallpaper() {
+            if (this.isWallpaperMode) {
+              if (this.box.usercfgs.changeBgImgEnterDefault) {
+                const bgUrl = this.bgimgs.find((bgimg) => bgimg.name === this.box.usercfgs.changeBgImgEnterDefault).url
+                if (bgUrl) {
+                  this.box.usercfgs.bgimg = bgUrl
+                  this.saveUserCfgs(false)
+                }
+              }
+            } else {
+              if (this.box.usercfgs.changeBgImgOutDefault) {
+                const bgUrl = this.bgimgs.find((bgimg) => bgimg.name === this.box.usercfgs.changeBgImgOutDefault).url
+                if (bgUrl || bgUrl === '') {
+                  this.box.usercfgs.bgimg = bgUrl
+                  this.saveUserCfgs(false)
+                }
+              }
+            }
+          },
+          // 当前环境: Surge、QuanX、Loon、NodeJs
+          env: {
+            // 获取当前容器环境
+            get() {
+              return this.envs.find((env) => env.id === this.box.syscfgs.env)
+            },
+            // 设置当前容器环境
+            set(val) {
+              this.box.syscfgs.env = val
+            }
+          },
+          // 获取容器列表
+          envs() {
+            const envs = this.box.syscfgs.envs
+            envs.forEach((env) => (env.icon = env.icons[this.iconThemeIdx]))
+            return envs
+          },
+          // 获取当前路径
+          path: {
+            get() {
+              return this.ui.path
+            },
+            set(path) {
+              this.ui.path = path
+            }
+          },
+          // 获取上一个路径
+          bfpath() {
+            return this.ui.bfpath || ''
+          },
+          // 获取当前页面: http://boxjs.com/app/baidu => `app`
+          view() {
+            return this.ui.view || ''
+          },
+          // 获取当前页面: http://boxjs.com/app/baidu => `baidu`
+          subview() {
+            return this.ui.subview ? this.ui.subview : ''
+          },
+          // 判断当前是否`主页面` (非二级页面)
+          isMainView() {
+            return !this.subview
+          },
+          // 判断当前是否`暗黑模式`
+          isDarkMode() {
+            let isDark = true
+            const theme = this.box.usercfgs.theme
+            if (theme === 'auto') {
+              isDark = this.isSystemDarkMode
+            } else if (theme === 'light') {
+              isDark = false
+            }
+            return isDark
+          },
+          // 判断系统是否`暗黑模式`
+          isSystemDarkMode() {
+            return window.matchMedia('(prefers-color-scheme: dark)').matches
+          },
+          // 是否透明图标
+          isTransparentIcons() {
+            return this.box.usercfgs.isTransparentIcons
+          },
+          // 获取图标下标, 透明: 0, 彩色: 1 (默认)
+          iconThemeIdx() {
+            if (this.isDarkMode) {
+              return this.isTransparentIcons ? 0 : 1
+            }
+            return 1
+          },
+          // 获取环境图标下标, 透明: 0, 彩色: 1 (默认)
+          iconEnvThemeIdx() {
+            return this.isDarkMode ? 0 : 1
+          },
+          isHidedSearchBar: {
+            get() {
+              return this.box.usercfgs.isHidedSearchBar || this.isWallpaperMode
+            },
+            set(val) {
+              this.box.usercfgs.isHidedSearchBar = val === true
+            }
+          },
+          isAutoSearchBar: {
+            get() {
+              return this.box.usercfgs.isAutoSearchBar
+            },
+            set(val) {
+              this.box.usercfgs.isAutoSearchBar = val === true
+              if (val === false && !this.isHidedSearchBar) {
+                this.$refs.appBar.isActive = true
+              }
+            }
+          },
+          isHidedAppIcons: {
+            get() {
+              return this.box.usercfgs.isHidedAppIcons || this.isWallpaperMode
+            },
+            set(val) {
+              this.box.usercfgs.isHidedAppIcons = val === true
+            }
+          },
+          isHidedNaviBottom: {
+            get() {
+              return this.box.usercfgs.isHidedNaviBottom || this.isWallpaperMode
+            },
+            set(val) {
+              this.box.usercfgs.isHidedNaviBottom = val === true
+            }
+          },
+          isAutoNaviBottom: {
+            get() {
+              return this.box.usercfgs.isAutoNaviBottom
+            },
+            set(val) {
+              this.box.usercfgs.isAutoNaviBottom = val === true
+              if (val === false && !this.isHidedNaviBottom) {
+                this.$refs.naviBar.isActive = true
+              }
+            }
+          },
+          // 判断是否有壁纸
+          isWallpaper() {
+            return !!this.box.usercfgs.bgimg
+          },
+          // 是否存在多张壁纸
+          isMutiWallpaper() {
+            return this.bgimgs && this.bgimgs.length > 2
+          },
+          // 背景图片列表
+          bgimgs() {
+            const items = []
+            const bgimgs = this.box.usercfgs.bgimgs
+            if (bgimgs) {
+              bgimgs.split('\n').forEach((img) => {
+                const [name, url] = img.split(',')
+                items.push({ name, url })
+              })
+            }
+            return items
+          },
+          // 样式
+          appViewStyle() {
+            // 主题发生变化时给 <body> 设置背景色
+            if (this.isWallpaper) {
+              this.setWallpaper()
+            } else {
+              this.clearWallpaper()
+              const darkBg = `background: #121212;`
+              const lightWebappBg = `background-image: linear-gradient(to bottom,rgba(0,0,0,.2) 0,transparent 76px);`
+              const lightBg = `${this.isWebApp ? lightWebappBg : 'background: #fff;'}`
+              document.querySelector('#BG').setAttribute('style', this.isDarkMode ? darkBg : lightBg)
+            }
+            if (this.isWebApp) {
+              return { background: 'none' }
+            } else if (this.isWallpaper && !this.isTransparent) {
+              return { background: 'transparent' }
+            } else if (!this.isWallpaper && this.isTransparent) {
+              return { background: 'none' }
+            } else {
+              return
+            }
+          },
+          appTitleStyle() {
+            const style = {}
+            if (this.isWallpaper) {
+              style['color'] = '#fff'
+              style['text-shadow'] = 'black 0.1em 0.1em 0.2em'
+            }
+            return style
+          },
+          appBarBind() {
+            const app = true
+            const isEmptyLight = this.isWebApp && !this.isDarkMode && !this.isWallpaper
+            const color = isEmptyLight ? 'primary' : 'transparent'
+            const flat = color === 'transparent'
+            const hideOnScroll = !this.isHidedSearchBar && this.isAutoSearchBar
+            const collapseOnScroll = false
+            const scrollThreshold = 20
+            return { app, color, flat, hideOnScroll, collapseOnScroll, scrollThreshold }
+          },
+          searchBarBind() {
+            const color = this.isDarkMode ? null : 'primary'
+            return { color }
+          },
+          naviBarBind() {
+            const app = true
+            const grow = true
+            const color = 'primary'
+            const value = this.view
+            const inputValue = !this.isHidedNaviBottom
+            const hideOnScroll = !this.isHidedNaviBottom && this.isAutoNaviBottom
+            const scrollThreshold = 160
+            return { app, grow, color, value, inputValue, hideOnScroll, scrollThreshold }
+          },
+          appIconFontStyle() {
+            const style = {
+              'font-size': '10px',
+              'max-width': '54px'
+            }
+
+            if (this.isWallpaper) {
+              style['color'] = '#fff'
+              style['text-shadow'] = 'black 0.1em 0.1em 0.2em'
+            }
+            return style
+          },
+          // 是否保存用户偏好
+          isSaveUserCfgs: {
+            set(val) {
+              this.ui.isSaveUserCfgs = val
+            },
+            get() {
+              return this.ui.isSaveUserCfgs
+            }
+          },
+          // 我的图标
+          myIcon() {
+            return this.box.usercfgs.icon
+          },
+          // 是否隐藏`我的`标题
+          isHideMyTitle() {
+            return this.box.usercfgs.isHideMyTitle
+          },
+          // 添加`应用订阅`对话框
+          addAppSubDialog: {
+            get() {
+              return this.ui.addAppSubDialog.show
+            },
+            set(show) {
+              this.ui.addAppSubDialog.show = show
+            }
+          },
+          // 获取持久化数据
+          datas() {
+            return this.box.datas
+          },
+          // 应用会话数据
+          sessions() {
+            return this.box.sessions
+          },
+          // 获取`收藏`应用
+          favApps() {
+            const favapps = []
+            const favAppIds = this.box.usercfgs.favapps || []
+            if (favAppIds) {
+              favAppIds.forEach((favAppId) => {
+                const app = this.apps.find((app) => app.id === favAppId)
+                if (app) {
+                  favapps.push(app)
+                }
+              })
+            }
+            return favapps
+          },
+          // 获取`内置`应用
+          sysApps() {
+            const sysapps = this.box.sysapps || []
+            sysapps.forEach((app) => this.loadAppBaseInfo(app))
+            sysapps.sort((a, b) => a.name.localeCompare(b.name))
+            return sysapps
+          },
+          // 获取`订阅`应用 (注意: 这个接口是获取`应用`)
+          subApps() {
+            const apps = []
+            this.appSubs.forEach((appsub) => {
+              const sub = this.appSubCaches[appsub.url]
+              if (sub && sub.apps && Array.isArray(sub.apps) && !appsub.isErr) {
+                sub.apps.forEach((app) => {
+                  this.loadAppBaseInfo(app)
+                  apps.push(app)
+                })
+              }
+            })
+            return apps
+          },
+          // 获取`应用`订阅 (注意: 这个接口是获取`订阅`)
+          appSubs() {
+            // 深拷贝一份数据, 避免污染`usercfgs`
+            const subs = JSON.parse(JSON.stringify(this.box.usercfgs.appsubs))
+            subs.forEach((sub) => {
+              const raw = JSON.parse(JSON.stringify(sub))
+              const cacheSub = this.appSubCaches[sub.url]
+              const isValidSub = cacheSub && Array.isArray(cacheSub.apps) && cacheSub.apps.length > 0
+              const isValidSubApps = isValidSub && !cacheSub.apps.find((app) => !app.id)
+              if (cacheSub && isValidSub && isValidSubApps) {
+                Object.assign(sub, cacheSub)
+              } else {
+                sub.isErr = true
+                sub.apps = []
+              }
+              sub.name = sub.name ? sub.name : '匿名订阅'
+              sub.author = sub.author ? sub.author : '@anonymous'
+              sub.repo = sub.repo ? sub.repo : sub.url
+              sub.raw = raw
+            })
+            return subs
+          },
+          // 获取`订阅`缓存
+          appSubCaches() {
+            return this.box.appSubCaches
+          },
+          // 获取所有应用`内置应用`+`订阅应用`
+          apps() {
+            const apps = []
+            apps.push(...this.subApps)
+            apps.push(...this.sysApps)
+            return apps
+          },
+          searchApps() {
+            return this.apps.filter((app) => app.id.includes(this.ui.searchBar.input) || app.name.includes(this.ui.searchBar.input))
+          },
+          // 获取全局备份
+          baks() {
+            return this.box.globalbaks
+          },
+          // 当前应用
+          curapp() {
+            if (this.view === 'app' && !!this.subview) {
+              const appId = decodeURIComponent(decodeURIComponent(this.subview))
+              const app = this.apps.find((app) => app.id === appId)
+              this.loadAppDataInfo(app)
+              return app
+            }
+          },
+          // 当前备份
+          curbak() {
+            if (this.view === 'bak' && !!this.subview) {
+              const bakId = decodeURIComponent(decodeURIComponent(this.subview))
+              const bak = this.baks.find((bak) => bak.id === bakId)
+              return bak
+            }
+          }
+        },
+        watch: {
+          'ui.path': {
+            handler(newval, oldval) {
+              if (/^\/#/.test(newval)) {
+                newval = newval.replace('/#', '')
+              }
+              const [, view, subview] = newval.split('/')
+
+              this.ui.view = view
+              this.ui.subview = subview
+              if (oldval) {
+                const [, bfview, bfsubview] = oldval.split('/')
+                this.ui.bfpath = oldval
+                this.ui.bfview = bfview
+                this.ui.bfsubview = bfsubview
+              }
+              if (newval === '/coding') {
+                require.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/[email protected]/min/vs' } })
+                require(['vs/editor/editor.main'], () => {
+                  const envjs_demo = [
+                    '/** ',
+                    ' * 注意: ',
+                    ' * 在这里你可以使用完整的 EnvJs 环境',
+                    ' * ',
+                    ' * 同时: ',
+                    ' * 你`必须`手动调用 $done()',
+                    ' * ',
+                    ' * 因为: ',
+                    ' * BoxJs 不为主动执行的脚本调用 $done()',
+                    ' * 而把 $done 的时机完全交由脚本控制',
+                    ' * ',
+                    ' * 最后: ',
+                    ' * 这段脚本是可以直接运行的!',
+                    ' */ ',
+                    'const host = $.getdata("boxjs_host")',
+                    'console.log("输出的内容是返回给浏览器的!")',
+                    '$.msg($.name, host)',
+                    '$.done()',
+                    '// $done() 或 $.done() 都可以'
+                  ]
+                  const surgejs_demo = [
+                    '/** ',
+                    ' * 注意: ',
+                    ' * 你正在使用 Surge HTTP-API 环境',
+                    ' * ',
+                    ' * 在这里:你不可以使用 EnvJs',
+                    ' * 请确保:你的脚本能被 Surge 独立运行',
+                    ' * ',
+                    ' * 最后: ',
+                    ' * 这段脚本是可以直接运行的!',
+                    ' */ ',
+                    'const host = $persistentStore.read("boxjs_host")',
+                    'const msgs = [""]',
+                    '',
+                    'msgs.push("这是日志的内容")',
+                    'msgs.push("BoxJs host: " + host)',
+                    '',
+                    'console.log(msgs.join("\\n"))',
+                    '$done()'
+                  ]
+                  this.ui.editor = monaco.editor.create(document.getElementById('container'), {
+                    fontSize: 12,
+                    tabSize: 2,
+                    value: this.env.id === 'Surge' && this.box.usercfgs.httpapi ? surgejs_demo.join('\n') : envjs_demo.join('\n'),
+                    language: 'javascript',
+                    minimap: { enabled: false },
+                    theme: this.isDarkMode ? 'vs-dark' : 'vs'
+                  })
+                })
+              }
+              window.onresize = () => {
+                if (this.ui.editor) {
+                  this.ui.editor.layout()
+                }
+              }
+              // 还原视图当时的滚动值
+              const scrollY = this.ui.scrollY[this.path] || 0
+              const offsetTop = -this.$vuetify.application.top
+              this.$vuetify.goTo(scrollY, { duration: 0, offset: offsetTop })
+            }
+          },
+          'ui.searchDialog.show': {
+            handler(newval) {
+              if (newval === false) {
+                this.ui.searchBar.input = ''
+              } else {
+                if (this.$refs.search) {
+                  this.$nextTick(() => {
+                    setTimeout(() => this.$refs.search.$refs.input.focus(), 0)
+                  })
+                }
+              }
+            }
+          },
+          'ui.naviDrawer.show': {
+            handler(newval, oldval) {
+              // 获取贡献者列表
+              if (_.isEmpty(this.ui.contributors)) {
+                this.getContributors()
+              }
+            }
+          },
+          'box.usercfgs': {
+            deep: true,
+            handler(newval, oldval) {
+              if (oldval && this.isSaveUserCfgs) {
+                this.saveUserCfgs()
+              }
+              this.isSaveUserCfgs = true
+            }
+          },
+          'box.usercfgs.lang': {
+            handler(newval) {
+              this.$i18n.locale = newval
+            }
+          },
+          'box.usercfgs.theme': {
+            handler() {
+              if (this.ui.editor) {
+                this.ui.editor._themeService.setTheme(this.isDarkMode ? 'vs-dark' : 'vs')
+              }
+            }
+          },
+          'box.usercfgs.color_dark_primary': {
+            handler() {
+              this.loadTheme()
+            }
+          },
+          'box.usercfgs.color_light_primary': {
+            handler() {
+              this.loadTheme()
+            }
+          }
+        },
+        beforeCreate() {
+          // 请求&响应拦截器, 显示&隐藏加载条
+          axios.interceptors.request.use((cfg) => {
+            this.isLoading = true
+            return cfg
+          })
+          axios.interceptors.response.use(
+            (resp) => {
+              this.isLoading = false
+              return resp
+            },
+            (error) => (this.isLoading = false)
+          )
+        },
+        created() {
+          // 如果 url 参数中指定的 baseURL, 则后续的请求都请求到指定的域
+          if (window.location.search) {
+            const [, baseURL] = /baseURL=(.*?)(&|$)/.exec(window.location.search)
+            axios.defaults.baseURL = baseURL || ''
+            this.ui.isCors = true
+          }
+          // 根据路径跳转视图
+          const defview = '/'
+          if (!this.isCors) {
+            let path = location.pathname + location.hash
+            this.path = path === '/' ? defview : path
+          } else {
+            this.path = defview
+          }
+          // 监听浏览器后退事件
+          window.addEventListener('popstate', (e) => (this.path = e.state ? e.state.url : '/'), false)
+          // 如果后端没有渲染数据, 则发出请求获取数据
+          if (this.boxServerData) {
+            this.box = this.boxServerData
+            this.setHttpBackend()
+          } else {
+            axios.get('/query/boxdata').then((resp) => {
+              this.box = resp.data
+              this.setHttpBackend()
+            })
+          }
+
+          // 延时执行, 避免多个请求抢占资源
+          this.getVersions()
+          this.loadTheme()
+        },
+        mounted() {
+          const el = document.getElementById('appList')
+          const _this = this
+          const sortable = Sortable.create(el, {
+            animation: 600,
+            delay: 200,
+            onEnd(evt) {
+              const favApps = _this.box.usercfgs.favapps
+              const oldIdx = evt.oldIndex
+              const newIdx = evt.newIndex
+              const moveItem = favApps[oldIdx]
+              favApps.splice(oldIdx, 1)
+              favApps.splice(newIdx, 0, moveItem)
+            }
+          })
+
+          if (!this.box.usercfgs.lang) {
+            const locale = this.$i18n.locale
+            this.box.usercfgs.lang = locale === 'zh-CN' ? locale : 'en-US'
+            this.saveUserCfgs()
+          } else {
+            this.$i18n.locale = this.box.usercfgs.lang
+          }
+
+          if (this.path.includes('/#/bak/')) {
+            const [, backupId] = this.path.split('/#/bak/')
+            this.loadGlobalBak(backupId)
+          } else if (this.path.includes('/#/sub/add/')) {
+            const [, url] = this.path.split('/#/sub/add/')
+            this.addAppSub(decodeURIComponent(url), true)
+          }
+        },
+        methods: {
+          reload() {
+            this.isLoading = true
+            window.location.reload()
+          },
+          open(url) {
+            window.open(url)
+          },
+          update(url) {
+            this.open(url)
+            this.ui.versionSheet.show = false
+            this.ui.reloadDialog.show = true
+          },
+          openInstall(subId) {
+            const newsub = this.appSubs.find((s) => s.raw.id === subId)
+            const event = newsub.onInstall
+            if (event) {
+              const install = event.install
+              const redirect = install[this.env.id]
+              if (!redirect) return
+              this.ui.installConfirmDialog.show = true
+              this.ui.installConfirmDialog.title = event.title
+              this.ui.installConfirmDialog.message = event.message
+              this.ui.installConfirmDialog.url = redirect
+            }
+          },
+          install(url) {
+            this.open(url)
+            this.ui.installConfirmDialog.show = false
+          },
+          // 记录每个页面的滚动值
+          onScroll(event) {
+            const currentY = event.currentTarget.scrollY
+            const historyY = this.ui.scrollY[this.path]
+            this.ui.scrollY[this.path] = event.currentTarget.scrollY
+            // 下拉显示/隐藏顶栏
+            // 回弹时才触发显示与隐藏, 1 秒内不重复触发
+            if (currentY < historyY && currentY < -80 && !this.ui.isWaitToggleSearchBar) {
+              // 壁纸模式: 取消模式模式
+              if (this.isWallpaperMode) {
+                this.isWallpaperMode = false
+              }
+              // 非壁纸模式: 显示&隐藏顶栏
+              else {
+                this.ui.isWaitToggleSearchBar = true
+                this.isHidedSearchBar = !this.isHidedSearchBar
+                this.toggleWaitSearchBar()
+              }
+            }
+          },
+          setWallpaper() {
+            let bgimg = ''
+            if (this.box.usercfgs.bgimg === '跟随系统') {
+              const hasdark = this.bgimgs.find((bgimg) => bgimg.name == '暗黑' || bgimg.name == 'dark')
+              const haslight = this.bgimgs.find((bgimg) => bgimg.name == '明亮' || bgimg.name == 'light')
+              const darkbgimg = hasdark ? hasdark.url : ``
+              const lightbgimg = haslight ? haslight.url : ``
+              this.isDarkMode ? (bgimg = darkbgimg) : (bgimg = lightbgimg)
+              const bgStyle = [
+                `background-image: linear-gradient(to bottom,rgba(0,0,0,.2) 0,transparent 76px), url(${bgimg}?_=${Math.random()})`
+              ]
+              document.querySelector('#BG').setAttribute('style', bgStyle.join('; '))
+            } else {
+              const bgStyle = [
+                `background-image: linear-gradient(to bottom,rgba(0,0,0,.2) 0,transparent 76px), url(${
+                  this.box.usercfgs.bgimg
+                }?_=${Math.random()})`
+              ]
+              document.querySelector('#BG').setAttribute('style', bgStyle.join('; '))
+            }
+          },
+          clearWallpaper() {
+            document.querySelector('#BG').removeAttribute('style')
+          },
+          toggleWaitSearchBar: _.debounce(function () {
+            this.ui.isWaitToggleSearchBar = false
+          }, 1000),
+          handleHistory(path) {
+            const { hash } = window.location.href
+            const state = { title: 'BoxJs', url: '/' + (hash ? hash : '#/') }
+            if (!history.state) {
+              history.replaceState(state, '')
+            }
+            state.url = path
+            history.pushState(state, '', path)
+          },
+          // 页面返回
+          back() {
+            history.back()
+          },
+          // 切换当前容器环境
+          switchEnv(env) {
+            this.env = env
+          },
+          // 切换当前视图
+          switchView(path) {
+            path = `/#/${path}`
+            if (this.path !== path) {
+              this.path = path
+              this.handleHistory(this.path)
+            } else {
+              const scrollY = this.ui.scrollY[this.path]
+              const isTopY = _.isNil(scrollY) || scrollY === 0
+              if (path === '/#/' && isTopY) {
+                this.clearWallpaper()
+                this.setWallpaper()
+              } else if (path === '/#/app' && isTopY) {
+                Object.assign(this.box.usercfgs, { favapppanel: [], subapppanel: [], sysapppanel: [] })
+              } else if (path === '/#/sub' && isTopY) {
+                this.reloadAppSub()
+              }
+              if (this.ui.scrollY[path] !== 0) {
+                this.$vuetify.goTo(0, { duration: 200, offset: 0 })
+              }
+            }
+          },
+          // 切换应用视图
+          switchAppView(appId) {
+            const path = `/#/app/${appId}`
+            this.path = path
+            this.handleHistory(this.path)
+          },
+          // 切换备份视图
+          switchBakView(backupId) {
+            const path = `/#/bak/${backupId}`
+            this.loadGlobalBak(backupId).then((resp) => {
+              this.path = path
+              this.handleHistory(path)
+            })
+          },
+          // 重载主题
+          loadTheme() {
+            this.$vuetify.theme.dark = this.isDarkMode
+            this.$vuetify.theme.themes.light.primary = this.box.usercfgs.color_light_primary || '#F7BB0E'
+            this.$vuetify.theme.themes.dark.primary = this.box.usercfgs.color_dark_primary || '#2196F3'
+          },
+          // 复制文本
+          copy(str) {
+            this.$copyText(str).then(
+              (e) => {
+                this.ui.snackbar.show = true
+                this.ui.snackbar.msg = '复制成功!'
+                this.ui.snackbar.color = 'primary'
+              },
+              (e) => {
+                this.ui.snackbar.show = true
+                this.ui.snackbar.msg = '复制失败!'
+                this.ui.snackbar.color = 'error'
+              }
+            )
+          },
+          // 复制文本
+          share(str) {
+            const url = `http://boxjs.com/#/sub/add/${encodeURIComponent(str)}`
+            this.copy(url)
+          },
+          // 移动收藏
+          moveFav(favIdx, moveCnt) {
+            const favapps = this.box.usercfgs.favapps
+            const fromIdx = favIdx
+            const toIdx = favIdx + moveCnt
+            favapps.splice(fromIdx, 1, ...favapps.splice(toIdx, 1, favapps[fromIdx]))
+          },
+          // 移动订阅
+          moveSub(subIdx, moveCnt) {
+            const appsubs = this.box.usercfgs.appsubs
+            const fromIdx = subIdx
+            const toIdx = subIdx + moveCnt
+            appsubs.splice(fromIdx, 1, ...appsubs.splice(toIdx, 1, appsubs[fromIdx]))
+          },
+          // 删除订阅
+          delSub(subIdx) {
+            this.box.usercfgs.appsubs.splice(subIdx, 1)
+          },
+          // 收藏应用
+          favApp(appId) {
+            const favAppIdx = this.box.usercfgs.favapps.findIndex((favAppId) => favAppId === appId)
+            if (favAppIdx === -1) {
+              this.box.usercfgs.favapps.push(appId)
+            } else {
+              this.box.usercfgs.favapps.splice(favAppIdx, 1)
+            }
+          },
+          // 加载应用信息
+          loadAppBaseInfo(app) {
+            // 应用图标
+            app.icons = Array.isArray(app.icons) ? app.icons : this.ui.defaultIcons
+            const isBrokenIcons = app.icons.find((i) => i.includes('/Orz-3/task/master/'))
+            if (isBrokenIcons) {
+              app.icons[0] = app.icons[0].replace('/Orz-3/mini/master/', '/Orz-3/mini/master/Alpha/')
+              app.icons[1] = app.icons[1].replace('/Orz-3/task/master/', '/Orz-3/mini/master/Color/')
+            }
+            app.icon = app.icons[this.iconThemeIdx]
+
+            // 是否收藏
+            const isFav = this.box.usercfgs.favapps.includes(app.id)
+            app.favIcon = isFav ? 'mdi-star' : 'mdi-star-outline'
+            app.favIconColor = isFav ? 'primary' : 'grey'
+          },
+          // 加载应用数据
+          loadAppDataInfo(app) {
+            if (app.isLoaded) return
+            // 加载应用设置
+            if (app.settings) {
+              app.settings.forEach((setting) => {
+                const key = setting.id
+                const datval = this.datas[key]
+                if (setting.type === 'boolean') {
+                  setting.val = _.isEmpty(datval) ? setting.val : (datval === 'true' || datval === true)
+                } else if (setting.type === 'int') {
+                  setting.val = datval * 1 || setting.val
+                } else if (setting.type === 'checkboxes') {
+                  if (!_.isEmpty(datval)) {
+                    setting.val = datval ? datval.split(',') : []
+                  } else {
+                    setting.val = Array.isArray(setting.val) ? setting.val : setting.val.split(',')
+                  }
+                } else {
+                  setting.val = datval || setting.val
+                }
+              })
+            }
+            // 加载当前会话数据
+            if (app.keys) {
+              app.datas = []
+              app.keys.forEach((key) => {
+                const val = this.datas[key] || ''
+                app.datas.push({ key, val })
+              })
+            }
+            // 加载会话列表
+            const sessions = this.sessions.filter((session) => session.appId === app.id)
+            app.sessions = sessions || []
+
+            // 加载当前切换会话
+            const curSessionId = this.box.curSessions[app.id]
+            if (curSessionId) {
+              const curSession = this.sessions.find((session) => session.id === curSessionId)
+              app.curSession = curSession
+            }
+            app.isLoaded = true
+          },
+          // 运行远程脚本
+          runRemoteScript(url, timeout) {
+            const opts = { url, timeout, isRemote: true }
+            this.runScript(opts)
+          },
+          // 运行文本脚本
+          runTxtScript() {
+            const script = this.ui.editor.getValue()
+            const opts = { script }
+            this.runScript(opts)
+          },
+          runScript(opts) {
+            axios.post('/api/runScript', opts).then((resp) => {
+              if (!this.box.usercfgs.isMute) {
+                this.ui.exeScriptSheet.resp = resp.data
+                this.ui.exeScriptSheet.show = true
+              }
+            })
+          },
+          // 保存用户偏好
+          saveUserCfgs() {
+            const key = 'chavy_boxjs_userCfgs'
+            const val = JSON.stringify(this.box.usercfgs)
+            axios.post('/api/save', [{ key, val }]).then((resp) => {
+              this.loadTheme()
+            })
+          },
+          // 保存应用设置
+          saveAppSettings() {
+            const datas = []
+            this.curapp.settings.forEach((setting) => {
+              const isNilVal = _.isNil(setting.val)
+              const key = setting.id
+              const val = !isNilVal ? _.toString(setting.val) : ''
+              datas.push({ key, val })
+            })
+            axios.post('/api/save', datas).then((resp) => {
+              if (this.curapp.id === 'BoxSetting') {
+                this.isSaveUserCfgs = false
+              } else {
+                delete resp.data.usercfgs
+              }
+              Object.assign(this.box, resp.data)
+
+              if (this.curapp.id === 'BoxSetting') {
+                this.setHttpBackend()
+              }
+            })
+          },
+          // 保存应用会话
+          saveAppSession() {
+            const session = {
+              id: uuidv4(),
+              name: '会话 ' + (this.curapp.sessions.length + 1),
+              appId: this.curapp.id,
+              appName: this.curapp.name,
+              enable: true,
+              createTime: new Date(),
+              datas: this.curapp.datas
+            }
+            this.box.sessions.push(session)
+            const key = 'chavy_boxjs_sessions'
+            const val = JSON.stringify(this.box.sessions)
+            axios.post('/api/save', [{ key, val }]).then((resp) => {
+              delete resp.data.usercfgs
+              Object.assign(this.box, resp.data)
+            })
+          },
+          // 修改应用会话
+          updateAppSession(session) {
+            session.datas.forEach((dat) => {
+              // 如果属性值是 undefined 或 null, 则修改为 ``, 否则转为字符串
+              dat.val = !_.isNil(dat.val) ? _.toString(dat.val) : ''
+            })
+            const key = 'chavy_boxjs_sessions'
+            const val = JSON.stringify(this.box.sessions)
+            axios
+              .post('/api/save', [{ key, val }])
+              .then((resp) => {
+                delete resp.data.usercfgs
+                Object.assign(this.box, resp.data)
+              })
+              .finally(() => (this.ui.modSessionDialog.show = false))
+          },
+          // 删除应用会话
+          delAppSession(sessionId) {
+            const sessions = this.box.sessions
+            const sessionIdx = sessions.findIndex((session) => session.id === sessionId)
+            sessions.splice(sessionIdx, 1)
+            const key = 'chavy_boxjs_sessions'
+            const val = JSON.stringify(this.box.sessions)
+            axios.post('/api/save', [{ key, val }]).then((resp) => {
+              delete resp.data.usercfgs
+              Object.assign(this.box, resp.data)
+            })
+          },
+          // 使用应用会话
+          useAppSession(sessionId) {
+            const sessions = this.box.sessions
+            const session = sessions.find((session) => session.id === sessionId)
+            this.box.curSessions[session.appId] = sessionId
+
+            const key = 'chavy_boxjs_cur_sessions'
+            const val = JSON.stringify(this.box.curSessions)
+            const curSessions = [{ key, val }]
+            const datas = [...session.datas, ...curSessions]
+
+            this.clearAppDatas()
+            axios.post('/api/save', datas).then((resp) => {
+              delete resp.data.usercfgs
+              Object.assign(this.box, resp.data)
+            })
+          },
+          // 复制应用数据为对象数据
+          copyData(curdata) {
+            const datas = curdata.datas
+            let result = {}
+            datas.forEach(({ key, val }) => {
+              result[key] = val
+            })
+            this.copy(JSON.stringify(result))
+          },
+          // 保存应用数据
+          clearAppDatas(key) {
+            const datas = this.curapp.datas
+            if (key) {
+              const data = datas.find((data) => data.key === key)
+              data.val = ''
+            } else {
+              datas.forEach((data) => (data.val = ''))
+            }
+            axios.post('/api/save', datas).then((resp) => {
+              if (this.curapp.id === 'BoxSetting') {
+                this.isSaveUserCfgs = false
+              } else {
+                delete resp.data.usercfgs
+              }
+              Object.assign(this.box, resp.data)
+            })
+          },
+          // 导入应用数据
+          impAppDatas() {
+            const impval = this.ui.impAppDatasDialog.impval
+            const impapp = JSON.parse(impval)
+            const datas = impapp.datas || []
+            const settings = impapp.settings || []
+            settings.forEach((setting) => {
+              const { id: key, val } = setting
+              datas.push({ key, val })
+            })
+            axios
+              .post('/api/save', datas)
+              .then((resp) => {
+                delete resp.data.usercfgs
+                Object.assign(this.box, resp.data)
+              })
+              .finally(() => {
+                this.ui.impAppDatasDialog.show = false
+                this.ui.impAppDatasDialog.impval = ''
+              })
+          },
+          // 添加应用订阅
+          addAppSub(url, isRedirect) {
+            const sub = { id: uuidv4(), url, enable: true }
+            axios
+              .post('/api/addAppSub', sub)
+              .then((resp) => {
+                this.isSaveUserCfgs = false
+                Object.assign(this.box, resp.data)
+
+                if (isRedirect) {
+                  this.switchView('sub')
+                  this.ui.snackbar.show = true
+                  this.ui.snackbar.msg = '一键订阅: 成功!'
+                  this.ui.snackbar.color = 'success'
+                }
+
+                this.openInstall(sub.id)
+              })
+              .finally(() => (this.addAppSubDialog = false))
+          },
+          // 重载应用订阅
+          reloadAppSub(sub) {
+            axios.post('/api/reloadAppSub', sub).then((resp) => {
+              delete resp.data.usercfgs
+              Object.assign(this.box, resp.data)
+            })
+          },
+          // 加载完整的全局备份 (页面渲染时加载只是备份列表)
+          loadGlobalBak(backupId) {
+            return axios.get(`/query/baks/${backupId}`).then((resp) => {
+              const backup = this.box.globalbaks.find((backup) => backup.id === backupId)
+              backup.bak = resp.data
+            })
+          },
+          // 删除全局备份
+          delGlobalBak() {
+            const { id } = this.curbak
+            axios.post('/api/delGlobalBak', { id }).then((resp) => {
+              this.back()
+              delete resp.data.usercfgs
+              Object.assign(this.box, resp.data)
+            })
+          },
+          // 保存当前备份
+          updateGlobalBak() {
+            const { id, name } = this.curbak
+            axios.post('/api/updateGlobalBak', { id, name }).then((resp) => {
+              delete resp.data.usercfgs
+              Object.assign(this.box, resp.data)
+            })
+          },
+          // 导入全局备份
+          impGlobalBak() {
+            const impval = this.ui.impGlobalBakDialog.impval
+            const bak = {
+              id: uuidv4(),
+              name: `${this.$t('profile.bakName')} ` + (this.box.globalbaks.length + 1),
+              env: this.box.syscfgs.env,
+              version: this.box.syscfgs.version,
+              versionType: this.box.syscfgs.versionType,
+              createTime: new Date(),
+              bak: JSON.parse(impval)
+            }
+            bak.tags = [bak.env, bak.version, bak.versionType]
+            axios
+              .post('/api/impGlobalBak', bak)
+              .then((resp) => {
+                delete resp.data.usercfgs
+                Object.assign(this.box, resp.data)
+              })
+              .finally(() => {
+                this.ui.impGlobalBakDialog.impval = ''
+                this.ui.impGlobalBakDialog.show = false
+              })
+          },
+          // 保存备份
+          saveGlobalBak() {
+            const bak = {
+              id: uuidv4(),
+              name: `${this.$t('profile.bakName')} ` + (this.box.globalbaks.length + 1),
+              env: this.box.syscfgs.env,
+              version: this.box.syscfgs.version,
+              versionType: this.box.syscfgs.versionType,
+              createTime: new Date()
+            }
+            bak.tags = [bak.env, bak.version, bak.versionType]
+            axios.post('/api/saveGlobalBak', bak).then((resp) => {
+              delete resp.data.usercfgs
+              Object.assign(this.box, resp.data)
+            })
+          },
+          // 还原备份
+          revertGlobalBak() {
+            const { id } = this.curbak
+            axios
+              .post('/api/revertGlobalBak', { id })
+              .then((resp) => {
+                this.isSaveUserCfgs = false
+                Object.assign(this.box, resp.data)
+              })
+              .finally(() => this.loadTheme())
+          },
+          // 获取仓库贡献者
+          getContributors() {
+            const url = 'https://api.github.com/repos/chavyleung/scripts/contributors'
+            axios.get(url).then((resp) => {
+              if (!resp) return
+              resp.data.forEach((contributor) => {
+                const { login: id, login, html_url: repo, avatar_url: icon } = contributor
+                if ([29748519, 39037656, 9592236].includes(contributor.id)) {
+                  this.ui.collaborators.push({ id, login, repo, icon })
+                } else {
+                  this.ui.contributors.push({ id, login, repo, icon })
+                }
+              })
+            })
+          },
+          // 获取版本清单
+          getVersions() {
+            axios.get('/query/versions').then((resp) => {
+              if (resp.data && resp.data.releases) {
+                Object.assign(this.box, { versions: resp.data.releases })
+                if (this.hasNewVersion) {
+                  this.ui.versionSheet.show = true
+                }
+              }
+            })
+          },
+          // 查询数据
+          queryData() {
+            const key = this.ui.viewer.key
+            this.ui.viewer.key = key ? key : 'boxjs_host'
+            axios.get(`/query/data/${this.ui.viewer.key}`).then((resp) => {
+              this.ui.viewer.val = resp.data.val
+              this.box.usercfgs.viewkeys.unshift(this.ui.viewer.key)
+            })
+          },
+          saveData() {
+            const key = this.ui.viewer.key
+            const val = this.ui.viewer.val
+            if (key) {
+              axios.post('/api/saveData/', { key, val }).then((resp) => {
+                this.ui.viewer.val = resp.data.val
+              })
+            }
+          },
+          // 对比版本号
+          compareVersion(v1, v2) {
+            var _v1 = v1.split('.'),
+              _v2 = v2.split('.'),
+              _r = _v1[0] - _v2[0]
+            return _r == 0 && v1 != v2 ? this.compareVersion(_v1.splice(1).join('.'), _v2.splice(1).join('.')) : _r
+          },
+          // 设置HTTP Backend
+          setHttpBackend() {
+            // 目前HTTP Backend不能修改端口号
+            var regex = /^http:\/\/(.*):9999$/
+            if (this.box.syscfgs.env === 'QuanX') {
+              if (regex.test(window.location.origin)) {
+                axios.defaults.baseURL = ''
+                return
+              }
+              // 如果是Quantumult X环境并且配置了正确格式的HTTP Backend,将axios请求指向到HTTP Backend
+              if (this.box.usercfgs.http_backend && regex.test(this.box.usercfgs.http_backend)) {
+                axios.defaults.baseURL = this.box.usercfgs.http_backend
+                this.ui.isCors = true
+              } else {
+                axios.defaults.baseURL = ''
+              }
+            }
+          },
+          calculateUpgradePrice(purchaseDate, licenseType) {
+            const licensePrices = {
+              '1 Device License': 34.99,
+              '3 Devices License': 48.99,
+              '5 Devices License': 69.99,
+            }
+
+            const upgradePrice = licensePrices[licenseType]
+            if (!upgradePrice) {
+              throw new Error(`Invalid license type: ${licenseType}`)
+            }
+
+            const discountEndDate = dayjs('2022-04-15')
+            const freeDate = dayjs('2022-10-15')
+
+            if (dayjs(purchaseDate).isBefore(discountEndDate)) {
+              return licensePrices[licenseType]
+            }
+
+            const equivalentPurchaseDate = dayjs(purchaseDate)
+
+            const diffDays = freeDate.diff(discountEndDate, 'day')
+            const daysFromDiscountEndDate = equivalentPurchaseDate.diff(discountEndDate, 'day')
+
+            if (daysFromDiscountEndDate >= diffDays) {
+              // After free upgrade date
+              return 0
+            } else {
+              const ratio = 1 - daysFromDiscountEndDate / diffDays
+              const price = Math.ceil(ratio * upgradePrice * 100) / 100 - 0.01
+              return price < 1.99 ? 1.99 : price
+            }
+          },
+          calculateCost() {
+            this.cost = this.calculateUpgradePrice(this.purchaseDate, this.licenseType)
+          },
+        }
+      })
+    </script>
+  </body>
+</html>

Разница между файлами не показана из-за своего большого размера
+ 902 - 0
Scripts/box/chavy.boxjs.js


+ 688 - 0
Scripts/box/chavy.boxjs.json

@@ -0,0 +1,688 @@
+{
+  "id": "chavyleung.app.sub",
+  "name": "chavyleung应用订阅",
+  "author": "@chavyleung",
+  "icon": "https://avatars3.githubusercontent.com/u/29748519?s=460&u=392a19e85465abbcb1791c9b8b32184a16e6795e&v=4",
+  "repo": "https://github.com/chavyleung/scripts",
+  "apps": [
+    {
+      "id": "10000",
+      "name": "10000",
+      "keys": ["chavy_signheader_10000"],
+      "settings": [
+        {
+          "id": "chavy_mobile_10000",
+          "name": "手机号码",
+          "val": "",
+          "type": "textarea",
+          "placeholder": "18918920000,\n18918920000",
+          "autoGrow": true,
+          "rows": 5,
+          "desc": "以英文逗号分隔多个号码, 可加回车"
+        }
+      ],
+      "author": "@wangfei021325, @chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/blob/master/10000/10000.js",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/10000/10000.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/10000.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/10000.png"
+      ]
+    },
+    {
+      "id": "10010",
+      "name": "10010",
+      "keys": [
+        "chavy_tokenurl_10010",
+        "chavy_tokenheader_10010",
+        "chavy_signurl_10010",
+        "chavy_signheader_10010",
+        "chavy_loginlotteryurl_10010",
+        "chavy_loginlotteryheader_10010",
+        "chavy_findlotteryurl_10010",
+        "chavy_findlotteryheader_10010"
+      ],
+      "settings": [
+        {
+          "id": "chavy_golottery_10010",
+          "name": "天天抽奖",
+          "val": true,
+          "type": "boolean",
+          "desc": "天天抽奖开关"
+        },
+        {
+          "id": "chavy_gosign_10010",
+          "name": "签到",
+          "val": true,
+          "type": "boolean",
+          "desc": "签到开关"
+        }
+      ],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/10010",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/10010/10010.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/10010.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/10010.png"
+      ]
+    },
+    {
+      "id": "chavyleung.10086",
+      "name": "10086",
+      "keys": [
+        "chavy_autologin_cmcc",
+        "chavy_getfee_cmcc",
+        "chavy_tokenurl_10086",
+        "chavy_tokenheader_10086",
+        "chavy_signurl_10086",
+        "chavy_signheader_10086"
+      ],
+      "author": "@wangfei021325, @chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/blob/master/10086/10086.js",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/10086/10086.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/10086.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/10086.png"
+      ]
+    },
+    {
+      "id": "bcz",
+      "name": "百词斩",
+      "keys": ["senku_cookie_bcz", "senku_key_bcz"],
+      "author": "@GideonSenku",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/bcz",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/bcz/bcz.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/bcz.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/bcz.png"
+      ]
+    },
+    {
+      "id": "BAIDU",
+      "name": "百度签到",
+      "keys": ["chavy_cookie_tieba"],
+      "settings": [
+        {
+          "id": "CFG_tieba_isOrderBars",
+          "name": "按连签排序",
+          "val": false,
+          "type": "boolean",
+          "desc": "默认按经验排序"
+        },
+        {
+          "id": "CFG_tieba_maxShowBars",
+          "name": "每页显示数",
+          "val": 15,
+          "type": "number",
+          "desc": "每页最显示多少个吧信息"
+        },
+        {
+          "id": "CFG_tieba_maxSignBars",
+          "name": "每次并发",
+          "val": 5,
+          "type": "number",
+          "desc": "每次并发签到多少个吧"
+        },
+        {
+          "id": "CFG_tieba_signWaitTime",
+          "name": "并发间隔 (毫秒)",
+          "val": 2000,
+          "type": "number",
+          "desc": "每次并发间隔时间"
+        }
+      ],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/tieba",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/tieba/tieba.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/baidu.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/baidu.png"
+      ]
+    },
+    {
+      "id": "pagoda",
+      "name": "百果园",
+      "keys": ["chavy_sign_pagoda"],
+      "author": "@chavyleung",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/pagoda/pagoda.js",
+      "repo": "https://github.com/chavyleung/scripts/blob/master/pagoda",
+      "icons": [
+        "https://raw.githubusercontent.com/58xinian/icon/master/pagoda_mini.png",
+        "https://raw.githubusercontent.com/58xinian/icon/master/pagoda.png"
+      ]
+    },
+    {
+      "id": "dbsj",
+      "name": "豆瓣时间",
+      "keys": [
+        "senku_signurl_dbsj",
+        "senku_signheader_dbsj",
+        "senku_signbody_dbsj"
+      ],
+      "author": "@GideonSenku",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/dbsj",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/dbsj/dbsj.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/dbsj.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/dbsj.png"
+      ]
+    },
+    {
+      "id": "fandeng",
+      "name": "樊登读书",
+      "keys": [
+        "senku_signurl_pandeng",
+        "senku_signheader_pandeng",
+        "senku_signbody_pandeng"
+      ],
+      "author": "@GideonSenku",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/fandeng",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/fandeng/fandeng.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/fandeng.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/fandeng.png"
+      ]
+    },
+    {
+      "id": "fenqile",
+      "name": "分期乐",
+      "keys": [
+        "senku_signurl_fenqile",
+        "senku_signheader_fenqile",
+        "senku_signbody_fenqile",
+        "senku_signDailyKey_fenqile",
+        "senku_signDailyUrlKey_fenqile"
+      ],
+      "author": "@GideonSenku",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/fenqile",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/fenqile/fenqile.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/fenqile.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/fenqile.png"
+      ]
+    },
+    {
+      "id": "gdoil",
+      "name": "加油广东",
+      "keys": ["chavy_signurl_gdoil", "chavy_signheader_gdoil"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/gdoil",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/gdoil/gdoil.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/gdoil.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/gdoil.png"
+      ]
+    },
+    {
+      "id": "JD618",
+      "name": "京东618",
+      "keys": ["chavy_url_jd816", "chavy_body_jd816", "chavy_headers_jd816"],
+      "settings": [
+        {
+          "id": "CFG_618_radomms_min",
+          "name": "最小随机等待 (毫秒)",
+          "val": 2000,
+          "type": "text",
+          "desc": "在任务默认的等待时间基础上,再增加的随机等待时间!"
+        },
+        {
+          "id": "CFG_618_radomms_max",
+          "name": "最大随机等待 (毫秒)",
+          "val": 5000,
+          "type": "text",
+          "desc": "在任务默认的等待时间基础上,再增加的随机等待时间!"
+        },
+        {
+          "id": "CFG_618_isSignShop",
+          "name": "商店签到",
+          "val": true,
+          "type": "boolean",
+          "desc": "71 家商店, 如果每天都签不上, 可以关掉了! 默认: true"
+        },
+        {
+          "id": "CFG_618_isJoinBrand",
+          "name": "品牌会员",
+          "val": false,
+          "type": "boolean",
+          "desc": "25 个品牌, 会自动加入品牌会员! 默认: true"
+        },
+        {
+          "id": "CFG_BOOM_times_JD618",
+          "name": "炸弹次数",
+          "val": 1,
+          "type": "text",
+          "desc": "总共发送多少次炸弹! 默认: 1"
+        },
+        {
+          "id": "CFG_BOOM_interval_JD618",
+          "name": "炸弹间隔 (毫秒)",
+          "val": 100,
+          "type": "text",
+          "desc": "每次间隔多少毫秒! 默认: 100"
+        }
+      ],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/jd",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/jd/jd.618.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/jd.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/jd.png"
+      ]
+    },
+    {
+      "id": "chavyleung.mgtv",
+      "name": "芒果TV",
+      "keys": ["chavy_signurl_mgtv", "chavy_signheader_mgtv"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/blob/master/mgtv/mgtv.js",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/mgtv/mgtv.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/mgtv.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/mgtv.png"
+      ]
+    },
+    {
+      "id": "chavyleung.meituan",
+      "name": "美团",
+      "keys": [
+        "chavy_tokenurl_meituan",
+        "chavy_tokenheader_meituan",
+        "chavy_signurl_meituan",
+        "chavy_signheader_meituan",
+        "chavy_signbody_meituan"
+      ],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/blob/master/meituan/meituan.js",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/meituan/meituan.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/meituan.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/meituan.png"
+      ]
+    },
+    {
+      "id": "qmkg",
+      "name": "全民K歌",
+      "keys": [
+        "senku_signurl_qmkg",
+        "senku_signheader_qmkg",
+        "senku_signbody_qmkg"
+      ],
+      "author": "@GideonSenku",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/qmkg",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/qmkg/qmkg.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/qmkg.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/qmkg.png"
+      ]
+    },
+    {
+      "id": "smzdm",
+      "name": "什么值得买",
+      "keys": ["chavy_cookie_smzdm"],
+      "author": "@wangfei021325, @chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/smzdm",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/smzdm/smzdm.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/smzdm.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/smzdm.png"
+      ]
+    },
+    {
+      "id": "sfexpress",
+      "name": "顺丰速运",
+      "keys": ["chavy_login_sfexpress"],
+      "author": "@wangfei021325, @chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/blob/master/sfexpress",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/sfexpress/sfexpress.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/sfexpress.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/sfexpress.png"
+      ]
+    },
+    {
+      "id": "flyertea",
+      "name": "飞客茶馆",
+      "keys": ["chavy_cookie_flyertea", "chavy_token_flyertea"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/flyertea",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/flyertea/flyertea.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/flyertea.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/flyertea.png"
+      ]
+    },
+    {
+      "id": "chavyleung.suning",
+      "name": "苏宁易购",
+      "settings": [
+        {
+          "id": "chavy_logflag_suning",
+          "name": "响应日志",
+          "val": false,
+          "type": "boolean",
+          "desc": "是否输出响应返回体"
+        }
+      ],
+      "keys": [
+        "chavy_login_url_suning",
+        "chavy_login_body_suning",
+        "chavy_login_header_suning",
+        "chavy_sign_url_suning",
+        "chavy_sign_header_suning",
+        "chavy_signweb_url_suning",
+        "snyg_userTokenKey",
+        "chavy_signweb_header_suning",
+        "chavy_signgame_url_suning",
+        "chavy_signgame_header_suning",
+        "chavy_signgetgame_url_suning",
+        "chavy_signgetgame_header_suning"
+      ],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/blob/master/suning/suning.js",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/suning/suning.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/suning.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/suning.png"
+      ]
+    },
+    {
+      "id": "videoqq",
+      "name": "腾讯视频",
+      "keys": [
+        "chavy_cookie_videoqq",
+        "chavy_auth_url_videoqq",
+        "chavy_auth_header_videoqq",
+        "chavy_msign_url_videoqq",
+        "chavy_msign_header_videoqq"
+      ],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/videoqq",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/videoqq/videoqq.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/videoqq.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/videoqq.png"
+      ]
+    },
+    {
+      "id": "wanda",
+      "name": "万达电影",
+      "keys": ["senku_wanda_mi_"],
+      "author": "@GideonSenku",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/wanda",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/wanda/wanda.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/wanda.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/wanda.png"
+      ]
+    },
+    {
+      "id": "ithome",
+      "name": "IT之家",
+      "keys": ["senku_ithome_userHash"],
+      "author": "@GideonSenku",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/ithome",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/ithome/ithome.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/ithome.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/ithome.png"
+      ]
+    },
+    {
+      "id": "nfzm",
+      "name": "南方周末",
+      "keys": ["senku_nfzm_url"],
+      "author": "@GideonSenku",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/nfzm",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/nfzm/nfzm.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/nfzm.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/nfzm.png"
+      ]
+    },
+    {
+      "id": "NeteaseNews",
+      "name": "网易新闻",
+      "keys": ["chavy_cookie_neteasenews", "chavy_body_neteasenews"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/neteasenews",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/neteasenews/neteasenews.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/neteasenews.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/neteasenews.png"
+      ]
+    },
+    {
+      "id": "NeteaseMusic",
+      "name": "网易云音乐",
+      "keys": ["chavy_cookie_neteasemusic"],
+      "settings": [
+        {
+          "id": "CFG_neteasemusic_retryCnt",
+          "name": "重试次数",
+          "val": 10,
+          "type": "text",
+          "desc": "一直尝试签到直至出现“重复签到”标识!"
+        },
+        {
+          "id": "CFG_neteasemusic_retryInterval",
+          "name": "重试间隔 (毫秒)",
+          "val": 500,
+          "type": "text",
+          "desc": "每次重试间隔时间 (毫秒)!"
+        }
+      ],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/neteasemusic",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/neteasemusic/neteasemusic.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/neteasemusic.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/neteasemusic.png"
+      ]
+    },
+    {
+      "id": "feng",
+      "name": "威锋网",
+      "keys": ["chavy_login_feng"],
+      "author": "@wangfei021325, @chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/feng",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/feng/feng.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/feng.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/feng.png"
+      ]
+    },
+    {
+      "id": "NoteYoudao",
+      "name": "有道云笔记",
+      "keys": [
+        "chavy_signurl_noteyoudao",
+        "chavy_signbody_noteyoudao",
+        "chavy_signheaders_noteyoudao"
+      ],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/noteyoudao",
+      "url": "https://apps.apple.com/cn/app/有道云笔记-扫描王版/id450748070",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/noteyoudao/noteyoudao.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/noteyoudao.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/noteyoudao.png"
+      ],
+      "tasks": [{ "cron": "3 0 * * *", "script": "noteyoudao.js" }],
+      "rewrites": [
+        {
+          "type": "request",
+          "pattern": "^https://note.youdao.com/yws/mapi/user?method=checkin",
+          "script": "noteyoudao.cookie.js",
+          "body": true
+        }
+      ]
+    },
+    {
+      "id": "zxhc",
+      "name": "智行火车票",
+      "keys": [
+        "senku_signurl_zxhc",
+        "senku_signheader_zxhc",
+        "senku_signbody_zxhc"
+      ],
+      "author": "@GideonSenku",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/zxhc",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/zxhc/zxhc.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/zxhc.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/zxhc.png"
+      ]
+    },
+    {
+      "id": "zimuzu",
+      "name": "字幕组",
+      "keys": ["chavy_cookie_zimuzu", "chavy_auth_url_zimuzu_app"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/zimuzu",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/zimuzu/zimuzu.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/zimuzu.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/zimuzu.png"
+      ]
+    },
+    {
+      "id": "AcFun",
+      "name": "AcFun",
+      "keys": ["chavy_cookie_acfun", "chavy_token_acfun"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/acfun",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/acfun/acfun.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/acfun.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/acfun.png"
+      ]
+    },
+    {
+      "id": "ApkTw",
+      "name": "ApkTw",
+      "keys": ["chavy_cookie_apktw"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/apktw",
+      "url": "https://apk.tw/",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/apktw/apktw.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/apktw.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/apktw.png"
+      ],
+      "tasks": [{ "cron": "3 0 * * *", "script": "apktw.js" }],
+      "rewrites": [
+        {
+          "type": "request",
+          "pattern": "^https://apk.tw/member.php(.*?)action=login",
+          "script": "apktw.cookie.js",
+          "body": true
+        }
+      ]
+    },
+    {
+      "id": "chavyleung.bilibili.live",
+      "name": "bilibili直播",
+      "keys": ["chavy_cookie_bilibili"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/blob/master/bilibili/bilibili.js",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/bilibili/bilibili.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/bilibili.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/bilibili.png"
+      ]
+    },
+    {
+      "id": "V2EX",
+      "name": "V2EX",
+      "keys": ["chavy_cookie_v2ex"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/v2ex",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/v2ex/v2ex.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/v2ex.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/v2ex.png"
+      ]
+    },
+    {
+      "id": "WPS",
+      "name": "WPS",
+      "keys": ["chavy_signhomeurl_wps", "chavy_signhomeheader_wps"],
+      "settings": [
+        {
+          "id": "CFG_wps_inviteTime",
+          "name": "邀请间隔 (毫秒)",
+          "val": 2000,
+          "type": "number",
+          "desc": "每次邀请间隔时间"
+        }
+      ],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/wps",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/wps/wps.js",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/wps.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/wps.png"
+      ]
+    },
+    {
+      "id": "ximalaya",
+      "name": "喜马拉雅",
+      "keys": ["chavy_cookie_ximalaya"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/ximalaya",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/ximalaya.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/ximalaya.png"
+      ],
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/ximalaya/ximalaya.js"
+    },
+    {
+      "id": "rrtv",
+      "name": "人人视频",
+      "keys": ["chavy_cookie_rrtv"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/rrtv",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/rrtv.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/rrtv.png"
+      ],
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/rrtv/rrtv.js"
+    },
+    {
+      "id": "everphoto",
+      "name": "时光相册",
+      "keys": ["chavy_sign_url_everphoto", "chavy_sign_header_everphoto"],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/tree/master/everphoto",
+      "icons": [
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/everphoto.png",
+        "https://raw.githubusercontent.com/Orz-3/mini/master/Color/everphoto.png"
+      ],
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/everphoto/everphoto.js"
+    },
+    {
+      "id": "testflight",
+      "name": "TestFlight",
+      "keys": ["boxapp_testflight_har"],
+      "settings": [
+        {
+          "id": "boxapp_testflight_app",
+          "name": "应用编号",
+          "val": "",
+          "type": "textarea",
+          "placeholder": "McBV96Wi,lNmLTx8d,ZfyeFB1S,srPJRks9,uEXBDwt2",
+          "autoGrow": true,
+          "rows": 5,
+          "desc": "以英文逗号分隔多个号码"
+        }
+      ],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts/blob/master/testflight",
+      "script": "https://raw.githubusercontent.com/chavyleung/scripts/master/testflight/testflight.js",
+      "icons": [
+        "https://raw.githubusercontent.com/githubdulong/Script/master/Images/testflight.png",
+        "https://raw.githubusercontent.com/githubdulong/Script/master/Images/testflight.png"
+      ]
+    }
+  ]
+}

+ 29 - 0
Scripts/box/chavy.boxjs.test.json

@@ -0,0 +1,29 @@
+{
+  "id": "chavyleung.app.test.sub",
+  "name": "测试一键订阅 (请自行删除)",
+  "author": "@chavyleung",
+  "icon": "https://avatars3.githubusercontent.com/u/29748519?s=460&u=392a19e85465abbcb1791c9b8b32184a16e6795e&v=4",
+  "repo": "https://github.com/chavyleung/scripts",
+  "onInstall": {
+    "title": "安装确认",
+    "message": "本订阅包含重写资源, 是否需要自动安装?",
+    "install": {
+      "QuanX": "quantumult-x:///add-resource?remote-resource=%7B%22rewrite_remote%22%3A%5B%22https%3A%2F%2Fgithub.com%2Fchavyleung%2Fscripts%2Fraw%2Fmaster%2Fbox%2Frewrite%2Fboxjs.rewrite.quanx.conf%2Ctag%3Dboxjs%22%5D%7D",
+      "Loon": "loon://import?plugin=https://raw.githubusercontent.com/chavyleung/scripts/master/box/rewrite/boxjs.rewrite.loon.plugin"
+    }
+  },
+  "apps": [
+    {
+      "id": "chavy_test_sub",
+      "name": "测试应用 (请删除)",
+      "keys": [],
+      "settings": [],
+      "author": "@chavyleung",
+      "repo": "https://github.com/chavyleung/scripts",
+      "icons": [
+        "https://raw.githubusercontent.com/chavyleung/scripts/master/box/icons/BoxSetting.mini.png",
+        "https://raw.githubusercontent.com/chavyleung/scripts/master/box/icons/BoxSetting.png"
+      ]
+    }
+  ]
+}

BIN
Scripts/box/icons/BoxJs.png


BIN
Scripts/box/icons/BoxSetting.mini.png


BIN
Scripts/box/icons/BoxSetting.png


BIN
Scripts/box/icons/BoxSwitcher.mini.png


BIN
Scripts/box/icons/BoxSwitcher.png


+ 2433 - 0
Scripts/box/release/box.release.json

@@ -0,0 +1,2433 @@
+{
+  "releases": [
+    {
+      "version": "0.12.9",
+      "tags": ["beta"],
+      "author": "@GideonSenku",
+      "msg": "让 openAI 写了个 Surge 费用计算器",
+      "notes": [
+        {
+          "name": "实验",
+          "descs": ["Surge 费用计算器"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.6",
+      "tags": ["beta"],
+      "author": "@VirgilClyne",
+      "msg": "fix(boxjs): msg() on Shadowrocket",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["小火箭环境下消息提示问题"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@VirgilClyne PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.5",
+      "tags": ["beta"],
+      "author": "@VirgilClyne",
+      "msg": "fix(boxjs): 修复 Stash & ShadowRocket 报错问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["修复 Stash & ShadowRocket 报错问题"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@VirgilClyne PR", "Stash 团队反馈及协助定位问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.4",
+      "tags": ["beta"],
+      "author": "@lowking",
+      "msg": "fix(boxjs): 修复 Surge 环境下执行脚本超时问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["Surge 环境下执行脚本超时问题"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@lowking PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.3",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): 修复 开关控件 及 多选控件 不正确显示默认值问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["开关控件 及 多选控件 不正确显示默认值问题"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@Virgil_C 反馈及协助"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): 修复 stash 无法运行脚本问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["stash 无法运行脚本问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.1",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): 还原 gist 可能导致的白屏",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["还原 gist 可能导致的白屏"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): 添加订阅事件 onInstall",
+      "notes": [
+        {
+          "name": "新增 (本次更新主要面向开发者)",
+          "descs": [
+            "添加订阅时, 可自动触发资源安装, 如: 自动安装重写等)",
+            "订阅列表中, 可通过`更多 > 安装`来手动触发安装",
+            "",
+            "开发文档:",
+            "https://docs.boxjs.app/dev/configure#scenes-oninstall",
+            "",
+            "目前支持 (TestFlight):",
+            "1. Loon: v2.1.19 (386) 及以上",
+            "2. Quantumult X: v1.0.29 (670) 及以上"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.11.3",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "typo(boxjs): 修复一处拼写错误",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["一处拼写错误"]
+        }
+      ]
+    },
+    {
+      "version": "0.11.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): 发现新版本时可跳转至 app 内触发资源更新",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "发现新版本时可跳转至 app 内触发资源更新",
+            "目前支持 (TestFlight):",
+            "1. Loon: v2.1.19 (386) 及以上",
+            "2. Quantumult X: v1.0.29 (670) 及以上"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.10.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): 尝试修复删除订阅问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况删除订阅引发的问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.10.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): 一键订阅",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "一键订阅",
+            "点击链接就可以自动添加订阅, 免去手动添加的麻烦",
+            "制作一键订阅地址: ",
+            "http://boxjs.com/#/sub/add/经过encodeURIComponent()订阅地址",
+            "如: http://boxjs.com/#/sub/add/https%3A%2F%2Fraw.githubusercontent.com%2Fchavyleung%2Fscripts%2Fmaster%2Fbox%2Fchavy.boxjs.json"
+          ]
+        },
+        {
+          "name": "新增",
+          "descs": [
+            "可以`分享`订阅",
+            "复制与分享的区别: ",
+            "复制: 仅复制订阅地址",
+            "分享: 生成并复制一键订阅地址, 别人仅需点击该地址则可自动添加订阅"
+          ]
+        },
+        {
+          "name": "QX 用户注意",
+          "descs": [
+            "仅配置 httpbackend 的 QX 用户无法使用一键订阅",
+            "需要配置 `重写` 或同时配置 `重写` 及 `httpbackend` 才能使用一键订阅"
+          ]
+        },
+        {
+          "name": "其他",
+          "descs": ["合并了稳定版和测试版, 两个版本已经没有区别"]
+        }
+      ]
+    },
+    {
+      "version": "0.9.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "新增(BoxJs): 支持 Stash",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "支持 Stash TF (v1.5.0 Build 203+)",
+            "https://chavyleung.gitbook.io/boxjs/#stash"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.8.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "新增(BoxJs): selects (下拉) 控件",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "新增 selects (下拉) 控件",
+            "type: 'selects'",
+            "items: [{key: '', label: ''}]"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.92",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "新增(BoxJs): 内置 Gist 备份及还原脚本. @dompling",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["内置 Gist 备份及还原脚本. @dompling"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@dompling"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.91",
+      "tags": ["beta"],
+      "author": "@NobyDa",
+      "msg": "修复(BoxJs): 部分情况手动运行脚本异常",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况手动运行脚本异常"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@NobyDa PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.90",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): backup data display bug",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["备份数据太大导致无法进入备份详情"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.89",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): add data viewer",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["数据编辑 & 查看器"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.88",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): store each backup separately",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["独立存储每份备份数据, 避免备份数据过大问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.87",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): language switching bug",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["语言切换问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.85",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): add language (zh-CN & en-US)",
+      "notes": [
+        {
+          "name": "多语言 (beta)",
+          "descs": ["增加语言: 简中、英文 "]
+        },
+        {
+          "name": "Languages (beta)",
+          "descs": ["add zh-CN & en-US"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.84",
+      "tags": ["beta"],
+      "author": "@lowking",
+      "msg": "更新[BoxJs]: 修复部分情况下壁纸模式上滑手势失效问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况下壁纸模式上滑手势失效问题"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@lowking PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.83",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 增加图标拖拽动画",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["增加图标拖拽动画"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.82",
+      "tags": ["beta"],
+      "author": "@chouchoui",
+      "msg": "更新[BoxJs]: 格式不正确的HTTP Backend不会生效",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["格式不正确的HTTP Backend不会生效"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.81",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 修复拖拽图标的时候出现文本选择光标问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["拖拽图标的时候出现文本选择光标问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.80",
+      "tags": ["beta"],
+      "author": "@Senku",
+      "msg": "更新[BoxJs]: 调整拖拽延迟",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["降低首页图标拖拽灵敏度,长按拖动"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.79",
+      "tags": ["beta"],
+      "author": "@Senku",
+      "msg": "更新[BoxJs]: 首页图标可自定义顺序",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["首页图标可拖拽自定义顺序"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.78",
+      "tags": ["beta"],
+      "author": "@chouchoui",
+      "msg": "更新[BoxJs]: 增加版本说明",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "偏好设置增加 HTTP Backend (Quantumult X)",
+            "说明: ",
+            "发现: Quantumult X 通过重写的方式访问 BoxJs 可能会导致无法删除备份的问题, 但通过 HTTP Backend 方式访问则正常。",
+            "建议: 改用 HTTP Backend 或 重写与 HTTP Backend 结合的方式访问 BoxJs",
+            "姿势: 见 使用文档 (悬浮按钮 > ?)"
+          ]
+        },
+        {
+          "name": "优化",
+          "descs": ["增加底部空间避免悬浮按钮遮挡空间"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@chouchoui PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.77",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 更新文案",
+      "notes": [
+        {
+          "name": "更新",
+          "descs": ["部分文案"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.76",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 偏好设置内可以抹掉数据",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["偏好设置内可以抹掉数据"]
+        },
+        {
+          "name": "说明",
+          "descs": [
+            "抹掉:所有缓存",
+            "抹掉订阅及页面缓存,会导致所有订阅显示格式错误,双击底栏'订阅'菜单或更新订阅即可恢复",
+            "",
+            "抹掉:收藏应用",
+            "抹掉所有收藏的应用,排序出现问题时可尝试抹掉",
+            "",
+            "抹掉:用户偏好",
+            "抹掉头像、设置、收藏等个人相关的数据, 注意:不含会话、备份、缓存",
+            "",
+            "抹掉:所有会话",
+            "抹掉所有应用下的会话, 注意:不会抹掉当前会话",
+            "",
+            "抹掉:所有备份",
+            "抹掉所有全局备份, 注意:抹掉前可先把备份复制到其他文本类应用内",
+            "",
+            "抹掉:BoxJs",
+            "抹掉所有由 BoxJs 管理的数据, 如:备份、会话、偏好、缓存等 (不包含当前会话)"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.75",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 修复退出壁纸模式后壁纸无法还原问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["修复退出壁纸模式后壁纸无法还原问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.74",
+      "tags": ["beta"],
+      "author": "@lowking",
+      "msg": "更新[BoxJs]: 更方便快捷的看小姐姐",
+      "notes": [
+        {
+          "name": "新增特性",
+          "descs": ["悬浮图标下滑进入壁纸模式自动切换到配置好的壁纸,退出同理"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@lowking PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.73",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 修复小火箭环境下手动运行脚本报错问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["小火箭环境下手动运行脚本报错问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.72",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 适配小火箭, 感谢 @Orz-3 提供图标",
+      "notes": [
+        {
+          "name": "适配",
+          "descs": ["Shadowrocket (小火箭)"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@Orz-3 提供图标"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.71",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 修复备份数据异常导致无法进入页面问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["备份数据异常导致无法进入页面问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.69",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 移除 gitee 链接, 改用 github raw 及 jsdelivr",
+      "notes": [
+        {
+          "name": "说明",
+          "descs": [
+            "由于通过 gitee 访问部分仓库资源时出现 `根据相关法律政策,该内容无法显示`",
+            "虽然我手动同步 github 代码后已经可以正常访问",
+            "但为避免以后出现不可预知的情况:",
+            "我们把全部 gitee 链接替换为 github raw 及 jsdelivr",
+            "----",
+            "大家只需正常更新订阅并重启代理即可"
+          ]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@zZPiglet PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.68",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 订阅格式错误导致无法进入页面问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["订阅格式错误导致无法进入页面问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.67",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 自动替换 BoxJs 订阅中 Orz-3/mini 库的图标路径",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["Orz-3/mini 库图标路径"]
+        },
+        {
+          "name": "注意",
+          "descs": [
+            "如果订阅里有旧的图标路径,BoxJs 会自动转换为新路径,有问题请反馈"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.66",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 更新 Orz-3/mini 库图标路径",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["Orz-3/mini 库图标路径"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.65",
+      "tags": ["beta"],
+      "author": "@id77",
+      "msg": "更新[BoxJs]: 应用会话前,清空当前会话数据",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["应用会话前,清空当前会话数据"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@id77 PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.64",
+      "tags": ["beta"],
+      "author": "@whyour",
+      "msg": "更新[BoxJs]: 优化底栏按钮高亮样式",
+      "notes": [
+        {
+          "name": "增加",
+          "descs": ["只复制 App 数据为对象功能"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@whyour PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.62",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 优化底栏按钮高亮样式",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["去掉底栏按钮高亮时的背景色"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.61",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 修复订阅为 null 时数据加载报错",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": [
+            "由于网络问题,导致订阅数据异常后,访问页面时仅显示 BoxJs 字样问题。"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.60",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 增加判断 BoxJs 订阅格式判断",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["添加非 BoxJs 订阅时导致白屏问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.59",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: Vuetify 升级至 v2.4",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["升级 Vuetify 版本"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.58",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 刷新订阅添加时间缀避免网络缓存",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": [
+            "BoxJs 内的请求会可以被重写",
+            "刷新订阅添加时间缀避免网络缓存"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.56",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs TF]: 修复一处导致白屏逻辑",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["修复一处导致白屏逻辑"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.55",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs TF]: 顶栏和底栏可以设置跟随滚动",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["顶栏和底栏可以设置跟随滚动"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.54",
+      "tags": ["beta"],
+      "author": "@id77",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 侧栏增加新的贡献者 @id77",
+      "notes": [
+        {
+          "name": "贡献者",
+          "descs": ["新的贡献者 @id77"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.53",
+      "tags": ["beta"],
+      "author": "@GideonSenku",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 跟随系统壁纸设置同时支持中英文",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["跟随系统壁纸设置支持中英文,且优先考虑中文关键字"]
+        },
+        {
+          "name": "说明",
+          "descs": ["中文关键字为`暗黑`和`明亮`,英文关键字不变"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.52",
+      "tags": ["beta"],
+      "author": "@id77 @chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 删除备份后直接回到首页问题",
+      "notes": [
+        {
+          "name": "移除",
+          "descs": [
+            "主屏幕的左右滑动手势",
+            "原因: 与浏览器前进后退容易发生冲突"
+          ]
+        },
+        {
+          "name": "修复",
+          "descs": ["删除备份后直接回到首页问题"]
+        },
+        {
+          "name": "优化",
+          "descs": ["页面后退事件逻辑", "部分侧栏设置的小字说明"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.49",
+      "tags": ["beta"],
+      "author": "@GideonSenku",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复主屏左滑时与侧栏冲突问题",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["背景图片可跟随系统调整"]
+        },
+        {
+          "name": "调整",
+          "descs": ["背景清单图片默认`无`更改为`跟随系统`"]
+        },
+        {
+          "name": "修复",
+          "descs": ["主屏左滑时与侧栏冲突问题"]
+        },
+        {
+          "name": "说明",
+          "descs": [
+            "背景图片清单中设置:无{换行} 跟随系统,跟随系统{换行} light,图片地址{换行} dark,图片地址{换行}",
+            "如果不设置`跟随系统,跟随系统`,则默认跟随系统为无背景"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.47",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复代码编辑器高度, 部分界面左右滑动范围问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": [
+            "代码编辑器高度问题",
+            "部分界面只能在有内容的范围左右滑动问题"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.46",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 移除滑动动画, 勿扰模式不弹脚本执行结果页, 操作优化",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": [
+            "勿扰模式下运行脚本不弹出结果页",
+            "壁纸模式下滑更容易退出壁纸模式"
+          ]
+        },
+        {
+          "name": "移除",
+          "descs": ["左右滑动切换页面的动画"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.45",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复脚本执行结果、更新日志页面位置不正确, 主页左滑进入壁纸模式",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["主页左滑进入壁纸模式"]
+        },
+        {
+          "name": "修复",
+          "descs": ["脚本执行结果、更新日志页面位置不正确"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.44",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 主屏幕左右滑动可切换 首页、应用、订阅、我的 页面",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "Surge、QuanX、Loon 手动运行脚本时都可以显示执行结果",
+            "主屏幕左右滑动可切换 首页、应用、订阅、我的 页面"
+          ]
+        },
+        {
+          "name": "修复",
+          "descs": ["全局搜索结果位置不正确问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.43",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复非壁纸模式下上滑仍然重新渲染壁纸",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "在顶栏上滑可隐藏顶栏",
+            "在底栏下滑可以隐藏底栏",
+            "壁纸模式上滑可以重新渲染壁纸"
+          ]
+        },
+        {
+          "name": "修复",
+          "descs": [
+            "代码编辑器不显示问题",
+            "二次进入搜索界面无法自动获取焦点",
+            "非壁纸模式下上滑仍然重新渲染壁纸"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.41",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复顶栏隐藏时图标没往上挪, 悬浮按钮上滑切壁纸, 壁纸模式隐藏悬浮按钮",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["壁纸模式会把悬浮按钮也隐藏起来"]
+        },
+        {
+          "name": "修复",
+          "descs": ["顶栏隐藏时图标没有往上挪"]
+        },
+        {
+          "name": "悬浮按钮手势",
+          "descs": [
+            "上滑: 重渲染&切换壁纸",
+            "左滑: 悬浮按钮左靠",
+            "右滑: 悬浮按钮右靠",
+            "下滑: 切换壁纸模式"
+          ]
+        },
+        {
+          "name": "说明",
+          "descs": [
+            "壁纸模式下: 下滑取消壁纸模式",
+            "非壁纸模式: 下滑显示\\隐藏顶栏"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.40",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 新增壁纸模式、悬浮按钮手势",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["壁纸模式", "悬浮按钮手势"]
+        },
+        {
+          "name": "悬浮按钮手势",
+          "descs": [
+            "上滑: 刷新页面 (效果同双击)",
+            "左滑: 悬浮按钮左靠",
+            "右滑: 悬浮按钮右靠",
+            "下滑: 切换壁纸模式"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.39",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复部分情况下拉出顶栏事件失效问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况下拉出顶栏事件失效问题"]
+        },
+        {
+          "name": "优化",
+          "descs": ["原来顶部的加载条移到底栏上方"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.38",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 新增 Surge HTTP-API 环境下运行脚本会显示运行结果",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["Surge HTTP-API 环境下运行脚本会显示运行结果"]
+        },
+        {
+          "name": "优化",
+          "descs": ["页面样式"]
+        },
+        {
+          "name": "移除",
+          "descs": ["顶栏跟随滚动"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.37",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 应用标题加阴影, 优化调试代码, 单击首页重渲染壁纸",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["应用标题加阴影"]
+        },
+        {
+          "name": "调试",
+          "descs": ["优化代码"]
+        },
+        {
+          "name": "新增",
+          "descs": ["单击首页回到顶部, 再单击一次重新渲染壁纸"]
+        },
+        {
+          "name": "壁纸",
+          "descs": [
+            "无背景,",
+            "随机,https://uploadbeta.com/api/pictures/random",
+            "推女郎,https://uploadbeta.com/api/pictures/random/?key=推女郎",
+            "性感,https://uploadbeta.com/api/pictures/random/?key=性感",
+            "车模,https://uploadbeta.com/api/pictures/random/?key=车模",
+            "美腿,https://uploadbeta.com/api/pictures/random/?key=美腿",
+            "美女,https://uploadbeta.com/api/pictures/random/?key=美女",
+            "手机妹子,http://api.btstu.cn/sjbz/zsy.php",
+            "手机美女,http://api.btstu.cn/sjbz/?m_lx=suiji"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.36",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["下拉显示&隐藏搜索栏"]
+        },
+        {
+          "name": "优化",
+          "descs": ["固定背景"]
+        },
+        {
+          "name": "修复",
+          "descs": ["搜索栏高度问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.35",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "调试",
+          "descs": ["调试模式下支持自定义页面源码地址"]
+        },
+        {
+          "name": "修复",
+          "descs": [
+            "底栏事件无效问题",
+            "部分情况下贡献者重复加载问题",
+            "手势前进后退会白屏&卡屏问题"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.33",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["支持前进、后退", "WebApp 状态下刷新能留在当前页面"]
+        },
+        {
+          "name": "修复",
+          "descs": ["侧栏拉不到底缺陷"]
+        },
+        {
+          "name": "调试",
+          "descs": ["支持 vue devtool (侧栏开启调试模式)"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @id77 大佬 PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.30",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["首页背景可以一直固定住"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @id77 大佬 PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.29",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "代码编辑器",
+          "descs": ["Surge HTTP-API 环境下执行的代码能显示响应内容"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.28",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["数据后端渲染", "更快更平顺的首页加载", "不闪屏了"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @eslint 大佬提供帮助"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.27",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["首页样式", "操作体验"]
+        },
+        {
+          "name": "首页",
+          "descs": ["顶栏透明", "可以隐藏顶栏", "顶栏可以固定或跟随滚动"]
+        },
+        {
+          "name": "悬浮按钮",
+          "descs": ["增加搜索入口"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.26",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "调整",
+          "descs": ["搜索条样式", "搜索操作界面"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.24",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["解决首屏闪屏问题", "解决图标白边问题", "导入会话报错"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @eslint 大佬提供帮助"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.21",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["一键清空会话数据"]
+        },
+        {
+          "name": "优化",
+          "descs": ["壁纸状态下图标字体颜色为白色", "其他样式优化"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.20",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["勿扰模式下, 不再忽略手动执行脚本时发出的系统通知"]
+        },
+        {
+          "name": "新增",
+          "descs": ["可以设置多张壁纸 (偏好设置)"]
+        },
+        {
+          "name": "注意",
+          "descs": ["设置多张壁纸后,在侧栏切换"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.18",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["代码编辑器 (入口: 悬浮按钮)"]
+        },
+        {
+          "name": "说明",
+          "descs": [
+            "除了本机运行外",
+            "可以使用 PC 连上 QuanX 的 HTTP Backend",
+            "实现在 PC 上写代码然后发送到 QuanX 执行",
+            "Surge、Loon 同理"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.17",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["首页壁纸 (偏好设置)"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.16",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["首页图标样式"]
+        },
+        {
+          "name": "修复",
+          "descs": [
+            "首页图标点击无效问题",
+            "首页图标有轻微位移问题",
+            "帮助页面打开空白"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.11",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["首页显示收藏应用", "订阅中的更多按钮可以链接到作者仓库"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.9",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["可以修改会话", "增加帮忙手册入口", "推荐订阅入口"]
+        },
+        {
+          "name": "调整",
+          "descs": ["调整加载动态效果"]
+        },
+        {
+          "name": "修复",
+          "descs": ["boolean 控件偶尔触发键盘问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.7",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["全程无刷新", "独立分离页面", "优化数据结构减少内存占用"]
+        },
+        {
+          "name": "操作",
+          "descs": [
+            "可以修复全局备份的名字",
+            "点击'应用'回到顶部,再次单击折叠面板",
+            "点击'订阅'回到顶部,再次单击刷新订阅",
+            "点击具体订阅可刷新"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.6.20",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: BoxJs 内的请求会可以被重写",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": [
+            "BoxJs 内的请求会可以被重写",
+            "刷新订阅添加时间缀避免网络缓存"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.6.18",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["清空设置时一直转圈问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.6.17",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["勿扰模式", "应用界面双击底栏能返回应用列表"]
+        },
+        {
+          "name": "注意",
+          "descs": ["勿扰模式下仍然可以通过日志查看通过内容"]
+        }
+      ]
+    },
+    {
+      "version": "0.6.16",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "订阅配置",
+          "descs": [
+            "新增: desc、descs、desc_html、descs_html 属性",
+            "与 id、name 同级"
+          ]
+        },
+        {
+          "name": "示例",
+          "descs": [
+            "https://gist.githubusercontent.com/chavyleung/9d53fc4809eb41dca5f5923790ec5554/raw/09742d3473420d8e0bd7b02a910849f65af879fa/chavy.app.sub.simple.json"
+          ]
+        },
+        {
+          "name": "注意",
+          "descs": ["本次更新主要面向开发者"]
+        }
+      ]
+    },
+    {
+      "version": "0.6.15",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "偏好设置",
+          "descs": ["新增: http-api 超时时间, 默认 20 秒"]
+        },
+        {
+          "name": "订阅配置",
+          "descs": [
+            "增加 script_timeout 属性, 与 script 同级, 可指定 http-api 超时时间, 单位: 秒"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.6.14",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["可能导致白屏的问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.6.13",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["开关控件可以显示详情信息"]
+        },
+        {
+          "name": "域名",
+          "descs": ["新增: http://boxjs.com"]
+        },
+        {
+          "name": "新的重写订阅",
+          "descs": [
+            "Surge: https://raw.githubusercontent.com/chavyleung/scripts/master/box/rewrite/boxjs.rewrite.surge.sgmodule",
+            "QuanX: https://raw.githubusercontent.com/chavyleung/scripts/master/box/rewrite/boxjs.rewrite.quanx.conf",
+            "Loon: https://raw.githubusercontent.com/chavyleung/scripts/master/box/rewrite/boxjs.rewrite.loon.conf"
+          ]
+        },
+        {
+          "name": "注意",
+          "descs": [
+            "新的重写订阅只有 boxjs.com",
+            "旧的重写订阅仍然保留 8888 1111 和新增的 boxjs.com",
+            "可以直接访问 http://boxjs.com 不加/home"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.6.12",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": [
+            "双击底栏'应用'可以收缩面板并回到顶部",
+            "双击底栏'订阅'可以刷新订阅并回到顶部",
+            "双击'BoxJs'按钮可以刷新页面",
+            "保存应用设置、清存会话数据能马上生效 (不用刷新页面)",
+            "可以隐藏刷新按钮"
+          ]
+        },
+        {
+          "name": "主题",
+          "descs": ["页面更多元素会跟随主题色调"]
+        },
+        {
+          "name": "重写",
+          "descs": [
+            "BoxJs 的重写已经去除代码级依赖",
+            "意味着仅通过修改正则和主机名即可替换 BoxJs 的访问地址",
+            "同时征集一个比较理想的国内域名作为 BoxJs 的免翻墙访问地址",
+            "iOS14 Surge TF 下提示私密连接的问题, 可以找一个 http 的域名来试试"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.6.11",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["底栏颜色会跟随主题色调"]
+        }
+      ]
+    },
+    {
+      "version": "0.6.10",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "调整",
+          "descs": ["内置应用 偏好设置、切换会话 图标"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @Orz-3 制作图标"]
+        }
+      ]
+    },
+    {
+      "version": "0.6.9",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "内置应用: 偏好设置",
+            "可以设置多个 http-api (设置完后在侧栏选择)",
+            "可以分别设置暗黑、明亮主题下的主色调"
+          ]
+        },
+        {
+          "name": "控件",
+          "descs": ["拾色器: colorpicker"]
+        },
+        {
+          "name": "注意",
+          "descs": [
+            "设置多个 http-api 时, 建议以逗号开头, 侧栏中选择空白的那个就是走 eval() 方案"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.6.8",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "调整",
+          "descs": ["运行按钮位置"]
+        },
+        {
+          "name": "新增",
+          "descs": [
+            "可以显示当前切换至哪个会话",
+            "应用可以设定多个运行脚本 scripts: {name: '', script: ''}",
+            "示例: https://gist.githubusercontent.com/chavyleung/9d53fc4809eb41dca5f5923790ec5554/raw/4d8b140ba149c33aa1fc622e93c4035ae74a73bb/chavy.app.sub.simple.json"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.6.7",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "重写",
+          "descs": [
+            "BoxJs Surge 的重写超时改为 120 秒 (避免手动运行脚本容易超时)"
+          ]
+        },
+        {
+          "name": "调整",
+          "descs": [
+            "迁移 吾爱破解、爱奇艺 至原作者订阅: @NobyDa (野比)",
+            "https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.6.6",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "调整",
+          "descs": [
+            "迁移 腾讯新闻 至原作者订阅: @Sunert",
+            "https://raw.githubusercontent.com/Sunert/Scripts/master/Task/sunert.boxjs.json"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.6.5",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["Surge、QuanX、Loon 都可以在 BoxJs 中手动运行脚本"]
+        },
+        {
+          "name": "说明",
+          "descs": [
+            "手动运行脚本采用 eval() 方案",
+            "Surge 在配置了 http-api 参数下会使用 http-api 方案运行脚本",
+            "因为手法有点特殊, 不保证所有脚本都能良好"
+          ]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @NobyDa 野比大佬提醒可以使用 eval() 方案"]
+        }
+      ]
+    },
+    {
+      "version": "0.6.4",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["应用订阅可以排序"]
+        }
+      ]
+    },
+    {
+      "version": "0.6.3",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "主题",
+          "descs": ["非全屏状态下使用白色头部"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @chouchoui 的 PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.6.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "主题",
+          "descs": ["浅色主题下使用黄色头部", "全屏状态下使用透明头部"]
+        },
+        {
+          "name": "注意",
+          "descs": ["需要重新添加到桌面才能生效"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @chouchoui 的 PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.6.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["可在 BoxJs 下直接运行脚本 (Surge TF)"]
+        },
+        {
+          "name": "注意",
+          "descs": [
+            "目前仅支持 Surge iOS TF & Surge mac 4.x",
+            "需要在 Surge配置文件中指定 http-api",
+            "然后在 BoxJs 侧栏中设置 http-api 路径",
+            "目前内置应用和 chavy.boxjs.json 内的应用都可以手动运行, 其他订阅需订阅作者更新订阅",
+            "资料: https://community.nssurge.com/d/327-http-api"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.5.8",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["明亮主题下收藏按钮样式问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.5.7",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["Rewrite 地址换成 Gitee (更新 BoxJs 后注意重启)"]
+        },
+        {
+          "name": "教程",
+          "descs": ["QuanX 购买超 (90 > 30) 天即可一键更新"]
+        }
+      ]
+    },
+    {
+      "version": "0.5.6",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["版本判断地址调整为 Gitee"]
+        }
+      ]
+    },
+    {
+      "version": "0.5.4",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["版本刷新速度"]
+        }
+      ]
+    },
+    {
+      "version": "0.5.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["可以单独更新订阅"]
+        }
+      ]
+    },
+    {
+      "version": "0.5.1",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["版本判断速度 (jsdelivr)"]
+        }
+      ]
+    },
+    {
+      "version": "0.5.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "抹掉数据: https://8.8.8.8/revert (更新完需要重启代理)",
+            "出现问题时可单独访问页面抹掉数据"
+          ]
+        },
+        {
+          "name": "调整",
+          "descs": [
+            "迁移内置应用至订阅: https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.json (需要手动更新订阅)"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.4.23",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["侧栏样式 (紧凑化)"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.22",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["后台日志报 illegal 问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.21",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["颜色主题可跟随系统 (明亮主题下强制使用彩色图标)"]
+        },
+        {
+          "name": "修复",
+          "descs": ["有新版本但没有提示问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.20",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["明暗主题切换"]
+        },
+        {
+          "name": "优化",
+          "descs": ["页面渲染资源"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.19",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["v0.4.18 白屏问题 (百果园空图标导致)"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.18",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "仓库协作者&贡献者信息 (带跳转)",
+            "点击订阅可以跳转至作者仓库"
+          ]
+        },
+        {
+          "name": "修复",
+          "descs": ["删除多余日志输出"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.17",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["Loon升级教程字眼错误问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.16",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["iPhone X 底栏样式优化 (避免 bar 遮挡)"]
+        },
+        {
+          "name": "修复",
+          "descs": ["多行文本控件 rows 属性无效问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.15",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["多选组控件全部取消时会恢复到默认问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.14",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增 (面向开发者)",
+          "descs": ["数字控件 (number)"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.13",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "性能",
+          "descs": ["优化订阅刷新性能 (并行)"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.12",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况下刷新&添加订阅无效问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.11",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["收藏应用排序异常问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.10",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "调整",
+          "descs": [
+            "京东, 请使用野比大佬的订阅: https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.4.9",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增 (面向开发者)",
+          "descs": ["单选组控件", "多选组控件"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.8",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["添加&刷新订阅的消息通知"]
+        },
+        {
+          "name": "修复",
+          "descs": ["添加订阅时显示格式错误", "刷新订阅有时不生效"]
+        },
+        {
+          "name": "移除",
+          "descs": ["刷新等待秒数"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.7",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": [
+            "部分情况下无法清空会话数值问题 (更新脚本后, 需要手动刷新下订阅)"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.4.6",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["透明图标处理"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.5",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况下内置应用不显示问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.4",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["应用分类可以收纳"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.3",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["删除&导入会话时 Loading 动画不能自动消失问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": [
+            "部分情况下保存数据不生效问题 (实验)",
+            "Rewrite正则 (注意更新正则)"
+          ]
+        },
+        {
+          "name": "移除",
+          "descs": ["修复VPN断连设置项", "自动更新订阅 (可手动更新)"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.1",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "增加",
+          "descs": ["修复VPN断连设置项 (实验)"]
+        }
+      ]
+    },
+    {
+      "version": "0.4.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["可以修改已保存的会话"]
+        }
+      ]
+    },
+    {
+      "version": "0.3.10",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": [
+            "可以把当前会话保存至指定会话 (注意先保存设置再使用`保存至`)",
+            "可以设置刷新等待秒数 (为 0 时直接刷新不弹窗)"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.3.9",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": [
+            "可以复制单个应用订阅地址",
+            "增加底部间距避免界面被悬浮按钮遮挡"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.3.8",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": [
+            "刷新窗口增加 3 秒倒数自动刷新",
+            "添加订阅能马上刷新订阅",
+            "刷新窗口弹出时会顺便发起更新应用订阅",
+            "可以隐藏手动更新订阅的提示"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.3.7",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": [
+            "部分情况下导入空数据产生的问题 (如: 京东没有账号2, 导入后提示账号 2 签到失败问题)"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.3.6",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况下当前会话变双份问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.3.5",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["获取会话、应用会话、清空会话不生效问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.3.4",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": [
+            "页面渲染时会先出现一串代码问题",
+            "进入应用订阅页面提示手动刷新",
+            "可以隐藏|显示`我的`标题"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.3.3",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["Loon环境判断错误问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.3.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "调整",
+          "descs": ["应用订阅启用缓存机制 (需要手动更新)"]
+        }
+      ]
+    },
+    {
+      "version": "0.3.1",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["手动切换会话会导致自动切换顺序错误问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.3.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["全局搜索"]
+        }
+      ]
+    },
+    {
+      "version": "0.2.4",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["帮助页面样式", "订阅链接多余空格&换行等字符"]
+        }
+      ]
+    },
+    {
+      "version": "0.2.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["悬浮按钮刷新不用确认", "侧栏可以隐藏帮助按钮"]
+        }
+      ]
+    },
+    {
+      "version": "0.2.1",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["可以设置悬浮按钮的位置"]
+        }
+      ]
+    },
+    {
+      "version": "0.2.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["版本更新提醒", "BoxJs升级教程"]
+        }
+      ]
+    },
+    {
+      "version": "0.1.3",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["长文本控件", "读写表达式"]
+        }
+      ]
+    }
+  ]
+}

+ 1371 - 0
Scripts/box/release/box.release.tf.json

@@ -0,0 +1,1371 @@
+{
+  "releases": [
+    {
+      "version": "0.12.9",
+      "tags": ["beta"],
+      "author": "@GideonSenku",
+      "msg": "让 openAI 写了个 Surge 费用计算器",
+      "notes": [
+        {
+          "name": "实验",
+          "descs": ["Surge 费用计算器"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.6",
+      "tags": ["beta"],
+      "author": "@VirgilClyne",
+      "msg": "fix(boxjs): msg() on Shadowrocket",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["小火箭环境下消息提示问题"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@VirgilClyne PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.5",
+      "tags": ["beta"],
+      "author": "@VirgilClyne",
+      "msg": "fix(boxjs): 修复 Stash & ShadowRocket 报错问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["修复 Stash & ShadowRocket 报错问题"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@VirgilClyne PR", "Stash 团队反馈及协助定位问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.4",
+      "tags": ["beta"],
+      "author": "@lowking",
+      "msg": "fix(boxjs): 修复 Surge 环境下执行脚本超时问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["Surge 环境下执行脚本超时问题"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@lowking PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.3",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): 修复 开关控件 及 多选控件 不正确显示默认值问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["开关控件 及 多选控件 不正确显示默认值问题"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@Virgil_C 反馈及协助"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): 修复 stash 无法运行脚本问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["stash 无法运行脚本问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.1",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): 还原 gist 可能导致的白屏",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["还原 gist 可能导致的白屏"]
+        }
+      ]
+    },
+    {
+      "version": "0.12.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): 订阅添加事件 onInstall",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "添加订阅时, 可自动触发重写安装 (需要 App 支持)",
+            "订阅列表中, 可通过`更多 > 安装`来手动触发安装",
+            "",
+            "开发文档:",
+            "https://docs.boxjs.app/dev/configure#scenes-oninstall",
+            "",
+            "目前支持 (TestFlight):",
+            "1. Loon: v2.1.19 (386) 及以上",
+            "2. Quantumult X: v1.0.29 (670) 及以上"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.11.3",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "typo(boxjs): 修复一处拼写错误",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["一处拼写错误"]
+        }
+      ]
+    },
+    {
+      "version": "0.11.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): 发现新版本时可跳转至 app 内触发资源更新",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "发现新版本时可跳转至 app 内触发资源更新",
+            "目前支持 (TestFlight):",
+            "1. Loon: v2.1.19 (386) 及以上",
+            "2. Quantumult X: v1.0.29 (670) 及以上"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.10.2",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): 尝试修复删除订阅问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况删除订阅引发的问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.10.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): 一键订阅",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "一键订阅",
+            "点击链接就可以自动添加订阅, 免去手动添加的麻烦",
+            "制作一键订阅地址: ",
+            "http://boxjs.com/#/sub/add/经过encodeURIComponent()订阅地址",
+            "如: http://boxjs.com/#/sub/add/https%3A%2F%2Fraw.githubusercontent.com%2Fchavyleung%2Fscripts%2Fmaster%2Fbox%2Fchavy.boxjs.json"
+          ]
+        },
+        {
+          "name": "新增",
+          "descs": [
+            "可以`分享`订阅",
+            "复制与分享的区别: ",
+            "复制: 仅复制订阅地址",
+            "分享: 生成并复制一键订阅地址, 别人仅需点击该地址则可自动添加订阅"
+          ]
+        },
+        {
+          "name": "QX 用户注意",
+          "descs": [
+            "仅配置 httpbackend 的 QX 用户无法使用一键订阅",
+            "需要配置 `重写` 或同时配置 `重写` 及 `httpbackend` 才能使用一键订阅"
+          ]
+        },
+        {
+          "name": "其他",
+          "descs": ["合并了稳定版和测试版, 两个版本已经没有区别"]
+        }
+      ]
+    },
+    {
+      "version": "0.9.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "新增(BoxJs): 支持 Stash",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "支持 Stash TF (v1.5.0 Build 203+)",
+            "https://chavyleung.gitbook.io/boxjs/#stash"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.8.0",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "新增(BoxJs): selects (下拉) 控件",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "新增 selects (下拉) 控件",
+            "type: 'selects'",
+            "items: [{key: '', label: ''}]"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.92",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "新增(BoxJs): 内置 Gist 备份及还原脚本. @dompling",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["内置 Gist 备份及还原脚本. @dompling"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@dompling"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.91",
+      "tags": ["beta"],
+      "author": "@NobyDa",
+      "msg": "修复(BoxJs): 部分情况手动运行脚本异常",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况手动运行脚本异常"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@NobyDa PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.90",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): backup data display bug",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["备份数据太大导致无法进入备份详情"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.89",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): add data viewer",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["数据编辑 & 查看器"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.88",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): store each backup separately",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["独立存储每份备份数据, 避免备份数据过大问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.87",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "fix(boxjs): language switching bug",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["语言切换问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.85",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "feat(boxjs): add languages (zh-CN & en-US)",
+      "notes": [
+        {
+          "name": "多语言 (beta)",
+          "descs": ["增加语言: 简中、英文 "]
+        },
+        {
+          "name": "Languages (beta)",
+          "descs": ["add zh-CN & en-US"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.84",
+      "tags": ["beta"],
+      "author": "@lowking",
+      "msg": "更新[BoxJs]: 修复部分情况下壁纸模式上滑手势失效问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况下壁纸模式上滑手势失效问题"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@lowking PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.83",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 增加图标拖拽动画",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["增加图标拖拽动画"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.82",
+      "tags": ["beta"],
+      "author": "@chouchoui",
+      "msg": "更新[BoxJs]: 格式不正确的HTTP Backend不会生效",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["格式不正确的HTTP Backend不会生效"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.81",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 修复拖拽图标的时候出现文本选择光标问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["拖拽图标的时候出现文本选择光标问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.80",
+      "tags": ["beta"],
+      "author": "@Senku",
+      "msg": "更新[BoxJs]: 调整拖拽延迟",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["降低首页图标拖拽灵敏度,长按拖动"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.79",
+      "tags": ["beta"],
+      "author": "@Senku",
+      "msg": "更新[BoxJs]: 首页图标可自定义顺序",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["首页图标可拖拽自定义顺序"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.78",
+      "tags": ["beta"],
+      "author": "@chouchoui",
+      "msg": "更新[BoxJs]: 增加版本说明",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "偏好设置增加 HTTP Backend (Quantumult X)",
+            "说明: ",
+            "发现: Quantumult X 通过重写的方式访问 BoxJs 可能会导致无法删除备份的问题, 但通过 HTTP Backend 方式访问则正常。",
+            "建议: 改用 HTTP Backend 或 重写与 HTTP Backend 结合的方式访问 BoxJs",
+            "姿势: 见 使用文档 (悬浮按钮 > ?)"
+          ]
+        },
+        {
+          "name": "优化",
+          "descs": ["增加底部空间避免悬浮按钮遮挡空间"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@chouchoui PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.77",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 更新文案",
+      "notes": [
+        {
+          "name": "更新",
+          "descs": ["部分文案"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.76",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 偏好设置内可以抹掉数据",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["偏好设置内可以抹掉数据"]
+        },
+        {
+          "name": "说明",
+          "descs": [
+            "抹掉:所有缓存",
+            "抹掉订阅及页面缓存,会导致所有订阅显示格式错误,双击底栏'订阅'菜单或更新订阅即可恢复",
+            "",
+            "抹掉:收藏应用",
+            "抹掉所有收藏的应用,排序出现问题时可尝试抹掉",
+            "",
+            "抹掉:用户偏好",
+            "抹掉头像、设置、收藏等个人相关的数据, 注意:不含会话、备份、缓存",
+            "",
+            "抹掉:所有会话",
+            "抹掉所有应用下的会话, 注意:不会抹掉当前会话",
+            "",
+            "抹掉:所有备份",
+            "抹掉所有全局备份, 注意:抹掉前可先把备份复制到其他文本类应用内",
+            "",
+            "抹掉:BoxJs",
+            "抹掉所有由 BoxJs 管理的数据, 如:备份、会话、偏好、缓存等 (不包含当前会话)"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.75",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 修复退出壁纸模式后壁纸无法还原问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["修复退出壁纸模式后壁纸无法还原问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.74",
+      "tags": ["beta"],
+      "author": "@lowking",
+      "msg": "更新[BoxJs]: 更方便快捷的看小姐姐",
+      "notes": [
+        {
+          "name": "新增特性",
+          "descs": ["悬浮图标下滑进入壁纸模式自动切换到配置好的壁纸,退出同理"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@lowking PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.73",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 修复小火箭环境下手动运行脚本报错问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["小火箭环境下手动运行脚本报错问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.72",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 适配小火箭, 感谢 @Orz-3 提供图标",
+      "notes": [
+        {
+          "name": "适配",
+          "descs": ["Shadowrocket (小火箭)"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@Orz-3 提供图标"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.71",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 修复备份数据异常导致无法进入页面问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["备份数据异常导致无法进入页面问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.69",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 移除 gitee 链接, 改用 github raw 及 jsdelivr",
+      "notes": [
+        {
+          "name": "说明",
+          "descs": [
+            "由于通过 gitee 访问部分仓库资源时出现 `根据相关法律政策,该内容无法显示`",
+            "虽然我手动同步 github 代码后已经可以正常访问",
+            "但为避免以后出现不可预知的情况:",
+            "我们把全部 gitee 链接替换为 github raw 及 jsdelivr",
+            "----",
+            "大家只需正常更新订阅并重启代理即可"
+          ]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@zZPiglet PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.68",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 订阅格式错误导致无法进入页面问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["订阅格式错误导致无法进入页面问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.67",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 自动替换 BoxJs 订阅中 Orz-3/mini 库的图标路径",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["Orz-3/mini 库图标路径"]
+        },
+        {
+          "name": "注意",
+          "descs": [
+            "如果订阅里有旧的图标路径,BoxJs 会自动转换为新路径,有问题请反馈"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.66",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 更新 Orz-3/mini 库图标路径",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["Orz-3/mini 库图标路径"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.65",
+      "tags": ["beta"],
+      "author": "@id77",
+      "msg": "更新[BoxJs]: 应用会话前,清空当前会话数据",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["应用会话前,清空当前会话数据"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@id77 PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.64",
+      "tags": ["beta"],
+      "author": "@whyour",
+      "msg": "更新[BoxJs]: 增加只复制 App 数据为对象功能",
+      "notes": [
+        {
+          "name": "增加",
+          "descs": ["只复制 App 数据为对象功能"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["@whyour PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.62",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 优化底栏按钮高亮样式",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["去掉底栏按钮高亮时的背景色"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.61",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 修复订阅为 null 时数据加载报错",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": [
+            "由于网络问题,导致订阅数据异常后,访问页面时仅显示 BoxJs 字样问题。"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.60",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 增加判断 BoxJs 订阅格式判断",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["添加非 BoxJs 订阅时导致白屏问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.59",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: Vuetify 升级至 v2.4",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["升级 Vuetify 版本"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.58",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs]: 刷新订阅添加时间缀避免网络缓存",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": [
+            "BoxJs 内的请求会可以被重写",
+            "刷新订阅添加时间缀避免网络缓存"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.56",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs TF]: 修复一处导致白屏逻辑",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["修复一处导致白屏逻辑"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.55",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "msg": "更新[BoxJs TF]: 顶栏和底栏可以设置跟随滚动",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["顶栏和底栏可以设置跟随滚动"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.54",
+      "tags": ["beta"],
+      "author": "@id77",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 侧栏增加新的贡献者 @id77",
+      "notes": [
+        {
+          "name": "贡献者",
+          "descs": ["新的贡献者 @id77"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.53",
+      "tags": ["beta"],
+      "author": "@GideonSenku",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 跟随系统壁纸设置同时支持中英文",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["跟随系统壁纸设置支持中英文,且优先考虑中文关键字"]
+        },
+        {
+          "name": "说明",
+          "descs": ["中文关键字为`暗黑`和`明亮`,英文关键字不变"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.52",
+      "tags": ["beta"],
+      "author": "@id77 @chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 删除备份后直接回到首页问题",
+      "notes": [
+        {
+          "name": "移除",
+          "descs": [
+            "主屏幕的左右滑动手势",
+            "原因: 与浏览器前进后退容易发生冲突"
+          ]
+        },
+        {
+          "name": "修复",
+          "descs": ["删除备份后直接回到首页问题"]
+        },
+        {
+          "name": "优化",
+          "descs": ["页面后退事件逻辑", "部分侧栏设置的小字说明"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.49",
+      "tags": ["beta"],
+      "author": "@GideonSenku",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复主屏左滑时与侧栏冲突问题",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["背景图片可跟随系统调整"]
+        },
+        {
+          "name": "调整",
+          "descs": ["背景清单图片默认`无`更改为`跟随系统`"]
+        },
+        {
+          "name": "修复",
+          "descs": ["主屏左滑时与侧栏冲突问题"]
+        },
+        {
+          "name": "说明",
+          "descs": [
+            "背景图片清单中设置:无{换行} 跟随系统,跟随系统{换行} light,图片地址{换行} dark,图片地址{换行}",
+            "如果不设置`跟随系统,跟随系统`,则默认跟随系统为无背景"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.47",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复代码编辑器高度, 部分界面左右滑动范围问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": [
+            "代码编辑器高度问题",
+            "部分界面只能在有内容的范围左右滑动问题"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.46",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 移除滑动动画, 勿扰模式不弹脚本执行结果页, 操作优化",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": [
+            "勿扰模式下运行脚本不弹出结果页",
+            "壁纸模式下滑更容易退出壁纸模式"
+          ]
+        },
+        {
+          "name": "移除",
+          "descs": ["左右滑动切换页面的动画"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.45",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复脚本执行结果、更新日志页面位置不正确, 主页左滑进入壁纸模式",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["主页左滑进入壁纸模式"]
+        },
+        {
+          "name": "修复",
+          "descs": ["脚本执行结果、更新日志页面位置不正确"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.44",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 主屏幕左右滑动可切换 首页、应用、订阅、我的 页面",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "Surge、QuanX、Loon 手动运行脚本时都可以显示执行结果",
+            "主屏幕左右滑动可切换 首页、应用、订阅、我的 页面"
+          ]
+        },
+        {
+          "name": "修复",
+          "descs": ["全局搜索结果位置不正确问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.43",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复非壁纸模式下上滑仍然重新渲染壁纸",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": [
+            "在顶栏上滑可隐藏顶栏",
+            "在底栏下滑可以隐藏底栏",
+            "壁纸模式上滑可以重新渲染壁纸"
+          ]
+        },
+        {
+          "name": "修复",
+          "descs": [
+            "代码编辑器不显示问题",
+            "二次进入搜索界面无法自动获取焦点",
+            "非壁纸模式下上滑仍然重新渲染壁纸"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.41",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复顶栏隐藏时图标没往上挪, 悬浮按钮上滑切壁纸, 壁纸模式隐藏悬浮按钮",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["壁纸模式会把悬浮按钮也隐藏起来"]
+        },
+        {
+          "name": "修复",
+          "descs": ["顶栏隐藏时图标没有往上挪"]
+        },
+        {
+          "name": "悬浮按钮手势",
+          "descs": [
+            "上滑: 重渲染&切换壁纸",
+            "左滑: 悬浮按钮左靠",
+            "右滑: 悬浮按钮右靠",
+            "下滑: 切换壁纸模式"
+          ]
+        },
+        {
+          "name": "说明",
+          "descs": [
+            "壁纸模式下: 下滑取消壁纸模式",
+            "非壁纸模式: 下滑显示\\隐藏顶栏"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.40",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 新增壁纸模式、悬浮按钮手势",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["壁纸模式", "悬浮按钮手势"]
+        },
+        {
+          "name": "悬浮按钮手势",
+          "descs": [
+            "上滑: 刷新页面 (效果同双击)",
+            "左滑: 悬浮按钮左靠",
+            "右滑: 悬浮按钮右靠",
+            "下滑: 切换壁纸模式"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.39",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 修复部分情况下拉出顶栏事件失效问题",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["部分情况下拉出顶栏事件失效问题"]
+        },
+        {
+          "name": "优化",
+          "descs": ["原来顶部的加载条移到底栏上方"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.38",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 新增 Surge HTTP-API 环境下运行脚本会显示运行结果",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["Surge HTTP-API 环境下运行脚本会显示运行结果"]
+        },
+        {
+          "name": "优化",
+          "descs": ["页面样式"]
+        },
+        {
+          "name": "移除",
+          "descs": ["顶栏跟随滚动"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.37",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "msg": "更新[BoxJs TF]: 应用标题加阴影, 优化调试代码, 单击首页重渲染壁纸",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["应用标题加阴影"]
+        },
+        {
+          "name": "调试",
+          "descs": ["优化代码"]
+        },
+        {
+          "name": "新增",
+          "descs": ["单击首页回到顶部, 再单击一次重新渲染壁纸"]
+        },
+        {
+          "name": "壁纸",
+          "descs": [
+            "无背景,",
+            "随机,https://uploadbeta.com/api/pictures/random",
+            "推女郎,https://uploadbeta.com/api/pictures/random/?key=推女郎",
+            "性感,https://uploadbeta.com/api/pictures/random/?key=性感",
+            "车模,https://uploadbeta.com/api/pictures/random/?key=车模",
+            "美腿,https://uploadbeta.com/api/pictures/random/?key=美腿",
+            "美女,https://uploadbeta.com/api/pictures/random/?key=美女",
+            "手机妹子,http://api.btstu.cn/sjbz/zsy.php",
+            "手机美女,http://api.btstu.cn/sjbz/?m_lx=suiji"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.36",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["下拉显示&隐藏搜索栏"]
+        },
+        {
+          "name": "优化",
+          "descs": ["固定背景"]
+        },
+        {
+          "name": "修复",
+          "descs": ["搜索栏高度问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.35",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "调试",
+          "descs": ["调试模式下支持自定义页面源码地址"]
+        },
+        {
+          "name": "修复",
+          "descs": [
+            "底栏事件无效问题",
+            "部分情况下贡献者重复加载问题",
+            "手势前进后退会白屏&卡屏问题"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.33",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["支持前进、后退", "WebApp 状态下刷新能留在当前页面"]
+        },
+        {
+          "name": "修复",
+          "descs": ["侧栏拉不到底缺陷"]
+        },
+        {
+          "name": "调试",
+          "descs": ["支持 vue devtool (侧栏开启调试模式)"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @id77 大佬 PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.30",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["首页背景可以一直固定住"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @id77 大佬 PR"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.29",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "代码编辑器",
+          "descs": ["Surge HTTP-API 环境下执行的代码能显示响应内容"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.28",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["数据后端渲染", "更快更平顺的首页加载", "不闪屏了"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @eslint 大佬提供帮助"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.27",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["首页样式", "操作体验"]
+        },
+        {
+          "name": "首页",
+          "descs": ["顶栏透明", "可以隐藏顶栏", "顶栏可以固定或跟随滚动"]
+        },
+        {
+          "name": "悬浮按钮",
+          "descs": ["增加搜索入口"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.26",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "调整",
+          "descs": ["搜索条样式", "搜索操作界面"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.24",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "修复",
+          "descs": ["解决首屏闪屏问题", "解决图标白边问题", "导入会话报错"]
+        },
+        {
+          "name": "感谢",
+          "descs": ["感谢 @eslint 大佬提供帮助"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.21",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["一键清空会话数据"]
+        },
+        {
+          "name": "优化",
+          "descs": ["壁纸状态下图标字体颜色为白色", "其他样式优化"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.20",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["勿扰模式下, 不再忽略手动执行脚本时发出的系统通知"]
+        },
+        {
+          "name": "新增",
+          "descs": ["可以设置多张壁纸 (偏好设置)"]
+        },
+        {
+          "name": "注意",
+          "descs": ["设置多张壁纸后,在侧栏切换"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.18",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["代码编辑器 (入口: 悬浮按钮)"]
+        },
+        {
+          "name": "说明",
+          "descs": [
+            "除了本机运行外",
+            "可以使用 PC 连上 QuanX 的 HTTP Backend",
+            "实现在 PC 上写代码然后发送到 QuanX 执行",
+            "Surge、Loon 同理"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.17",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["首页壁纸 (偏好设置)"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.16",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["首页图标样式"]
+        },
+        {
+          "name": "修复",
+          "descs": [
+            "首页图标点击无效问题",
+            "首页图标有轻微位移问题",
+            "帮助页面打开空白"
+          ]
+        }
+      ]
+    },
+    {
+      "version": "0.7.11",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["首页显示收藏应用", "订阅中的更多按钮可以链接到作者仓库"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.9",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "新增",
+          "descs": ["可以修改会话", "增加帮忙手册入口", "推荐订阅入口"]
+        },
+        {
+          "name": "调整",
+          "descs": ["调整加载动态效果"]
+        },
+        {
+          "name": "修复",
+          "descs": ["boolean 控件偶尔触发键盘问题"]
+        }
+      ]
+    },
+    {
+      "version": "0.7.7",
+      "tags": ["beta"],
+      "author": "@chavyleung",
+      "icon": "https://avatars3.githubusercontent.com/u/29748519",
+      "repo": "https://github.com/chavyleung",
+      "notes": [
+        {
+          "name": "优化",
+          "descs": ["全程无刷新", "独立分离页面", "优化数据结构减少内存占用"]
+        },
+        {
+          "name": "操作",
+          "descs": [
+            "可以修复全局备份的名字",
+            "点击'应用'回到顶部,再次单击折叠面板",
+            "点击'订阅'回到顶部,再次单击刷新订阅",
+            "点击具体订阅可刷新"
+          ]
+        }
+      ]
+    }
+  ]
+}

+ 15 - 0
Scripts/box/rewrite/boxjs.rewrite.loon.plugin

@@ -0,0 +1,15 @@
+#!name=BoxJs
+#!desc=Data manager
+#!openUrl=http://boxjs.com
+#!author=chavyleung
+#!homepage=https://chavyleung.gitbook.io/boxjs/
+#!icon=https://raw.githubusercontent.com/chavyleung/scripts/master/box/icons/BoxJs.png
+
+[Rule]
+DOMAIN-SUFFIX,jsdelivr.net,PROXY
+
+[Script]
+http-request ^https?:\/\/(.+\.)?boxjs\.(com|net) script-path=https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.js, requires-body=true, timeout=120, tag=BoxJs
+
+[MITM]
+hostname = boxjs.com, boxjs.net, *.boxjs.com, *.boxjs.net

+ 15 - 0
Scripts/box/rewrite/boxjs.rewrite.loon.tf.plugin

@@ -0,0 +1,15 @@
+#!name=BoxJs
+#!desc=(TF)Data manager
+#!openUrl=http://boxjs.net
+#!author=chavyleung
+#!homepage=https://chavyleung.gitbook.io/boxjs/
+#!icon=https://raw.githubusercontent.com/chavyleung/scripts/master/box/icons/BoxJs.png
+
+[Rule]
+DOMAIN-SUFFIX,jsdelivr.net,PROXY
+
+[Script]
+http-request ^https?:\/\/(.+\.)?boxjs\.(com|net) script-path=https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.js, requires-body=true, timeout=120, tag=BoxJs
+
+[MITM]
+hostname = boxjs.com, boxjs.net, *.boxjs.com, *.boxjs.net

+ 3 - 0
Scripts/box/rewrite/boxjs.rewrite.quanx.conf

@@ -0,0 +1,3 @@
+hostname = boxjs.com, boxjs.net, *.boxjs.com, *.boxjs.net
+
+^https?:\/\/(.+\.)?boxjs\.(com|net) url script-analyze-echo-response https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.js

+ 3 - 0
Scripts/box/rewrite/boxjs.rewrite.quanx.tf.conf

@@ -0,0 +1,3 @@
+hostname = boxjs.com, boxjs.net, *.boxjs.com, *.boxjs.net
+
+^https?:\/\/(.+\.)?boxjs\.(com|net) url script-analyze-echo-response https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.js

+ 25 - 0
Scripts/box/rewrite/boxjs.rewrite.stash.stoverride

@@ -0,0 +1,25 @@
+name: BoxJs
+desc: http://boxjs.com
+
+http:
+  force-http-engine:
+    - "boxjs.com:80"
+    - "boxjs.net:80"
+    - "*.boxjs.com:80"
+    - "*.boxjs.net:80"
+  mitm:
+    - "boxjs.com"
+    - "boxjs.net"
+    - "*.boxjs.com"
+    - "*.boxjs.net"
+  script:
+    - match: ^https?:\/\/(.+\.)?boxjs\.(com|net)
+      name: BoxJs
+      type: request
+      require-body: true
+      timeout: 120
+
+script-providers:
+  BoxJs:
+    url: https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.js
+    interval: 86400

+ 25 - 0
Scripts/box/rewrite/boxjs.rewrite.stash.tf.stoverride

@@ -0,0 +1,25 @@
+name: BoxJs
+desc: http://boxjs.net
+
+http:
+  force-http-engine:
+    - "boxjs.com:80"
+    - "boxjs.net:80"
+    - "*.boxjs.com:80"
+    - "*.boxjs.net:80"
+  mitm:
+    - "boxjs.com"
+    - "boxjs.net"
+    - "*.boxjs.com"
+    - "*.boxjs.net"
+  script:
+    - match: ^https?:\/\/(.+\.)?boxjs\.(com|net)
+      name: BoxJs
+      type: request
+      require-body: true
+      timeout: 120
+
+script-providers:
+  BoxJs:
+    url: https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.js
+    interval: 86400

+ 11 - 0
Scripts/box/rewrite/boxjs.rewrite.surge.sgmodule

@@ -0,0 +1,11 @@
+#!name=BoxJs
+#!desc=http://boxjs.com
+
+[General]
+force-http-engine-hosts = %APPEND% boxjs.com, boxjs.net, *.boxjs.com, *.boxjs.net
+
+[Script]
+Rewrite: BoxJs = type=http-request,pattern=^https?:\/\/(.+\.)?boxjs\.(com|net),script-path=https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.js, requires-body=true, timeout=120
+
+[MITM]
+hostname = %INSERT% boxjs.com, boxjs.net, *.boxjs.com, *.boxjs.net

+ 11 - 0
Scripts/box/rewrite/boxjs.rewrite.surge.tf.sgmodule

@@ -0,0 +1,11 @@
+#!name=BoxJs
+#!desc=http://boxjs.net
+
+[General]
+force-http-engine-hosts = %APPEND% boxjs.com, boxjs.net, *.boxjs.com, *.boxjs.net
+
+[Script]
+Rewrite: BoxJs = type=http-request,pattern=^https?:\/\/(.+\.)?boxjs\.(com|net),script-path=https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.js, requires-body=true, timeout=120
+
+[MITM]
+hostname = %INSERT% boxjs.com, boxjs.net, *.boxjs.com, *.boxjs.net

Разница между файлами не показана из-за своего большого размера
+ 16 - 0
Scripts/box/scripts/boxjs.revert.baks.js


Разница между файлами не показана из-за своего большого размера
+ 32 - 0
Scripts/box/scripts/boxjs.revert.boxjs.js


Разница между файлами не показана из-за своего большого размера
+ 13 - 0
Scripts/box/scripts/boxjs.revert.caches.js


Разница между файлами не показана из-за своего большого размера
+ 14 - 0
Scripts/box/scripts/boxjs.revert.usercfgs.favapps.js


Разница между файлами не показана из-за своего большого размера
+ 14 - 0
Scripts/box/scripts/boxjs.revert.usercfgs.httpbackend.js


Разница между файлами не показана из-за своего большого размера
+ 11 - 0
Scripts/box/scripts/boxjs.revert.usercfgs.js


Разница между файлами не показана из-за своего большого размера
+ 13 - 0
Scripts/box/scripts/boxjs.revert.usercfgs.sessions.js


Разница между файлами не показана из-за своего большого размера
+ 93 - 0
Scripts/box/switcher/box.switcher.js


Некоторые файлы не были показаны из-за большого количества измененных файлов