web.service.ts raw
1 import { TWebMetadata } from '@/types'
2 import DataLoader from 'dataloader'
3
4 class WebService {
5 static instance: WebService
6
7 private proxyUrl(url: string): string {
8 const proxyServer = import.meta.env.VITE_PROXY_SERVER
9 if (proxyServer) {
10 return `${proxyServer}/sites/${encodeURIComponent(url)}`
11 }
12 return url
13 }
14
15 private webMetadataDataLoader = new DataLoader<string, TWebMetadata>(
16 async (urls) => {
17 return await Promise.all(
18 urls.map(async (url) => {
19 try {
20 const res = await fetch(this.proxyUrl(url))
21 const html = await res.text()
22 const parser = new DOMParser()
23 const doc = parser.parseFromString(html, 'text/html')
24
25 const title =
26 doc.querySelector('meta[property="og:title"]')?.getAttribute('content') ||
27 doc.querySelector('title')?.textContent
28 const description =
29 doc.querySelector('meta[property="og:description"]')?.getAttribute('content') ||
30 (doc.querySelector('meta[name="description"]') as HTMLMetaElement | null)?.content
31 const image = (doc.querySelector('meta[property="og:image"]') as HTMLMetaElement | null)
32 ?.content
33
34 return { title, description, image }
35 } catch {
36 return {}
37 }
38 })
39 )
40 },
41 { maxBatchSize: 1 }
42 )
43
44 constructor() {
45 if (!WebService.instance) {
46 WebService.instance = this
47 }
48 return WebService.instance
49 }
50
51 async fetchWebMetadata(url: string) {
52 return await this.webMetadataDataLoader.load(url)
53 }
54 }
55
56 const instance = new WebService()
57
58 export default instance
59