sinzmise-cetastories 1.7.0-1719905916712 → 1.7.0-1719906729469

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. package/404/index.html +1 -1
  2. package/404.html +1 -1
  3. package/about/index.html +1 -1
  4. package/album/index.html +1 -1
  5. package/archives/2021/12/index.html +1 -1
  6. package/archives/2021/index.html +1 -1
  7. package/archives/2022/12/index.html +1 -1
  8. package/archives/2022/index.html +1 -1
  9. package/archives/2023/01/index.html +1 -1
  10. package/archives/2023/02/index.html +1 -1
  11. package/archives/2023/03/index.html +1 -1
  12. package/archives/2023/04/index.html +1 -1
  13. package/archives/2023/07/index.html +1 -1
  14. package/archives/2023/08/index.html +1 -1
  15. package/archives/2023/09/index.html +1 -1
  16. package/archives/2023/10/index.html +1 -1
  17. package/archives/2023/11/index.html +1 -1
  18. package/archives/2023/12/index.html +1 -1
  19. package/archives/2023/index.html +1 -1
  20. package/archives/2023/page/2/index.html +1 -1
  21. package/archives/2023/page/3/index.html +1 -1
  22. package/archives/2024/01/index.html +1 -1
  23. package/archives/2024/02/index.html +1 -1
  24. package/archives/2024/03/index.html +1 -1
  25. package/archives/2024/04/index.html +1 -1
  26. package/archives/2024/05/index.html +1 -1
  27. package/archives/2024/06/index.html +1 -1
  28. package/archives/2024/index.html +1 -1
  29. package/archives/2024/page/2/index.html +1 -1
  30. package/archives/index.html +1 -1
  31. package/archives/page/2/index.html +1 -1
  32. package/archives/page/3/index.html +1 -1
  33. package/archives/page/4/index.html +1 -1
  34. package/article.json +1 -1
  35. package/atom.xml +27 -27
  36. package/baidu_verify_codeva-NA6uDlCuZg.html +1 -1
  37. package/baidusitemap.xml +35 -35
  38. package/bangumis/index.html +1 -1
  39. package/bbs/index.html +1 -1
  40. package/cacheList.json +1 -0
  41. package/categories/index.html +1 -1
  42. package/categories//344/270/252/344/272/272/345/260/217/350/256/260/index.html +1 -1
  43. package/categories//344/270/252/344/272/272/345/260/217/350/256/260/page/2/index.html +1 -1
  44. package/categories//346/255/214/346/233/262/346/224/266/351/233/206/index.html +1 -1
  45. package/categories//346/270/270/346/210/217/347/233/270/345/205/263/index.html +1 -1
  46. package/categories//347/253/231/347/202/271/346/212/230/350/205/276/index.html +1 -1
  47. package/categories//347/253/231/347/202/271/346/212/230/350/205/276/page/2/index.html +1 -1
  48. package/categories//351/241/271/347/233/256/346/212/230/350/205/276/index.html +1 -1
  49. package/charts/index.html +1 -1
  50. package/comments/index.html +1 -1
  51. package/essay/index.html +1 -1
  52. package/fcircle/index.html +1 -1
  53. package/google8073542809160a67.html +1 -1
  54. package/index.html +1 -1
  55. package/js/randompost.js +1 -1
  56. package/link/index.html +1 -1
  57. package/music/index.html +1 -1
  58. package/package.json +1 -1
  59. package/page/2/index.html +1 -1
  60. package/page/3/index.html +1 -1
  61. package/page/4/index.html +1 -1
  62. package/posts/10021/index.html +1 -1
  63. package/posts/10045/index.html +1 -1
  64. package/posts/10996/index.html +1 -1
  65. package/posts/12779/index.html +1 -1
  66. package/posts/13624/index.html +1 -1
  67. package/posts/15748/index.html +1 -1
  68. package/posts/15842/index.html +1 -1
  69. package/posts/16107/index.html +1 -1
  70. package/posts/18063/index.html +1 -1
  71. package/posts/20412/index.html +1 -1
  72. package/posts/21375/index.html +1 -1
  73. package/posts/22945/index.html +1 -1
  74. package/posts/23021/index.html +1 -1
  75. package/posts/27531/index.html +1 -1
  76. package/posts/27762/index.html +1 -1
  77. package/posts/28536/index.html +1 -1
  78. package/posts/28733/index.html +1 -1
  79. package/posts/29196/index.html +1 -1
  80. package/posts/38917/index.html +1 -1
  81. package/posts/38964/index.html +1 -1
  82. package/posts/42487/index.html +1 -1
  83. package/posts/42580/index.html +1 -1
  84. package/posts/45875/index.html +1 -1
  85. package/posts/48762/index.html +1 -1
  86. package/posts/50710/index.html +1 -1
  87. package/posts/52677/index.html +1 -1
  88. package/posts/53662/index.html +1 -1
  89. package/posts/54386/index.html +1 -1
  90. package/posts/54481/index.html +1 -1
  91. package/posts/54787/index.html +1 -1
  92. package/posts/56467/index.html +1 -1
  93. package/posts/57692/index.html +1 -1
  94. package/posts/58203/index.html +1 -1
  95. package/posts/61417/index.html +1 -1
  96. package/posts/646/index.html +1 -1
  97. package/seas/index.html +1 -1
  98. package/sitemap.xml +62 -62
  99. package/sw-dom.js +73 -0
  100. package/sw.js +586 -0
  101. package/tags/Flash/347/233/270/345/205/263/index.html +1 -1
  102. package/tags/Steam/346/270/270/346/210/217/index.html +1 -1
  103. package/tags/Windows/350/275/257/344/273/266/index.html +1 -1
  104. package/tags/index.html +1 -1
  105. package/tags//344/270/252/344/272/272/345/260/217/350/256/260/index.html +1 -1
  106. package/tags//344/270/252/344/272/272/345/260/217/350/256/260/page/2/index.html +1 -1
  107. package/tags//345/205/266/345/256/203/346/270/270/346/210/217/index.html +1 -1
  108. package/tags//346/202/254/346/265/256/345/256/240/347/211/251-/347/234/213/346/235/277/345/250/230/index.html +1 -1
  109. package/tags//346/255/214/346/233/262/346/224/266/351/233/206/index.html +1 -1
  110. package/tags//346/270/270/346/210/217/347/233/270/345/205/263/index.html +1 -1
  111. package/tags//347/253/231/347/202/271/345/272/225/351/203/250/351/255/224/346/224/271/index.html +1 -1
  112. package/tags//347/253/231/347/202/271/346/212/230/350/205/276/index.html +1 -1
  113. package/tags//347/253/231/347/202/271/346/212/230/350/205/276/page/2/index.html +1 -1
  114. package/tags//350/207/252/345/273/272/351/203/250/347/275/262/index.html +1 -1
  115. package/tags//351/241/265/351/235/242/351/255/224/346/224/271/index.html +1 -1
  116. package/tags//351/241/271/347/233/256/346/212/230/350/205/276/index.html +1 -1
  117. package/update/index.html +1 -1
  118. package/update.json +1 -0
