131 lines
3.3 KiB
JavaScript
131 lines
3.3 KiB
JavaScript
const { request, downloadFile, readFile } = require('./wx-promisify')
|
|
|
|
const localFonts = require('../../assets/fonts')
|
|
|
|
const fontBufferCache = new Map()
|
|
const MAX_FONT_CACHE = 4
|
|
|
|
function normalizePath(path, baseUrl) {
|
|
if (!path) {
|
|
return ''
|
|
}
|
|
if (/^https?:\/\//i.test(path)) {
|
|
return path
|
|
}
|
|
if (path.startsWith('//')) {
|
|
return `https:${path}`
|
|
}
|
|
if (path.startsWith('/')) {
|
|
return `${baseUrl}${path}`
|
|
}
|
|
return `${baseUrl}/${path}`
|
|
}
|
|
|
|
function normalizeFontItem(item, baseUrl) {
|
|
const path = item.path || item.url || ''
|
|
const normalizedPath = normalizePath(path, baseUrl)
|
|
const filename = item.filename || normalizedPath.split('/').pop() || `${item.name || 'font'}.ttf`
|
|
return {
|
|
id: item.id || `${item.category || '默认'}/${item.name || filename}`,
|
|
name: item.name || filename.replace(/\.[^.]+$/, ''),
|
|
category: item.category || '默认',
|
|
filename,
|
|
path,
|
|
url: normalizedPath,
|
|
}
|
|
}
|
|
|
|
function normalizeManifest(fonts, baseUrl) {
|
|
if (!Array.isArray(fonts)) {
|
|
return []
|
|
}
|
|
return fonts
|
|
.map((item) => normalizeFontItem(item, baseUrl))
|
|
.filter((item) => item.url)
|
|
}
|
|
|
|
async function loadFontsManifest(options = {}) {
|
|
const app = getApp()
|
|
const manifestUrl = options.manifestUrl || app.globalData.fontsManifestUrl
|
|
const baseUrl = options.baseUrl || app.globalData.fontsBaseUrl
|
|
|
|
if (Array.isArray(app.globalData.fonts) && app.globalData.fonts.length > 0) {
|
|
return app.globalData.fonts
|
|
}
|
|
|
|
try {
|
|
const response = await request({
|
|
url: manifestUrl,
|
|
method: 'GET',
|
|
timeout: 10000,
|
|
})
|
|
|
|
if (response.statusCode < 200 || response.statusCode >= 300) {
|
|
throw new Error(`获取字体清单失败,状态码: ${response.statusCode}`)
|
|
}
|
|
|
|
const fonts = normalizeManifest(response.data, baseUrl)
|
|
if (!fonts.length) {
|
|
throw new Error('字体清单为空')
|
|
}
|
|
|
|
app.globalData.fonts = fonts
|
|
return fonts
|
|
} catch (error) {
|
|
console.warn('远程字体清单加载失败,回退到本地清单:', error)
|
|
const fallbackFonts = normalizeManifest(localFonts, baseUrl)
|
|
app.globalData.fonts = fallbackFonts
|
|
return fallbackFonts
|
|
}
|
|
}
|
|
|
|
function setLruCache(key, value) {
|
|
if (fontBufferCache.has(key)) {
|
|
fontBufferCache.delete(key)
|
|
}
|
|
fontBufferCache.set(key, value)
|
|
|
|
while (fontBufferCache.size > MAX_FONT_CACHE) {
|
|
const firstKey = fontBufferCache.keys().next().value
|
|
fontBufferCache.delete(firstKey)
|
|
}
|
|
}
|
|
|
|
async function loadFontBuffer(fontItem) {
|
|
const cacheKey = fontItem.id
|
|
if (fontBufferCache.has(cacheKey)) {
|
|
const cached = fontBufferCache.get(cacheKey)
|
|
setLruCache(cacheKey, cached)
|
|
return cached
|
|
}
|
|
|
|
if (!fontItem.url) {
|
|
throw new Error('字体地址为空')
|
|
}
|
|
|
|
const downloadRes = await downloadFile({ url: fontItem.url })
|
|
if (downloadRes.statusCode < 200 || downloadRes.statusCode >= 300) {
|
|
throw new Error(`字体下载失败,状态码: ${downloadRes.statusCode}`)
|
|
}
|
|
|
|
const readRes = await readFile(downloadRes.tempFilePath)
|
|
const result = {
|
|
tempFilePath: downloadRes.tempFilePath,
|
|
buffer: readRes.data,
|
|
}
|
|
|
|
setLruCache(cacheKey, result)
|
|
return result
|
|
}
|
|
|
|
function listCategories(fonts) {
|
|
const set = new Set(fonts.map((font) => font.category || '默认'))
|
|
return ['全部', '收藏', ...Array.from(set)]
|
|
}
|
|
|
|
module.exports = {
|
|
loadFontsManifest,
|
|
loadFontBuffer,
|
|
listCategories,
|
|
}
|