logicdn 1.0.757 → 1.0.758

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.
@@ -0,0 +1,1250 @@
1
+ (() => {
2
+ 'use strict';
3
+
4
+ const CONFIG = {
5
+ // danmakuAPI: `${location.origin}/danmaku/`,
6
+ danmakuAPI:
7
+ 'https://cd.logi.im/services/serverless/forward/?url=https://dplayer.moerats.com/',
8
+ };
9
+
10
+ // 事件监听
11
+ document.addEventListener('DOMContentLoaded', () => {
12
+ if (LocalConst.ENABLE_PJAX) {
13
+ initPJAX();
14
+
15
+ const complete = Mirages.doPJAXCompleteAction;
16
+ Mirages.doPJAXCompleteAction = () => {
17
+ complete();
18
+
19
+ initImageProxy();
20
+ initQrcode();
21
+ initDplayer();
22
+ initAplayer();
23
+ initCopyButton();
24
+ initDescription();
25
+ initFriendLinks();
26
+ initReplayHandler();
27
+ //initGoogleAdsense();
28
+ initCodeCopyButton();
29
+ initOuterLinkInComment();
30
+ initPJAX();
31
+ expandTOC();
32
+ };
33
+ }
34
+
35
+ initImageProxy();
36
+ initDescription();
37
+ initCopyButton();
38
+ initCodeCopyButton();
39
+ initDplayer();
40
+ initNavLink();
41
+ initQrcode();
42
+ initLiveDay();
43
+ initOuterLinkInComment();
44
+ initReplayHandler();
45
+ initAplayer();
46
+ initNotice();
47
+ sayHello();
48
+ initFriendLinks();
49
+ expandTOC();
50
+ //initGoogleAdsense();
51
+ });
52
+
53
+ // 本地保存和获取 JSON
54
+ const STORAGE = {
55
+ set: (key, value) => localStorage.setItem(key, JSON.stringify(value)),
56
+ get: (key) => {
57
+ const value = localStorage.getItem(key);
58
+ try {
59
+ return JSON.parse(value);
60
+ } catch {
61
+ return value;
62
+ }
63
+ },
64
+ };
65
+
66
+ const REQUIREMENTS = {
67
+ vue: {
68
+ promise: null,
69
+ srcs: [
70
+ '//lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.10/vue.min.js',
71
+ ],
72
+ },
73
+ elementUI: {
74
+ promise: null,
75
+ srcs: [
76
+ '//lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.8.2/theme-chalk/index.css',
77
+ '//lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.8.2/index.js',
78
+ ],
79
+ caches: [
80
+ '//lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.8.2/theme-chalk/fonts/element-icons.ttf',
81
+ '//lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.8.2/theme-chalk/fonts/element-icons.woff',
82
+ '//cdn.cbd.int/logicdn@1.0.628/logi.im/usr/fonts/nasalization-rg.ttf',
83
+ ],
84
+ },
85
+ dplayer: {
86
+ promise: null,
87
+ srcs: [
88
+ '//cdn.cbd.int/dplayer@1.26.0/dist/DPlayer.min.js',
89
+ '//lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/hls.js/1.1.2/hls.light.min.js',
90
+ '//cdn.cbd.int/flv.js@1.5.0/dist/flv.min.js',
91
+ ],
92
+ },
93
+ aplayer: {
94
+ promise: null,
95
+ srcs: [
96
+ '//lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/aplayer/1.10.1/APlayer.min.css',
97
+ '//lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/aplayer/1.10.1/APlayer.min.js',
98
+ '//cdn.cbd.int/meting@2.0.1/dist/Meting.min.js',
99
+ ],
100
+ },
101
+ qrcode: {
102
+ promise: null,
103
+ srcs: [
104
+ '//lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery.qrcode/1.0/jquery.qrcode.min.js',
105
+ ],
106
+ },
107
+ ajaxhook: {
108
+ promise: null,
109
+ srcs: ['//cdn.cbd.int/ajax-hook/dist/ajaxhook.min.js'],
110
+ },
111
+ };
112
+
113
+ // 加载多个 REQUIREMENTS 的 Promise
114
+ function loadRequirements(...reqs) {
115
+ return Promise.all(
116
+ reqs.map((req) => {
117
+ if (req.Promise) return req.Promise;
118
+
119
+ const promises = req.srcs.map((src) => {
120
+ return new Promise((resolve, reject) => {
121
+ const suffix = src.split('.').pop();
122
+
123
+ const element = document.createElement(
124
+ { js: 'script', css: 'link' }[suffix]
125
+ );
126
+
127
+ element.onload = () => {
128
+ element.onload = null;
129
+ resolve('Successfully loaded: ' + src);
130
+ };
131
+
132
+ element.onerror = function () {
133
+ reject(Error('Filed to load: ' + src));
134
+ };
135
+
136
+ if (suffix === 'css') {
137
+ element.rel = 'stylesheet';
138
+ element.href = src;
139
+ } else {
140
+ element.src = src;
141
+ }
142
+
143
+ document.getElementsByTagName('head')[0].appendChild(element);
144
+ });
145
+ });
146
+
147
+ if (req.caches) {
148
+ req.caches.forEach((cache) => {
149
+ promises.push(fetch(cache));
150
+ });
151
+ }
152
+
153
+ req.Promise = Promise.all(promises);
154
+ return req.Promise;
155
+ })
156
+ );
157
+ }
158
+
159
+ // 通过 STRING 生成 HTML 元素
160
+ function generateHTMLElement(content) {
161
+ return document.createRange().createContextualFragment(content)
162
+ .firstElementChild;
163
+ }
164
+
165
+ // 把字符串转为 HTML 元素插入 HEAD
166
+ function appendToHead(content) {
167
+ const element = generateHTMLElement(content);
168
+ if (!document.getElementById(element.getAttribute('id'))) {
169
+ document.getElementsByTagName('head')[0].appendChild(element);
170
+ }
171
+ }
172
+
173
+ // 复制传入的文本
174
+ function copyText(text) {
175
+ const target = document.createElement('pre'); // textarea
176
+ target.style.opacity = '0';
177
+ target.textContent = text;
178
+ document.body.appendChild(target);
179
+ try {
180
+ const range = document.createRange();
181
+ range.selectNode(target);
182
+ window.getSelection().removeAllRanges();
183
+ window.getSelection().addRange(range);
184
+ document.execCommand('copy');
185
+ window.getSelection().removeAllRanges();
186
+ message('复制成功!', 'success');
187
+ } catch (e) {
188
+ message('复制失败!', 'error');
189
+ }
190
+ document.body.removeChild(target);
191
+ }
192
+
193
+ // 加载 ELEMENTUI
194
+ function registerElementUI() {
195
+ return loadRequirements(REQUIREMENTS.vue)
196
+ .then(() => loadRequirements(REQUIREMENTS.elementUI))
197
+ .then(() => {
198
+ window.VueRootInstance = new Vue({
199
+ el: document.createElement('div'),
200
+ created() {
201
+ window.alert = this.alert;
202
+ window.message = this.message;
203
+ },
204
+ methods: {
205
+ alert: function (
206
+ message,
207
+ type,
208
+ title,
209
+ duration,
210
+ showClose,
211
+ offset,
212
+ onClose
213
+ ) {
214
+ if (duration === undefined) duration = 6000;
215
+ this.$notify({
216
+ message: message,
217
+ type: type || 'error',
218
+ title: title || '警告',
219
+ duration: duration,
220
+ showClose: showClose || false,
221
+ offset: offset || 0,
222
+ onClose: onClose,
223
+ });
224
+ },
225
+ message: function (text, type) {
226
+ this.$message({
227
+ message: text,
228
+ type: type,
229
+ });
230
+ },
231
+ },
232
+ });
233
+ });
234
+ }
235
+
236
+ // 等待元素的 promise
237
+ function waitElements(selector) {
238
+ return new Promise((resolve, reject) => {
239
+ const waitId = setInterval(() => {
240
+ const elems = document.querySelectorAll(selector);
241
+ if (elems.length) {
242
+ clearInterval(waitId);
243
+ resolve(elems);
244
+ }
245
+ }, 200);
246
+
247
+ setTimeout(() => {
248
+ clearInterval(waitId);
249
+ reject(new Error(`wait ${selector} time out`));
250
+ }, 1000 * 10);
251
+ });
252
+ }
253
+
254
+ // 反代图床
255
+ function initImageProxy() {}
256
+
257
+ // 拓宽目录显示
258
+ async function expandTOC() {
259
+ if (body.offsetWidth < 1000) return;
260
+
261
+ const menu = document.querySelector('#post-menu');
262
+ const toggle = document.querySelector('#toggle-menu-tree');
263
+ const backtop = document.querySelector('#backtop');
264
+ backtop ? backtop.removeAttribute('style') : null;
265
+
266
+ if (!toggle || !menu || !backtop) return;
267
+
268
+ appendToHead(
269
+ `
270
+ <style id='body-width-for-toc'>
271
+ @media screen and (min-width: 1000px) {
272
+ body.desktop #wrap.display-menu-tree {
273
+ width:calc(100% - 27rem) !important;
274
+ }
275
+ }
276
+ </style>
277
+ `
278
+ );
279
+
280
+ const tocs = await waitElements('span.toc');
281
+ if (!tocs) return;
282
+
283
+ let expanded = toggle.querySelector('fa-angle-left');
284
+ [toggle, ...tocs].forEach((e) =>
285
+ e.addEventListener('click', () => {
286
+ if (!expanded) {
287
+ menu.style.width = '27.5rem';
288
+ toggle.style.transform = 'translateX(-27.5rem)';
289
+ backtop.style.transform = 'translateX(-27.5rem)';
290
+ } else {
291
+ menu.removeAttribute('style');
292
+ toggle.removeAttribute('style');
293
+ backtop.removeAttribute('style');
294
+ }
295
+ expanded = !expanded;
296
+ })
297
+ );
298
+ }
299
+
300
+ // 显示欢迎语
301
+ function sayHello() {
302
+ if (!document.querySelector('meta[property="og:site_name"]')) return;
303
+
304
+ const hours = new Date().getHours();
305
+ let hello;
306
+ if (hours < 5) {
307
+ hello = '凌晨好,注意休息哦!';
308
+ } else if (hours >= 5 && hours < 8) {
309
+ hello = '早上好,新的一天又是元气满满呢!';
310
+ } else if (hours >= 8 && hours < 12) {
311
+ hello = '上午好!';
312
+ } else if (hours === 12) {
313
+ hello = '中午好!';
314
+ } else if (hours > 12 && hours <= 18) {
315
+ hello = '下午好!';
316
+ } else if (hours > 18 && hours <= 22) {
317
+ hello = '晚上好!';
318
+ } else if (hours > 22 && hours < 24) {
319
+ hello = '夜深了,注意休息哦!';
320
+ }
321
+
322
+ const helloMessage = new Date().toLocaleDateString() + hello;
323
+ if (STORAGE.get('HELLO') === helloMessage) return;
324
+
325
+ registerElementUI().then(() => {
326
+ setTimeout(() => {
327
+ const siteName = document.querySelector(
328
+ 'meta[property="og:site_name"]'
329
+ ).content;
330
+ let welcome = '欢迎来到 ' + siteName;
331
+ if (!/博客|小站|小窝|blog/i.test(siteName)) {
332
+ welcome += ' 的博客!';
333
+ }
334
+
335
+ alert(welcome, 'success', hello, 3000);
336
+ STORAGE.set('HELLO', helloMessage);
337
+ }, 2500);
338
+ });
339
+ }
340
+
341
+ // 自定义公告样式
342
+ appendToHead(
343
+ `<style id="blod-notice">
344
+ .blog-notice {
345
+ display: none !important;
346
+ }
347
+ .el-message {
348
+ top: .75rem !important;
349
+ }
350
+ @media screen and (max-device-width: 767px) {
351
+ .el-notification.right {
352
+ margin: 0 auto;
353
+ left: 0;
354
+ right: 0 !important;
355
+ }
356
+ .el-message {
357
+ min-width: unset !important;
358
+ width: 90vw !important;
359
+ }
360
+ }
361
+ </style>`
362
+ );
363
+ function initNotice() {
364
+ const blgNotice = document.querySelector('.blog-notice p');
365
+ if (blgNotice) {
366
+ const oldNotice = STORAGE.get('NOTICE');
367
+ const newNotice = blgNotice.innerText;
368
+ if (!oldNotice || oldNotice !== newNotice) {
369
+ registerElementUI().then(() => {
370
+ alert(newNotice, 'info', '公告', 0, true, null, () => {
371
+ STORAGE.set('NOTICE', newNotice);
372
+ });
373
+ });
374
+ }
375
+ }
376
+ }
377
+
378
+ function bundleDataCallback(render) {
379
+ const api = (action) =>
380
+ `//cd.logi.im/services/serverless/forward/?url=https://${action}.jsdelivr.net/npm/logicdn/logi.im/api/asset/data/bundle.json`;
381
+
382
+ const refresh = async () => fetch(api('purge'));
383
+
384
+ const validateData = (data) => {
385
+ if (new Date(data.date).toDateString() === new Date().toDateString()) {
386
+ return true;
387
+ }
388
+ refresh();
389
+ return false;
390
+ };
391
+
392
+ const data = STORAGE.get('API_BUNDLE_DATA');
393
+ if (data) {
394
+ render(data);
395
+ if (validateData(data)) return;
396
+ }
397
+
398
+ fetch(api('cdn'), {
399
+ cache: 'no-store',
400
+ })
401
+ .then((response) => response.json())
402
+ .then((json) => {
403
+ if (!data) render(json);
404
+ STORAGE.set('API_BUNDLE_DATA', json);
405
+ });
406
+ }
407
+
408
+ // 获取每日一句并显示
409
+ function initDescription() {
410
+ if (location.href !== location.origin + '/') return;
411
+
412
+ bundleDataCallback((data) => {
413
+ const getRandomInt = (max) => Math.floor(Math.random() * max);
414
+ data = data.sentences[getRandomInt(data.sentences.length)];
415
+ const h1 = document.querySelector('h1.blog-title');
416
+ const h2 = document.querySelector('h2.blog-description');
417
+ // (h1.innerHTML = data.translation), (h2.innerHTML = data.sentence);
418
+ h1.innerHTML = data.sentence.split(/[.?!]/)[0] + '.';
419
+ });
420
+ }
421
+
422
+ // 获取友链健康数据
423
+
424
+ appendToHead(
425
+ `<style id="friend-status">
426
+ .status::before {
427
+ content: "";
428
+ width: 20px;
429
+ height: 10px;
430
+ border-radius: 4px;
431
+ box-sizing: border-box;
432
+ position: absolute;
433
+ top: 2px;
434
+ right: 2px;
435
+ }
436
+ .online::before {
437
+ background: #5bca24;
438
+ }
439
+ .offline::before {
440
+ border: red 1px solid;
441
+ }
442
+ .untracked::before {
443
+ border: #f9a146 1px solid;
444
+ border-right-width: 15px;
445
+ }
446
+ </style>`
447
+ );
448
+ function initFriendLinks() {
449
+ if (!location.href.startWith(`${location.origin}/about.html`)) {
450
+ return;
451
+ }
452
+
453
+ Array.prototype.shuffle = function () {
454
+ for (let i = this.length - 1; i > 0; i--) {
455
+ let j = Math.floor(Math.random() * i);
456
+ [this[i], this[j]] = [this[j], this[i]];
457
+ }
458
+ return this;
459
+ };
460
+
461
+ const render = (data) => {
462
+ function randomAvatar(suffix) {
463
+ return `//source.boringavatars.com/beam/200/${btoa(suffix)}`;
464
+ }
465
+
466
+ const online = generateHTMLElement(`<div class="link-box"></div>`);
467
+ const offline = generateHTMLElement(`<div class="link-box"></div>`);
468
+
469
+ data.friends.shuffle().forEach((friend) => {
470
+ const toStart = (date) => date.setHours(0, 0, 0, 0);
471
+
472
+ const offlineDays =
473
+ (toStart(new Date()) - toStart(new Date(friend.lastOnlineDate))) /
474
+ (1000 * 60 * 60 * 24);
475
+
476
+ const isOnline = friend.online || offlineDays < 5;
477
+ friend.untracked =
478
+ friend.untracked || (offlineDays > 2 && offlineDays < 5);
479
+
480
+ const friendElem = generateHTMLElement(`
481
+ <a href="${
482
+ friend.link
483
+ }" target="_blank" class="no-underline">
484
+ <div class="thumb">
485
+ <img width="200" height="200" src="${
486
+ isOnline
487
+ ? `//cdn.cbd.int/logicdn@1.0.628/logi.im/api/` +
488
+ friend.avatar
489
+ : randomAvatar(friend.avatar)
490
+ }?t=${Date.now()}" alt="${friend.name}">
491
+ </div>
492
+ <div class="content status ${
493
+ friend.untracked
494
+ ? 'untracked'
495
+ : isOnline
496
+ ? 'online'
497
+ : 'offline'
498
+ }">
499
+ <p class="title">
500
+ ${friend.name}${
501
+ !isOnline ? '<br>已离线 ' + offlineDays + ' 天' : ''
502
+ }</p>
503
+ </div>
504
+ </a>
505
+ `);
506
+
507
+ if (isOnline) {
508
+ online.appendChild(friendElem);
509
+ } else {
510
+ offline.appendChild(friendElem);
511
+ }
512
+ });
513
+
514
+ document.querySelector('#friend-online').appendChild(online);
515
+ document.querySelector('#friend-offline').appendChild(offline);
516
+ };
517
+
518
+ bundleDataCallback(render);
519
+ }
520
+
521
+ // 创建隐藏内容的复制按钮
522
+ function initCopyButton() {
523
+ const cps = document.querySelectorAll('cp');
524
+ if (cps.length) {
525
+ registerElementUI().then(() => {
526
+ cps.forEach((btn) => {
527
+ btn.style.display = '0';
528
+ let text = btn.getAttribute('text');
529
+ text = text[0] === '\n' ? text.slice(1) : text;
530
+ const button = document.createElement('a');
531
+ button.href = '#';
532
+ button.innerHTML = btn.getAttribute('name');
533
+ button.className = 'btn btn-primary';
534
+ button.onclick = (event) => {
535
+ event.preventDefault();
536
+ copyText(text);
537
+ // return false;
538
+ };
539
+ btn.parentNode.insertBefore(button, btn);
540
+ });
541
+ });
542
+ }
543
+ }
544
+
545
+ // 在代码块右上角添加复制按钮
546
+ function initCodeCopyButton() {
547
+ const pres = document.querySelectorAll('pre');
548
+ if (pres.length) {
549
+ appendToHead(
550
+ `<style id="btn-code">
551
+ @font-face {
552
+ font-family: "Nasalization";
553
+ src: url("//cdn.cbd.int/logicdn@1.0.628/logi.im/usr/fonts/nasalization-rg.ttf") format("truetype");
554
+ }
555
+ .code-wrapper {
556
+ position: absolute;
557
+ display: flex;
558
+ top: .1em;
559
+ right: .1em;
560
+ }
561
+ .btn-code {
562
+ font-family: Nasalization;
563
+ margin-left: .2rem;
564
+ border-radius: .1rem;
565
+ text-align: center;
566
+ user-select: none;
567
+ line-height: .95rem;
568
+ height: 1rem;
569
+ padding: 0 .2rem;
570
+ color: white;
571
+ font-size: 80%;
572
+ opacity: .4;
573
+ background: #4e4e4e;
574
+ }
575
+ .btn-code.copy:hover {
576
+ background: black;
577
+ cursor: pointer;
578
+ }
579
+ </style>`
580
+ );
581
+ }
582
+
583
+ registerElementUI().then(() => {
584
+ pres.forEach((pre) => {
585
+ const code = pre.querySelector('code');
586
+ if (code) {
587
+ const preParent = pre.parentElement;
588
+ const newPreParent = document.createElement('div');
589
+ newPreParent.style = 'position: relative';
590
+ preParent.insertBefore(newPreParent, pre);
591
+
592
+ const wrapper = document.createElement('div');
593
+ wrapper.className = 'code-wrapper';
594
+ newPreParent.appendChild(wrapper);
595
+
596
+ const copyBtn = document.createElement('div');
597
+ copyBtn.innerHTML = 'copy';
598
+ copyBtn.className = 'btn-code copy';
599
+ copyBtn.addEventListener('click', () => copyText(code.textContent));
600
+ wrapper.appendChild(copyBtn);
601
+
602
+ const lang = code.classList[0].split('-')[1];
603
+ if (lang) {
604
+ const langDiv = document.createElement('div');
605
+ langDiv.innerHTML = lang;
606
+ langDiv.className = 'btn-code';
607
+ wrapper.insertBefore(langDiv, copyBtn);
608
+ }
609
+
610
+ newPreParent.appendChild(pre);
611
+ }
612
+ });
613
+ });
614
+ }
615
+
616
+ // DPlayer API
617
+ function initDplayer() {
618
+ const dps = document.getElementsByTagName('dp');
619
+ if (dps.length) {
620
+ appendToHead(`
621
+ <style id="dplayer-danmaku">
622
+ .dplayer-danmaku {
623
+ z-index:1;
624
+ }
625
+ .dplayer-controller,.dplayer-mask.dplayer-mask-show {
626
+ z-index:2;
627
+ }
628
+ .dplayer-danmaku .dplayer-danmaku-right.dplayer-danmaku-move {
629
+ animation:danmaku 12s linear !important;
630
+ }
631
+ .dplayer:-webkit-full-screen .dplayer-danmaku .dplayer-danmaku-right.dplayer-danmaku-move {
632
+ animation:danmaku 15s linear !important;
633
+ animation-play-state:inherit !important;
634
+ }
635
+ .dplayer-paused .dplayer-danmaku .dplayer-danmaku-right.dplayer-danmaku-move {
636
+ animation-play-state:paused !important;
637
+ }
638
+ .dplayer-danmaku .dplayer-danmaku-item {
639
+ margin-top:2px !important;
640
+ text-shadow:0.5px 0.5px 1px black !important;
641
+ font-weight:bold !important;
642
+ }
643
+ </style>`);
644
+ function fixVideoSize() {
645
+ let outerTimer = false;
646
+ const outerInterval = setInterval(() => {
647
+ if (outerTimer) return;
648
+ const videos = document.getElementsByTagName('video');
649
+ if (videos.length === dps.length) {
650
+ const dplayerWraps = document.querySelectorAll(
651
+ '.dplayer-video-wrap'
652
+ );
653
+ for (let i = 0; i < dps.length; i++) {
654
+ const videoContainers = dplayerWraps[i].querySelectorAll(
655
+ '.video-container.video-4-3'
656
+ );
657
+ if (videoContainers.length) {
658
+ videoContainers[0].style = 'position: initial;';
659
+ videoContainers[0].className = 'video-container video-16-9';
660
+ console.log('Dplayer: video-4-3 fixed.');
661
+ } else {
662
+ const videoContainer = document.createElement('div');
663
+ videoContainer.style = 'position: initial;';
664
+ videoContainer.className = 'video-container video-16-9';
665
+ videoContainer.appendChild(videos[i]);
666
+ dplayerWraps[i].appendChild(videoContainer);
667
+ console.log('Dplayer: video-16-9 inserted.');
668
+ const targetNode = videoContainer;
669
+ const config = { childList: true };
670
+ const callback = (_, observer) => {
671
+ const newVideoContainers = videoContainer.querySelectorAll(
672
+ '.video-container.video-4-3'
673
+ );
674
+ if (newVideoContainers.length) {
675
+ newVideoContainers[0].className = '';
676
+ console.log('Dplayer: auto inserted video-4-3 fixed.');
677
+ observer.disconnect();
678
+ }
679
+ };
680
+ const observer = new MutationObserver(callback);
681
+ observer.observe(targetNode, config);
682
+ setTimeout(() => observer.disconnect(), 1000 * 120);
683
+ }
684
+ }
685
+ outerTimer = true;
686
+ clearInterval(outerInterval);
687
+ }
688
+ }, 500);
689
+ }
690
+
691
+ loadRequirements(REQUIREMENTS.dplayer).then(() => {
692
+ for (let i = 0; i < dps.length; i++) {
693
+ const child = document.createElement('div');
694
+ const src = dps[i].getAttribute('src');
695
+ const cid = dps[i].getAttribute('cid');
696
+ dps[i].parentNode.insertBefore(child, dps[i]);
697
+ dps[i].style.display = 'none';
698
+ const type = src.split('.').pop();
699
+ const video = { url: src };
700
+ type === 'flv' ? (video.type = type) : null;
701
+ const option = {
702
+ container: child,
703
+ preload: 'none',
704
+ autoplay: false,
705
+ screenshot: false,
706
+ video: video,
707
+ };
708
+ if (cid) {
709
+ option.danmaku = {
710
+ id: `cid_${cid}`,
711
+ token: '299b6a5543616b5508c1ce8616ed530b',
712
+ api: CONFIG.danmakuAPI,
713
+ addition: [`${CONFIG.danmakuAPI}v3/bilibili/?cid=${cid}`],
714
+ };
715
+ }
716
+ new DPlayer(option);
717
+ }
718
+
719
+ window.Mirages ? fixVideoSize() : null;
720
+ });
721
+ }
722
+ }
723
+
724
+ // 自定义导航栏
725
+ function initNavLink() {
726
+ [
727
+ ...document.querySelectorAll('#nav a'),
728
+ ...document.querySelectorAll('#navbarCollapse a'),
729
+ ].forEach((a) => {
730
+ if ('游戏 网盘 商店 音乐'.split(' ').indexOf(a.title) !== -1) {
731
+ a.target = '_blank';
732
+ } else if (a.title === '关于' && a.className === 'nav-linkcurrent') {
733
+ a.className = 'nav-link current';
734
+ }
735
+ });
736
+ }
737
+
738
+ // QRCODE API
739
+ function initQrcode() {
740
+ const common = {
741
+ initOptions: function (source, options) {
742
+ options = options || {};
743
+ 'text size border'.split(' ').forEach((key) => {
744
+ const value =
745
+ source instanceof URLSearchParams
746
+ ? source.get(key)
747
+ : source.getAttribute(key);
748
+ if (value) {
749
+ if (key === 'size') {
750
+ options.width = value;
751
+ options.height = value;
752
+ } else {
753
+ options[key] = value;
754
+ }
755
+ }
756
+ });
757
+ return options;
758
+ },
759
+ makeQrcode: function (source, options) {
760
+ const div = document.createElement('div');
761
+ jQuery(div).qrcode(options);
762
+ const canvas = div.querySelector('canvas');
763
+ const dataURL = canvas.toDataURL('image/jpeg', 1.0);
764
+ if (!options.hasOwnProperty('border')) {
765
+ source.src = dataURL;
766
+ return;
767
+ }
768
+
769
+ const context = canvas.getContext('2d');
770
+ const image = new Image();
771
+ image.onload = function () {
772
+ const size = options.width - 2 * options.border;
773
+ context.fillStyle = '#FFF';
774
+ context.fillRect(0, 0, canvas.width, canvas.height);
775
+ context.drawImage(image, options.border, options.border, size, size);
776
+ source.src = canvas.toDataURL('image/jpeg', 1.0);
777
+ };
778
+ image.src = dataURL;
779
+ },
780
+ makeQrcodes: function (sources) {
781
+ for (let i = 0; i < sources.length; i++) {
782
+ const options = this.initOptions(sources[i]);
783
+ if (options.hasOwnProperty('text')) {
784
+ const image = new Image();
785
+ sources[i].parentNode.insertBefore(image, sources[i]);
786
+ sources[i].style.display = 'none';
787
+ this.makeQrcode(image, options);
788
+ }
789
+ }
790
+ },
791
+ };
792
+ const mirages = {
793
+ addQrcode: function (qrBox, makeQrcode, initOptions) {
794
+ const image = qrBox.querySelector('img');
795
+ if (!image.src.startWith(location.href)) {
796
+ return;
797
+ }
798
+ const splitedSrc = image.src.split('?');
799
+ let options = { text: splitedSrc[0] };
800
+ if (splitedSrc[1]) {
801
+ options = initOptions(new URLSearchParams(splitedSrc[1]), options);
802
+ }
803
+ makeQrcode(image, options);
804
+ },
805
+ };
806
+
807
+ const position = document.querySelector('.post-qr-code-box');
808
+ const qrs = document.getElementsByTagName('qr');
809
+ if (position) {
810
+ loadRequirements(REQUIREMENTS.qrcode).then(() => {
811
+ mirages.addQrcode(position, common.makeQrcode, common.initOptions);
812
+ });
813
+ }
814
+
815
+ if (qrs.length) {
816
+ loadRequirements(REQUIREMENTS.qrcode).then(() => {
817
+ common.makeQrcodes(qrs);
818
+ });
819
+ }
820
+ }
821
+
822
+ // 添加站点生存时间
823
+ function initLiveDay() {
824
+ const birthTime = '2015/2/21 10:23:12';
825
+ const template = (A, B, C, D) => `Struggling for ${A}d ${B}h ${C}m ${D}s.`;
826
+
827
+ const container = footer.querySelector('.container');
828
+ const p = document.createElement('p');
829
+ container.insertBefore(p, container.firstElementChild);
830
+
831
+ const msoad = 24 * 60 * 60 * 1000;
832
+ const wrap = (n) => (n > 9 ? n : '0' + n);
833
+ const toInt = (n) => wrap(Math.floor(n));
834
+ setInterval(() => {
835
+ const lived = new Date() - new Date(birthTime);
836
+ const days = lived / msoad;
837
+ const intDays = toInt(days);
838
+ const hours = (days - intDays) * 24;
839
+ const intHours = toInt(hours);
840
+ const minutes = (hours - intHours) * 60;
841
+ const intMinutes = toInt(minutes);
842
+ const seconds = (minutes - intMinutes) * 60;
843
+ const intSeconds = toInt(seconds);
844
+ p.innerHTML = template(intDays, intHours, intMinutes, intSeconds);
845
+ }, 1000);
846
+ }
847
+
848
+ // 评论区外链在新窗口打开
849
+ function initOuterLinkInComment() {
850
+ document
851
+ .querySelectorAll('.comment-list a[href^="' + location.origin + '/go/"]')
852
+ .forEach((a) => (a.target = '_blank'));
853
+ }
854
+
855
+ // PJAX 下,若存在隐藏内容,回复后自动刷新
856
+ function initReplayHandler() {
857
+ // 顺便改下提示
858
+ const comments = document.querySelector('#comments');
859
+ if (!comments) return;
860
+
861
+ const commentTemplate = `
862
+ <ol class="comment-list">
863
+ <li
864
+ itemscope=""
865
+ itemtype="http://schema.org/UserComments"
866
+ id="comment-3006"
867
+ class="comment-body comment-child comment-level-odd comment-odd comment-by-author"
868
+ >
869
+ <div
870
+ class="comment-author"
871
+ itemprop="creator"
872
+ itemscope=""
873
+ itemtype="http://schema.org/Person"
874
+ >
875
+ <span itemprop="image"
876
+ ><img
877
+ class="avatar"
878
+ src="https://code.bdstatic.com/npm/logicdn@1.0.0/logi.im/usr/images/global/logo.webp"
879
+ data-src=""
880
+ alt="LOGI"
881
+ width="100"
882
+ height="100"
883
+ /></span>
884
+ <cite class="fn color-main" itemprop="name"
885
+ ><a href="${location.origin}" rel="external nofollow">LOGI</a></cite
886
+ >
887
+ </div>
888
+ <div class="comment-content" itemprop="commentText">
889
+ <p>
890
+ 强调几点:(该留言由系统自动生成!)<br />
891
+ 1. 请不要刷广告,本站没有流量!<br />
892
+ 2. 我不回复虚假邮箱,因为回复了你也看不到!<br />
893
+ 3. 存在必须回复的隐藏内容时,可以直接使用表情框里的阿鲁表情!
894
+ </p>
895
+ </div>
896
+ </li>
897
+ </ol>`;
898
+ const seperatorTemplate = `
899
+ <div class="comment-separator">
900
+ <div class="comment-tab-current">
901
+ <span class="comment-num">已有 1 条评论</span>
902
+ </div>
903
+ </div>`;
904
+
905
+ const author = comments.querySelector('#author');
906
+ const email = comments.querySelector('#mail');
907
+ const url = comments.querySelector('#url');
908
+ const textarea = comments.querySelector('#textarea');
909
+ const respond = comments.querySelector('.respond');
910
+ let separator = comments.querySelector('.comment-separator');
911
+ if (email && author && url && textarea) {
912
+ author.placeholder = '您的昵称(必填)';
913
+ email.placeholder = '您的邮箱(必填)';
914
+ url.placeholder = '您的网站(选填)';
915
+ textarea.placeholder = '在这里输入您的评论!';
916
+
917
+ if (!separator) {
918
+ comments.insertBefore(
919
+ generateHTMLElement(seperatorTemplate),
920
+ respond.nextElementSibling
921
+ );
922
+ separator = comments.querySelector('.comment-separator');
923
+ }
924
+
925
+ comments.insertBefore(
926
+ generateHTMLElement(commentTemplate),
927
+ separator.nextElementSibling
928
+ );
929
+ }
930
+
931
+ const commentForm = comments.querySelector('#comment-form');
932
+ const reply2View = document.querySelector('.reply2view');
933
+ if (commentForm && reply2View && reply2View.className === 'reply2view') {
934
+ const submit = commentForm.querySelector('#submit');
935
+ const template = (sec) => `评论提交成功,重载倒计时${sec}.`;
936
+ submit.setAttribute('data-posted', template(3));
937
+
938
+ const reload = async () => {
939
+ const status = document.querySelector('span.comment-posted');
940
+ if (status) {
941
+ ah.unProxy();
942
+
943
+ function count(rest) {
944
+ if (rest < 1) {
945
+ $.pjax.reload('#body', {
946
+ scrollTo: reply2View.scrollTop,
947
+ timeout: 8000,
948
+ });
949
+ return;
950
+ }
951
+ status.innerHTML = template(rest);
952
+ setTimeout(() => count(rest - 1), 1000);
953
+ }
954
+
955
+ count(3);
956
+ return;
957
+ }
958
+
959
+ setTimeout(reload, 100);
960
+ };
961
+
962
+ loadRequirements(REQUIREMENTS.ajaxhook).then(() => {
963
+ ah.proxy({
964
+ onRequest: (config, handler) => {
965
+ handler.next(config);
966
+ },
967
+ onError: (err, handler) => {
968
+ handler.next(err);
969
+ },
970
+ onResponse: (response, handler) => {
971
+ if (
972
+ response.config.url ===
973
+ `${location.href.match(/http.+html/)[0]}/comment`
974
+ ) {
975
+ reload();
976
+ }
977
+ handler.next(response);
978
+ },
979
+ });
980
+ });
981
+ /*
982
+ const callback = (mutations, observer) => {
983
+ mutations.forEach((mutation) => {
984
+ mutation.addedNodes.forEach((node) => {
985
+ let status = null;
986
+ if (typeof node.querySelector === "function") {
987
+ status = node.querySelector(".comment-meta .comment-posted");
988
+ }
989
+ if (status) {
990
+ console.log("Comment success observed.");
991
+ let countDown = 2;
992
+ const countDownWaiter = setInterval(() => {
993
+ if (countDown < 0) {
994
+ clearInterval(countDownWaiter);
995
+ observer.disconnect();
996
+ return;
997
+ }
998
+ status.innerText = template(countDown--);
999
+ if (countDown === 0) {
1000
+ $.pjax.reload({
1001
+ url: location.href,
1002
+ container: "#body",
1003
+ fragment: "#body",
1004
+ scrollTo: reply2View.scrollTop,
1005
+ timeout: 8000,
1006
+ });
1007
+ initReplayHandler();
1008
+ console.log("Comment observation finished.");
1009
+ clearInterval(countDownWaiter);
1010
+ observer.disconnect();
1011
+ }
1012
+ }, 800);
1013
+ }
1014
+ });
1015
+ });
1016
+ };
1017
+ const observer = new MutationObserver(callback);
1018
+ commentForm.addEventListener("submit", () => {
1019
+ console.log("Start to observe comment");
1020
+ observer.observe(comments, { childList: true, subtree: true });
1021
+ });
1022
+ */
1023
+ }
1024
+ }
1025
+
1026
+ // APlayer API
1027
+ window.aplayers = window.aplayers || [];
1028
+ window.initAplayer = initAplayer;
1029
+ function initAplayer(option) {
1030
+ function createAplayers(sources) {
1031
+ for (let i = 0; i < sources.length; i++) {
1032
+ const child = document.createElement('div');
1033
+ sources[i].parentNode.insertBefore(child, sources[i]);
1034
+ sources[i].style.display = 'none';
1035
+ const songTags = sources[i].querySelectorAll('s');
1036
+ const songs = [];
1037
+ songTags.forEach((songTag) => {
1038
+ const song = {};
1039
+ for (let i = 0; i < songTag.attributes.length; i++) {
1040
+ song[songTag.attributes[i].name] = songTag.attributes[i].value;
1041
+ }
1042
+ songs.push(song);
1043
+ });
1044
+ const options = {
1045
+ container: child,
1046
+ preload: 'none',
1047
+ autoplay: false,
1048
+ audio: songs,
1049
+ };
1050
+ const optionMap = sources[i].attributes;
1051
+ for (let i = 0; i < optionMap.length; i++) {
1052
+ options[optionMap[i].name] = optionMap[i].value;
1053
+ }
1054
+ loadRequirements(REQUIREMENTS.aplayer).then(() =>
1055
+ window.aplayers.push(new APlayer(options))
1056
+ );
1057
+ }
1058
+ }
1059
+
1060
+ if (option == 'manual') return loadRequirements(REQUIREMENTS.aplayer);
1061
+
1062
+ const aps = document.querySelectorAll('ap');
1063
+ if (aps.length) createAplayers(aps);
1064
+
1065
+ const mts = document.querySelectorAll('meting-js');
1066
+ if (mts.length) {
1067
+ mts.forEach((mt) => {
1068
+ const t = document.createElement('textarea');
1069
+ t.style.display = 'none';
1070
+ t.value = mt.outerHTML;
1071
+ t.id = 'meting-js';
1072
+ mt.parentElement.replaceChild(t, mt);
1073
+ });
1074
+
1075
+ loadRequirements(REQUIREMENTS.aplayer).then(() => {
1076
+ document.querySelectorAll('#meting-js').forEach((t) => {
1077
+ t.parentElement.replaceChild(generateHTMLElement(t.value), t);
1078
+ });
1079
+ });
1080
+ }
1081
+ }
1082
+
1083
+ // PJAX 相关 BUG
1084
+ function initPJAX() {
1085
+ window.addEventListener(
1086
+ 'popstate',
1087
+ (e) => {
1088
+ window.aplayers.forEach((ap) => {
1089
+ ap.list.index = undefined;
1090
+ ap.destroy();
1091
+ });
1092
+
1093
+ if (e.state.url === location.href) {
1094
+ let needReload = false;
1095
+ [
1096
+ '.collapse-block',
1097
+ '.content-tabs',
1098
+ '#toggle-menu-tree',
1099
+ 'meting-js',
1100
+ 'pre code',
1101
+ ].forEach((s) =>
1102
+ document.querySelectorAll(s).forEach((e) => {
1103
+ e.style.display = 'none';
1104
+ needReload = true;
1105
+ })
1106
+ );
1107
+
1108
+ if (needReload) {
1109
+ document.querySelectorAll('.dplayer').forEach((dp) => {
1110
+ appendToHead(`
1111
+ <style id="dplayer-height">
1112
+ .dplayer {
1113
+ height: ${(600 * 9) / 16}px !important;
1114
+ }
1115
+ </style>`);
1116
+ });
1117
+
1118
+ $.pjax.reload('#body', { timeout: 8000 });
1119
+ }
1120
+ }
1121
+ },
1122
+ false
1123
+ );
1124
+ }
1125
+
1126
+ function initGoogleAdsense() {
1127
+ if (
1128
+ location.pathname.startsWith('/about.html') ||
1129
+ location.pathname.startsWith('/comments.html') ||
1130
+ location.pathname.startsWith('/archives.html') ||
1131
+ location.pathname.startsWith(
1132
+ '/security/android-package-name-deception.html'
1133
+ ) ||
1134
+ location.pathname.startsWith(
1135
+ '/script/unblocking-bilibili-without-perception.html/comment-page-2'
1136
+ )
1137
+ )
1138
+ return;
1139
+
1140
+ const articlePost = document.querySelector('article.post');
1141
+ if (!articlePost) return;
1142
+
1143
+ window.LAST_REGISTERED_URL = location.href;
1144
+ const initMask = () => {
1145
+ if (
1146
+ window.LAST_REGISTERED_URL !== location.href ||
1147
+ document.querySelector('#fullscreenMask')
1148
+ ) {
1149
+ return;
1150
+ }
1151
+
1152
+ document
1153
+ .querySelectorAll('ins')
1154
+ .forEach((ins) => ins.parentElement.removeChild(ins));
1155
+
1156
+ const mask = document.createElement('div');
1157
+ mask.id = 'fullscreenMask';
1158
+ mask.style.background = 'black';
1159
+ mask.style.position = 'fixed';
1160
+ mask.style.top = '0';
1161
+ mask.style.left = '0';
1162
+ mask.style.opacity = '.5';
1163
+ mask.style.zIndex = '2000';
1164
+ mask.style.width = '100vw';
1165
+ mask.style.height = '100vh';
1166
+ document.body.appendChild(mask);
1167
+ alert(
1168
+ '请大佬关闭广告屏蔽插件或将本站加入白名单后刷新页面,感谢您的支持!',
1169
+ 'error',
1170
+ '恳请',
1171
+ null,
1172
+ 0
1173
+ );
1174
+ };
1175
+ fetch('//www.googletagservices.com/activeview/js/current/osd.js', {
1176
+ mode: 'no-cors',
1177
+ }).catch(() => {
1178
+ document
1179
+ .querySelectorAll('ins')
1180
+ .forEach((ins) => ins.parentElement.removeChild(ins));
1181
+ setTimeout(initMask, 5000);
1182
+ });
1183
+
1184
+ document
1185
+ .querySelectorAll('#body-bottom .container ins.adsbygoogle')
1186
+ .forEach((ad) => {
1187
+ ad.parentElement.removeChild(ad);
1188
+ });
1189
+
1190
+ let width,
1191
+ adloader = document.createElement('script');
1192
+
1193
+ if (!LocalConst.IS_PHONE) {
1194
+ adloader.setAttribute('async', true);
1195
+ adloader.src =
1196
+ '//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?ts=' +
1197
+ Date.now();
1198
+ document.body.appendChild(adloader);
1199
+
1200
+ const postContent = document.querySelector('div.post-content');
1201
+ width = postContent.offsetWidth;
1202
+ postContent.insertBefore(
1203
+ generateHTMLElement(`
1204
+ <ins class="adsbygoogle"
1205
+ style="display:block; text-align:center; width:${width}px;"
1206
+ data-ad-layout="in-article"
1207
+ data-ad-format="fluid"
1208
+ data-ad-client="ca-pub-2697499514807797"
1209
+ data-ad-slot="7068019113">
1210
+ </ins>`),
1211
+ postContent.firstElementChild
1212
+ );
1213
+ (window.adsbygoogle = window.adsbygoogle || []).push({});
1214
+ }
1215
+
1216
+ adloader = document.createElement('script');
1217
+ adloader.setAttribute('async', true);
1218
+ adloader.src =
1219
+ '//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?ts=' +
1220
+ Date.now();
1221
+ document.body.appendChild(adloader);
1222
+ const bodyBottomContainer = document.querySelector(
1223
+ '#body-bottom .container'
1224
+ );
1225
+ const comments = bodyBottomContainer.querySelector('#comments');
1226
+ const postNear = bodyBottomContainer.querySelector('.post-near');
1227
+ postNear.style.marginBottom = '1em';
1228
+ width = postNear.offsetWidth;
1229
+ bodyBottomContainer.insertBefore(
1230
+ generateHTMLElement(`
1231
+ <ins class="adsbygoogle"
1232
+ style="display:block; text-align:center; width:${width}px;"
1233
+ data-ad-client="ca-pub-2697499514807797"
1234
+ data-ad-slot="1677404715"
1235
+ data-ad-format="auto"
1236
+ data-full-width-responsive="false">
1237
+ </ins>`),
1238
+ comments
1239
+ );
1240
+ (window.adsbygoogle = window.adsbygoogle || []).push({});
1241
+ console.log('Adding adsense');
1242
+
1243
+ setTimeout(() => {
1244
+ if (document.querySelector('ins.adsbygoogle iframe')) {
1245
+ return;
1246
+ }
1247
+ initMask();
1248
+ }, 5000);
1249
+ }
1250
+ })();