package/sw.js ADDED
@@ -0,0 +1,586 @@
1
+ // noinspection JSIgnoredPromiseFromCall
2
+
3
+ (() => {
4
+ /** 缓存库名称 */
5
+ const CACHE_NAME = 'StoriHouseCache'
6
+ /** 控制信息存储地址(必须以`/`结尾) */
7
+ const CTRL_PATH = 'https://id.v3/'
8
+
9
+ const ejectDomain = 'blog.sinzmise.top'
10
+ const ejectMirror = ['https://registry.npmmirror.com/sinzmise-cetastories/latest']
11
+
12
+
13
+ /**
14
+ * 读取本地版本号
15
+ * @return {Promise<BrowserVersion|undefined>}
16
+ */
17
+ const readVersion = () => caches.match(CTRL_PATH).then(response => response?.json())
18
+ /**
19
+ * 写入版本号
20
+ * @param version {BrowserVersion}
21
+ * @return {Promise<void>}
22
+ */
23
+ const writeVersion = version => caches.open(CACHE_NAME)
24
+ .then(cache => cache.put(CTRL_PATH, new Response(JSON.stringify(version))))
25
+
26
+ self.addEventListener('install', () => {
27
+ self.skipWaiting()
28
+ const escape = 0
29
+ if (escape) {
30
+ readVersion().then(async oldVersion => {
31
+ // noinspection JSIncompatibleTypesComparison
32
+ if (oldVersion && oldVersion.escape !== escape) {
33
+ const list = await caches.open(CACHE_NAME)
34
+ .then(cache => cache.keys())
35
+ .then(keys => keys?.map(it => it.url))
36
+ await caches.delete(CACHE_NAME)
37
+ const info = await updateJson()
38
+ info.type = 'escape'
39
+ info.list = list
40
+ // noinspection JSUnresolvedReference
41
+ const clientList = await clients.matchAll()
42
+ clientList.forEach(client => client.postMessage(info))
43
+ }
44
+ })
45
+ }
46
+ })
47
+
48
+ // sw 激活后立即对所有页面生效,而非等待刷新
49
+ // noinspection JSUnresolvedReference
50
+ self.addEventListener('activate', event => event.waitUntil(clients.claim()))
51
+
52
+ /**
53
+ * 基础 fetch
54
+ * @param request {Request|string}
55
+ * @param banCache {boolean} 是否禁用缓存
56
+ * @param cors {boolean} 是否启用 cors
57
+ * @param optional {RequestInit?} 额外的配置项
58
+ * @return {Promise<Response>}
59
+ */
60
+ const baseFetcher = (request, banCache, cors, optional) => {
61
+ if (!optional) optional = {}
62
+ optional.cache = banCache ? 'no-store' : 'default'
63
+ if (cors) {
64
+ optional.mode = 'cors'
65
+ optional.credentials = 'same-origin'
66
+ }
67
+ return fetch(request, optional)
68
+ }
69
+
70
+ /**
71
+ * 添加 cors 配置请求指定资源
72
+ * @param request {Request}
73
+ * @param optional {RequestInit?} 额外的配置项
74
+ * @return {Promise<Response>}
75
+ */
76
+ const fetchWithCache = (request, optional) =>
77
+ baseFetcher(request, false, isCors(request), optional)
78
+
79
+ // noinspection JSUnusedLocalSymbols
80
+ /**
81
+ * 添加 cors 配置请求指定资源
82
+ * @param request {Request}
83
+ * @param banCache {boolean} 是否禁用 HTTP 缓存
84
+ * @param optional {RequestInit?} 额外的配置项
85
+ * @return {Promise<Response>}
86
+ */
87
+ const fetchWithCors = (request, banCache, optional) =>
88
+ baseFetcher(request, banCache, true, optional)
89
+
90
+ /**
91
+ * 判断指定 url 击中了哪一种缓存,都没有击中则返回 null
92
+ * @param url {URL}
93
+ */
94
+ const findCache = url => {
95
+ if (url.hostname === 'localhost') return
96
+ for (let key in cacheRules) {
97
+ const value = cacheRules[key]
98
+ if (value.match(url)) return value
99
+ }
100
+ }
101
+
102
+ // noinspection JSFileReferences
103
+ let skipRequest = request => request.url.startsWith('https://i0.hdslb.com')
104
+ let cacheRules = {
105
+ simple: {
106
+ clean: true,
107
+ search: false,
108
+ match: url => {
109
+ const allowedHost = ejectDomain;
110
+ const allowedPaths = ["/404.html", "/css/index.css"];
111
+ return url.host === allowedHost && allowedPaths.includes(url.pathname);
112
+ }}
113
+ ,
114
+ cdn: {
115
+ clean: true,
116
+ match: url =>
117
+ [
118
+ "unpkg.com",
119
+ "cdn.cbd.int",
120
+ "lf26-cdn-tos.bytecdntp.com",
121
+ "lf6-cdn-tos.bytecdntp.com",
122
+ "lf3-cdn-tos.bytecdntp.com",
123
+ "lf9-cdn-tos.bytecdntp.com",
124
+ "npm.onmicrosoft.cn",
125
+ "cdn.staticfile.org",
126
+ "npm.elemecdn.com",
127
+ ].includes(url.host) && url.pathname.match(/\.(js|css|woff2|woff|ttf|cur)$/)}
128
+ }
129
+
130
+ let getSpareUrls = srcUrl => {
131
+ if (srcUrl.startsWith("https://npm.elemecdn.com")) {
132
+ return {
133
+ timeout: 3000,
134
+ list: [srcUrl, `https://cdn.cbd.int/${new URL(srcUrl).pathname}`],
135
+ };
136
+ }
137
+ }
138
+ let selfdb = () => {
139
+ self.db = { //全局定义db,只要read和write,看不懂可以略过
140
+ read: (key, config) => {
141
+ if (!config) { config = { type: "text" } }
142
+ return new Promise((resolve, reject) => {
143
+ caches.open(CACHE_NAME).then(cache => {
144
+ cache.match(new Request(`https://LOCALCACHE/${encodeURIComponent(key)}`)).then(function (res) {
145
+ if (!res) resolve(null)
146
+ res.text().then(text => resolve(text))
147
+ }).catch(() => {
148
+ resolve(null)
149
+ })
150
+ })
151
+ })
152
+ },
153
+ write: (key, value) => {
154
+ return new Promise((resolve, reject) => {
155
+ caches.open(CACHE_NAME).then(function (cache) {
156
+ cache.put(new Request(`https://LOCALCACHE/${encodeURIComponent(key)}`), new Response(value));
157
+ resolve()
158
+ }).catch(() => {
159
+ reject()
160
+ })
161
+ })
162
+ }
163
+ }
164
+ }
165
+ let lfetch = async (urls, url) => {
166
+ let controller = new AbortController();
167
+ const PauseProgress = async (res) => {
168
+ return new Response(await (res).arrayBuffer(), { status: res.status, headers: res.headers });
169
+ };
170
+ if (!Promise.any) {
171
+ Promise.any = function (promises) {
172
+ return new Promise((resolve, reject) => {
173
+ promises = Array.isArray(promises) ? promises : []
174
+ let len = promises.length
175
+ let errs = []
176
+ if (len === 0) return reject(new AggregateError('All promises were rejected'))
177
+ promises.forEach((promise) => {
178
+ promise.then(value => {
179
+ resolve(value)
180
+ }, err => {
181
+ len--
182
+ errs.push(err)
183
+ if (len === 0) {
184
+ reject(new AggregateError(errs))
185
+ }
186
+ })
187
+ })
188
+ })
189
+ }
190
+ }
191
+ return Promise.any(urls.map(urls => {
192
+ return new Promise((resolve, reject) => {
193
+ fetch(urls, {
194
+ signal: controller.signal
195
+ })
196
+ .then(PauseProgress)
197
+ .then(res => {
198
+ if (res.status == 200) {
199
+ controller.abort();
200
+ resolve(res)
201
+ } else {
202
+ reject(res)
203
+ }
204
+ })
205
+ })
206
+ }))
207
+ }
208
+ let fullpath = (path) => {
209
+ path = path.split('?')[0].split('#')[0]
210
+ if (path.match(/\/$/)) {
211
+ path += 'index'
212
+ }
213
+ if (!path.match(/\.[a-zA-Z]+$/)) {
214
+ path += '.html'
215
+ }
216
+ return path
217
+ }
218
+ let generate_blog_urls = () => {
219
+ const npmmirror = [
220
+ // `https://unpkg.zhimg.com/${packagename}@${blogversion}`,
221
+ // `https://npm.elemecdn.com/${packagename}@${blogversion}`,
222
+ // `https://cdn1.tianli0.top/npm/${packagename}@${blogversion}`,
223
+ // `https://cdn.afdelivr.top/npm/${packagename}@${blogversion}`,
224
+ `https://registry.npmmirror.com/${packagename}/${blogversion}/files`
225
+ ]
226
+ for (var i in npmmirror) {
227
+ npmmirror[i] += path
228
+ }
229
+ return npmmirror
230
+ }
231
+ let get_newest_version = async (ejectMirror) => {
232
+ return lfetch(ejectMirror, ejectMirror[0])
233
+ .then(res => res.json())
234
+ .then(res.version)
235
+ }
236
+ let set_newest_version = async (ejectMirror) => {
237
+ return lfetch(ejectMirror, ejectMirror[0])
238
+ .then(res => res.json()) //JSON Parse
239
+ .then(async res => {
240
+ await db.write('blog_version', res.version) //写入
241
+ return;
242
+ })
243
+ }
244
+ let set_newest_time = () => {
245
+ setInterval(async() => {
246
+ await set_newest_version(mirror) //定时更新,一分钟一次
247
+ }, 60*1000);
248
+
249
+ setTimeout(async() => {
250
+ await set_newest_version(mirror)//打开五秒后更新,避免堵塞
251
+ },5000)
252
+ function getFileType(fileName) {
253
+ suffix=fileName.split('.')[fileName.split('.').length-1]
254
+ if(suffix=="html"||suffix=="htm") {
255
+ return 'text/html';
256
+ }
257
+ if(suffix=="js") {
258
+ return 'text/javascript';
259
+ }
260
+ if(suffix=="css") {
261
+ return 'text/css';
262
+ }
263
+ if(suffix=="jpg"||suffix=="jpeg") {
264
+ return 'image/jpeg';
265
+ }
266
+ if(suffix=="ico") {
267
+ return 'image/x-icon';
268
+ }
269
+ if(suffix=="png") {
270
+ return 'image/png';
271
+ }
272
+ return 'text/plain';
273
+ }
274
+ }
275
+ let handle = async(req)=> {
276
+ const urlStr = req.url
277
+ const urlObj = new URL(urlStr);
278
+ const urlPath = urlObj.pathname;
279
+ const domain = urlObj.hostname;
280
+ //从这里开始
281
+ lxs=[]
282
+ if(domain === "blog.sinzmise.top"){//这里写你需要拦截的域名
283
+ var l=lfetch(generate_blog_urls('sinzmise-cetastories',await db.read('blog_version') || 'latest',fullpath(urlPath)))
284
+ return l
285
+ .then(res=>res.arrayBuffer())
286
+ .then(buffer=>new Response(buffer,{headers:{"Content-Type":`${getFileType(fullpath(urlPath).split("/")[fullpath(urlPath).split("/").length-1].split("\\")[fullpath(urlPath).split("/")[fullpath(urlPath).split("/").length-1].split("\\").length-1])};charset=utf-8`}}));//重新定义header
287
+ }
288
+ else{
289
+ return fetch(req);
290
+ }
291
+ }
292
+ let isCors = () => false
293
+ let isMemoryQueue = () => false
294
+ const fetchFile = (request, banCache, urls = null) => {
295
+ if (!urls) {
296
+ urls = getSpareUrls(request.url)
297
+ if (!urls) return fetchWithCors(request, banCache)
298
+ }
299
+ const list = urls.list
300
+ const controllers = new Array(list.length)
301
+ // noinspection JSCheckFunctionSignatures
302
+ const startFetch = index => fetchWithCors(
303
+ new Request(list[index], request),
304
+ banCache,
305
+ {signal: (controllers[index] = new AbortController()).signal}
306
+ ).then(response => checkResponse(response) ? {r: response, i: index} : Promise.reject())
307
+ return new Promise((resolve, reject) => {
308
+ let flag = true
309
+ const startAll = () => {
310
+ flag = false
311
+ Promise.any([
312
+ first,
313
+ ...Array.from({
314
+ length: list.length - 1
315
+ }, (_, index) => index + 1).map(index => startFetch(index))
316
+ ]).then(res => {
317
+ for (let i = 0; i !== list.length; ++i) {
318
+ if (i !== res.i)
319
+ controllers[i].abort()
320
+ }
321
+ resolve(res.r)
322
+ }).catch(() => reject(`请求 ${request.url} 失败`))
323
+ }
324
+ const id = setTimeout(startAll, urls.timeout)
325
+ const first = startFetch(0)
326
+ .then(res => {
327
+ if (flag) {
328
+ clearTimeout(id)
329
+ resolve(res.r)
330
+ }
331
+ }).catch(() => {
332
+ if (flag) {
333
+ clearTimeout(id)
334
+ startAll()
335
+ }
336
+ return Promise.reject()
337
+ })
338
+ })
339
+ }
340
+
341
+ // 检查请求是否成功
342
+ // noinspection JSUnusedLocalSymbols
343
+ const checkResponse = response => response.ok || [301, 302, 307, 308].includes(response.status)
344
+
345
+ /**
346
+ * 删除指定缓存
347
+ * @param list 要删除的缓存列表
348
+ * @return {Promise<string[]>} 删除的缓存的URL列表
349
+ */
350
+ const deleteCache = list => caches.open(CACHE_NAME).then(cache => cache.keys()
351
+ .then(keys => Promise.all(
352
+ keys.map(async it => {
353
+ const url = it.url
354
+ if (url !== CTRL_PATH && list.match(url)) {
355
+ // [debug delete]
356
+ // noinspection ES6MissingAwait,JSCheckFunctionSignatures
357
+ cache.delete(it)
358
+ return url
359
+ }
360
+ return null
361
+ })
362
+ )).then(list => list.filter(it => it))
363
+ )
364
+
365
+ /**
366
+ * 缓存列表
367
+ * @type {Map<string, function(any)[]>}
368
+ */
369
+ const cacheMap = new Map()
370
+
371
+ self.addEventListener('fetch', event => {
372
+ let request = event.request
373
+ let url = new URL(request.url)
374
+ // [blockRequest call]
375
+ if (request.method !== 'GET' || !request.url.startsWith('http')) return
376
+ // [modifyRequest call]
377
+ if (skipRequest(request)) return;
378
+ let cacheKey = url.hostname + url.pathname + url.search
379
+ let cache
380
+ if (isMemoryQueue(request)) {
381
+ cache = cacheMap.get(cacheKey)
382
+ if (cache) {
383
+ return event.respondWith(
384
+ new Promise((resolve, reject) => {
385
+ cacheMap.get(cacheKey).push(arg => arg.body ? resolve(arg) : reject(arg))
386
+ })
387
+ )
388
+ }
389
+ cacheMap.set(cacheKey, cache = [])
390
+ }
391
+ /** 处理拉取 */
392
+ const handleFetch = promise => {
393
+ event.respondWith(
394
+ cache ? promise.then(response => {
395
+ for (let item of cache) {
396
+ item(response.clone())
397
+ }
398
+ }).catch(err => {
399
+ for (let item of cache) {
400
+ item(err)
401
+ }
402
+ }).then(() => {
403
+ cacheMap.delete(cacheKey)
404
+ return promise
405
+ }) : promise
406
+ )
407
+ }
408
+ const cacheRule = findCache(url)
409
+ if (cacheRule) {
410
+ let key = `https://${url.host}${url.pathname}`
411
+ if (key.endsWith('/index.html')) key = key.substring(0, key.length - 10)
412
+ if (cacheRule.search) key += url.search
413
+ handleFetch(
414
+ caches.match(key).then(
415
+ cache => cache ?? fetchFile(request, true)
416
+ .then(response => {
417
+ if (checkResponse(response)) {
418
+ const clone = response.clone()
419
+ caches.open(CACHE_NAME).then(it => it.put(key, clone))
420
+ // [debug put]
421
+ }
422
+ return response
423
+ })
424
+ )
425
+ )
426
+ } else {
427
+ const urls = getSpareUrls(request.url)
428
+ if (urls) handleFetch(fetchFile(request, false, urls))
429
+ // [modifyRequest else-if]
430
+ else handleFetch(fetchWithCache(request).catch(err => new Response(err, {status: 499})))
431
+ }
432
+ })
433
+
434
+ self.addEventListener('message', event => {
435
+ // [debug message]
436
+ if (event.data === 'update')
437
+ updateJson().then(info => {
438
+ info.type = 'update'
439
+ event.source.postMessage(info)
440
+ })
441
+ })
442
+
443
+ /**
444
+ * 根据JSON删除缓存
445
+ * @returns {Promise<UpdateInfo>}
446
+ */
447
+ const updateJson = async () => {
448
+ /**
449
+ * 解析elements,并把结果输出到list中
450
+ * @return boolean 是否刷新全站缓存
451
+ */
452
+ const parseChange = (list, elements, ver) => {
453
+ for (let element of elements) {
454
+ const {version, change} = element
455
+ if (version === ver) return false
456
+ if (change) {
457
+ for (let it of change)
458
+ list.push(new CacheChangeExpression(it))
459
+ }
460
+ }
461
+ // 跨版本幅度过大,直接清理全站
462
+ return true
463
+ }
464
+ /**
465
+ * 解析字符串
466
+ * @return {Promise<{
467
+ * list?: VersionList,
468
+ * new: BrowserVersion,
469
+ * old: BrowserVersion
470
+ * }>}
471
+ */
472
+ const parseJson = json => readVersion().then(oldVersion => {
473
+ const {info, global} = json
474
+ /** @type {BrowserVersion} */
475
+ const newVersion = {global, local: info[0].version, escape: oldVersion?.escape ?? 0}
476
+ // 新用户和刚进行过逃逸操作的用户不进行更新操作
477
+ if (!oldVersion) {
478
+ // noinspection JSValidateTypes
479
+ newVersion.escape = 0
480
+ writeVersion(newVersion)
481
+ return {new: newVersion, old: oldVersion}
482
+ }
483
+ let list = new VersionList()
484
+ let refresh = parseChange(list, info, oldVersion.local)
485
+ writeVersion(newVersion)
486
+ // [debug escape]
487
+ // 如果需要清理全站
488
+ if (refresh) {
489
+ if (global !== oldVersion.global) list.force = true
490
+ else list.refresh = true
491
+ }
492
+ return {list, new: newVersion, old: oldVersion}
493
+ })
494
+ const response = await fetchFile(new Request('/update.json'), false)
495
+ if (!checkResponse(response))
496
+ throw `加载 update.json 时遇到异常,状态码:${response.status}`
497
+ const json = await response.json()
498
+ const result = await parseJson(json)
499
+ if (result.list) {
500
+ const list = await deleteCache(result.list)
501
+ result.list = list?.length ? list : null
502
+ }
503
+ // noinspection JSValidateTypes
504
+ return result
505
+ }
506
+
507
+ /**
508
+ * 版本列表
509
+ * @constructor
510
+ */
511
+ function VersionList() {
512
+
513
+ const list = []
514
+
515
+ /**
516
+ * 推送一个表达式
517
+ * @param element {CacheChangeExpression} 要推送的表达式
518
+ */
519
+ this.push = element => {
520
+ list.push(element)
521
+ }
522
+
523
+ /**
524
+ * 判断指定 URL 是否和某一条规则匹配
525
+ * @param url {string} URL
526
+ * @return {boolean}
527
+ */
528
+ this.match = url => {
529
+ if (this.force) return true
530
+ // noinspection JSValidateTypes
531
+ url = new URL(url)
532
+ if (this.refresh) {
533
+ // noinspection JSCheckFunctionSignatures
534
+ return findCache(url).clean
535
+ }
536
+ else {
537
+ for (let it of list) {
538
+ if (it.match(url)) return true
539
+ }
540
+ }
541
+ return false
542
+ }
543
+
544
+ }
545
+
546
+ // noinspection SpellCheckingInspection
547
+ /**
548
+ * 缓存更新匹配规则表达式
549
+ * @param json 格式{"flag": ..., "value": ...}
550
+ * @see https://kmar.top/posts/bcfe8408/#23bb4130
551
+ * @constructor
552
+ */
553
+ function CacheChangeExpression(json) {
554
+ /**
555
+ * 遍历所有value
556
+ * @param action {function(string): boolean} 接受value并返回bool的函数
557
+ * @return {boolean} 如果value只有一个则返回`action(value)`,否则返回所有运算的或运算(带短路)
558
+ */
559
+ const forEachValues = action => {
560
+ const value = json.value
561
+ if (Array.isArray(value)) {
562
+ for (let it of value) {
563
+ if (action(it)) return true
564
+ }
565
+ return false
566
+ } else return action(value)
567
+ }
568
+ const getMatch = () => {
569
+ switch (json['flag']) {
570
+ case 'html':
571
+ return url => url.pathname.match(/(\/|\.html)$/)
572
+ case 'end':
573
+ return url => forEachValues(value => url.href.endsWith(value))
574
+ case 'begin':
575
+ return url => forEachValues(value => url.pathname.startsWith(value))
576
+ case 'str':
577
+ return url => forEachValues(value => url.href.includes(value))
578
+ case 'reg':
579
+ // noinspection JSCheckFunctionSignatures
580
+ return url => forEachValues(value => url.href.match(new RegExp(value, 'i')))
581
+ default: throw `未知表达式:${JSON.stringify(json)}`
582
+ }
583
+ }
584
+ this.match = getMatch()
585
+ }
586
+ })()