惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog RSS Feed
C
CERT Recently Published Vulnerability Notes
P
Proofpoint News Feed
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
云风的 BLOG
云风的 BLOG
H
Help Net Security
Recorded Future
Recorded Future
The Register - Security
The Register - Security
F
Full Disclosure
N
Netflix TechBlog - Medium
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hackread – Cybersecurity News, Data Breaches, AI and More
爱范儿
爱范儿
Security Archives - TechRepublic
Security Archives - TechRepublic
Simon Willison's Weblog
Simon Willison's Weblog
Cisco Talos Blog
Cisco Talos Blog
I
InfoQ
T
Tenable Blog
T
Tor Project blog
人人都是产品经理
人人都是产品经理
D
DataBreaches.Net
NISL@THU
NISL@THU
Google DeepMind News
Google DeepMind News
博客园 - 叶小钗
B
Blog
V
V2EX
Jina AI
Jina AI
L
LangChain Blog
月光博客
月光博客
W
WeLiveSecurity
U
Unit 42
AWS News Blog
AWS News Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
博客园 - 聂微东
V
Visual Studio Blog
A
Arctic Wolf
T
Tailwind CSS Blog
The Cloudflare Blog
SecWiki News
SecWiki News
S
SegmentFault 最新的问题
Hacker News - Newest:
Hacker News - Newest: "LLM"
宝玉的分享
宝玉的分享
MyScale Blog
MyScale Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Securelist
www.infosecurity-magazine.com
www.infosecurity-magazine.com
腾讯CDC
雷峰网
雷峰网

山岳库博

自建虚拟局域网实现文明六稳定联机 追光者 快手面经(二〇二四年五月九日) 一文搞懂伪代码 2023 级新生周赛第二周题解 Swpp Backends 官方文档 Butterfly 友链魔改教程 在 MavenCentral 上发布你的项目 控制台游戏引擎开发文档 MI——高级合成表模块 人狼羊菜过河详细题解 蓝桥杯 2023 训练四 Java 全解 蓝桥杯 2023 训练三 Java 全解 蓝桥杯 2023 训练二 Java 全解 全自动博客部署方案 小白也能用的 SW 构建插件 MI—电力系统工作原理 MI文档——自动化GUI绘制 网站加载速度优化方案总结 给博客添加自定义的通知悬浮窗
给博客添加追番页面
空梦 · 2022-06-26 · via 山岳库博

注意:如果你的博客开启了 pjax,请务必使用 pjax 兼容的方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
!=page.content

#bangumis
#bangumi-top
.multi#cats
p 分类
.list
.wantWatch 想看
.watching 在看
.watched 已看
.multi#tags
p 标签
.list
.all.active 所有

div#inner

.bangumi-tabs#bangumi-bottom
button#bottom-first 首页
button#bottom-pre 上一页
p#bottom-num 0/0
button#bottom-next 下一页
button#bottom-end 尾页

