Bilibili-Evolved/registry/lib/components/utils/image-exporter/feed.ts

114 lines
4.3 KiB
TypeScript

import { FeedsCard, addMenuItem, forEachFeedsCard, RepostFeedsCard } from '@/components/feeds/api'
import { ComponentEntry } from '@/components/types'
import { getBlob } from '@/core/ajax'
import { DownloadPackage } from '@/core/download'
import { Toast } from '@/core/toast'
import { getVue2Data, matchUrlPattern, retrieveImageUrl } from '@/core/utils'
import { formatTitle, getTitleVariablesFromDate } from '@/core/utils/title'
import { feedsUrls } from '@/core/utils/urls'
import { Options } from '.'
import { useScopedConsole } from '@/core/utils/log'
const isSameImage = (imageUrl: string, otherUrl: string) => {
try {
return new URL(imageUrl).pathname === new URL(otherUrl).pathname
} catch {
return false
}
}
export const setupFeedImageExporter: ComponentEntry<Options> = async ({
settings: { options },
}) => {
if (!feedsUrls.some(url => matchUrlPattern(url))) {
return
}
const addExportButton = (card: FeedsCard) => {
addMenuItem(card, {
className: 'image-export',
text: '导出图片',
action: async () => {
const imageUrls: { url: string; extension: string }[] = []
const console = useScopedConsole('导出图片')
dqa(
card.element,
'.main-content .img-content, .bili-album__preview__picture__img, .bili-album .preview__picture__img, .bili-dyn-gallery__image img, .bili-album__watch__track__item img',
).forEach((img: HTMLImageElement | HTMLDivElement) => {
const urlData = retrieveImageUrl(img)
if (urlData && !imageUrls.some(({ url }) => isSameImage(url, urlData.url))) {
imageUrls.push(urlData)
}
})
if (imageUrls.length === 0) {
Toast.info('此条动态没有检测到任何图片.', '导出图片')
return
}
console.log({ imageUrls })
const toast = Toast.info('下载中...', '导出图片')
let downloadedCount = 0
const vueData = getVue2Data(card.element)
const authorModule = lodash.get(vueData, 'data.modules.module_author', {})
const repostAuthorModule = lodash.get(vueData, 'data.orig.modules.module_author', {})
const date = getTitleVariablesFromDate(new Date(authorModule.pub_ts * 1000))
const repostDate = getTitleVariablesFromDate(
new Date((repostAuthorModule.pub_ts ?? authorModule.pub_ts) * 1000),
)
const variables = {
id: card.id,
user: card.username,
userID: authorModule.mid?.toString(),
originalUser: (card as RepostFeedsCard).repostUsername ?? card.username,
originalUserID: repostAuthorModule.mid?.toString() ?? authorModule.mid?.toString(),
originalID: lodash.get(vueData, 'data.orig.id_str', card.id),
publishYear: date.year,
publishMonth: date.month,
publishDay: date.day,
publishHour: date.hour,
publishMinute: date.minute,
publishSecond: date.second,
publishMillisecond: date.millisecond,
originalPublishYear: repostDate.year,
originalPublishMonth: repostDate.month,
originalPublishDay: repostDate.day,
originalPublishHour: repostDate.hour,
originalPublishMinute: repostDate.minute,
originalPublishSecond: repostDate.second,
originalPublishMillisecond: repostDate.millisecond,
}
const imageBlobs = await Promise.all(
imageUrls.map(async ({ url }) => {
const blob = await getBlob(url)
downloadedCount++
toast.message = `下载中... (${downloadedCount}/${imageUrls.length})`
return blob
}),
)
const pack = new DownloadPackage()
const { feedFormat } = options
imageBlobs.forEach((blob, index) => {
const titleData = {
n: (index + 1).toString(),
...variables,
}
pack.add(
`${formatTitle(feedFormat, false, titleData)}${imageUrls[index].extension}`,
blob,
)
})
toast.close()
const packTitleData = {
n: '',
...variables,
}
await pack.emit(`${formatTitle(feedFormat, false, packTitleData)}.zip`)
},
})
}
forEachFeedsCard({
added: addExportButton,
})
}