mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Add column image exporter
This commit is contained in:
parent
d1d024b319
commit
def6ea5449
2
@types/global/index.d.ts
vendored
2
@types/global/index.d.ts
vendored
@ -500,6 +500,7 @@ declare global {
|
||||
copyCommentLink: boolean,
|
||||
unfoldFeeds: boolean,
|
||||
feedsImageExporter: boolean,
|
||||
columnImageExporter: boolean,
|
||||
latestVersionLink: string,
|
||||
currentVersion: string,
|
||||
}
|
||||
@ -559,5 +560,6 @@ declare global {
|
||||
const getScriptVersion: () => ScriptVersion
|
||||
const playerReady: () => Promise<void>
|
||||
const formData: (obj: any) => string
|
||||
const retrieveImageUrl: (element: Element) => { url: string; extension: string } | null
|
||||
}
|
||||
export { }
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -28,6 +28,7 @@
|
||||
"clear-cache.min.js": "9AB1536D8278DA681831A589AD1414425BF206B36AE109FB4EC1E8A685BB2A9F",
|
||||
"collapse-live-side-bar.min.css": "22348786547D2D8DB659A306AF2E9C1F2050D66488778C71545AAEF785FD57E6",
|
||||
"collapse-live-side-bar.min.js": "BB1B1CF157099A70F1AEA3F154C84D9CA1A84A29B5F6E42357CA9F51FFC4965C",
|
||||
"column-image-exporter.min.js": "EC98F065908736A6DA91A3F8AA68BF8DC9D4D3F2973E374BA7C36C66F5669345",
|
||||
"combo-like.min.js": "368DA34768E947628099D258ED23BC5FFFCFFD25A47346E086C7975C8A52F997",
|
||||
"comment.min.css": "6A72677F3DAFC1227B058C9487A00DAEE6A1E4BF9839C55888EDF7AFBD8DFF23",
|
||||
"comment.min.js": "64F7B6951861C25799C48BB1ABCF2A73F79BCBBFC1E9D3BD45EC1F16F94F6451",
|
||||
@ -102,7 +103,7 @@
|
||||
"feeds-apis.min.js": "0A70658F6A398AC5122C4328F69EC93FC122BD19319F89C3DECF60389DC68C30",
|
||||
"feeds-filter.min.js": "9E8BC1A669D97992E888A3154FCE64912CE0B7A303D6BE40C3CA0C71A9533B96",
|
||||
"feeds-filter-card.vue.min.js": "D743BEF3C77C8A9AB8AA5DD24E8BD0A7AF7E638319137A103F3A9CF278F66CB4",
|
||||
"feeds-image-exporter.min.js": "22A675B0FD8FFE49394686EDA2F871AE1BE91C856BA4116FE024B22244BBB721",
|
||||
"feeds-image-exporter.min.js": "E92D2820FF7BD37AA4D930C9A89DF32B989B4E6A06F8AF6E0C3D9AE777343F81",
|
||||
"feeds-translate.min.css": "54E959EC2AD38451B288E0DC669A269BF916CDB0F6B78497E2C315EB2811EF02",
|
||||
"feeds-translate.min.js": "02C12D7A3382E185FF67C503C6287759ED18D2E9C838C2B94668953272BA09B1",
|
||||
"feeds-translate-providers.min.js": "DD3B48C051ED1CD89AB79B2563723B2639D8737EF2194136D63ABAA8D4B64F6C",
|
||||
@ -124,7 +125,7 @@
|
||||
"gbk.min.js": "872D7A4562F13A539C4A9AF1825DE89E610C775F1AD026EA6986A80DD74E4B53",
|
||||
"get-number.min.js": "7B81A45D0F7D7F68CC6EDE25E02FCD76F8A05B2CF29274F94A99980BB23D8B76",
|
||||
"gui-settings.min.css": "787D487EF39F28C18815C755BB4CA336355B84778861DCC70AA5AC998FDB9CC7",
|
||||
"gui-settings.min.html": "25C8D590B625A310CEE53F685286B252C7DB0B7EE8FB294B8A7A3C9A8E1D1170",
|
||||
"gui-settings.min.html": "760D5BFDF0A042C1FA0D13CF978C02AC4B3EC81D6E895527C1B53DE0F199B6DC",
|
||||
"gui-settings.min.js": "A092181BBAF56712E2F62B46552DE97D582FB1891B626D9D55276E577BC44D7A",
|
||||
"haruna-scale.min.js": "FD079C86741F614FD63E733CF9B7B896A7D20110754815A540F3341D4DC252B2",
|
||||
"hide-bangumi-reviews.min.js": "7265C0CE994FDA926355A9A4F9B207E7E68E749D47332F3C537EF93E97927A23",
|
||||
|
||||
BIN
min/bundle.zip
BIN
min/bundle.zip
Binary file not shown.
1
min/column-image-exporter.min.js
vendored
Normal file
1
min/column-image-exporter.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
(()=>{return(t,n)=>{return{widget:{condition:()=>document.URL.startsWith("https://www.bilibili.com/read/cv"),content:`\n<button class="gui-settings-flat-button column-image-export">\n<i class="mdi mdi-24px mdi-export"></i>\n<span>导出图片</span>\n</button>`,success:()=>{const t=dq(".column-image-export");const e=dq(t,"span");t.addEventListener("click",async()=>{try{t.disabled=true;e.textContent="下载中...";const o=[];const a=document.title.replace(/ - 哔哩哔哩$/,"");const i=dq(".banner-img-holder");const s=retrieveImageUrl(i);if(s){o.push({...s,name:`${a}-banner${s.extension}`})}const c=dqa('.article-holder img:not([class*="cut-off-"])');c.forEach(t=>{const n=retrieveImageUrl(t);if(n){o.push({...n,name:`${a}-${o.length-1}${n.extension}`})}});if(o.length===0){Toast.info("此专栏没有检测到任何图片.","专栏图片导出");return}const{DownloadVideoPackage:r}=await n.importAsync("download-video-package");const l=await Promise.all(o.map(({url:t})=>Ajax.getBlob(t)));const d=new r;l.forEach((t,n)=>d.add(o[n].name,t));await d.emit(`${a}.zip`)}catch(t){logError(t)}finally{e.textContent="导出图片";t.disabled=false}})}}}}})();
|
||||
2
min/feeds-image-exporter.min.js
vendored
2
min/feeds-image-exporter.min.js
vendored
@ -1 +1 @@
|
||||
(()=>{return(e,a)=>{(async()=>{const{forEachFeedsCard:e,addMenuItem:t}=await a.importAsync("feeds-apis");const n=e=>{t(e,{className:"image-export",text:"导出图片",action:async()=>{const t=[];dqa(e.element,"img, .img-content").forEach(e=>{let a;if(e instanceof HTMLImageElement){a=e.src}else{const t=e.style.backgroundImage;if(!t){return}const n=t.match(/url\("(.+)"\)/);if(!n){return}a=n[1]}const n=a.match(/^(.+)(\..+?)(@.+)$/);if(!n){return}t.push({url:n[1]+n[2],extension:n[2]})});const{DownloadVideoPackage:n}=await a.importAsync("download-video-package");const o=await Promise.all(t.map(({url:e})=>Ajax.getBlob(e)));const s=new n;o.forEach((a,n)=>s.add(`${e.username}-${e.id}-${n}${t[n].extension}`,a));await s.emit(`${e.username}-${e.id}.zip`)}})};e({added:n})})()}})();
|
||||
(()=>{return(a,e)=>{(async()=>{const{forEachFeedsCard:a,addMenuItem:t}=await e.importAsync("feeds-apis");const n=a=>{t(a,{className:"image-export",text:"导出图片",action:async()=>{const t=[];dqa(a.element,"img, .img-content").forEach(a=>{const e=retrieveImageUrl(a);if(e){t.push(e)}});if(t.length===0){Toast.info("此条动态没有检测到任何图片.","动态图片导出");return}const{DownloadVideoPackage:n}=await e.importAsync("download-video-package");const o=await Promise.all(t.map(({url:a})=>Ajax.getBlob(a)));const i=new n;o.forEach((e,n)=>i.add(`${a.username}-${a.id}-${n}${t[n].extension}`,e));await i.emit(`${a.username}-${a.id}.zip`)}})};a({added:n})})()}})();
|
||||
File diff suppressed because one or more lines are too long
@ -9,29 +9,15 @@ import { FeedsCard } from './feeds-apis'
|
||||
action: async () => {
|
||||
const imageUrls: { url: string; extension: string }[] = []
|
||||
dqa(card.element, 'img, .img-content').forEach((img: HTMLImageElement | HTMLDivElement) => {
|
||||
let url: string
|
||||
if (img instanceof HTMLImageElement) {
|
||||
url = img.src
|
||||
} else {
|
||||
const backgroundImage = img.style.backgroundImage
|
||||
if (!backgroundImage) {
|
||||
return
|
||||
}
|
||||
const match = backgroundImage.match(/url\("(.+)"\)/)
|
||||
if (!match) {
|
||||
return
|
||||
}
|
||||
url = match[1]
|
||||
const urlData = retrieveImageUrl(img)
|
||||
if (urlData) {
|
||||
imageUrls.push(urlData)
|
||||
}
|
||||
const thumbMatch = url.match(/^(.+)(\..+?)(@.+)$/)
|
||||
if (!thumbMatch) {
|
||||
return
|
||||
}
|
||||
imageUrls.push({
|
||||
url: thumbMatch[1] + thumbMatch[2],
|
||||
extension: thumbMatch[2],
|
||||
})
|
||||
})
|
||||
if (imageUrls.length === 0) {
|
||||
Toast.info('此条动态没有检测到任何图片.', '动态图片导出')
|
||||
return
|
||||
}
|
||||
const { DownloadVideoPackage } = await import('../video/download-video/download-video-package')
|
||||
const imageBlobs = await Promise.all(imageUrls.map(({ url }) => Ajax.getBlob(url)))
|
||||
const pack = new DownloadVideoPackage()
|
||||
|
||||
@ -973,5 +973,11 @@ Resource.manifest = {
|
||||
feedsImageExporter: '动态图片导出',
|
||||
},
|
||||
},
|
||||
columnImageExporter: {
|
||||
path: 'column-image-exporter.min.js',
|
||||
displayNames: {
|
||||
columnImageExporter: '专栏图片导出',
|
||||
},
|
||||
},
|
||||
}
|
||||
export const resourceManifest = Resource.manifest
|
||||
|
||||
@ -247,6 +247,7 @@ export const settings = {
|
||||
copyCommentLink: false,
|
||||
unfoldFeeds: true,
|
||||
feedsImageExporter: false,
|
||||
columnImageExporter: false,
|
||||
cache: {},
|
||||
}
|
||||
const fixedSettings = {
|
||||
|
||||
@ -203,3 +203,32 @@ export const playerReady = () => {
|
||||
)
|
||||
}
|
||||
export const formData = (obj) => Object.entries(obj).map(([k, v]) => `${k}=${v}`).join('&')
|
||||
export const retrieveImageUrl = (element) => {
|
||||
if (!(element instanceof HTMLElement)) {
|
||||
return null
|
||||
}
|
||||
let url
|
||||
if (element.hasAttribute('data-src')) {
|
||||
url = element.getAttribute('data-src')
|
||||
} else if (element instanceof HTMLImageElement) {
|
||||
url = element.src
|
||||
} else {
|
||||
const backgroundImage = element.style.backgroundImage
|
||||
if (!backgroundImage) {
|
||||
return null
|
||||
}
|
||||
const match = backgroundImage.match(/url\("(.+)"\)/)
|
||||
if (!match) {
|
||||
return null
|
||||
}
|
||||
url = match[1]
|
||||
}
|
||||
const thumbMatch = url.match(/^(.+)(\..+?)(@.+)$/)
|
||||
if (!thumbMatch) {
|
||||
return null
|
||||
}
|
||||
return {
|
||||
url: thumbMatch[1] + thumbMatch[2],
|
||||
extension: thumbMatch[2],
|
||||
}
|
||||
}
|
||||
|
||||
54
src/utils/column-image-exporter.ts
Normal file
54
src/utils/column-image-exporter.ts
Normal file
@ -0,0 +1,54 @@
|
||||
export default {
|
||||
widget: {
|
||||
condition: () => document.URL.startsWith('https://www.bilibili.com/read/cv'),
|
||||
content: /* html */`
|
||||
<button class="gui-settings-flat-button column-image-export">
|
||||
<i class="mdi mdi-24px mdi-export"></i>
|
||||
<span>导出图片</span>
|
||||
</button>`,
|
||||
success: () => {
|
||||
const button = dq('.column-image-export') as HTMLButtonElement
|
||||
const text = dq(button, 'span') as HTMLSpanElement
|
||||
button.addEventListener('click', async () => {
|
||||
try {
|
||||
button.disabled = true
|
||||
text.textContent = '下载中...'
|
||||
const images: { name: string; extension: string; url: string }[] = []
|
||||
const title = document.title.replace(/ - 哔哩哔哩$/, '')
|
||||
const bannerElement = dq('.banner-img-holder') as HTMLDivElement
|
||||
const bannerUrl = retrieveImageUrl(bannerElement)
|
||||
if (bannerUrl) {
|
||||
images.push({
|
||||
...bannerUrl,
|
||||
name: `${title}-banner${bannerUrl.extension}`,
|
||||
})
|
||||
}
|
||||
const articleImages = dqa('.article-holder img:not([class*="cut-off-"])')
|
||||
articleImages.forEach(image => {
|
||||
const url = retrieveImageUrl(image)
|
||||
if (url) {
|
||||
images.push({
|
||||
...url,
|
||||
name: `${title}-${images.length - 1}${url.extension}`,
|
||||
})
|
||||
}
|
||||
})
|
||||
if (images.length === 0) {
|
||||
Toast.info('此专栏没有检测到任何图片.', '专栏图片导出')
|
||||
return
|
||||
}
|
||||
const { DownloadVideoPackage } = await import('../video/download-video/download-video-package')
|
||||
const imageBlobs = await Promise.all(images.map(({ url }) => Ajax.getBlob(url)))
|
||||
const pack = new DownloadVideoPackage()
|
||||
imageBlobs.forEach((blob, index) => pack.add(images[index].name, blob))
|
||||
await pack.emit(`${title}.zip`)
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
} finally {
|
||||
text.textContent = '导出图片'
|
||||
button.disabled = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,6 +164,7 @@
|
||||
<checkbox indent="0" key="urlParamsClean" dependencies=""></checkbox>
|
||||
<checkbox indent="0" key="preferAvUrl" dependencies=""></checkbox>
|
||||
<checkbox indent="0" key="copyCommentLink" dependencies=""></checkbox>
|
||||
<checkbox indent="0" key="columnImageExporter" dependencies=""></checkbox>
|
||||
<!-- <checkbox indent="0" key="restoreFloors" dependencies=""></checkbox> -->
|
||||
<category icon="touch">触摸</category>
|
||||
<checkbox indent="0" key="touchNavBar" dependencies=""></checkbox>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user