script.
document.addEventListener('DOMContentLoaded', async function fun() {
/**
* 分离Json的读取器
*
* @param root {string} 根目录,不以`/`结尾
* @param amount {number} 每页的数量
* @param dataAmount {number} 每个文件中数据的数量
* @param size {number} 项目总量
* @constructor
*/

function ApartJson(root, amount, dataAmount, size) {
// 下一个要读取项目编号
let readIndex = 0
// 读取的文件列表
const fileList = new Map()
// 标记最后一个index
const lastIndex = Math.ceil(size / dataAmount) - 1

/**
* 读取指定下标的文件
* @param index {number} 文件下标
* @return {Promise}
*/
const readFile = index => new Promise(resolve => {
if (index > lastIndex || index < 0) throw `${index} not in [0, ${lastIndex}]`
if (fileList.has(index)) {
let id
const task = () => {
const cache = fileList.get(index)
if (cache) {
if (id) clearInterval(id)
resolve(cache)
}
}
task()
id = setInterval(task, 100)
} else {
fileList.set(index, null)
fetch(`${root}/${index}.json`)
.then(response => response.json().then(json => {
fileList.set(index, json)

resolve(json)
}))
}
})

const readHelper = id => new Promise(resolve => {
if (size && id > size) return resolve(null)
const fileIndex = Math.floor(id / dataAmount)
const innerIndex = id % dataAmount
readFile(fileIndex).then(json => {
// noinspection JSCheckFunctionSignatures
const keys = Object.keys(json)
resolve(json[keys[innerIndex]])
})
})

// noinspection JSUnusedGlobalSymbols
/**
* 读取上一项
* @return {Promise}
*/
this.readNext = () => readHelper(readIndex++)

/**
* 读取上一项
* @return {Promise}
*/
//this.readPrev = () => readHelper(readIndex--)

// noinspection CommaExpressionJS,JSUnusedGlobalSymbols
/**
* 设置页码,从0开始
* @param page {number} 页面编号
*/
this.setPage = page => {
readIndex = page * amount
}

/** 获取页码数量 */
this.size = () => Math.ceil(size / amount)

/** 获取数据总量 */
this.amount = () => size

// noinspection JSUnusedGlobalSymbols
/**
* 判断指定页面是否为末页
* @param page {number|null} 指定页面编号,留空为当前页面编号
* @return {boolean}
*/
this.isLastPage = (page = null) => {
if (page === null) page = Math.floor(readIndex / amount)
return page === this.size() - 1
}
}

const isSupportWebp = (() => {
try {
return document.createElement('canvas').toDataURL('image/webp', 0.5).indexOf('data:image/webp') === 0;
} catch (ignore) {
return false;
}
})()
const root = '/bilibili/'
const config = await (await fetch(`${root}config.json`)).json()
const sizeList = config.size
// 单页卡片数量限制
const maxCount = 10
const dataAmount = config.amount
// JSON
const jsonMap = {
wantWatch: new ApartJson(`${root}wantWatch`, maxCount, dataAmount, sizeList.wantWatch),
watching: new ApartJson(`${root}watching`, maxCount, dataAmount, sizeList.watching),
watched: new ApartJson(`${root}watched`, maxCount, dataAmount, sizeList.watched)
}

/** 处理参数 */
const parseArg = () => {
const url = location.href
let arg
if (url.endsWith('/')) {
arg = {id: 'watching', page: 1}
} else {
arg = JSON.parse(decodeURIComponent(location.hash.substring(1)))
// 校对参数
if (!arg.id || (arg.id !== 'watching' &&
arg.id !== 'wantWatch' && arg.id !== 'watched'))
arg.id = 'watching'
if (!arg.page || arg.page < 1) arg.page = 1
}
sessionStorage.setItem('bangumis', JSON.stringify(arg))
return arg
}

const arg = await parseArg()
let tagFilter = null
const top = document.querySelector('#bangumi-top')
const cats = top.querySelector('#cats')
const tags = top.querySelector('#tags')
const tabs = document.querySelector('.bangumi-tabs')

/** 更新列表内容 */
async function update(updateURL = true) {
tabs.querySelectorAll('button').forEach(button => button.classList.add('disable'))
top.querySelectorAll('div').forEach(div => div.classList.add('disable'))
for (let value of cats.querySelector('.list').children) {
if (value.classList.contains(arg.id)) value.classList.add('active')
else value.classList.remove('active')
}
const json = jsonMap[arg.id]
json.setPage(arg.page - 1)

function buildCard(title, img, href, follow, type, area, play, coin, danmaku, score, tagList, index) {
if (!img.startsWith('http')) img = `https://i0.hdslb.com/bfs/bangumi/${img}${isSupportWebp ? '@220w_280h.webp' : ''}`
let tags = ''
for (let name of tagList) tags += `<p>${name}</p>`
// noinspection HtmlUnknownAttribute,HtmlRequiredAltAttribute
return `<div class="card" link="${href}" index="${index}"><img src="${img}" referrerpolicy="no-referrer"><div class="info"><a class="title">${title}</a><div class="details"><span class="area"><p>${type}</p><em>${area}</em></span><span class="play"><p>播放量</p><em>${play}</em></span><span class="follow"><p>追番</p><em>${follow}</em></span><span class="coin"><p>硬币</p><em>${coin}</em></span><span class="danmaku"><p>弹幕</p><em>${danmaku}</em></span><span class="score"><p>评分</p><em>${score}</em></span></div><div class="tags">${tags}</div></div></div>`
}

const inner = document.getElementById('inner')
inner.innerHTML = ''
if (updateURL) location.hash = JSON.stringify(arg)
for (let i = 0; i !== maxCount;) {
const value = await json.readNext()
if (!value) break
if (tagFilter && !tagFilter(value)) continue
const id = value.id ?? 0
const href = id === 0 ? '' : (typeof id !== 'number' ? id : `https://www.bilibili.com/bangumi/media/md${id}/`)
inner.innerHTML += buildCard(value.title, value.cover, href ?? 0,
value.follow ?? '-', value.type ?? '番剧', value.area ?? '日本', value.view ?? '-',
value.coin ?? '-', value.danmaku ?? '-', value.score ?? '-', value.tags ?? [], value.index ?? 0)
++i
}

const pageNum = document.getElementById('bottom-num')
appendText(pageNum, tagFilter ? 'disabled' : `${arg.page} / ${json.size()}`, true)
tabs.querySelectorAll('button').forEach(button => button.classList.remove('disable'))
top.querySelectorAll('div').forEach(div => div.classList.remove('disable'))

const pre = document.getElementById('bottom-pre').classList
const next = document.getElementById('bottom-next').classList
if (arg.page === 1) pre.add('disable')
if (json.isLastPage(arg.page - 1)) next.add('disable')
}

const init = () => {
const buildTag = (name) => `<div class="${name}">${name}</div>`
cats.addEventListener('click', event => {
const target = event.target
const classList = target.classList
if (!target.parentNode?.classList?.contains('list') ||
classList.contains('active') || classList.contains('disable')) return
arg.id = target.className
arg.page = 1
update()
})
const tagList = tags.querySelector('.list')
for (let tag of config.tags) {
tagList.innerHTML += buildTag(tag)
}
tagList.onclick = event => {
const target = event.target
const parent = target.parentNode
const classList = target.classList
if (!parent.classList?.contains('list') ||
classList.contains('active') || classList.contains('disable')) return
for (let node of parent.children) {
node.classList.remove('active')
}
const name = target.className
tagFilter = name === 'all' ? null : card => card.tags?.includes(name)
classList.add('active')
update(false)
}
}

/** 追加文本 */
function appendText(element, text, clean) {
text = `(${text})`
if (navigator.userAgent.includes('Firefox')) {
if (!clean && element.textContent.endsWith(')')) return
element.textContent = clean ? text : element.textContent + text
} else {
if (!clean && element.innerText.endsWith(')')) return
element.innerText = clean ? text : element.innerText + text
}
}

/** 注册点击事件 */
function initClick(arg) {
const top = document.getElementById('bangumi-top')
top.addEventListener('click', event => {
const element = event.target.id ? event.target : event.target.parentNode
if (element.nodeName !== 'BUTTON') return
const classList = element.classList
if (classList.contains('active') || classList.contains('disable')) return
classList.add('active')
for (let value of top.children) {
if (value.id !== element.id) value.classList.remove('active')
}
arg.id = element.id
arg.page = 1
sessionStorage.setItem('bangumis', JSON.stringify(arg))
update()
})
const bottom = document.getElementById('bangumi-bottom')
const height = document.getElementById('page-header').clientHeight
bottom.addEventListener('click', event => {
const element = event.target.id ? event.target : event.target.parentNode
if (element.nodeName !== 'BUTTON' || element.classList.contains('disable')) return
btf.scrollToDest(height)
switch (element.id) {
case 'bottom-first':
arg.page = 1
break
case 'bottom-end':
arg.page = jsonMap[arg.id].size()
break
case 'bottom-next':
++arg.page
break
case 'bottom-pre':
--arg.page
break
}
setTimeout(() => update(arg), 200)
})
const card = document.getElementById('inner')
card.addEventListener('click', event => {
let element = event.target.id ? event.target : event.target.parentNode
if (!element.classList.contains('descr')) {
while (!element.classList.contains('card')) element = element.parentElement
const link = element.getAttribute('link')
if (link.length > 1) open(link)
else btf.snackbarShow('博主没有为这个番剧设置链接~')
}
})
}

init()
const hashchangeTask = () => {
const newArg = parseArg()
if (newArg.id !== arg.id && newArg.page !== arg.page) {
arg.id = newArg.id
arg.page = newArg.page
update(false)
}
}
addEventListener('hashchange', hashchangeTask)
for (let key in sizeList) {
appendText(cats.querySelector(`.${key}`), sizeList[key], false)
}
initClick(arg)
// noinspection ES6MissingAwait
update(false)
})

