Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
NODE_OPTIONS=--network-family-autoselection-attempt-timeout=5000

DRIVE_IMAGE_CDN=https://coscup-2025-drive-cache.b-cdn.net/
PRETALX_BASE_URL=
PRETALX_TOKEN=
VITE_API_KEY=
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 5 additions & 16 deletions loaders/community.data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { defineLoader, loadEnv } from 'vitepress'
import { getDriveImage } from './utils'

// API 設定
const env = loadEnv('', process.cwd())
Expand Down Expand Up @@ -50,18 +51,6 @@ interface Booths {
'trackroom': string
}

// 處理 Google Drive 圖片
async function getDriveImageThumbnail(imageUrl: string): Promise<string> {
if (!imageUrl) {
return ''
}

const getImageID = imageUrl.match(/\/d\/([^/]+)\//)
const imageID = getImageID ? getImageID[1] : null

return `https://drive.google.com/thumbnail?id=${imageID}`
}

// 取得 Google Sheets 資料
async function fetchCommunities(): Promise<Community[]> {
try {
Expand All @@ -82,10 +71,10 @@ async function fetchCommunities(): Promise<Community[]> {
}), {} as Community),
)

return Promise.all(communities.map(async (communities) => ({
...communities,
image: await getDriveImageThumbnail(communities.image),
})))
return communities.map((community) => ({
...community,
image: getDriveImage(community.image),
}))
} catch (error) {
console.error('Error fetching communities:', error)
return []
Expand Down
8 changes: 4 additions & 4 deletions loaders/sponsor-news.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ async function fetchSponsorsNews(): Promise<SponsorNews[]> {
}), {} as SponsorNews))
.filter((sponsor) => sponsor.sponsorId && sponsor.canPublish === 'Y')

return await Promise.all(sponsors.map(async (sponsor) => ({
return sponsors.map((sponsor) => ({
...sponsor,
'image:horizontal': await getDriveImage(sponsor['image:horizontal']) || '',
'image:vertical': await getDriveImage(sponsor['image:vertical']) || '',
})))
'image:horizontal': getDriveImage(sponsor['image:horizontal']),
'image:vertical': getDriveImage(sponsor['image:vertical']),
}))
} catch (error) {
console.error('Error fetching sponsors:', error)
return []
Expand Down
7 changes: 3 additions & 4 deletions loaders/sponsor.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,10 @@ async function fetchSponsors(): Promise<Sponsor[]> {
}), {} as Sponsor))
.filter((sponsor) => sponsor.id && sponsor.canPublish === 'Y')

// Replace image URLs with actual image content
return Promise.all(sponsors.map(async (sponsor) => ({
return sponsors.map((sponsor) => ({
...sponsor,
image: await getDriveImage(sponsor.image),
})))
image: getDriveImage(sponsor.image),
}))
} catch (error) {
console.error('Error fetching sponsors:', error)
return []
Expand Down
55 changes: 22 additions & 33 deletions loaders/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { conference } from '../data/conference.ts'

interface GoogleSheetResponse {
majorDimension: string
range: string
Expand Down Expand Up @@ -47,43 +49,30 @@ export async function getGoogleSheet<SheetRow extends Record<string, string>>({
}

/**
* The CDN URL for Google Drive images.
*
* If you want to self-host this, you might need to set up a
* [image-compress-server](https://github.com/COSCUP/image-compress-server)
* instance and point the `DRIVE_IMAGE_CDN` environment variable to it.
* Extract the Google Drive file ID from a share URL like
* `https://drive.google.com/file/d/{ID}/view`.
*
* Set this value to `https://drive.google.com/uc?export=view&id=` to
* use the Google Drive URL directly if you don't prefer a CDN.
* @param imageUrl The Google Drive share URL.
* @returns The file ID, or `null` if the URL is not in the expected shape.
*/
const driveImageCdn = process.env.DRIVE_IMAGE_CDN || 'https://coscup-2025-drive-cache.b-cdn.net/'
export function extractDriveId(imageUrl: string): string | null {
if (!imageUrl) return null
const match = imageUrl.match(/\/d\/([^/]+)\//)
return match ? match[1] : null
}

/**
* Get the optimized Google Drive image URL.
* Map a Google Drive share URL to the local WebP asset path produced by
* `scripts/assets-download.ts`. Includes the VitePress `base` prefix
* (`/${conference.year}`) so the path resolves correctly when the site is
* deployed under a subpath. Run the download script to refresh the files in
* `content/public/assets/drive/` after the source Google Sheets change.
*
* @param imageUrl The URL of the Google Drive image.
* @returns The absolute path to the optimized image.
* @param imageUrl The Google Drive share URL.
* @returns The absolute site path to the local WebP, or `''` if `imageUrl` is empty
* or unrecognized.
*/
export async function getDriveImage(imageUrl: string): Promise<string> {
if (!imageUrl) {
return ''
}

const getImageID = imageUrl.match(/\/d\/([^/]+)\//)
const imageID = getImageID ? getImageID[1] : null

const optimizedImageUrl = `${driveImageCdn}${imageID}`

// preload this image so it will be cached, since the
// optimization usually takes 2+ seconds to complete
try {
const response = await fetch(optimizedImageUrl)
if (!response.ok) {
console.error(`Failed to preload image: ${response.statusText}`)
}
} catch (error) {
console.error('Failed to preload image:', error)
}

return optimizedImageUrl
export function getDriveImage(imageUrl: string): string {
const id = extractDriveId(imageUrl)
return id ? `/${conference.year}/assets/drive/${id}.webp` : ''
}
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"#*": "./*"
},
"engines": {
"node": ">=22.14.0"
"node": ">=22.18.0"
},
"scripts": {
"gen:pretalx": "openapi-ts",
Expand All @@ -16,7 +16,8 @@
"prepare": "husky",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"type-check": "vue-tsc"
"type-check": "vue-tsc",
"assets:download": "env-cmd -- node scripts/assets-download.ts"
Comment thread
pan93412 marked this conversation as resolved.
},
"dependencies": {
"@iconify-json/fa-brands": "1.2.2",
Expand Down Expand Up @@ -46,6 +47,7 @@
"eslint-plugin-format": "1.0.2",
"husky": "9.1.7",
"lint-staged": "16.2.3",
"sharp": "0.34.5",
"typescript": "5.9.3",
"vite": "7.1.9",
"vue-tsc": "3.1.0"
Expand All @@ -54,7 +56,8 @@
"onlyBuiltDependencies": [
"vue-demi",
"unrs-resolver",
"esbuild"
"esbuild",
"sharp"
]
},
"lint-staged": {
Expand Down
Loading
Loading