mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-02 20:26:36 +08:00
优化
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import { isRenderableCover } from './coverUrl.ts'
|
||||
|
||||
function check(name: string, condition: boolean) {
|
||||
if (!condition) throw new Error(`coverUrl: ${name}`)
|
||||
}
|
||||
|
||||
check('empty is not renderable', !isRenderableCover(''))
|
||||
check('null is not renderable', !isRenderableCover(null))
|
||||
check('undefined is not renderable', !isRenderableCover(undefined))
|
||||
check('blank string is not renderable', !isRenderableCover(' '))
|
||||
check('https cover is renderable', isRenderableCover('https://img.example.com/a.jpg'))
|
||||
check('http cover is renderable', isRenderableCover('http://img.example.com/a.jpg'))
|
||||
check('leading spaces are tolerated', isRenderableCover(' https://img.example.com/a.jpg '))
|
||||
check('uppercase scheme is renderable', isRenderableCover('HTTPS://img.example.com/a.jpg'))
|
||||
check('inline image data uri is renderable', isRenderableCover('data:image/png;base64,iVBORw0KGgo='))
|
||||
check('local asset path is renderable', isRenderableCover('/api/reader/local/asset?b=1&p=2&s=3'))
|
||||
check('protocol relative cover is renderable', isRenderableCover('//img.example.com/a.jpg'))
|
||||
// 聚合书源把搜索参数信封当封面返回的真实取值
|
||||
check(
|
||||
'search envelope data uri is not renderable',
|
||||
!isRenderableCover(
|
||||
'data:;base64,eyJrZXkiOiLlhajnkIPpq5jmraYiLCJ0YWIiOiLlsI/or7QiLCJzb3VyY2VzS2V5Ijoi5YWo6YOoIiwicGFnZSI6MSwiZGlzYWJsZWRfc291cmNlcyI6IjAifQ==',
|
||||
),
|
||||
)
|
||||
check('text data uri is not renderable', !isRenderableCover('data:text/plain;base64,aGk='))
|
||||
check('source name is not renderable', !isRenderableCover('光遇聚合'))
|
||||
check('bare relative path is not renderable', !isRenderableCover('files/a.jpg'))
|
||||
check('javascript url is not renderable', !isRenderableCover('javascript:alert(1)'))
|
||||
|
||||
console.log('coverUrl.test.ts ok')
|
||||
@@ -0,0 +1,20 @@
|
||||
// 判断一个封面地址能否真正被浏览器渲染成图片。
|
||||
//
|
||||
// 书源在「这本书没有封面」时不一定返回空值:聚合类书源(如「光遇聚合」)的
|
||||
// 搜索请求地址本身是 data:;base64,... 参数信封,规则取值为空时会把它当地址
|
||||
// 兜底返回,于是 cover_url 变成一串 data: 文本。这类地址 media type 为空,
|
||||
// 浏览器按 text/plain 解码,必然显示破图。
|
||||
export function isRenderableCover(url?: string | null): boolean {
|
||||
const value = (url ?? '').trim()
|
||||
if (!value) return false
|
||||
|
||||
const lower = value.toLowerCase()
|
||||
if (lower.startsWith('http://') || lower.startsWith('https://')) return true
|
||||
if (lower.startsWith('data:image/')) return true
|
||||
// 应用自身生成的相对地址(本地书封面 /api/reader/local/asset?...)以及
|
||||
// //host/path 这种协议相对地址。书源给出的相对地址同样落在这里,加载失败
|
||||
// 时由 <img> 的 onError 兜底回退成占位图。
|
||||
if (value.startsWith('/')) return true
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { splitKindTags } from './kindTags.ts'
|
||||
|
||||
function check(name: string, condition: boolean) {
|
||||
if (!condition) throw new Error(`kindTags: ${name}`)
|
||||
}
|
||||
|
||||
const eq = (a: string[], b: string[]) => a.length === b.length && a.every((v, i) => v === b[i])
|
||||
|
||||
check('空值返回空数组', splitKindTags(undefined).length === 0)
|
||||
check('空串返回空数组', splitKindTags('').length === 0)
|
||||
check('全空段返回空数组', splitKindTags(',,,').length === 0)
|
||||
// 聚合源的真实取值:只有状态/分类有值,其余为空
|
||||
check('丢掉空段', eq(splitKindTags('已完结,,,'), ['已完结']))
|
||||
check('保留有效段顺序', eq(splitKindTags('已完结,玄幻,'), ['已完结', '玄幻']))
|
||||
check('去掉段内空白', eq(splitKindTags(' 连载 , 都市 '), ['连载', '都市']))
|
||||
check('无逗号时整体作一段', eq(splitKindTags('有声小说'), ['有声小说']))
|
||||
// 更新时间段也是合法标签(legado 同样展示)
|
||||
check('保留更新时间段', eq(splitKindTags(',,有声小说,2018-12-11 22:01:22'), ['有声小说', '2018-12-11 22:01:22']))
|
||||
|
||||
console.log('kindTags.test.ts ok')
|
||||
@@ -0,0 +1,11 @@
|
||||
// 书源的 kind 规则普遍是逗号拼接的多段,例如聚合源的
|
||||
// `{{$.status}},{{$.score}},{{$.tags}},{{$.last_chapter_update_time}}`。
|
||||
//
|
||||
// 取不到值的段会是空串(如 "已完结,,,"),直接展示会变成 ",,有声小说," 这种噪音,
|
||||
// 所以按逗号切分后丢掉空段,只保留有效标签(legado 也是按段展示)。
|
||||
export function splitKindTags(kind?: string | null): string[] {
|
||||
return (kind ?? '')
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
Reference in New Issue
Block a user