首先在你的某一个所有页面都需要加载的 JS 文件中写入如下代码:

1
2
3
4
5
document.addEventListener('DOMContentLoaded', () => {
const pushEvent = () => document.dispatchEvent(new Event('kms:loaded'))
document.addEventListener('pjax:complete', pushEvent)
pushEvent()
})

然后编写 PUG 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
!=page.content

#bangumis
#bangumi-top
.multi#cats
p 分类
.list
.wantWatch 想看
.watching 在看
.watched 已看
.multi#tags
p 标签
.list
.all.active 所有

div#inner

.bangumi-tabs#bangumi-bottom
button#bottom-first 首页
button#bottom-pre 上一页
p#bottom-num 0/0
button#bottom-next 下一页
button#bottom-end 尾页

script.
document.addEventListener('kms:loaded', async function fun() {
document.removeEventListener('kms:loaded', fun)

/**
* 分离Json的读取器
*
* @param root {string} 根目录,不以`/`结尾
* @param amount {number} 每页的数量
* @param dataAmount {number} 每个文件中数据的数量
* @param size {number} 项目总量
* @constructor
*/

function ApartJson(root, amount, dataAmount, size) {

// 下一个要读取项目编号
let readIndex = 0
// 读取的文件列表
const fileList = new Map()
// 标记最后一个index
const lastIndex = Math.ceil(size / dataAmount) - 1

/**
* 读取指定下标的文件
* @param index {number} 文件下标
* @return {Promise}
*/
const readFile = index => new Promise(resolve => {
if (index > lastIndex || index < 0) throw `${index} not in [0, ${lastIndex}]`
if (fileList.has(index)) {
let id
const task = () => {
const cache = fileList.get(index)
if (cache) {
if (id) clearInterval(id)
resolve(cache)
}
}
task()
id = setInterval(task, 100)
} else {
fileList.set(index, null)
fetch(`${root}/${index}.json`)
.then(response => response.json().then(json => {
fileList.set(index, json)

resolve(json)
}))
}
})

const readHelper = id => new Promise(resolve => {
if (size && id > size) return resolve(null)
const fileIndex = Math.floor(id / dataAmount)
const innerIndex = id % dataAmount
readFile(fileIndex).then(json => {
// noinspection JSCheckFunctionSignatures
const keys = Object.keys(json)
resolve(json[keys[innerIndex]])
})
})

// noinspection JSUnusedGlobalSymbols
/**
* 读取上一项
* @return {Promise}
*/
this.readNext = () => readHelper(readIndex++)

/**
* 读取上一项
* @return {Promise}
*/
//this.readPrev = () => readHelper(readIndex--)

// noinspection CommaExpressionJS,JSUnusedGlobalSymbols
/**
* 设置页码,从0开始
* @param page {number} 页面编号
*/
this.setPage = page => {
readIndex = page * amount
}

/** 获取页码数量 */
this.size = () => Math.ceil(size / amount)

/** 获取数据总量 */
this.amount = () => size

// noinspection JSUnusedGlobalSymbols
/**
* 判断指定页面是否为末页
* @param page {number|null} 指定页面编号,留空为当前页面编号
* @return {boolean}
*/
this.isLastPage = (page = null) => {
if (page === null) page = Math.floor(readIndex / amount)
return page === this.size() - 1
}
}

const isSupportWebp = (() => {
try {
return document.createElement('canvas').toDataURL('image/webp', 0.5).indexOf('data:image/webp') === 0;
} catch (ignore) {
return false;
}
})()
const root = '/bilibili/'
const config = await (await fetch(`${root}config.json`)).json()
const sizeList = config.size
// 单页卡片数量限制
const maxCount = 10
const dataAmount = config.amount
// JSON
const jsonMap = {
wantWatch: new ApartJson(`${root}wantWatch`, maxCount, dataAmount, sizeList.wantWatch),
watching: new ApartJson(`${root}watching`, maxCount, dataAmount, sizeList.watching),
watched: new ApartJson(`${root}watched`, maxCount, dataAmount, sizeList.watched)
}

/** 处理参数 */
const parseArg = () => {
const url = location.href
let arg
if (url.endsWith('/')) {
arg = {id: 'watching', page: 1}
} else {
arg = JSON.parse(decodeURIComponent(location.hash.substring(1)))
// 校对参数
if (!arg.id || (arg.id !== 'watching' &&
arg.id !== 'wantWatch' && arg.id !== 'watched'))
arg.id = 'watching'
if (!arg.page || arg.page < 1) arg.page = 1
}
sessionStorage.setItem('bangumis', JSON.stringify(arg))
return arg
}

const arg = await parseArg()
let tagFilter = null
const top = document.querySelector('#bangumi-top')
const cats = top.querySelector('#cats')
const tags = top.querySelector('#tags')
const tabs = document.querySelector('.bangumi-tabs')

/** 更新列表内容 */
async function update(updateURL = true) {
tabs.querySelectorAll('button').forEach(button => button.classList.add('disable'))
top.querySelectorAll('div').forEach(div => div.classList.add('disable'))
for (let value of cats.querySelector('.list').children) {
if (value.classList.contains(arg.id)) value.classList.add('active')
else value.classList.remove('active')
}
const json = jsonMap[arg.id]
json.setPage(arg.page - 1)

function buildCard(title, img, href, follow, type, area, play, coin, danmaku, score, tagList, index) {
if (!img.startsWith('http')) img = `https://i0.hdslb.com/bfs/bangumi/${img}${isSupportWebp ? '@220w_280h.webp' : ''}`
let tags = ''
for (let name of tagList) tags += `<p>${name}</p>`
// noinspection HtmlUnknownAttribute,HtmlRequiredAltAttribute
return `<div class="card" link="${href}" index="${index}"><img src="${img}" referrerpolicy="no-referrer"><div class="info"><a class="title">${title}</a><div class="details"><span class="area"><p>${type}</p><em>${area}</em></span><span class="play"><p>播放量</p><em>${play}</em></span><span class="follow"><p>追番</p><em>${follow}</em></span><span class="coin"><p>硬币</p><em>${coin}</em></span><span class="danmaku"><p>弹幕</p><em>${danmaku}</em></span><span class="score"><p>评分</p><em>${score}</em></span></div><div class="tags">${tags}</div></div></div>`
}

const inner = document.getElementById('inner')
inner.innerHTML = ''
if (updateURL) location.hash = JSON.stringify(arg)
for (let i = 0; i !== maxCount;) {
const value = await json.readNext()
if (!value) break
if (tagFilter && !tagFilter(value)) continue
const id = value.id ?? 0
const href = id === 0 ? '' : (typeof id !== 'number' ? id : `https://www.bilibili.com/bangumi/media/md${id}/`)
inner.innerHTML += buildCard(value.title, value.cover, href ?? 0,
value.follow ?? '-', value.type ?? '番剧', value.area ?? '日本', value.view ?? '-',
value.coin ?? '-', value.danmaku ?? '-', value.score ?? '-', value.tags ?? [], value.index ?? 0)
++i
}

const pageNum = document.getElementById('bottom-num')
appendText(pageNum, tagFilter ? 'disabled' : `${arg.page} / ${json.size()}`, true)
tabs.querySelectorAll('button').forEach(button => button.classList.remove('disable'))
top.querySelectorAll('div').forEach(div => div.classList.remove('disable'))

const pre = document.getElementById('bottom-pre').classList
const next = document.getElementById('bottom-next').classList
if (arg.page === 1) pre.add('disable')
if (json.isLastPage(arg.page - 1)) next.add('disable')
}

const init = () => {
const buildTag = (name) => `<div class="${name}">${name}</div>`
cats.addEventListener('click', event => {
const target = event.target
const classList = target.classList
if (!target.parentNode?.classList?.contains('list') ||
classList.contains('active') || classList.contains('disable')) return
arg.id = target.className
arg.page = 1
update()
})
const tagList = tags.querySelector('.list')
for (let tag of config.tags) {
tagList.innerHTML += buildTag(tag)
}
tagList.onclick = event => {
const target = event.target
const parent = target.parentNode
const classList = target.classList
if (!parent.classList?.contains('list') ||
classList.contains('active') || classList.contains('disable')) return
for (let node of parent.children) {
node.classList.remove('active')
}
const name = target.className
tagFilter = name === 'all' ? null : card => card.tags?.includes(name)
classList.add('active')
update(false)
}
}

/** 追加文本 */
function appendText(element, text, clean) {
text = `(${text})`
if (navigator.userAgent.includes('Firefox')) {
if (!clean && element.textContent.endsWith(')')) return
element.textContent = clean ? text : element.textContent + text
} else {
if (!clean && element.innerText.endsWith(')')) return
element.innerText = clean ? text : element.innerText + text
}
}

/** 注册点击事件 */
function initClick(arg) {
const top = document.getElementById('bangumi-top')
top.addEventListener('click', event => {
const element = event.target.id ? event.target : event.target.parentNode
if (element.nodeName !== 'BUTTON') return
const classList = element.classList
if (classList.contains('active') || classList.contains('disable')) return
classList.add('active')
for (let value of top.children) {
if (value.id !== element.id) value.classList.remove('active')
}
arg.id = element.id
arg.page = 1
sessionStorage.setItem('bangumis', JSON.stringify(arg))
update()
})
const bottom = document.getElementById('bangumi-bottom')
const height = document.getElementById('page-header').clientHeight
bottom.addEventListener('click', event => {
const element = event.target.id ? event.target : event.target.parentNode
if (element.nodeName !== 'BUTTON' || element.classList.contains('disable')) return
btf.scrollToDest(height)
switch (element.id) {
case 'bottom-first':
arg.page = 1
break
case 'bottom-end':
arg.page = jsonMap[arg.id].size()
break
case 'bottom-next':
++arg.page
break
case 'bottom-pre':
--arg.page
break
}
setTimeout(() => update(arg), 200)
})
const card = document.getElementById('inner')
card.addEventListener('click', event => {
let element = event.target.id ? event.target : event.target.parentNode
if (!element.classList.contains('descr')) {
while (!element.classList.contains('card')) element = element.parentElement
const link = element.getAttribute('link')
if (link.length > 1) open(link)
else btf.snackbarShow('博主没有为这个番剧设置链接~')
}
})
}

init()
const hashchangeTask = () => {
const newArg = parseArg()
if (newArg.id !== arg.id && newArg.page !== arg.page) {
arg.id = newArg.id
arg.page = newArg.page
update(false)
}
}
addEventListener('hashchange', hashchangeTask)
for (let key in sizeList) {
appendText(cats.querySelector(`.${key}`), sizeList[key], false)
}
initClick(arg)
// noinspection ES6MissingAwait
update(false)
})