mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Add feeds image exporter
This commit is contained in:
parent
84a47147d4
commit
d1d024b319
2
@types/global/index.d.ts
vendored
2
@types/global/index.d.ts
vendored
@ -498,6 +498,8 @@ declare global {
|
||||
commentsTranslate: boolean,
|
||||
copyFeedsLink: boolean,
|
||||
copyCommentLink: boolean,
|
||||
unfoldFeeds: boolean,
|
||||
feedsImageExporter: boolean,
|
||||
latestVersionLink: string,
|
||||
currentVersion: string,
|
||||
}
|
||||
|
||||
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
@ -37,7 +37,7 @@
|
||||
"compact-layout.min.css": "CAC8B0DBA8E90B38D31F0811B7B469709052204AC36D5D3F20FE5D0899FDDCCB",
|
||||
"compact-layout.min.js": "B20609A7CBBDB1845FA0156FB5BE6B1E1A1B8B069EA85F65D16241DD2C12D738",
|
||||
"copy-comment-link.min.js": "0488EB370A89B79F39120AB5EF7696F9FEF354E12724E7E41197AE8D1A9A6553",
|
||||
"copy-feeds-link.min.js": "579381349AA2A54A7B8A9AA67A7D35E83DBB456E0A73081E80D4C8DB404604A1",
|
||||
"copy-feeds-link.min.js": "E13B09593E00520336D9DB97383437ACE66F8E49CD408E336A536C22538EA98A",
|
||||
"custom-control-background.min.css": "1981FD2BF3B17ECF33F98D5DEDAF0D32ACBE9532A51FDB70822286991AB98EF3",
|
||||
"custom-control-background.min.js": "B9F366B251D1572ACE801FF6ECF15D4D1AAB3EA5A5B04B961B6F4310E2AB1A84",
|
||||
"custom-navbar.min.css": "96663A9903546E9E69A9E9BD619ED350E738D76DA7AB63C1DF5F1F878DAB272C",
|
||||
@ -65,11 +65,13 @@
|
||||
"danmaku-send-bar.min.css": "52149D46CF3A15CF6EB186CB49F298DE18B0723E52D8693228F66099847EDCCB",
|
||||
"danmaku-send-bar.min.js": "7108E72F00C169F26E20409F4AA79F05553310375BABC392EB7E2166224B800A",
|
||||
"dark.min.css": "7B31789D505589C30EA61AEA4789426D1444490E218CB2A9BFA251F224533A73",
|
||||
"dark.user.css": "93B67B95FFDBD1FCF0ECD360662B215A8F9062970C3B73E3967798D261A49DAB",
|
||||
"dark.user.css": "F8534277BB8C9F1DCF8BE1E497CCAF2EE3A9CE15B5A46250F842D9DAEC06AD85",
|
||||
"dark-color-scheme.min.js": "6D353AC738180317ACF9D2E046BFFBA0ACC0FA7A8D22B8E16C51127CDE4FE96B",
|
||||
"dark-important.min.css": "546E3C3E0F181EB710CFE486A81CCB5CCC22D61E6C5D442182294CE03D8F4DDF",
|
||||
"dark-navbar.min.css": "7FAD547E326B768904B3739C978DF86FFDDD5E5064FB8F490710D197CCC3018B",
|
||||
"dark-schedule.min.js": "853C446547603F4F0425F19F09F73335C9EC451A790C1C07E5E5B88A09E9B453",
|
||||
"dark-slice-1.min.css": "E53F714FB59F62A80537B0715CE29CF0D9D1859CD217C15B647535A2679CE5ED",
|
||||
"dark-slice-12.min.css": "24AC275EA1A0E74A928498974A0875584D345BE98214B10BFE324CF8CEBEE55B",
|
||||
"dark-styles.min.js": "77F12E4F159C5139E1FC6030615F88EFD0A02443D34C3C4EDC3DB0B85F081631",
|
||||
"debounce.min.js": "54D33E1273C1F3FE19550BF1844339C3D54D6B01DF8A39C3162D95B93B079CFA",
|
||||
"default-danmaku-settings.min.css": "D9942B184FEDA7B08CFA0C34920E97D7A83B81762DCBF757642EBB60F95FF25D",
|
||||
@ -97,9 +99,10 @@
|
||||
"extend-feeds-live.min.css": "BD0BF6E670808C940B3F3F7D8798B02676A58AA204449AAAE6E162D27EB8598A",
|
||||
"extend-feeds-live.min.js": "AC4C8018F5597536501DC8450F1572D6CF9D417229B84D2FE9A0F32E18942ED6",
|
||||
"favorites-redirect.min.js": "70D6ECCE0402AA76387D2A3288C1148C60CC88D5378B7A2BDC813F3F78E4EE84",
|
||||
"feeds-apis.min.js": "1FEB6EAFD6FA6948D6E51F29F5C7B91AF3ADB4C1F20654E9857405F4BD37B722",
|
||||
"feeds-apis.min.js": "0A70658F6A398AC5122C4328F69EC93FC122BD19319F89C3DECF60389DC68C30",
|
||||
"feeds-filter.min.js": "9E8BC1A669D97992E888A3154FCE64912CE0B7A303D6BE40C3CA0C71A9533B96",
|
||||
"feeds-filter-card.vue.min.js": "D743BEF3C77C8A9AB8AA5DD24E8BD0A7AF7E638319137A103F3A9CF278F66CB4",
|
||||
"feeds-image-exporter.min.js": "22A675B0FD8FFE49394686EDA2F871AE1BE91C856BA4116FE024B22244BBB721",
|
||||
"feeds-translate.min.css": "54E959EC2AD38451B288E0DC669A269BF916CDB0F6B78497E2C315EB2811EF02",
|
||||
"feeds-translate.min.js": "02C12D7A3382E185FF67C503C6287759ED18D2E9C838C2B94668953272BA09B1",
|
||||
"feeds-translate-providers.min.js": "DD3B48C051ED1CD89AB79B2563723B2639D8737EF2194136D63ABAA8D4B64F6C",
|
||||
@ -121,7 +124,7 @@
|
||||
"gbk.min.js": "872D7A4562F13A539C4A9AF1825DE89E610C775F1AD026EA6986A80DD74E4B53",
|
||||
"get-number.min.js": "7B81A45D0F7D7F68CC6EDE25E02FCD76F8A05B2CF29274F94A99980BB23D8B76",
|
||||
"gui-settings.min.css": "787D487EF39F28C18815C755BB4CA336355B84778861DCC70AA5AC998FDB9CC7",
|
||||
"gui-settings.min.html": "D223BF882657CA6DE6B1D637687D2EB4F1ABC201423505C92C015C6FCF426FF1",
|
||||
"gui-settings.min.html": "25C8D590B625A310CEE53F685286B252C7DB0B7EE8FB294B8A7A3C9A8E1D1170",
|
||||
"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.
2
min/copy-feeds-link.min.js
vendored
2
min/copy-feeds-link.min.js
vendored
@ -1 +1 @@
|
||||
(()=>{return(t,e)=>{(async()=>{const t=["https://t.bilibili.com/","https://space.bilibili.com/","https://live.bilibili.com/"];if(t.every(t=>!document.URL.includes(t))){return}const{forEachFeedsCard:i}=await e.importAsync("feeds-apis");const n=t=>{const e=dq(t.element,".more-panel");if(!e||dq(e,".copy-link")){return}const i=document.createElement("p");i.classList.add("child-button","c-pointer","copy-link");i.textContent="复制链接";const n=[...new Set([...e.children].map(t=>{return t.getAttributeNames().filter(t=>t.startsWith("data-v-"))}).flat())];n.forEach(t=>i.setAttribute(t,""));i.addEventListener("click",()=>{GM_setClipboard(`https://t.bilibili.com/${t.id}`,{mimetype:"text/plain"});t.element.click()});e.appendChild(i)};i({added:n})})()}})();
|
||||
(()=>{return(i,t)=>{(async()=>{const i=["https://t.bilibili.com/","https://space.bilibili.com/","https://live.bilibili.com/"];if(i.every(i=>!document.URL.includes(i))){return}const{forEachFeedsCard:e,addMenuItem:s}=await t.importAsync("feeds-apis");const c=i=>{s(i,{className:"copy-link",text:"复制链接",action:()=>{GM_setClipboard(`https://t.bilibili.com/${i.id}`,{mimetype:"text/plain"})}})};e({added:c})})()}})();
|
||||
@ -3,7 +3,7 @@
|
||||
@namespace Bilibili-Evolved
|
||||
@homepageURL https://github.com/the1812/Bilibili-Evolved
|
||||
@updateURL https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/min/dark.user.css
|
||||
@version 823.28.0
|
||||
@version 824.25.0
|
||||
@license MIT
|
||||
@author Grant Howard (https://github.com/the1812), Coulomb-G (https://github.com/Coulomb-G)
|
||||
==/UserStyle== */
|
||||
|
||||
2
min/feeds-apis.min.js
vendored
2
min/feeds-apis.min.js
vendored
File diff suppressed because one or more lines are too long
1
min/feeds-image-exporter.min.js
vendored
Normal file
1
min/feeds-image-exporter.min.js
vendored
Normal file
@ -0,0 +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})})()}})();
|
||||
File diff suppressed because one or more lines are too long
@ -9,24 +9,15 @@ import { FeedsCard } from '../feeds-apis'
|
||||
if (urlList.every(url => !document.URL.includes(url))) {
|
||||
return
|
||||
}
|
||||
const { forEachFeedsCard } = await import('../feeds-apis')
|
||||
const { forEachFeedsCard, addMenuItem } = await import('../feeds-apis')
|
||||
const addCopyLinkButton = (card: FeedsCard) => {
|
||||
const morePanel = dq(card.element, '.more-panel') as HTMLElement
|
||||
if (!morePanel || dq(morePanel, '.copy-link')) {
|
||||
return
|
||||
}
|
||||
const copyLinkButton = document.createElement('p')
|
||||
copyLinkButton.classList.add('child-button', 'c-pointer', 'copy-link')
|
||||
copyLinkButton.textContent = '复制链接'
|
||||
const vueScopeAttributes = [...new Set([...morePanel.children].map((element: HTMLElement) => {
|
||||
return element.getAttributeNames().filter(it => it.startsWith('data-v-'))
|
||||
}).flat())]
|
||||
vueScopeAttributes.forEach(attr => copyLinkButton.setAttribute(attr, ''))
|
||||
copyLinkButton.addEventListener('click', () => {
|
||||
addMenuItem(card, {
|
||||
className: 'copy-link',
|
||||
text: '复制链接',
|
||||
action: () => {
|
||||
GM_setClipboard(`https://t.bilibili.com/${card.id}`, { mimetype: 'text/plain' })
|
||||
card.element.click()
|
||||
}
|
||||
})
|
||||
morePanel.appendChild(copyLinkButton)
|
||||
}
|
||||
forEachFeedsCard({
|
||||
added: addCopyLinkButton,
|
||||
|
||||
@ -404,7 +404,16 @@ export const getVideoFeeds = async (type: 'video' | 'bangumi' = 'video'): Promis
|
||||
}
|
||||
|
||||
export const forEachFeedsCard = (callback: FeedsCardCallback) => {
|
||||
(async () => {
|
||||
const feedsUrls = [
|
||||
/^https:\/\/t\.bilibili\.com\/$/,
|
||||
/^https:\/\/space\.bilibili\.com\//,
|
||||
/^https:\/\/live\.bilibili\.com\/(blanc\/)?[\d]+/,
|
||||
/^https:\/\/t\.bilibili\.com\//,
|
||||
]
|
||||
if (feedsUrls.every(url => !url.test(document.URL))) {
|
||||
return
|
||||
}
|
||||
;(async () => {
|
||||
const success = await feedsCardsManager.startWatching()
|
||||
if (!success) {
|
||||
console.error('feedsCardsManager.startWatching() failed')
|
||||
@ -419,6 +428,34 @@ export const forEachFeedsCard = (callback: FeedsCardCallback) => {
|
||||
feedsCardCallbacks.push({ added: none, removed: none, ...callback })
|
||||
})()
|
||||
}
|
||||
/**
|
||||
* 向动态卡片的菜单中添加菜单项
|
||||
* @param card 动态卡片
|
||||
* @param config 菜单项配置
|
||||
*/
|
||||
export const addMenuItem = (card: FeedsCard, config: {
|
||||
className: string
|
||||
text: string
|
||||
action: (e: MouseEvent) => void
|
||||
}) => {
|
||||
const morePanel = dq(card.element, '.more-panel') as HTMLElement
|
||||
const { className, text, action } = config
|
||||
if (!morePanel || dq(morePanel, `.${className}`)) {
|
||||
return
|
||||
}
|
||||
const menuItem = document.createElement('p')
|
||||
menuItem.classList.add('child-button', 'c-pointer', className)
|
||||
menuItem.textContent = text
|
||||
const vueScopeAttributes = [...new Set([...morePanel.children].map((element: HTMLElement) => {
|
||||
return element.getAttributeNames().filter(it => it.startsWith('data-v-'))
|
||||
}).flat())]
|
||||
vueScopeAttributes.forEach(attr => menuItem.setAttribute(attr, ''))
|
||||
menuItem.addEventListener('click', e => {
|
||||
action(e)
|
||||
card.element.click()
|
||||
})
|
||||
morePanel.appendChild(menuItem)
|
||||
}
|
||||
|
||||
export default {
|
||||
export: {
|
||||
@ -426,5 +463,6 @@ export default {
|
||||
feedsCardTypes,
|
||||
getVideoFeeds,
|
||||
forEachFeedsCard,
|
||||
addMenuItem,
|
||||
},
|
||||
}
|
||||
|
||||
46
src/activity/feeds-image-exporter.ts
Normal file
46
src/activity/feeds-image-exporter.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { FeedsCard } from './feeds-apis'
|
||||
|
||||
(async () => {
|
||||
const { forEachFeedsCard, addMenuItem } = await import('./feeds-apis')
|
||||
const addExportButton = (card: FeedsCard) => {
|
||||
addMenuItem(card, {
|
||||
className: 'image-export',
|
||||
text: '导出图片',
|
||||
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 thumbMatch = url.match(/^(.+)(\..+?)(@.+)$/)
|
||||
if (!thumbMatch) {
|
||||
return
|
||||
}
|
||||
imageUrls.push({
|
||||
url: thumbMatch[1] + thumbMatch[2],
|
||||
extension: thumbMatch[2],
|
||||
})
|
||||
})
|
||||
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()
|
||||
imageBlobs.forEach((blob, index) => pack.add(`${card.username}-${card.id}-${index}${imageUrls[index].extension}`, blob))
|
||||
await pack.emit(`${card.username}-${card.id}.zip`)
|
||||
},
|
||||
})
|
||||
}
|
||||
forEachFeedsCard({
|
||||
added: addExportButton,
|
||||
})
|
||||
})()
|
||||
@ -967,5 +967,11 @@ Resource.manifest = {
|
||||
unfoldFeeds: '动态反折叠',
|
||||
},
|
||||
},
|
||||
feedsImageExporter: {
|
||||
path: 'feeds-image-exporter.min.js',
|
||||
displayNames: {
|
||||
feedsImageExporter: '动态图片导出',
|
||||
},
|
||||
},
|
||||
}
|
||||
export const resourceManifest = Resource.manifest
|
||||
|
||||
@ -246,6 +246,7 @@ export const settings = {
|
||||
copyFeedsLink: false,
|
||||
copyCommentLink: false,
|
||||
unfoldFeeds: true,
|
||||
feedsImageExporter: false,
|
||||
cache: {},
|
||||
}
|
||||
const fixedSettings = {
|
||||
|
||||
@ -131,6 +131,7 @@
|
||||
<checkbox indent="0" key="disableFeedsDetails" dependencies=""></checkbox>
|
||||
<checkbox indent="0" key="copyFeedsLink" dependencies=""></checkbox>
|
||||
<checkbox indent="0" key="unfoldFeeds" dependencies=""></checkbox>
|
||||
<checkbox indent="0" key="feedsImageExporter" dependencies=""></checkbox>
|
||||
<category icon="video-outline">直播</category>
|
||||
<checkbox indent="0" key="useDefaultLiveQuality" dependencies=""></checkbox>
|
||||
<dropdown indent="1" key="defaultLiveQuality" dependencies="useDefaultLiveQuality"></dropdown>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user