import { TestPattern } from '@/core/common-types' import { childList, childListSubtree } from '@/core/observer' import { select } from '@/core/spin-query' import { liveUrls } from '@/core/utils/urls' import { addData } from '@/plugins/data' import { FeedsCardsManager } from './base' /** 表示一个动态卡片列表适配器, 可以对在不同页面的地方里的动态列表提供支持 */ export interface FeedsCardsListAdaptor { /** 名称 */ name: string /** 匹配的网址 */ match: TestPattern /** * 开始监测 * @param manager `FeedsCardsManager` 的实例 * @returns 是否监测成功 */ watchCardsList: (manager: FeedsCardsManager) => Promise } export const ListAdaptorKey = 'feeds.manager.listAdaptors' addData(ListAdaptorKey, (adaptors: FeedsCardsListAdaptor[]) => { adaptors.push( { name: 'live', match: [...liveUrls], watchCardsList: async manager => { const feedsContainer = (await select('.room-feed')) as HTMLElement if (!feedsContainer) { return false } console.log('live watch') let cardListObserver: MutationObserver | null = null childList(feedsContainer, async () => { if (dq('.room-feed-content')) { const cardsList = (await select('.room-feed-content .content')) as HTMLElement cardListObserver?.disconnect() ;[cardListObserver] = manager.updateCards(cardsList) } else { cardListObserver?.disconnect() cardListObserver = null await Promise.all(manager.cards.map(c => c.element).map(e => manager.removeCard(e))) } }) return true }, }, { name: 'space', match: ['https://space.bilibili.com/'], watchCardsList: async manager => { const container = (await select('.s-space, .space-main')) as HTMLDivElement if (!container) { return false } const vm: { observer?: Promise listElement?: Promise } = {} const stop = () => { if (!vm.listElement || !vm.observer) { return } console.log('space feeds stop') vm.observer?.then(it => it.disconnect()) delete vm.observer delete vm.listElement manager.cleanUpCards() } const start = () => { if (vm.observer) { return vm.observer } const newListPromise = select('.bili-dyn-list__items') as Promise vm.observer = (async () => { const newList = await newListPromise if (newList !== (await vm.listElement)) { if (vm.listElement) { stop() } vm.listElement = newListPromise start() } console.log('space feeds start') const [cardListObserver] = manager.updateCards(newList) return cardListObserver })() return vm.observer } childListSubtree(container, async () => { if (dq('.bili-dyn-list__items')) { start() } else { stop() } }) return true }, }, { name: 'topic', match: ['https://t.bilibili.com/topic'], watchCardsList: async manager => { const feedsContainer = (await select('.page-container')) as HTMLElement if (!feedsContainer) { return false } let cardListObserver: MutationObserver | null = null childList(feedsContainer, async () => { if (dq('.page-container .feed')) { const cardsList = (await select('.feed .feed-topic')) as HTMLElement cardListObserver?.disconnect() ;[cardListObserver] = manager.updateCards(cardsList) } else { cardListObserver?.disconnect() cardListObserver = null await Promise.all(manager.cards.map(c => c.element).map(e => manager.removeCard(e))) } }) return true }, }, { name: 'opus-detail', match: ['https://www.bilibili.com/opus/'], watchCardsList: async manager => { const opusContainer = (await select('.opus-detail')) as HTMLElement if (!opusContainer) { return false } manager.updateCards(opusContainer) return true }, }, { name: 'default', match: ['https://t.bilibili.com/'], watchCardsList: async manager => { const list = (await select( '.feed-card .content, .detail-content .detail-card, #app > .content > .card, .bili-dyn-list__items', )) as HTMLElement if (!list) { return false } if (list.classList.contains('bili-dyn-list__items')) { const section = list.parentElement.parentElement let cardListObserver: MutationObserver childList(section, () => { const changedList = dq(section, '.bili-dyn-list__items') as HTMLElement if (!changedList) { return } cardListObserver?.disconnect() manager.cards = [] ;[cardListObserver] = manager.updateCards(changedList) }) } else { manager.updateCards(list) } return true }, }, ) })