release: v1.1.3 — dual-domain separation and URL options
ci / ci (22, ubuntu-latest) (push) Canceled after 0s
Publish Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Canceled after 0s
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Canceled after 0s
Publish Docker image / merge (push) Canceled after 0s
GitHub Release / release (push) Canceled after 0s

Add admin/image domain separation with host isolation middleware,
optional hide-folder public URLs, GitHub release update check, and
Lucky/Nginx deployment docs. Switch license to GPL-3.0-only.
This commit is contained in:
O96u committed 2026-08-27 12:13:58 +08:00
1 parent 55effa204e
commit d8c1303c32
41 files changed
+2170 -299

No files matched your search

+77
View File
@@ -0,0 +1,77 @@
const GITHUB_REPO = 'O96u/PicHost'
const RELEASES_LATEST_URL = `https://api.github.com/repos/${GITHUB_REPO}/releases/latest`
const CACHE_TTL_MS = 60 * 60 * 1000
export interface LatestReleaseInfo {
latestVersion: string
releaseUrl: string
}
let cachedRelease: { fetchedAt: number, value: LatestReleaseInfo | null } | null = null
export function normalizeVersionTag(tag: string): string {
return tag.trim().replace(/^v/i, '')
}
export function parseVersionParts(version: string): number[] {
return normalizeVersionTag(version)
.split('.')
.map(part => Number.parseInt(part, 10))
.map(part => (Number.isFinite(part) ? part : 0))
}
export function isVersionNewer(candidate: string, current: string): boolean {
const a = parseVersionParts(candidate)
const b = parseVersionParts(current)
const length = Math.max(a.length, b.length)
for (let i = 0; i < length; i++) {
const diff = (a[i] ?? 0) - (b[i] ?? 0)
if (diff !== 0) return diff > 0
}
return false
}
export async function fetchLatestGitHubRelease(): Promise<LatestReleaseInfo | null> {
const now = Date.now()
if (cachedRelease && now - cachedRelease.fetchedAt < CACHE_TTL_MS) {
return cachedRelease.value
}
try {
const response = await fetch(RELEASES_LATEST_URL, {
headers: {
'Accept': 'application/vnd.github+json',
'User-Agent': 'PicHost'
},
signal: AbortSignal.timeout(8000)
})
if (!response.ok) {
cachedRelease = { fetchedAt: now, value: null }
return null
}
const data = await response.json() as {
tag_name?: string
html_url?: string
}
const tag = typeof data.tag_name === 'string' ? data.tag_name : ''
const releaseUrl = typeof data.html_url === 'string' ? data.html_url : ''
if (!tag) {
cachedRelease = { fetchedAt: now, value: null }
return null
}
const value: LatestReleaseInfo = {
latestVersion: normalizeVersionTag(tag),
releaseUrl: releaseUrl || `https://github.com/${GITHUB_REPO}/releases/latest`
}
cachedRelease = { fetchedAt: now, value }
return value
} catch {
cachedRelease = { fetchedAt: now, value: null }
return null
}
}