mirror of
https://github.com/jerryc127/hexo-theme-butterfly.git
synced 2026-08-10 20:48:42 +08:00
feat: add wordcount helpers, waline lightbox, and extensive bug fixes
- wordcount/min2read/totalcount built-in helpers (replaces hexo-wordcount) - cloudTags random sort support - waline lightbox via MutationObserver - subtitle: seq guard prevents stale API response race - newest-comments: escapeHtml XSS fix, unified fetchAndRender with cache fallback - katex: try/catch asset load, encrypt re-render - chartjs: destroy charts on pjax, fix theme property check - mathjax: DOMContentLoaded instead of load - mermaid: clean stale error elements - medium-zoom: single instance, detach on pjax - getScrollPercent: WeakMap cache with resize invalidation - overflowPaddingR: avoid stale DOM refs - readmode: dedupe button, pjax cleanup - hexo-blog-decrypt: null-guard translateFn and encryptFn - tw_cn: expand skipped translate tags - localStorage: try/catch setItem - cdn.js: fix [lib|dist]* character class regex bug - findArchivesTitle: support custom archive_dir - shuoshuoFN: guard moment.tz when timezone empty - umami: no-store cache, error handling, path param - artalk: vote config option - bump version 5.7.1.260810
This commit is contained in:
+22
-1
@@ -20,8 +20,29 @@ script.
|
||||
path: isShuoshuo ? path : (option && option.path) || path
|
||||
})
|
||||
|
||||
let lightboxObserver = null
|
||||
if (GLOBAL_CONFIG.lightbox !== 'null') {
|
||||
const wrap = el.querySelector('#waline-wrap')
|
||||
if (wrap) {
|
||||
lightboxObserver = new MutationObserver(mutations => {
|
||||
const imgs = []
|
||||
mutations.forEach(mutation => {
|
||||
mutation.addedNodes.forEach(node => {
|
||||
if (node.nodeType !== 1) return
|
||||
const nodeImgs = node.matches && node.matches('img') ? [node] : node.querySelectorAll('img')
|
||||
nodeImgs.forEach(img => imgs.push(img))
|
||||
})
|
||||
})
|
||||
const lightboxImgs = imgs.filter(img => img.closest('.wl-content') && !img.classList.contains('wl-emoji'))
|
||||
if (lightboxImgs.length) btf.loadLightbox(lightboxImgs)
|
||||
})
|
||||
lightboxObserver.observe(wrap, { childList: true, subtree: true })
|
||||
}
|
||||
}
|
||||
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyWaline = () => {
|
||||
lightboxObserver && lightboxObserver.disconnect()
|
||||
destroyWaline(waline)
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
@@ -46,7 +67,7 @@ script.
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{use[0]}' === 'Waline'
|
||||
? window.shuoshuoComment = { loadComment: loadWaline }
|
||||
? window.shuoshuoComment = { loadComment: loadWaline }
|
||||
: window.loadOtherComment = loadWaline
|
||||
return
|
||||
}
|
||||
|
||||
+14
-3
@@ -22,7 +22,7 @@ script.
|
||||
const value = obj[key]
|
||||
// If the property is an object and has theme-specific options, apply them
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (value[theme]) {
|
||||
if (theme in value) {
|
||||
obj[key] = value[theme] // Apply the value for the current theme
|
||||
} else {
|
||||
// Recursively process child objects
|
||||
@@ -32,6 +32,11 @@ script.
|
||||
})
|
||||
}
|
||||
|
||||
const destroyChart = canvas => {
|
||||
const chart = canvas && window.Chart && Chart.getChart(canvas)
|
||||
if (chart) chart.destroy()
|
||||
}
|
||||
|
||||
const runChartJS = ele => {
|
||||
window.loadChartJS = true
|
||||
|
||||
@@ -41,9 +46,10 @@ script.
|
||||
const width = item.getAttribute('data-width')
|
||||
const existingCanvas = document.getElementById(chartID)
|
||||
|
||||
// If a canvas already exists, remove it to avoid rendering duplicates
|
||||
// If a canvas already exists, destroy its chart and remove it to avoid rendering duplicates
|
||||
if (existingCanvas) {
|
||||
existingCanvas.parentNode.remove()
|
||||
destroyChart(existingCanvas)
|
||||
existingCanvas.parentNode.remove()
|
||||
}
|
||||
|
||||
const chartDefinition = chartSrc.textContent
|
||||
@@ -83,6 +89,11 @@ script.
|
||||
window.loadChartJS ? runChartJS(chartJSEle) : btf.getScript('!{url_for(theme.asset.chartjs)}').then(() => runChartJS(chartJSEle))
|
||||
}
|
||||
|
||||
// Destroy all charts before navigating away to avoid leaks
|
||||
btf.addGlobalFn('pjaxSendOnce', () => {
|
||||
document.querySelectorAll('.chartjs-wrap canvas').forEach(destroyChart)
|
||||
}, 'chartjs')
|
||||
|
||||
// Listen for theme change events
|
||||
btf.addGlobalFn('themeChange', loadChartJS, 'chartjs')
|
||||
btf.addGlobalFn('encrypt', loadChartJS, 'chartjs')
|
||||
|
||||
+21
-16
@@ -1,16 +1,21 @@
|
||||
script.
|
||||
(async () => {
|
||||
const showKatex = () => {
|
||||
document.querySelectorAll('#article-container .katex').forEach(el => el.classList.add('katex-show'))
|
||||
}
|
||||
|
||||
if (!window.katex_js_css) {
|
||||
window.katex_js_css = true
|
||||
await btf.getCSS('!{url_for(theme.asset.katex)}')
|
||||
if (!{theme.math.katex.copy_tex}) {
|
||||
await btf.getScript('!{url_for(theme.asset.katex_copytex)}')
|
||||
}
|
||||
}
|
||||
|
||||
showKatex()
|
||||
})()
|
||||
script.
|
||||
(async () => {
|
||||
const showKatex = () => {
|
||||
document.querySelectorAll('#article-container .katex').forEach(el => el.classList.add('katex-show'))
|
||||
}
|
||||
|
||||
if (!window.katex_js_css) {
|
||||
window.katex_js_css = true
|
||||
try {
|
||||
await btf.getCSS('!{url_for(theme.asset.katex)}')
|
||||
if (!{theme.math.katex.copy_tex}) {
|
||||
await btf.getScript('!{url_for(theme.asset.katex_copytex)}')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[katex] failed to load assets, showing formulas anyway:', e)
|
||||
}
|
||||
}
|
||||
|
||||
showKatex()
|
||||
btf.addGlobalFn('encrypt', showKatex, 'katex')
|
||||
})()
|
||||
|
||||
+3
-1
@@ -77,5 +77,7 @@ script.
|
||||
}
|
||||
|
||||
btf.addGlobalFn('encrypt', loadMathjax, 'mathjax')
|
||||
window.pjax ? loadMathjax() : window.addEventListener('load', loadMathjax)
|
||||
if (window.pjax) loadMathjax()
|
||||
else if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', loadMathjax)
|
||||
else loadMathjax()
|
||||
})()
|
||||
+3
-1
@@ -282,12 +282,14 @@ script.
|
||||
const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{theme.mermaid.theme.dark}' : '!{theme.mermaid.theme.light}'
|
||||
ele.forEach((item, index) => {
|
||||
const mermaidSrc = item.firstElementChild
|
||||
// Clean up event listeners before removing old SVG
|
||||
// Clean up event listeners and stale content before re-rendering
|
||||
if (item.__mermaidAbortController) {
|
||||
item.__mermaidAbortController.abort()
|
||||
}
|
||||
const oldSvg = item.querySelector('svg')
|
||||
if (oldSvg) oldSvg.remove()
|
||||
const oldError = item.querySelector('.mermaid-error')
|
||||
if (oldError) oldError.remove()
|
||||
let config = {}
|
||||
try {
|
||||
config = mermaidSrc.dataset.config ? JSON.parse(mermaidSrc.dataset.config) : {}
|
||||
|
||||
+60
-67
@@ -1,67 +1,60 @@
|
||||
- const { server, site, option } = theme.artalk
|
||||
- const avatarCdn = (option !== null && option.gravatar && option.gravatar.mirror) || ''
|
||||
- const avatarDefault = (option !== null && option.gravatar && (option.gravatar.params || option.gravatar.default)) || ''
|
||||
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.addEventListener('load', () => {
|
||||
const keyName = 'artalk-newest-comments'
|
||||
const { changeContent, generateHtml, run } = window.newestComments
|
||||
|
||||
const getAvatarValue = async () => {
|
||||
const predefinedAvatarCdn = '!{avatarCdn}'
|
||||
const predefinedAvatarDefault = '!{avatarDefault}'
|
||||
|
||||
const avatarDefaultFormat = e => e.startsWith('d=') ? e : `d=${e}`
|
||||
|
||||
if (predefinedAvatarCdn && predefinedAvatarDefault) {
|
||||
return { avatarCdn: predefinedAvatarCdn, avatarDefault: avatarDefaultFormat(predefinedAvatarDefault) }
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('!{server}/api/v2/conf')
|
||||
const result = await res.json()
|
||||
const { mirror, params, default: defaults } = result.frontend_conf.gravatar
|
||||
const avatarCdn = predefinedAvatarCdn || mirror
|
||||
let avatarDefault = avatarDefaultFormat(predefinedAvatarDefault || params || defaults)
|
||||
return { avatarCdn, avatarDefault}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return { avatarCdn: predefinedAvatarCdn, avatarDefault: avatarDefaultFormat(predefinedAvatarDefault) }
|
||||
}
|
||||
}
|
||||
|
||||
const searchParams = new URLSearchParams({
|
||||
'site_name': '!{site}',
|
||||
'limit': '!{newestCommentsLimit * 2}', // Fetch more comments to filter pending comments
|
||||
})
|
||||
|
||||
const getComment = async (ele) => {
|
||||
try {
|
||||
const res = await fetch(`!{server}/api/v2/stats/latest_comments?${searchParams}`)
|
||||
const result = await res.json()
|
||||
const { avatarCdn, avatarDefault } = await getAvatarValue()
|
||||
const artalk = result.data
|
||||
.filter(e => !e.is_pending) // Filter pending comments
|
||||
.slice(0, !{newestCommentsLimit}) // Limit the number of comments
|
||||
.map(e => {
|
||||
const avatar = avatarCdn && e.email_encrypted ? `${avatarCdn}${e.email_encrypted}?${avatarDefault}` : ''
|
||||
return {
|
||||
'avatar': avatar,
|
||||
'content': changeContent(e.content_marked),
|
||||
'nick': e.nick,
|
||||
'url': e.page_url,
|
||||
'date': e.date,
|
||||
}
|
||||
})
|
||||
btf.saveToLocal.set(keyName, JSON.stringify(artalk), !{theme.aside.card_newest_comments.storage}/(60*24))
|
||||
generateHtml(artalk, ele)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
ele.textContent= "!{_p('aside.card_newest_comments.error')}"
|
||||
}
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
- const { server, site, option } = theme.artalk
|
||||
- const avatarCdn = (option !== null && option.gravatar && option.gravatar.mirror) || ''
|
||||
- const avatarDefault = (option !== null && option.gravatar && (option.gravatar.params || option.gravatar.default)) || ''
|
||||
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.newestComments.ready(() => {
|
||||
const keyName = 'artalk-newest-comments'
|
||||
const { changeContent, run } = window.newestComments
|
||||
|
||||
const getAvatarValue = async () => {
|
||||
const predefinedAvatarCdn = '!{avatarCdn}'
|
||||
const predefinedAvatarDefault = '!{avatarDefault}'
|
||||
|
||||
const avatarDefaultFormat = e => e.startsWith('d=') ? e : `d=${e}`
|
||||
|
||||
if (predefinedAvatarCdn && predefinedAvatarDefault) {
|
||||
return { avatarCdn: predefinedAvatarCdn, avatarDefault: avatarDefaultFormat(predefinedAvatarDefault) }
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('!{server}/api/v2/conf')
|
||||
const result = await res.json()
|
||||
const { mirror, params, default: defaults } = result.frontend_conf.gravatar
|
||||
const avatarCdn = predefinedAvatarCdn || mirror
|
||||
const avatarDefault = avatarDefaultFormat(predefinedAvatarDefault || params || defaults)
|
||||
return { avatarCdn, avatarDefault }
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return { avatarCdn: predefinedAvatarCdn, avatarDefault: avatarDefaultFormat(predefinedAvatarDefault) }
|
||||
}
|
||||
}
|
||||
|
||||
const searchParams = new URLSearchParams({
|
||||
'site_name': '!{site}',
|
||||
'limit': '!{newestCommentsLimit * 2}', // Fetch more comments to filter pending comments
|
||||
})
|
||||
|
||||
const getComment = async () => {
|
||||
const res = await fetch(`!{server}/api/v2/stats/latest_comments?${searchParams}`)
|
||||
const result = await res.json()
|
||||
const { avatarCdn, avatarDefault } = await getAvatarValue()
|
||||
return result.data
|
||||
.filter(e => !e.is_pending) // Filter pending comments
|
||||
.slice(0, !{newestCommentsLimit}) // Limit the number of comments
|
||||
.map(e => {
|
||||
const avatar = avatarCdn && e.email_encrypted ? `${avatarCdn}${e.email_encrypted}?${avatarDefault}` : ''
|
||||
return {
|
||||
'avatar': avatar,
|
||||
'content': changeContent(e.content_marked),
|
||||
'nick': e.nick,
|
||||
'url': e.page_url,
|
||||
'date': e.date,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
|
||||
+97
-61
@@ -1,61 +1,97 @@
|
||||
script.
|
||||
window.newestComments = {
|
||||
changeContent: content => {
|
||||
if (content === '') return content
|
||||
|
||||
content = content.replace(/<img.*?src="(.*?)"?[^\>]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link
|
||||
content = content.replace(/<a[^>]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url
|
||||
content = content.replace(/<pre><code>.*?<\/pre>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
|
||||
content = content.replace(/<code>.*?<\/code>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
|
||||
content = content.replace(/<[^>]+>/g, "") // remove html tag
|
||||
|
||||
if (content.length > 150) {
|
||||
content = content.substring(0, 150) + '...'
|
||||
}
|
||||
return content
|
||||
},
|
||||
|
||||
generateHtml: (array, ele) => {
|
||||
let result = ''
|
||||
|
||||
if (array.length) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
result += '<div class="aside-list-item">'
|
||||
|
||||
if (!{theme.aside.card_newest_comments.avatar} && array[i].avatar) {
|
||||
const imgAttr = '!{theme.lazyload.enable && !theme.lazyload.native ? "data-lazy-src" : "src"}'
|
||||
const lazyloadNative = '!{theme.lazyload.enable && theme.lazyload.native ? "loading=\"lazy\"" : ""}'
|
||||
result += `<a href="${array[i].url}" class="thumbnail"><img ${imgAttr}="${array[i].avatar}" alt="${array[i].nick}" ${lazyloadNative}></a>`
|
||||
}
|
||||
|
||||
result += `<div class="content">
|
||||
<a class="comment" href="${array[i].url}" title="${array[i].content}">${array[i].content}</a>
|
||||
<div class="name"><span>${array[i].nick} / </span><time datetime="${array[i].date}">${btf.diffDate(array[i].date, true)}</time></div>
|
||||
</div></div>`
|
||||
}
|
||||
} else {
|
||||
result += '!{_p("aside.card_newest_comments.zero")}'
|
||||
}
|
||||
|
||||
ele.innerHTML = result
|
||||
window.lazyLoadInstance && window.lazyLoadInstance.update()
|
||||
window.pjax && window.pjax.refresh(ele)
|
||||
},
|
||||
|
||||
newestCommentInit: (name, getComment) => {
|
||||
const $dom = document.querySelector('#card-newest-comments .aside-list')
|
||||
if ($dom) {
|
||||
const data = btf.saveToLocal.get(name)
|
||||
if (data) {
|
||||
newestComments.generateHtml(JSON.parse(data), $dom)
|
||||
} else {
|
||||
getComment($dom)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
run: (name, getComment) => {
|
||||
newestComments.newestCommentInit(name, getComment)
|
||||
btf.addGlobalFn('pjaxComplete', () => newestComments.newestCommentInit(name, getComment), name)
|
||||
}
|
||||
}
|
||||
script.
|
||||
window.newestComments = {
|
||||
ready: fn => {
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', fn, { once: true })
|
||||
} else {
|
||||
fn()
|
||||
}
|
||||
},
|
||||
|
||||
escapeHtml: str => {
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
},
|
||||
|
||||
changeContent: content => {
|
||||
if (!content) return ''
|
||||
|
||||
content = content.replace(/<img[^>]*>/gis, '[!{_p("aside.card_newest_comments.image")}]') // replace image link
|
||||
content = content.replace(/<pre><code>[\s\S]*?<\/pre>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code block
|
||||
content = content.replace(/<a[^>]+?>[\s\S]*?<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url
|
||||
content = content.replace(/<code[^>]*?>[\s\S]*?<\/code>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
|
||||
content = content.replace(/<[^>]+>/g, '') // remove html tag
|
||||
|
||||
if (content.length > 150) {
|
||||
content = Array.from(content).slice(0, 150).join('') + '...'
|
||||
}
|
||||
|
||||
return content
|
||||
},
|
||||
|
||||
generateHtml: (array, ele) => {
|
||||
const { escapeHtml } = window.newestComments
|
||||
let result = ''
|
||||
|
||||
if (array.length) {
|
||||
result = array.map(item => {
|
||||
let html = '<div class="aside-list-item">'
|
||||
|
||||
if (!{theme.aside.card_newest_comments.avatar} && item.avatar) {
|
||||
const imgAttr = '!{theme.lazyload.enable && !theme.lazyload.native ? "data-lazy-src" : "src"}'
|
||||
const lazyloadNative = '!{theme.lazyload.enable && theme.lazyload.native ? "loading=\"lazy\"" : ""}'
|
||||
html += `<a href="${escapeHtml(item.url)}" class="thumbnail"><img ${imgAttr}="${escapeHtml(item.avatar)}" alt="${escapeHtml(item.nick)}" ${lazyloadNative}></a>`
|
||||
}
|
||||
|
||||
html += `<div class="content">
|
||||
<a class="comment" href="${escapeHtml(item.url)}" title="${escapeHtml(item.content)}">${escapeHtml(item.content)}</a>
|
||||
<div class="name"><span>${escapeHtml(item.nick)} / </span><time datetime="${escapeHtml(item.date)}">${btf.diffDate(item.date, true)}</time></div>
|
||||
</div></div>`
|
||||
|
||||
return html
|
||||
}).join('')
|
||||
} else {
|
||||
result += '!{_p("aside.card_newest_comments.zero")}'
|
||||
}
|
||||
|
||||
ele.innerHTML = result
|
||||
window.lazyLoadInstance && window.lazyLoadInstance.update()
|
||||
window.pjax && window.pjax.refresh(ele)
|
||||
},
|
||||
|
||||
fetchAndRender: (keyName, ele, getComment) => {
|
||||
Promise.resolve(getComment(ele)).then(array => {
|
||||
btf.saveToLocal.set(keyName, JSON.stringify(array), !{theme.aside.card_newest_comments.storage}/(60*24))
|
||||
newestComments.generateHtml(array, ele)
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
const data = btf.saveToLocal.get(keyName)
|
||||
if (data) {
|
||||
newestComments.generateHtml(JSON.parse(data), ele)
|
||||
} else {
|
||||
ele.textContent = '!{_p("aside.card_newest_comments.error")}'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
newestCommentInit: (name, getComment) => {
|
||||
const $dom = document.querySelector('#card-newest-comments .aside-list')
|
||||
if ($dom) {
|
||||
const data = btf.saveToLocal.get(name)
|
||||
if (data) {
|
||||
newestComments.generateHtml(JSON.parse(data), $dom)
|
||||
} else {
|
||||
newestComments.fetchAndRender(name, $dom, getComment)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
run: (name, getComment) => {
|
||||
newestComments.newestCommentInit(name, getComment)
|
||||
btf.addGlobalFn('pjaxComplete', () => newestComments.newestCommentInit(name, getComment), name)
|
||||
}
|
||||
}
|
||||
|
||||
+23
-34
@@ -1,34 +1,23 @@
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.addEventListener('load', () => {
|
||||
const keyName = 'disqus-newest-comments'
|
||||
const { changeContent, generateHtml, run } = window.newestComments
|
||||
|
||||
const getComment = ele => {
|
||||
fetch('https://disqus.com/api/3.0/forums/listPosts.json?forum=!{forum}&related=thread&limit=!{newestCommentsLimit}&api_key=!{apiKey}')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const disqusArray = data.response.map(item => {
|
||||
return {
|
||||
'avatar': item.author.avatar.cache,
|
||||
'content': changeContent(item.message),
|
||||
'nick': item.author.name,
|
||||
'url': item.url,
|
||||
'date': item.createdAt
|
||||
}
|
||||
})
|
||||
|
||||
btf.saveToLocal.set(keyName, JSON.stringify(disqusArray), !{theme.aside.card_newest_comments.storage}/(60*24))
|
||||
generateHtml(disqusArray, ele)
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
ele.textContent= "!{_p('aside.card_newest_comments.error')}"
|
||||
})
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
|
||||
|
||||
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.newestComments.ready(() => {
|
||||
const keyName = 'disqus-newest-comments'
|
||||
const { changeContent, run } = window.newestComments
|
||||
|
||||
const getComment = () => {
|
||||
return fetch('https://disqus.com/api/3.0/forums/listPosts.json?forum=!{forum}&related=thread&limit=!{newestCommentsLimit}&api_key=!{apiKey}')
|
||||
.then(response => response.json())
|
||||
.then(data => data.response.map(item => {
|
||||
return {
|
||||
'avatar': item.author.avatar.cache,
|
||||
'content': changeContent(item.message),
|
||||
'nick': item.author.name,
|
||||
'url': item.url,
|
||||
'date': item.createdAt
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
|
||||
+49
-62
@@ -1,62 +1,49 @@
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.addEventListener('load', () => {
|
||||
const keyName = 'github-newest-comments'
|
||||
const { changeContent, generateHtml, run } = window.newestComments
|
||||
|
||||
const findTrueUrl = (array, ele) => {
|
||||
Promise.all(array.map(item =>
|
||||
fetch(item.url).then(resp => resp.json()).then(data => {
|
||||
let urlArray = data.body ? data.body.match(/(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?/ig) : []
|
||||
if (!Array.isArray(urlArray) || urlArray.length === 0) {
|
||||
urlArray = [`${data.html_url}`]
|
||||
}
|
||||
if (data.user.login === 'utterances-bot') {
|
||||
return urlArray.pop()
|
||||
} else {
|
||||
return urlArray.shift()
|
||||
}
|
||||
})
|
||||
)).then(res => {
|
||||
array = array.map((i,index)=> {
|
||||
return {
|
||||
...i,
|
||||
url: res[index]
|
||||
}
|
||||
})
|
||||
|
||||
btf.saveToLocal.set(keyName, JSON.stringify(array), !{theme.aside.card_newest_comments.storage}/(60*24))
|
||||
generateHtml(array, ele)
|
||||
});
|
||||
}
|
||||
|
||||
const getComment = ele => {
|
||||
fetch('https://api.github.com/repos/!{userRepo}/issues/comments?sort=updated&direction=desc&per_page=!{newestCommentsLimit}&page=1',{
|
||||
"headers": {
|
||||
Accept: 'application/vnd.github.v3.html+json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const githubArray = data.map(item => {
|
||||
return {
|
||||
'avatar': item.user.avatar_url,
|
||||
'content': changeContent(item.body_html || item.body),
|
||||
'nick': item.user.login,
|
||||
'url': item.issue_url,
|
||||
'date': item.updated_at
|
||||
}
|
||||
})
|
||||
findTrueUrl(githubArray, ele)
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
ele.textContent= "!{_p('aside.card_newest_comments.error')}"
|
||||
})
|
||||
}
|
||||
run(keyName, getComment)
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.newestComments.ready(() => {
|
||||
const keyName = 'github-newest-comments'
|
||||
const { changeContent, run } = window.newestComments
|
||||
|
||||
const findTrueUrl = array => {
|
||||
return Promise.all(array.map(item =>
|
||||
fetch(item.url)
|
||||
.then(resp => resp.json())
|
||||
.then(data => {
|
||||
let urlArray = data.body ? data.body.match(/(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?/ig) : []
|
||||
if (!Array.isArray(urlArray) || urlArray.length === 0) {
|
||||
urlArray = [item.html_url]
|
||||
}
|
||||
const isBot = data.user && data.user.login === 'utterances-bot'
|
||||
return isBot ? urlArray.pop() : urlArray.shift()
|
||||
})
|
||||
.catch(() => item.html_url)
|
||||
)).then(res => array.map((item, index) => {
|
||||
return {
|
||||
...item,
|
||||
url: res[index]
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
const getComment = () => {
|
||||
return fetch('https://api.github.com/repos/!{userRepo}/issues/comments?sort=updated&direction=desc&per_page=!{newestCommentsLimit}&page=1', {
|
||||
"headers": {
|
||||
Accept: 'application/vnd.github.v3.html+json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => data.map(item => {
|
||||
return {
|
||||
'avatar': item.user.avatar_url,
|
||||
'content': changeContent(item.body_html || item.body),
|
||||
'nick': item.user.login,
|
||||
'url': item.html_url,
|
||||
'date': item.updated_at
|
||||
}
|
||||
}))
|
||||
.then(findTrueUrl)
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
|
||||
+24
-31
@@ -1,31 +1,24 @@
|
||||
- const { host, siteId } = theme.remark42
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.addEventListener('load', () => {
|
||||
const keyName = 'remark42-newest-comments'
|
||||
const { changeContent, generateHtml, run } = window.newestComments
|
||||
|
||||
const getComment = ele => {
|
||||
fetch('!{host}/api/v1/last/!{newestCommentsLimit}?site=!{siteId}')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const remark42 = data.map(e => {
|
||||
return {
|
||||
'avatar': e.user.picture,
|
||||
'content': changeContent(e.text),
|
||||
'nick': e.user.name,
|
||||
'url': e.locator.url,
|
||||
'date': e.time,
|
||||
}
|
||||
})
|
||||
btf.saveToLocal.set(keyName, JSON.stringify(remark42), !{theme.aside.card_newest_comments.storage}/(60*24))
|
||||
generateHtml(remark42, ele)
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
ele.textContent= "!{_p('aside.card_newest_comments.error')}"
|
||||
})
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
- const { host, siteId } = theme.remark42
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.newestComments.ready(() => {
|
||||
const keyName = 'remark42-newest-comments'
|
||||
const { changeContent, run } = window.newestComments
|
||||
|
||||
const getComment = () => {
|
||||
return fetch('!{host}/api/v1/last/!{newestCommentsLimit}?site=!{siteId}')
|
||||
.then(response => response.json())
|
||||
.then(data => data.map(e => {
|
||||
return {
|
||||
'avatar': e.user.picture,
|
||||
'content': changeContent(e.text),
|
||||
'nick': e.user.name,
|
||||
'url': e.locator.url,
|
||||
'date': e.time,
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
|
||||
+32
-45
@@ -1,45 +1,32 @@
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.addEventListener('load', () => {
|
||||
const keyName = 'twikoo-newest-comments'
|
||||
const { changeContent, generateHtml, run } = window.newestComments
|
||||
|
||||
const getComment = ele => {
|
||||
const runTwikoo = () => {
|
||||
twikoo.getRecentComments({
|
||||
envId: '!{theme.twikoo.envId}',
|
||||
region: '!{theme.twikoo.region}',
|
||||
pageSize: !{newestCommentsLimit},
|
||||
includeReply: true
|
||||
}).then(res => {
|
||||
const twikooArray = res.map(e => {
|
||||
return {
|
||||
'content': changeContent(e.comment),
|
||||
'avatar': e.avatar,
|
||||
'nick': e.nick,
|
||||
'url': e.url + '#' + e.id,
|
||||
'date': new Date(e.created).toISOString()
|
||||
}
|
||||
})
|
||||
|
||||
btf.saveToLocal.set(keyName, JSON.stringify(twikooArray), !{theme.aside.card_newest_comments.storage}/(60*24))
|
||||
generateHtml(twikooArray, ele)
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
ele.textContent= "!{_p('aside.card_newest_comments.error')}"
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof twikoo === 'object') {
|
||||
runTwikoo()
|
||||
} else {
|
||||
btf.getScript('!{url_for(theme.asset.twikoo)}').then(runTwikoo)
|
||||
}
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
|
||||
|
||||
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.newestComments.ready(() => {
|
||||
const keyName = 'twikoo-newest-comments'
|
||||
const { changeContent, run } = window.newestComments
|
||||
|
||||
const getComment = async () => {
|
||||
const runTwikoo = () => twikoo.getRecentComments({
|
||||
envId: '!{theme.twikoo.envId}',
|
||||
region: '!{theme.twikoo.region}',
|
||||
pageSize: !{newestCommentsLimit},
|
||||
includeReply: true
|
||||
}).then(res => res.map(e => {
|
||||
return {
|
||||
'content': changeContent(e.comment),
|
||||
'avatar': e.avatar,
|
||||
'nick': e.nick,
|
||||
'url': (e.url || '') + '#' + e.id,
|
||||
'date': new Date(e.created).toISOString()
|
||||
}
|
||||
}))
|
||||
|
||||
if (typeof twikoo === 'undefined') {
|
||||
await btf.getScript('!{url_for(theme.asset.twikoo)}')
|
||||
}
|
||||
|
||||
return runTwikoo()
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
|
||||
+44
-51
@@ -1,51 +1,44 @@
|
||||
- let default_avatar = theme.valine.avatar
|
||||
|
||||
script(src=url_for(theme.asset.blueimp_md5))
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.addEventListener('load', () => {
|
||||
const keyName = 'valine-newest-comments'
|
||||
const { changeContent, generateHtml, run } = window.newestComments
|
||||
|
||||
const getIcon = (icon, mail) => {
|
||||
if (icon) return icon
|
||||
let defaultIcon = '!{ default_avatar ? `?d=${default_avatar}` : ''}'
|
||||
let iconUrl = `https://gravatar.loli.net/avatar/${md5(mail.toLowerCase()) + defaultIcon}`
|
||||
return iconUrl
|
||||
}
|
||||
|
||||
const getComment = ele => {
|
||||
const serverURL = '!{theme.valine.serverURLs || `https://${theme.valine.appId.substring(0,8)}.api.lncldglobal.com` }'
|
||||
|
||||
var settings = {
|
||||
"method": "GET",
|
||||
"headers": {
|
||||
"X-LC-Id": '!{theme.valine.appId}',
|
||||
"X-LC-Key": '!{theme.valine.appKey}',
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
}
|
||||
|
||||
fetch(`${serverURL}/1.1/classes/Comment?limit=!{newestCommentsLimit}&order=-createdAt`,settings)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const valineArray = data.results.map(e => {
|
||||
return {
|
||||
'avatar': getIcon(e.QQAvatar, e.mail),
|
||||
'content': changeContent(e.comment),
|
||||
'nick': e.nick,
|
||||
'url': e.url + '#' + e.objectId,
|
||||
'date': e.updatedAt,
|
||||
}
|
||||
})
|
||||
btf.saveToLocal.set(keyName, JSON.stringify(valineArray), !{theme.aside.card_newest_comments.storage}/(60*24))
|
||||
generateHtml(valineArray, ele)
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
ele.textContent= "!{_p('aside.card_newest_comments.error')}"
|
||||
})
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
- let default_avatar = theme.valine.avatar
|
||||
|
||||
script(src=url_for(theme.asset.blueimp_md5))
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.newestComments.ready(() => {
|
||||
const keyName = 'valine-newest-comments'
|
||||
const { changeContent, run } = window.newestComments
|
||||
|
||||
const getIcon = (icon, mail) => {
|
||||
if (icon) return icon
|
||||
let defaultIcon = '!{ default_avatar ? `?d=${default_avatar}` : ''}'
|
||||
let iconUrl = `https://gravatar.loli.net/avatar/${md5(mail.toLowerCase()) + defaultIcon}`
|
||||
return iconUrl
|
||||
}
|
||||
|
||||
const getComment = async () => {
|
||||
const serverURL = '!{theme.valine.serverURLs || `https://${theme.valine.appId.substring(0,8)}.api.lncldglobal.com` }'
|
||||
|
||||
const settings = {
|
||||
"method": "GET",
|
||||
"headers": {
|
||||
"X-LC-Id": '!{theme.valine.appId}',
|
||||
"X-LC-Key": '!{theme.valine.appKey}',
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
}
|
||||
|
||||
const res = await fetch(`${serverURL}/1.1/classes/Comment?limit=!{newestCommentsLimit}&order=-createdAt`, settings)
|
||||
const data = await res.json()
|
||||
return data.results.map(e => {
|
||||
return {
|
||||
'avatar': getIcon(e.QQAvatar, e.mail),
|
||||
'content': changeContent(e.comment),
|
||||
'nick': e.nick,
|
||||
'url': (e.url || '') + '#' + e.objectId,
|
||||
'date': e.updatedAt,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
|
||||
+25
-32
@@ -1,32 +1,25 @@
|
||||
- const serverURL = theme.waline.serverURL.replace(/\/$/, '')
|
||||
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.addEventListener('load', () => {
|
||||
const keyName = 'waline-newest-comments'
|
||||
const { changeContent, generateHtml, run } = window.newestComments
|
||||
|
||||
const getComment = async (ele) => {
|
||||
try {
|
||||
const res = await fetch('!{serverURL}/api/comment?type=recent&count=!{newestCommentsLimit}')
|
||||
const result = await res.json()
|
||||
const walineArray = result.data.map(e => {
|
||||
return {
|
||||
'content': changeContent(e.comment),
|
||||
'avatar': e.avatar,
|
||||
'nick': e.nick,
|
||||
'url': e.url + '#' + e.objectId,
|
||||
'date': e.time || e.insertedAt
|
||||
}
|
||||
})
|
||||
btf.saveToLocal.set(keyName, JSON.stringify(walineArray), !{theme.aside.card_newest_comments.storage}/(60*24))
|
||||
generateHtml(walineArray, ele)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
ele.textContent= "!{_p('aside.card_newest_comments.error')}"
|
||||
}
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
- const serverURL = theme.waline.serverURL ? theme.waline.serverURL.replace(/\/$/, '') : ''
|
||||
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.newestComments.ready(() => {
|
||||
const keyName = 'waline-newest-comments'
|
||||
const { changeContent, run } = window.newestComments
|
||||
|
||||
const getComment = async () => {
|
||||
const res = await fetch('!{serverURL}/api/comment?type=recent&count=!{newestCommentsLimit}')
|
||||
const result = await res.json()
|
||||
return result.data.map(e => {
|
||||
return {
|
||||
'content': changeContent(e.comment),
|
||||
'avatar': e.avatar,
|
||||
'nick': e.nick,
|
||||
'url': (e.url || '') + '#' + e.objectId,
|
||||
'date': e.time || e.insertedAt
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
run(keyName, getComment)
|
||||
})
|
||||
|
||||
+120
-113
@@ -1,113 +1,120 @@
|
||||
- const { effect, source, sub, typed_option } = theme.subtitle
|
||||
- let subContent = typeof sub === 'string' ? [sub] : (sub || new Array())
|
||||
|
||||
script.
|
||||
window.typedJSFn = {
|
||||
init: str => {
|
||||
window.typed = new Typed('#subtitle', Object.assign({
|
||||
strings: str,
|
||||
startDelay: 300,
|
||||
typeSpeed: 150,
|
||||
loop: true,
|
||||
backSpeed: 50,
|
||||
}, !{JSON.stringify(typed_option)}))
|
||||
},
|
||||
run: subtitleType => {
|
||||
if (!{effect}) {
|
||||
if (typeof Typed === 'function') {
|
||||
subtitleType()
|
||||
} else {
|
||||
btf.getScript('!{url_for(theme.asset.typed)}').then(subtitleType)
|
||||
}
|
||||
} else {
|
||||
subtitleType()
|
||||
}
|
||||
},
|
||||
processSubtitle: (content, extraContents = []) => {
|
||||
if (!{effect}) {
|
||||
const sub = !{JSON.stringify(subContent)}.slice()
|
||||
|
||||
if (extraContents.length > 0) {
|
||||
sub.unshift(...extraContents)
|
||||
}
|
||||
|
||||
if (typeof content === 'string') {
|
||||
sub.unshift(content)
|
||||
} else if (Array.isArray(content)) {
|
||||
sub.unshift(...content)
|
||||
}
|
||||
|
||||
sub.length > 0 && typedJSFn.init(sub)
|
||||
} else {
|
||||
document.getElementById('subtitle').textContent = typeof content === 'string' ? content :
|
||||
(Array.isArray(content) && content.length > 0 ? content[0] : '')
|
||||
}
|
||||
}
|
||||
}
|
||||
btf.addGlobalFn('pjaxSendOnce', () => { typed && typed.destroy() }, 'typedDestroy')
|
||||
|
||||
case source
|
||||
when 1
|
||||
script.
|
||||
function subtitleType () {
|
||||
fetch('https://v1.hitokoto.cn')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const from = data.from ? '出自 ' + data.from : ''
|
||||
typedJSFn.processSubtitle(data.hitokoto, from ? [from] : [])
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Failed to get the Hitokoto API:', err)
|
||||
typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
|
||||
})
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
when 2
|
||||
script.
|
||||
function subtitleType () {
|
||||
fetch('https://v.api.aa1.cn/api/yiyan/index.php')
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
const reg = /<p>(.*?)<\/p>/g
|
||||
const result = reg.exec(data)
|
||||
if (result && result[1]) {
|
||||
typedJSFn.processSubtitle(result[1])
|
||||
} else {
|
||||
throw new Error('Failed to parse the return value of the Yiyan API')
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Failed to get the Yiyan API:', err)
|
||||
typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
|
||||
})
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
when 3
|
||||
script.
|
||||
function subtitleType () {
|
||||
btf.getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js')
|
||||
.then(() => {
|
||||
jinrishici.load(result => {
|
||||
if (result && result.data && result.data.content) {
|
||||
typedJSFn.processSubtitle(result.data.content)
|
||||
} else {
|
||||
throw new Error('Failed to parse the return value of Jinrishici API')
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Failed to get the Jinrishici API:', err)
|
||||
typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
|
||||
})
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
default
|
||||
if subContent.length > 0
|
||||
script.
|
||||
function subtitleType () {
|
||||
typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
- const { effect, source, sub, typed_option } = theme.subtitle
|
||||
- let subContent = typeof sub === 'string' ? [sub] : (sub || new Array())
|
||||
|
||||
script.
|
||||
window.typedJSFn = {
|
||||
_seq: 0,
|
||||
init: str => {
|
||||
window.typed = new Typed('#subtitle', Object.assign({
|
||||
strings: str,
|
||||
startDelay: 300,
|
||||
typeSpeed: 150,
|
||||
loop: true,
|
||||
backSpeed: 50,
|
||||
}, !{JSON.stringify(typed_option)}))
|
||||
},
|
||||
run: subtitleType => {
|
||||
const seq = ++window.typedJSFn._seq
|
||||
const invoke = () => {
|
||||
if (seq === window.typedJSFn._seq) subtitleType()
|
||||
}
|
||||
|
||||
if (!{effect}) {
|
||||
if (typeof Typed === 'function') invoke()
|
||||
else btf.getScript('!{url_for(theme.asset.typed)}').then(invoke)
|
||||
} else {
|
||||
invoke()
|
||||
}
|
||||
},
|
||||
fetchSubtitle: (fetcher, parser) => {
|
||||
const seq = window.typedJSFn._seq
|
||||
Promise.resolve()
|
||||
.then(fetcher)
|
||||
.then(parser)
|
||||
.then(({ content, extra = [] }) => {
|
||||
if (seq !== window.typedJSFn._seq) return
|
||||
typedJSFn.processSubtitle(content, extra)
|
||||
})
|
||||
.catch(err => {
|
||||
if (seq !== window.typedJSFn._seq) return
|
||||
console.error('Failed to get the subtitle API:', err)
|
||||
typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
|
||||
})
|
||||
},
|
||||
processSubtitle: (content, extraContents = []) => {
|
||||
if (!{effect}) {
|
||||
const sub = !{JSON.stringify(subContent)}.slice()
|
||||
|
||||
if (extraContents.length > 0) {
|
||||
sub.unshift(...extraContents)
|
||||
}
|
||||
|
||||
if (typeof content === 'string') {
|
||||
sub.unshift(content)
|
||||
} else if (Array.isArray(content)) {
|
||||
sub.unshift(...content)
|
||||
}
|
||||
|
||||
sub.length > 0 && typedJSFn.init(sub)
|
||||
} else {
|
||||
document.getElementById('subtitle').textContent = typeof content === 'string' ? content :
|
||||
(Array.isArray(content) && content.length > 0 ? content[0] : '')
|
||||
}
|
||||
}
|
||||
}
|
||||
btf.addGlobalFn('pjaxSendOnce', () => {
|
||||
window.typedJSFn._seq++
|
||||
typed && typed.destroy()
|
||||
window.typed = null
|
||||
}, 'typedDestroy')
|
||||
|
||||
case source
|
||||
when 1
|
||||
script.
|
||||
function subtitleType () {
|
||||
typedJSFn.fetchSubtitle(
|
||||
() => fetch('https://v1.hitokoto.cn').then(response => response.json()),
|
||||
data => ({ content: data.hitokoto, extra: data.from ? ['出自 ' + data.from] : [] })
|
||||
)
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
when 2
|
||||
script.
|
||||
function subtitleType () {
|
||||
typedJSFn.fetchSubtitle(
|
||||
() => fetch('https://v.api.aa1.cn/api/yiyan/index.php').then(response => response.text()),
|
||||
data => {
|
||||
const reg = /<p>(.*?)<\/p>/g
|
||||
const result = reg.exec(data)
|
||||
if (result && result[1]) return { content: result[1] }
|
||||
throw new Error('Failed to parse the return value of the Yiyan API')
|
||||
}
|
||||
)
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
when 3
|
||||
script.
|
||||
function subtitleType () {
|
||||
typedJSFn.fetchSubtitle(
|
||||
() => btf.getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js').then(() =>
|
||||
new Promise((resolve, reject) => {
|
||||
jinrishici.load(result => {
|
||||
if (result && result.data && result.data.content) resolve(result.data.content)
|
||||
else reject(new Error('Failed to parse the return value of Jinrishici API'))
|
||||
})
|
||||
})
|
||||
),
|
||||
content => ({ content })
|
||||
)
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
default
|
||||
if subContent.length > 0
|
||||
script.
|
||||
function subtitleType () {
|
||||
typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
+32
-38
@@ -30,29 +30,25 @@ script.
|
||||
|
||||
const extractValue = stat => (stat && typeof stat.value !== 'undefined') ? stat.value : stat
|
||||
|
||||
const getData = async (isPost) => {
|
||||
try {
|
||||
const now = Date.now()
|
||||
const pathQuery = isPost ? `&url=${window.location.pathname}&path=${window.location.pathname}` : ''
|
||||
const headers = {
|
||||
'Accept': 'application/json',
|
||||
[!{isServerURL} ? 'Authorization' : 'x-umami-api-key']: !{isServerURL} ? `Bearer ${config.token}` : config.token
|
||||
}
|
||||
|
||||
const res = await fetch(`!{apiUrl}/websites/!{website_id}/stats?startAt=0000000000&endAt=${now}${pathQuery}`, {
|
||||
method: 'GET',
|
||||
headers
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP error! status: ${res.status}`)
|
||||
}
|
||||
|
||||
return await res.json()
|
||||
} catch (error) {
|
||||
console.error('Umami Analytics: Failed to fetch data', error)
|
||||
throw error
|
||||
const getData = async (isPost, path = window.location.pathname) => {
|
||||
const now = Date.now()
|
||||
const pathQuery = isPost ? `&url=${path}&path=${path}` : ''
|
||||
const headers = {
|
||||
'Accept': 'application/json',
|
||||
[!{isServerURL} ? 'Authorization' : 'x-umami-api-key']: !{isServerURL} ? `Bearer ${config.token}` : config.token
|
||||
}
|
||||
|
||||
const res = await fetch(`!{apiUrl}/websites/!{website_id}/stats?startAt=0000000000&endAt=${now}${pathQuery}`, {
|
||||
method: 'GET',
|
||||
headers,
|
||||
cache: 'no-store'
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP error! status: ${res.status}`)
|
||||
}
|
||||
|
||||
return await res.json()
|
||||
}
|
||||
|
||||
const insertData = async () => {
|
||||
@@ -63,7 +59,8 @@ script.
|
||||
tasks.push((async () => {
|
||||
const pagePV = document.getElementById('umamiPV')
|
||||
if (pagePV) {
|
||||
const data = await getData(true)
|
||||
const path = pagePV.dataset.path || window.location.pathname
|
||||
const data = await getData(true, path)
|
||||
if (data && data.pageviews) {
|
||||
pagePV.textContent = extractValue(data.pageviews)
|
||||
} else {
|
||||
@@ -73,26 +70,23 @@ script.
|
||||
})())
|
||||
}
|
||||
|
||||
if (config.site_uv || config.site_pv) {
|
||||
const siteUV = config.site_uv ? document.getElementById('umami-site-uv') : null
|
||||
const sitePV = config.site_pv ? document.getElementById('umami-site-pv') : null
|
||||
|
||||
if (siteUV || sitePV) {
|
||||
tasks.push((async () => {
|
||||
const data = await getData(false)
|
||||
|
||||
if (config.site_uv) {
|
||||
const siteUV = document.getElementById('umami-site-uv')
|
||||
if (siteUV && data && data.visitors) {
|
||||
siteUV.textContent = extractValue(data.visitors)
|
||||
} else if (siteUV) {
|
||||
console.warn('Umami Analytics: Invalid site UV data received')
|
||||
}
|
||||
if (siteUV && data && data.visitors) {
|
||||
siteUV.textContent = extractValue(data.visitors)
|
||||
} else if (siteUV) {
|
||||
console.warn('Umami Analytics: Invalid site UV data received')
|
||||
}
|
||||
|
||||
if (config.site_pv) {
|
||||
const sitePV = document.getElementById('umami-site-pv')
|
||||
if (sitePV && data && data.pageviews) {
|
||||
sitePV.textContent = extractValue(data.pageviews)
|
||||
} else if (sitePV) {
|
||||
console.warn('Umami Analytics: Invalid site PV data received')
|
||||
}
|
||||
if (sitePV && data && data.pageviews) {
|
||||
sitePV.textContent = extractValue(data.pageviews)
|
||||
} else if (sitePV) {
|
||||
console.warn('Umami Analytics: Invalid site PV data received')
|
||||
}
|
||||
})())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user