ani-auto 1.4.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/anime/LICENSE +21 -0
- package/anime/api/index.js +110 -0
- package/anime/app.js +79 -0
- package/anime/controllers/animeInfoController.js +48 -0
- package/anime/controllers/animeListController.js +21 -0
- package/anime/controllers/homeController.js +42 -0
- package/anime/controllers/playController.js +140 -0
- package/anime/controllers/queueController.js +20 -0
- package/anime/controllers/testController.js +667 -0
- package/anime/index.js +139 -0
- package/anime/middleware/cache.js +64 -0
- package/anime/middleware/errorHandler.js +33 -0
- package/anime/middleware/rateLimiter.js +73 -0
- package/anime/models/animeInfoModel.js +193 -0
- package/anime/models/animeListModel.js +69 -0
- package/anime/models/homeModel.js +33 -0
- package/anime/models/playModel.js +528 -0
- package/anime/models/queueModel.js +22 -0
- package/anime/package.json +27 -0
- package/anime/pnpm-lock.yaml +1774 -0
- package/anime/readme.md +236 -0
- package/anime/routes/animeInfoRoutes.js +9 -0
- package/anime/routes/animeListRoutes.js +9 -0
- package/anime/routes/homeRoutes.js +10 -0
- package/anime/routes/playRoutes.js +11 -0
- package/anime/routes/queueRoutes.js +8 -0
- package/anime/routes/testRoutes.js +325 -0
- package/anime/routes/webhookRoutes.js +23 -0
- package/anime/scrapers/animepahe.js +1053 -0
- package/anime/test-server.js +10 -0
- package/anime/test.sh +275 -0
- package/anime/utils/browser.js +172 -0
- package/anime/utils/config.js +209 -0
- package/anime/utils/dataProcessor.js +172 -0
- package/anime/utils/diskCache.js +228 -0
- package/anime/utils/flaresolverr.js +361 -0
- package/anime/utils/jsParser.js +19 -0
- package/anime/utils/redis.js +64 -0
- package/anime/utils/requestManager.js +706 -0
- package/anime/utils/urlConverter.js +88 -0
- package/anime/utils/webhookNotifier.js +190 -0
- package/cookiereader.py +291 -0
- package/package.json +14 -6
- package/src/anilist.js +19 -2
- package/src/api/anilist.js +32 -0
- package/src/api/anime.js +181 -0
- package/src/api/cf-bypass.js +131 -0
- package/src/api/config.js +134 -0
- package/src/api/daemon.js +62 -0
- package/src/api/download.js +98 -0
- package/src/api/match.js +58 -0
- package/src/api/runs.js +15 -0
- package/src/api/update.js +96 -0
- package/src/cli.js +18 -2
- package/src/config.js +14 -2
- package/src/daemon.js +1 -1
- package/src/db.js +38 -11
- package/src/engine.js +66 -13
- package/src/notify.js +82 -7
- package/src/scraper.js +2 -2
- package/src/server.js +108 -0
- package/utils.js +21 -21
- package/web/index.html +13 -0
- package/web/package-lock.json +1420 -0
- package/web/package.json +24 -0
- package/web/src/App.vue +200 -0
- package/web/src/api/client.js +75 -0
- package/web/src/assets/styles/base.css +961 -0
- package/web/src/components/UpdateModal.vue +157 -0
- package/web/src/components/sidebar/SidebarResizable.vue +170 -0
- package/web/src/components/sidebar/sidebarConfig.js +24 -0
- package/web/src/main.js +104 -0
- package/web/src/router/index.js +44 -0
- package/web/src/stores/config.js +27 -0
- package/web/src/stores/download.js +107 -0
- package/web/src/stores/update.js +73 -0
- package/web/src/views/About.vue +42 -0
- package/web/src/views/AniListSync.vue +122 -0
- package/web/src/views/AnimeDetail.vue +202 -0
- package/web/src/views/AnimeList.vue +110 -0
- package/web/src/views/CFResult.vue +312 -0
- package/web/src/views/DaemonControl.vue +83 -0
- package/web/src/views/Dashboard.vue +187 -0
- package/web/src/views/DownloadCenter.vue +153 -0
- package/web/src/views/MatchFinder.vue +131 -0
- package/web/src/views/OAuthCallback.vue +44 -0
- package/web/src/views/Onboarding.vue +93 -0
- package/web/src/views/RunHistory.vue +122 -0
- package/web/src/views/Settings.vue +410 -0
- package/web/vite.config.js +23 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div class="page-header">
|
|
4
|
+
<h2>Settings</h2>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<Skeleton v-if="loading" width="100%" height="400px" />
|
|
8
|
+
|
|
9
|
+
<Tabs v-else-if="config" v-model:value="activeTab">
|
|
10
|
+
<TabList>
|
|
11
|
+
<Tab value="0">AniList</Tab>
|
|
12
|
+
<Tab value="1">Download</Tab>
|
|
13
|
+
<Tab value="2">Daemon</Tab>
|
|
14
|
+
<Tab value="3">Notifications</Tab>
|
|
15
|
+
<Tab value="4">Updates</Tab>
|
|
16
|
+
</TabList>
|
|
17
|
+
<TabPanels>
|
|
18
|
+
<TabPanel value="0">
|
|
19
|
+
<Card>
|
|
20
|
+
<template #content>
|
|
21
|
+
<div class="form-group">
|
|
22
|
+
<label>Username</label>
|
|
23
|
+
<InputText v-model="form.anilistUsername" placeholder="AniList username" fluid />
|
|
24
|
+
</div>
|
|
25
|
+
<div class="form-group">
|
|
26
|
+
<label>Token <Badge v-if="config.anilistToken === '[set]'" value="set" severity="success" size="small" style="margin-left:6px" /></label>
|
|
27
|
+
<div class="form-field-row">
|
|
28
|
+
<InputText v-model="form.anilistToken" :placeholder="config.anilistToken === '[set]' ? 'Token is set' : 'Paste token'" type="password" fluid style="flex:1" />
|
|
29
|
+
<Button label="Verify" @click="verifyToken" :disabled="!form.anilistToken" />
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
<div v-if="!config.anilistUsername" class="form-group" style="margin-top:16px">
|
|
33
|
+
<p style="margin-bottom:8px;color:var(--ink-400);font-size:13px">Or sign in with AniList:</p>
|
|
34
|
+
<Button label="Connect AniList" severity="primary" @click="connectAnilist" />
|
|
35
|
+
</div>
|
|
36
|
+
<div v-else class="form-group" style="margin-top:16px">
|
|
37
|
+
<Button label="Disconnect AniList" severity="danger" @click="disconnectAnilist" />
|
|
38
|
+
</div>
|
|
39
|
+
<div class="form-group">
|
|
40
|
+
<label>Watch Statuses</label>
|
|
41
|
+
<div class="checkbox-group">
|
|
42
|
+
<div v-for="s in statuses" :key="s" class="checkbox-item">
|
|
43
|
+
<Checkbox v-model="form.watchStatuses" :value="s" :inputId="'status-' + s" />
|
|
44
|
+
<label :for="'status-' + s">{{ s }}</label>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="form-group" style="margin-top:16px;padding-top:16px;border-top:1px solid var(--border-color)">
|
|
49
|
+
<label>AnimePahe Access</label>
|
|
50
|
+
<p style="color:var(--ink-400);font-size:12px;margin-bottom:8px">
|
|
51
|
+
Cloudflare bypass status: <strong>{{ cfStatus }}</strong>
|
|
52
|
+
</p>
|
|
53
|
+
|
|
54
|
+
<div class="form-field-row" style="margin-bottom:8px">
|
|
55
|
+
<Button
|
|
56
|
+
label="Bypass Cloudflare"
|
|
57
|
+
severity="secondary"
|
|
58
|
+
@click="startCfBypass"
|
|
59
|
+
/>
|
|
60
|
+
<Button
|
|
61
|
+
v-if="config.animepaheCfClearance === '[set]'"
|
|
62
|
+
label="Clear Cookies"
|
|
63
|
+
severity="danger"
|
|
64
|
+
@click="clearCfBypass"
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div class="form-group" style="margin-top:8px">
|
|
69
|
+
<label for="cf-input">cf_clearance Value</label>
|
|
70
|
+
<Textarea
|
|
71
|
+
id="cf-input"
|
|
72
|
+
v-model="cfInput"
|
|
73
|
+
:placeholder="config.animepaheCfClearance === '[set]' ? 'cf_clearance is set — paste new value to replace' : 'Paste cf_clearance value here'"
|
|
74
|
+
rows="2"
|
|
75
|
+
fluid
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div class="form-group" style="margin-top:8px">
|
|
80
|
+
<label for="ua-input">User-Agent</label>
|
|
81
|
+
<InputText
|
|
82
|
+
id="ua-input"
|
|
83
|
+
v-model="uaInput"
|
|
84
|
+
placeholder="Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0"
|
|
85
|
+
fluid
|
|
86
|
+
/>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="form-field-row">
|
|
90
|
+
<Button
|
|
91
|
+
label="Save & Verify"
|
|
92
|
+
severity="primary"
|
|
93
|
+
@click="saveAndVerify"
|
|
94
|
+
:disabled="!cfInput"
|
|
95
|
+
:loading="verifying"
|
|
96
|
+
/>
|
|
97
|
+
<span v-if="verifyResult" :class="verifyResult.ok ? 'text-green-600' : 'text-red-500'" style="font-size:13px;margin-left:8px">
|
|
98
|
+
{{ verifyResult.message }}
|
|
99
|
+
</span>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
</template>
|
|
103
|
+
</Card>
|
|
104
|
+
</TabPanel>
|
|
105
|
+
<TabPanel value="1">
|
|
106
|
+
<Card>
|
|
107
|
+
<template #content>
|
|
108
|
+
<div class="form-row">
|
|
109
|
+
<div class="form-group">
|
|
110
|
+
<label>Quality</label>
|
|
111
|
+
<Select v-model="form.quality" :options="['1080p', '720p', '360p']" fluid />
|
|
112
|
+
</div>
|
|
113
|
+
<div class="form-group">
|
|
114
|
+
<label>Language</label>
|
|
115
|
+
<Select v-model="form.language" :options="['sub', 'dub']" fluid />
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
<div class="form-row">
|
|
119
|
+
<div class="form-group">
|
|
120
|
+
<label>Concurrency</label>
|
|
121
|
+
<InputNumber v-model="form.concurrency" :min="1" :max="10" fluid />
|
|
122
|
+
</div>
|
|
123
|
+
<div class="form-group">
|
|
124
|
+
<label>Max Retries</label>
|
|
125
|
+
<InputNumber v-model="form.maxRetries" :min="0" :max="10" fluid />
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="form-group">
|
|
129
|
+
<label>Output Directory</label>
|
|
130
|
+
<InputText v-model="form.outputDir" fluid />
|
|
131
|
+
</div>
|
|
132
|
+
</template>
|
|
133
|
+
</Card>
|
|
134
|
+
</TabPanel>
|
|
135
|
+
<TabPanel value="2">
|
|
136
|
+
<Card>
|
|
137
|
+
<template #content>
|
|
138
|
+
<div class="form-row">
|
|
139
|
+
<div class="form-group">
|
|
140
|
+
<label>Check Interval (minutes)</label>
|
|
141
|
+
<InputNumber v-model="form.daemonIntervalMinutes" :min="5" :max="1440" fluid />
|
|
142
|
+
</div>
|
|
143
|
+
<div class="form-group">
|
|
144
|
+
<label>Airing Buffer (minutes)</label>
|
|
145
|
+
<InputNumber v-model="form.airingBufferMinutes" fluid />
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</template>
|
|
149
|
+
</Card>
|
|
150
|
+
</TabPanel>
|
|
151
|
+
<TabPanel value="3">
|
|
152
|
+
<Card>
|
|
153
|
+
<template #content>
|
|
154
|
+
<div class="form-group">
|
|
155
|
+
<label>Telegram Chat ID</label>
|
|
156
|
+
<InputText v-model="form.telegramChatId" fluid />
|
|
157
|
+
</div>
|
|
158
|
+
<div class="form-group">
|
|
159
|
+
<div class="checkbox-item">
|
|
160
|
+
<ToggleSwitch v-model="form.telegramNotify" :inputId="'tg-notify'" />
|
|
161
|
+
<label :for="'tg-notify'" style="margin-left:8px">Enable Telegram notifications</label>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</template>
|
|
165
|
+
</Card>
|
|
166
|
+
</TabPanel>
|
|
167
|
+
<TabPanel value="4">
|
|
168
|
+
<Card>
|
|
169
|
+
<template #content>
|
|
170
|
+
<div class="form-group">
|
|
171
|
+
<div class="checkbox-item">
|
|
172
|
+
<ToggleSwitch v-model="form.autoUpdateCheck" :inputId="'auto-update'" />
|
|
173
|
+
<label :for="'auto-update'" style="margin-left:8px">Auto-check for updates on app start</label>
|
|
174
|
+
</div>
|
|
175
|
+
<p class="form-hint">When enabled, ani-auto will check for new versions when you open the web UI.</p>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="form-group">
|
|
178
|
+
<label>Current Version</label>
|
|
179
|
+
<span class="version-display">v1.4.4</span>
|
|
180
|
+
</div>
|
|
181
|
+
<div class="form-group">
|
|
182
|
+
<Button
|
|
183
|
+
label="Check for Updates"
|
|
184
|
+
@click="checkUpdate"
|
|
185
|
+
:loading="updateStore.checking"
|
|
186
|
+
:disabled="updateStore.installing"
|
|
187
|
+
/>
|
|
188
|
+
</div>
|
|
189
|
+
<div v-if="updateStore.updateAvailable" class="update-result">
|
|
190
|
+
<span class="update-result-text">Update v{{ updateStore.latestVersion }} available</span>
|
|
191
|
+
<Button
|
|
192
|
+
label="Install Update"
|
|
193
|
+
@click="installUpdate"
|
|
194
|
+
:loading="updateStore.installing"
|
|
195
|
+
/>
|
|
196
|
+
</div>
|
|
197
|
+
<div v-if="updateStore.currentVersion && !updateStore.updateAvailable && !updateStore.checking" class="update-result">
|
|
198
|
+
<span class="update-result-text update-result-ok">Already on latest version (v{{ updateStore.currentVersion }})</span>
|
|
199
|
+
</div>
|
|
200
|
+
</template>
|
|
201
|
+
</Card>
|
|
202
|
+
</TabPanel>
|
|
203
|
+
</TabPanels>
|
|
204
|
+
</Tabs>
|
|
205
|
+
|
|
206
|
+
<div v-if="config" class="settings-actions">
|
|
207
|
+
<Button label="Save Settings" @click="save" />
|
|
208
|
+
<span v-if="saved" class="saved-msg">Saved</span>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</template>
|
|
212
|
+
|
|
213
|
+
<script setup>
|
|
214
|
+
import { ref, reactive, computed, onMounted, onBeforeUnmount } from 'vue'
|
|
215
|
+
import { useRouter, useRoute } from 'vue-router'
|
|
216
|
+
import { api } from '../api/client'
|
|
217
|
+
import { useConfigStore } from '../stores/config'
|
|
218
|
+
import Tabs from 'primevue/tabs'
|
|
219
|
+
import TabList from 'primevue/tablist'
|
|
220
|
+
import Tab from 'primevue/tab'
|
|
221
|
+
import TabPanels from 'primevue/tabpanels'
|
|
222
|
+
import TabPanel from 'primevue/tabpanel'
|
|
223
|
+
|
|
224
|
+
import { useUpdateStore } from '../stores/update'
|
|
225
|
+
|
|
226
|
+
const router = useRouter()
|
|
227
|
+
const route = useRoute()
|
|
228
|
+
const configStore = useConfigStore()
|
|
229
|
+
const updateStore = useUpdateStore()
|
|
230
|
+
const loading = ref(true)
|
|
231
|
+
const config = ref(null)
|
|
232
|
+
const saved = ref(false)
|
|
233
|
+
const activeTab = ref('0')
|
|
234
|
+
const closeFirefoxWarning = ref(false)
|
|
235
|
+
const cfInput = ref('')
|
|
236
|
+
const uaInput = ref('')
|
|
237
|
+
const verifying = ref(false)
|
|
238
|
+
const verifyResult = ref(null)
|
|
239
|
+
|
|
240
|
+
const cfStatus = computed(() => config.value?.animepaheCfClearance === '[set]' ? 'Active' : 'Not bypassed')
|
|
241
|
+
|
|
242
|
+
const statuses = ['CURRENT', 'PLANNING', 'PAUSED', 'REPEATING']
|
|
243
|
+
|
|
244
|
+
const form = reactive({
|
|
245
|
+
anilistUsername: '',
|
|
246
|
+
anilistToken: '',
|
|
247
|
+
watchStatuses: ['CURRENT'],
|
|
248
|
+
quality: '1080p',
|
|
249
|
+
language: 'sub',
|
|
250
|
+
concurrency: 2,
|
|
251
|
+
maxRetries: 3,
|
|
252
|
+
outputDir: '',
|
|
253
|
+
daemonIntervalMinutes: 120,
|
|
254
|
+
airingBufferMinutes: 5,
|
|
255
|
+
telegramChatId: '',
|
|
256
|
+
telegramNotify: true,
|
|
257
|
+
autoUpdateCheck: true,
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
onMounted(async () => {
|
|
261
|
+
try {
|
|
262
|
+
config.value = await api.config.get()
|
|
263
|
+
Object.assign(form, config.value)
|
|
264
|
+
if (form.anilistToken === '[set]') form.anilistToken = ''
|
|
265
|
+
delete form.animepaheCfClearance
|
|
266
|
+
delete form.animepaheUserAgent
|
|
267
|
+
|
|
268
|
+
const state = history.state
|
|
269
|
+
if (state?.cfClearance) {
|
|
270
|
+
cfInput.value = state.cfClearance
|
|
271
|
+
}
|
|
272
|
+
if (state?.userAgent) {
|
|
273
|
+
uaInput.value = state.userAgent
|
|
274
|
+
}
|
|
275
|
+
history.replaceState(null, '')
|
|
276
|
+
} catch (e) {
|
|
277
|
+
console.error(e)
|
|
278
|
+
} finally {
|
|
279
|
+
loading.value = false
|
|
280
|
+
}
|
|
281
|
+
const handler = async (e) => {
|
|
282
|
+
if (e.data?.type === 'anilist-token') {
|
|
283
|
+
const updated = await api.config.get()
|
|
284
|
+
config.value = updated
|
|
285
|
+
Object.assign(form, updated)
|
|
286
|
+
if (form.anilistToken === '[set]') form.anilistToken = ''
|
|
287
|
+
delete form.animepaheCfClearance
|
|
288
|
+
delete form.animepaheUserAgent
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
window.addEventListener('message', handler)
|
|
292
|
+
onBeforeUnmount(() => window.removeEventListener('message', handler))
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
async function verifyToken() {
|
|
296
|
+
if (!form.anilistToken) return
|
|
297
|
+
try {
|
|
298
|
+
const res = await api.config.verifyToken(form.anilistToken)
|
|
299
|
+
if (res.ok) {
|
|
300
|
+
await api.config.update({
|
|
301
|
+
anilistToken: form.anilistToken,
|
|
302
|
+
anilistUsername: res.name,
|
|
303
|
+
anilistAvatar: res.avatar,
|
|
304
|
+
})
|
|
305
|
+
form.anilistUsername = res.name
|
|
306
|
+
form.anilistAvatar = res.avatar
|
|
307
|
+
form.anilistToken = ''
|
|
308
|
+
await configStore.fetch()
|
|
309
|
+
config.value = configStore.config
|
|
310
|
+
Object.assign(form, config.value)
|
|
311
|
+
if (form.anilistToken === '[set]') form.anilistToken = ''
|
|
312
|
+
} else {
|
|
313
|
+
alert(`Verification failed: ${res.error}`)
|
|
314
|
+
}
|
|
315
|
+
} catch (e) {
|
|
316
|
+
alert(`Error: ${e.message}`)
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async function connectAnilist() {
|
|
321
|
+
const { url } = await api.config.oauthUrl()
|
|
322
|
+
window.open(url, 'anilist-oauth', 'width=600,height=700')
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async function disconnectAnilist() {
|
|
326
|
+
await api.config.update({
|
|
327
|
+
anilistToken: null,
|
|
328
|
+
anilistUsername: null,
|
|
329
|
+
anilistAvatar: null,
|
|
330
|
+
onboardingSkipped: true,
|
|
331
|
+
})
|
|
332
|
+
configStore.config = null
|
|
333
|
+
await configStore.fetch()
|
|
334
|
+
if (configStore.config) {
|
|
335
|
+
config.value = configStore.config
|
|
336
|
+
Object.assign(form, config.value)
|
|
337
|
+
if (form.anilistToken === '[set]') form.anilistToken = ''
|
|
338
|
+
}
|
|
339
|
+
router.push('/settings')
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async function startCfBypass() {
|
|
343
|
+
router.push({ name: 'cf-result' })
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
async function clearCfBypass() {
|
|
347
|
+
try {
|
|
348
|
+
closeFirefoxWarning.value = false
|
|
349
|
+
verifyResult.value = null
|
|
350
|
+
const res = await api.cfBypass.clear()
|
|
351
|
+
config.value = await api.config.get()
|
|
352
|
+
Object.assign(form, config.value)
|
|
353
|
+
if (form.anilistToken === '[set]') form.anilistToken = ''
|
|
354
|
+
cfInput.value = ''
|
|
355
|
+
uaInput.value = ''
|
|
356
|
+
if (res.locked?.length > 0) {
|
|
357
|
+
closeFirefoxWarning.value = true
|
|
358
|
+
}
|
|
359
|
+
} catch (e) {
|
|
360
|
+
alert(`Clear failed: ${e.message}`)
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async function saveAndVerify() {
|
|
365
|
+
if (!cfInput.value) return
|
|
366
|
+
verifying.value = true
|
|
367
|
+
verifyResult.value = null
|
|
368
|
+
try {
|
|
369
|
+
const res = await api.cfBypass.save({ cfClearance: cfInput.value, userAgent: uaInput.value })
|
|
370
|
+
if (res.ok) {
|
|
371
|
+
verifyResult.value = { ok: true, message: 'Saved and verified!' }
|
|
372
|
+
config.value = await api.config.get()
|
|
373
|
+
Object.assign(form, config.value)
|
|
374
|
+
if (form.anilistToken === '[set]') form.anilistToken = ''
|
|
375
|
+
delete form.animepaheCfClearance
|
|
376
|
+
delete form.animepaheUserAgent
|
|
377
|
+
} else {
|
|
378
|
+
verifyResult.value = { ok: false, message: res.error || 'Verification failed' }
|
|
379
|
+
}
|
|
380
|
+
} catch (e) {
|
|
381
|
+
verifyResult.value = { ok: false, message: e.message }
|
|
382
|
+
} finally {
|
|
383
|
+
verifying.value = false
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
async function save() {
|
|
388
|
+
saved.value = false
|
|
389
|
+
try {
|
|
390
|
+
const payload = { ...form }
|
|
391
|
+
if (!payload.anilistToken && config.value?.anilistToken === '[set]') {
|
|
392
|
+
delete payload.anilistToken
|
|
393
|
+
}
|
|
394
|
+
await api.config.update(payload)
|
|
395
|
+
await configStore.fetch()
|
|
396
|
+
saved.value = true
|
|
397
|
+
setTimeout(() => saved.value = false, 2000)
|
|
398
|
+
} catch (e) {
|
|
399
|
+
alert(`Save failed: ${e.message}`)
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async function checkUpdate() {
|
|
404
|
+
await updateStore.check()
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function installUpdate() {
|
|
408
|
+
updateStore.install()
|
|
409
|
+
}
|
|
410
|
+
</script>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import vue from '@vitejs/plugin-vue'
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [vue()],
|
|
6
|
+
server: {
|
|
7
|
+
port: 2641,
|
|
8
|
+
proxy: {
|
|
9
|
+
'/api': {
|
|
10
|
+
target: 'http://localhost:2640',
|
|
11
|
+
changeOrigin: true,
|
|
12
|
+
},
|
|
13
|
+
'/ws': {
|
|
14
|
+
target: 'ws://localhost:2640',
|
|
15
|
+
ws: true,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
build: {
|
|
20
|
+
outDir: 'dist',
|
|
21
|
+
emptyOutDir: true,
|
|
22
|
+
},
|
|
23
|
+
})
|