From f7f771ecc0b15ac33fdcd1f915a585b9920e205f Mon Sep 17 00:00:00 2001 From: Chilfish Date: Thu, 29 Feb 2024 01:50:28 +0800 Subject: [PATCH] fix(web): enable cdn remote image in preview --- package.json | 1 + packages/core/src/utils/image.ts | 28 ++++++++++++++++++++++++++++ packages/core/src/utils/index.ts | 11 +++++++++++ packages/core/src/utils/parse.ts | 30 ++++++++---------------------- packages/ui/src/MainHeader.vue | 9 +++++++++ packages/ui/src/MainImage.vue | 7 +++++++ packages/ui/src/post/Meta.vue | 22 ++++++++++++++++++++-- pnpm-lock.yaml | 19 +++++++++++-------- 8 files changed, 95 insertions(+), 32 deletions(-) create mode 100644 packages/core/src/utils/image.ts diff --git a/package.json b/package.json index 385eaff..c9a35b7 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ }, "dependencies": { "@vueuse/core": "^10.8.0", + "destr": "^2.0.3", "pinia": "^2.1.7", "vue": "^3.4.19", "vue-router": "^4.3.0" diff --git a/packages/core/src/utils/image.ts b/packages/core/src/utils/image.ts new file mode 100644 index 0000000..2897e11 --- /dev/null +++ b/packages/core/src/utils/image.ts @@ -0,0 +1,28 @@ +import { imgCdn, imgViewSrc } from '../constants' +import { storage } from './index' + +/** + * 将图片的远程 url 替换为本地图片 + * 格式:域名-文件名 + */ +export function replaceImg(img: string) { + if (!img) + return imgViewSrc + + if (img.includes('data:image') || img.startsWith(imgCdn)) + return img + + const useCdn = storage('useCdn', false) + + if (useCdn) { + const { pathname } = new URL(img) + return `https://cdn.ipfsscan.io/weibo${pathname}` + } + + const name = img.split('/').pop()?.replace(/\?.+/, '') // 同时去除 params + const prefix = img.match(/^(?:https?:\/\/)?([^:\/\n]+)/im)?.[1] // 域名 + + if (!prefix || !name) + return img + return `/assets/img/${prefix}-${name}` +} diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 01ff9f0..c4c43c9 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -1,9 +1,11 @@ +import { destr } from 'destr' import type { FetchOptions } from '@types' export * from './parse' export * from './dom' export * from './protocol' export * from './fetch' +export * from './image' export const isElectron = import.meta.env.VITE_IS_ELECTRON === 'true' @@ -11,6 +13,15 @@ export const isInMonkey = typeof document !== 'undefined' ? document.URL.include export const referrerPolicy = isInMonkey ? 'origin' : 'no-referrer' +export function storage(key: string, defaultVal: T) { + const str = localStorage.getItem(key) + if (str === null) { + localStorage.setItem(key, JSON.stringify(defaultVal)) + return defaultVal + } + return destr(str) +} + export function delay(ms = 2000) { const randomMs = Math.random() * ms + 1000 return new Promise(resolve => setTimeout(resolve, randomMs)) diff --git a/packages/core/src/utils/parse.ts b/packages/core/src/utils/parse.ts index 5905660..858d4f9 100644 --- a/packages/core/src/utils/parse.ts +++ b/packages/core/src/utils/parse.ts @@ -1,7 +1,12 @@ -import type { CardInfo, Comment, FetchOptions, ParseResult, PicInfo, Post } from '@types' +import type { + CardInfo, + Comment, + FetchOptions, + ParseResult, + PicInfo, + Post, +} from '@types' import { fetchComments, fetchLongText } from '../services' -import { imgViewSrc } from '../constants' -import { imgCdn } from './../constants/index' import { getOptions } from '.' export const weibo = 'https://weibo.com' @@ -34,25 +39,6 @@ export function parseText(text?: string) { return parsed } -/** - * 将图片的远程 url 替换为本地图片 - * 格式:域名-文件名 - */ -export function replaceImg(img?: string) { - if (!img) - return imgViewSrc - - if (img.includes('data:image') || img.startsWith(imgCdn)) - return img - - const name = img.split('/').pop()?.replace(/\?.+/, '') // 同时去除 params - const prefix = img.match(/^(?:https?:\/\/)?([^:\/\n]+)/im)?.[1] // 域名 - - if (!prefix || !name) - return img - return `/assets/img/${prefix}-${name}` -} - /** * 提取原图链接 */ diff --git a/packages/ui/src/MainHeader.vue b/packages/ui/src/MainHeader.vue index 909861f..fed9904 100644 --- a/packages/ui/src/MainHeader.vue +++ b/packages/ui/src/MainHeader.vue @@ -19,6 +19,7 @@ const headerStyle = computed(() => { const router = useRouter() const route = useRoute() const searchInput = ref(route.query?.q?.toString() || '') +const useLocalImage = useStorage('useCdn', false) async function search() { const res = await usePostStore().searchText(searchInput.value) @@ -56,6 +57,14 @@ onMounted(() => { > + +
+ 使用远程图片 + +
+ diff --git a/packages/ui/src/MainImage.vue b/packages/ui/src/MainImage.vue index f5ec6b8..8688be9 100644 --- a/packages/ui/src/MainImage.vue +++ b/packages/ui/src/MainImage.vue @@ -16,6 +16,13 @@ const props = withDefaults(defineProps<{ const realSrc = ref(props.src) const imgRef = ref() const disconnectFn = ref<() => void>() +const useCdn = useStorage('useCdn', false) + +watch(useCdn, () => { + realSrc.value = replaceImg(props.src) + imgRef.value.imageRef.src = realSrc.value + imgRef.value.imageRef.parentElement.classList.remove('img-error') +}) onMounted(() => { const img = imgRef.value.imageRef as HTMLImageElement diff --git a/packages/ui/src/post/Meta.vue b/packages/ui/src/post/Meta.vue index 8bc671e..c8eece4 100644 --- a/packages/ui/src/post/Meta.vue +++ b/packages/ui/src/post/Meta.vue @@ -1,5 +1,6 @@