mirror of
https://github.com/naiyQAQ/fanqie-assistant.git
synced 2026-10-21 10:24:47 +00:00
initial commit
This commit is contained in:
commit
5626fb6558
25 files changed
+3948
No files matched your search
@@ -0,0 +1,192 @@
|
||||
import { type HookConfig } from '../config'
|
||||
import { getChapter } from '../api/content'
|
||||
import { getBookInfoAndCatalog } from '../api/book'
|
||||
// import defaultcss from '../assets/default.css?raw';
|
||||
import { cloneElement } from '../utils';
|
||||
import { type Book } from '../types'
|
||||
import moment from 'moment'
|
||||
|
||||
let currentBook: Book | null = null
|
||||
async function insertContent() {
|
||||
const itemId = window.location.pathname.split('/').pop()?.substring(0, 19) || ''
|
||||
if (!itemId) {
|
||||
console.warn('No item_id found in URL')
|
||||
return
|
||||
}
|
||||
const chapter = await getChapter(itemId)
|
||||
if (!chapter) {
|
||||
console.warn('No chapter found for item_id:', itemId)
|
||||
return
|
||||
}
|
||||
console.log('Chapter:', chapter)
|
||||
|
||||
const pageState: any = (unsafeWindow as typeof unsafeWindow & {
|
||||
__INITIAL_STATE__?: { reader?: { chapterData?: { title?: string } } }
|
||||
}).__INITIAL_STATE__
|
||||
const chapterTitle = chapter.novel_data?.title || pageState?.reader?.chapterData?.title
|
||||
if (typeof chapter.content === 'string') {
|
||||
// TODO: 支持部分书籍的CSS内容
|
||||
const dp = new DOMParser()
|
||||
const doc = dp.parseFromString(chapter.content, 'text/html')
|
||||
const body = doc.body
|
||||
const article = body.querySelector('article')
|
||||
const toProcess = article || body
|
||||
|
||||
for (let i = 0; i < toProcess.childNodes.length; i++) {
|
||||
if (i < 1 && (toProcess.childNodes[i] as HTMLElement)?.innerHTML.includes(chapterTitle)) {
|
||||
// remove duplicate title
|
||||
toProcess.removeChild(toProcess.childNodes[i] as HTMLElement)
|
||||
}
|
||||
}
|
||||
const readerContainer = document.querySelector("div.muye-reader-content")
|
||||
let scriptContainer: HTMLDivElement | null = null
|
||||
if (readerContainer) {
|
||||
scriptContainer = cloneElement(readerContainer) as HTMLDivElement
|
||||
scriptContainer.classList.add('fqa')
|
||||
scriptContainer.classList.remove('noselect') // allow text selection
|
||||
// readerContainer应该已经被注入的内容CSS隐藏掉了
|
||||
scriptContainer.innerHTML = ''
|
||||
scriptContainer.appendChild(toProcess)
|
||||
readerContainer.insertAdjacentElement('beforebegin', scriptContainer)
|
||||
}
|
||||
}
|
||||
const muyeReaderTitle = document.querySelector("h1.muye-reader-title")
|
||||
const muyeReaderSubtitle = document.querySelector("div.muye-reader-subtitle")
|
||||
if (muyeReaderTitle) {
|
||||
muyeReaderTitle.textContent = chapterTitle
|
||||
}
|
||||
// <div class="muye-reader-subtitle">
|
||||
// <span class="desc-item">
|
||||
// <span class="title">本章字数:</span>
|
||||
// 1916字
|
||||
// </span>
|
||||
// <span class="desc-item">
|
||||
// <span class="title">更新时间:</span>
|
||||
// 2025-05-24
|
||||
// </span>
|
||||
// </div>
|
||||
/*
|
||||
if (muyeReaderSubtitle) {
|
||||
muyeReaderSubtitle.innerHTML = ''
|
||||
const wordCntSpan = document.createElement('span')
|
||||
wordCntSpan.className = 'desc-item'
|
||||
wordCntSpan.innerHTML = `<span class="title">本章字数:</span> ${chapter.char_count}字`
|
||||
muyeReaderSubtitle.appendChild(wordCntSpan)
|
||||
const updateTimeSpan = document.createElement('span')
|
||||
updateTimeSpan.className = 'desc-item'
|
||||
updateTimeSpan.innerHTML = `<span class="title">更新时间:</span> ${chapter.update_time}`
|
||||
muyeReaderSubtitle.appendChild(updateTimeSpan)
|
||||
}
|
||||
*/
|
||||
|
||||
if (muyeReaderSubtitle && pageState?.reader?.chapterData?.itemId === itemId) {
|
||||
// 写入更精确的更新时间
|
||||
let updateTimeSpan = muyeReaderSubtitle.querySelectorAll('span.desc-item')[1]
|
||||
if (updateTimeSpan) {
|
||||
let uttspan = updateTimeSpan.firstChild as HTMLSpanElement
|
||||
// seconds
|
||||
updateTimeSpan.innerHTML =
|
||||
uttspan.innerHTML +
|
||||
moment(pageState?.reader?.chapterData?.firstPassTime * 1000).format('YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
}
|
||||
/*
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (readerContainer) {
|
||||
readerContainer.innerHTML = ''
|
||||
readerContainer.appendChild(toProcess)
|
||||
}
|
||||
// TODO: 改优雅点
|
||||
// 防止和页面已有脚本相互作用导致正文没覆盖上
|
||||
await sleep(100)
|
||||
}
|
||||
*/
|
||||
console.log('Current book:', currentBook)
|
||||
if (!currentBook || currentBook == null || currentBook.book_id !== chapter.novel_data?.book_id) {
|
||||
currentBook = await getBookInfoAndCatalog(chapter.novel_data?.book_id)
|
||||
console.log('Current book:', currentBook)
|
||||
}
|
||||
if (currentBook && currentBook.chapter_list) {
|
||||
const currentChapterItem = currentBook.chapter_list.find(c => c.item_id === itemId)
|
||||
if (currentChapterItem) {
|
||||
console.log('Current chapter:', currentChapterItem)
|
||||
if (document.getElementById('fqa-current-chapter-volume')) {
|
||||
const c = document.getElementById('fqa-current-chapter-volume')
|
||||
if (c) {
|
||||
c.textContent = currentChapterItem.volume_title
|
||||
}
|
||||
} else {
|
||||
const volSpan = document.createElement('span')
|
||||
volSpan.className = 'desc-item'
|
||||
volSpan.id = 'fqa-current-chapter-volume'
|
||||
volSpan.textContent = currentChapterItem.volume_title
|
||||
// muyeReaderSubtitle?.firstChild: HTMLSpanElement.insertAdjacentElement('beforebegin', volSpan)
|
||||
const c = muyeReaderSubtitle?.firstChild as HTMLSpanElement
|
||||
if (c) {
|
||||
c.insertAdjacentElement('beforebegin', volSpan)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// let currentBook: Book | null = null
|
||||
async function onUrlChange(_previous: string): Promise<void> {
|
||||
// TODO: 记录并上报阅读历史和记录
|
||||
await insertContent()
|
||||
}
|
||||
async function onHashChange(_previous: string): Promise<void> {
|
||||
// TODO: 支持从hash里解析并跳转到指定行
|
||||
}
|
||||
async function onLoad(): Promise<void> {
|
||||
/*
|
||||
if (!document.getElementById('fqa-inject-css-reader')) {
|
||||
const style = document.createElement('style')
|
||||
style.id = 'fqa-inject-css-reader'
|
||||
style.innerHTML = defaultcss
|
||||
document.head.appendChild(style)
|
||||
}
|
||||
*/
|
||||
const btns = document.querySelector("div.muye-reader-btns") // single div
|
||||
if (btns) {
|
||||
// TODO: 直接覆写按钮行为,切章节由脚本完成
|
||||
// btns.innerHTML = btns.innerHTML // clear default onclick
|
||||
// 上一章
|
||||
// byte-btn byte-btn-dashed byte-btn-size-large byte-btn-shape-square muye-button chapter-btn last
|
||||
// 下一章
|
||||
// fatherdiv: chapter-btn next btn-next-relative-container
|
||||
// byte-btn byte-btn-primary byte-btn-size-large byte-btn-shape-square muye-button
|
||||
|
||||
/*const prevBtn = btns.querySelector('.chapter-btn.last')
|
||||
const nextBtn = btns.querySelector('.chapter-btn.next')?.firstChild
|
||||
if (prevBtn) {
|
||||
|
||||
}*/
|
||||
}
|
||||
await insertContent()
|
||||
}
|
||||
|
||||
function readerFilter(path: string, _query: URLSearchParams, _hash: string) {
|
||||
return path.startsWith('/reader') || path.startsWith('reader')
|
||||
}
|
||||
|
||||
export default [
|
||||
{
|
||||
id: 'readerHook_load',
|
||||
event: 'load',
|
||||
handler: onLoad,
|
||||
filter: readerFilter
|
||||
} as HookConfig,
|
||||
{
|
||||
id: 'readerHook_urlChange',
|
||||
event: 'onUrlChange',
|
||||
handler: onUrlChange,
|
||||
filter: readerFilter
|
||||
} as HookConfig,
|
||||
{
|
||||
id: 'readerHook_hashChange',
|
||||
event: 'onHashChange',
|
||||
handler: onHashChange,
|
||||
filter: readerFilter
|
||||
} as HookConfig
|
||||
] as HookConfig[]
|
||||
Reference in new issue
Block a user