修复离线镜像下载

This commit is contained in:
user123456
2025-06-12 13:43:25 +08:00
parent 27834e5140
commit d503e0036b
2 changed files with 69 additions and 6 deletions

View File

@@ -894,15 +894,21 @@
function createResultCard(result) {
const card = document.createElement('div');
card.className = 'result-card';
card.onclick = () => viewImageTags(result.repo_name || result.name);
card.onclick = () => viewImageTags(result.repo_name || result.name, result.is_official);
const badges = [];
if (result.is_official) badges.push('<span class="badge badge-official">官方</span>');
if (result.is_automated) badges.push('<span class="badge badge-automated">自动构建</span>');
// 只有真正的官方镜像才去掉 library/ 前缀
const originalName = result.repo_name || result.name;
const displayName = (result.is_official && originalName.startsWith('library/'))
? originalName.substring(8)
: originalName;
card.innerHTML = `
<div class="result-title">
🐳 ${result.repo_name || result.name}
🐳 ${displayName}
${badges.join('')}
</div>
<div class="result-description">
@@ -926,7 +932,7 @@
}
// 查看镜像标签
async function viewImageTags(imageName) {
async function viewImageTags(imageName, isOfficial = false) {
if (isLoading) return;
isLoading = true;
@@ -952,7 +958,7 @@
if (Array.isArray(data)) {
allTags = data;
displayImageTags(imageName, data);
displayImageTags(imageName, data, isOfficial);
elements.backToSearch.classList.add('show');
} else {
showToast('获取标签失败:' + (data.error || '未知错误'), 'error');
@@ -967,12 +973,17 @@
}
// 显示镜像标签
function displayImageTags(imageName, tags) {
function displayImageTags(imageName, tags, isOfficial = false) {
const fullDomain = window.location.host;
// 只有真正的官方镜像才去掉 library/ 前缀
const displayName = (isOfficial && imageName.startsWith('library/'))
? imageName.substring(8)
: imageName;
elements.tagInfo.innerHTML = `
<div class="tag-title">
🐳 ${imageName}
🐳 ${displayName}
</div>
<div class="tag-description">
${tags.length} 个标签版本

View File

@@ -110,6 +110,9 @@ func initSkopeoRoutes(router *gin.Engine) {
// 下载文件
router.GET("/api/files/:filename", serveFile)
// 通过任务ID下载文件
router.GET("/api/download/:taskId/file", serveFileByTaskId)
// 启动清理过期文件的goroutine
go cleanupTempFiles()
@@ -1059,6 +1062,55 @@ func sendTaskUpdate(task *DownloadTask) {
}
}
// 通过任务ID提供文件下载
func serveFileByTaskId(c *gin.Context) {
taskID := c.Param("taskId")
tasksLock.Lock()
task, exists := tasks[taskID]
tasksLock.Unlock()
if !exists {
c.JSON(http.StatusNotFound, gin.H{"error": "任务不存在"})
return
}
// 确保任务状态为已完成
task.StatusLock.RLock()
isCompleted := task.Status == StatusCompleted
task.StatusLock.RUnlock()
if !isCompleted {
c.JSON(http.StatusBadRequest, gin.H{"error": "任务尚未完成"})
return
}
// 确保所有进度都是100%
ensureTaskCompletion(task)
// 检查文件是否存在
filePath := task.OutputFile
if filePath == "" || !fileExists(filePath) {
c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
return
}
// 获取文件信息
fileInfo, err := os.Stat(filePath)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "无法获取文件信息"})
return
}
// 设置文件名
downloadName := filepath.Base(filePath)
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", downloadName))
c.Header("Content-Length", fmt.Sprintf("%d", fileInfo.Size()))
// 返回文件
c.File(filePath)
}
// 提供文件下载
func serveFile(c *gin.Context) {
filename := c.Param("filename")