fix: anima-extract 支援 wiki URL 與自然語言參數,並依序逐章處理
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
1ce475024d
commit
74a5d4949c
@@ -228,3 +228,50 @@ export const parseRemote = (url: string): { host: string; repo: string } | undef
|
||||
const m = url.trim().match(/^(?:https?:\/\/(?:[^@/]+@)?|ssh:\/\/(?:[^@/]+@)?|[^@/]+@)([^/:]+)(?::\d+)?[/:](.+?)(?:\.git)?$/)
|
||||
return m ? { host: m[1]!, repo: m[2]! } : undefined
|
||||
}
|
||||
|
||||
export type WikiSource = { kind: 'list' | 'page'; url: string; origin: string; base: string; page?: string }
|
||||
|
||||
// 從自然語言參數中取出第一個 URL;Gitea wiki 頁面清單(?action=_pages 或 /wiki 首頁)視為整本逐章,單頁網址視為一章。
|
||||
export const parseWikiSource = (args: string): WikiSource | undefined => {
|
||||
const raw = /https?:\/\/[^\s<>"'「」『』()()]+/.exec(args)?.[0]?.replace(/[,。、;,.;:!?!?]+$/, '')
|
||||
if (!raw) return undefined
|
||||
let u: URL
|
||||
try {
|
||||
u = new URL(raw)
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
const m = /^(.*\/wiki)(?:\/(.*))?$/.exec(u.pathname.replace(/\/+$/, ''))
|
||||
if (!m) return { kind: 'page', url: raw, origin: u.origin, base: raw }
|
||||
const base = `${u.origin}${m[1]}`
|
||||
const page = m[2] && !m[2].startsWith('raw/') && m[2] !== '_pages' ? decodeURIComponent(m[2]) : undefined
|
||||
if (u.searchParams.get('action') === '_pages' || !page) return { kind: 'list', url: raw, origin: u.origin, base }
|
||||
return { kind: 'page', url: raw, origin: u.origin, base, page }
|
||||
}
|
||||
|
||||
const SKIP_PAGES = new Set(['home', 'sidebar', 'footer', '_sidebar', '_footer', '_pages', 'new'])
|
||||
|
||||
// 解析 Gitea wiki 頁面清單 HTML,依章節名稱自然排序(第2章 < 第10章)。
|
||||
export const parseWikiPages = (html: string, base: string): string[] => {
|
||||
const path = new URL(base).pathname
|
||||
const names = new Set<string>()
|
||||
for (const m of html.matchAll(/href="([^"#]+)"/g)) {
|
||||
let p: string
|
||||
try {
|
||||
p = new URL(m[1]!.replace(/&/g, '&'), base).pathname
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
if (!p.startsWith(`${path}/`)) continue
|
||||
const rest = p.slice(path.length + 1)
|
||||
if (!rest || rest.includes('/')) continue
|
||||
let name: string
|
||||
try {
|
||||
name = decodeURIComponent(rest)
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
if (!SKIP_PAGES.has(name.toLowerCase())) names.add(name)
|
||||
}
|
||||
return [...names].sort((a, b) => a.localeCompare(b, 'zh-Hant', { numeric: true }))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user