diff --git a/ghproxy/public/search.html b/ghproxy/public/search.html index dacd6b3..3cff243 100644 --- a/ghproxy/public/search.html +++ b/ghproxy/public/search.html @@ -670,7 +670,13 @@ card.addEventListener('click', () => { currentRepo = result; - loadTags(result.is_official ? 'library' : (result.repo_owner || ''), name); + const namespace = result.namespace || (result.is_official ? 'library' : ''); + const repoName = result.name || result.repo_name; + if (!namespace || !repoName) { + showToast('无效的仓库信息'); + return; + } + loadTags(namespace, repoName); }); resultsContainer.appendChild(card); @@ -681,23 +687,18 @@ showLoading(); try { console.log('加载标签:', namespace, name); - if (!name) { - showToast('镜像名称不能为空'); + if (!namespace || !name) { + showToast('命名空间和镜像名称不能为空'); return; } - // 处理官方镜像 - if (currentRepo.is_official) { - namespace = 'library'; - } - - const response = await fetch(`/tags/${namespace}/${name}`); - const data = await response.json(); - + const response = await fetch(`/tags/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}`); if (!response.ok) { - throw new Error(data.error || '获取标签信息失败'); + const errorText = await response.text(); + throw new Error(errorText || '获取标签信息失败'); } + const data = await response.json(); console.log('标签数据:', data); displayTags(data); showTagList(); @@ -711,24 +712,28 @@ function displayTags(tags) { const tagList = document.getElementById('tagList'); - const repoName = currentRepo.repo_name; + const namespace = currentRepo.namespace || (currentRepo.is_official ? 'library' : ''); + const repoName = currentRepo.name || currentRepo.repo_name; + const fullRepoName = namespace ? `${namespace}/${repoName}` : repoName; let header = `
- ${repoName} + ${fullRepoName} ${currentRepo.is_official ? '官方' : ''} + ${currentRepo.affiliation ? `By ${currentRepo.affiliation}` : ''} ${currentRepo.is_automated ? '自动构建' : ''}
${currentRepo.short_description || '暂无描述'}
${currentRepo.star_count > 0 ? `⭐ ${formatNumber(currentRepo.star_count)}` : ''} ${currentRepo.pull_count > 0 ? `⬇️ ${formatNumber(currentRepo.pull_count)}` : ''} + ${currentRepo.last_updated ? `更新于 ${formatTimeAgo(currentRepo.last_updated)}` : ''}
- docker pull ${repoName} - + docker pull ${fullRepoName} +
@@ -758,8 +763,8 @@ ${tag.full_size ? `大小: ${formatSize(tag.full_size)}` : ''}
- docker pull ${repoName}:${tag.name} - + docker pull ${fullRepoName}:${tag.name} +
${architectures ? `
${architectures}
` : ''} diff --git a/ghproxy/search.go b/ghproxy/search.go index 17f72d2..75b94ae 100644 --- a/ghproxy/search.go +++ b/ghproxy/search.go @@ -35,6 +35,7 @@ type Repository struct { Status int `json:"status"` Organization string `json:"affiliation"` PullsLastWeek int `json:"pulls_last_week"` + Namespace string `json:"namespace"` } // TagInfo 标签信息 @@ -158,25 +159,40 @@ func searchDockerHub(ctx context.Context, query string, page, pageSize int) (*Se i, repo.Name, repo.RepoOwner, repo.Description, repo.IsOfficial) } + // 处理搜索结果 + for i := range result.Results { + // 从 repo_name 中提取 namespace + if !result.Results[i].IsOfficial { + parts := strings.Split(result.Results[i].Name, "/") + if len(parts) > 1 { + result.Results[i].Namespace = parts[0] + result.Results[i].Name = parts[1] + } else { + result.Results[i].Namespace = result.Results[i].RepoOwner + } + } else { + result.Results[i].Name = strings.TrimPrefix(result.Results[i].Name, "library/") + result.Results[i].Namespace = "library" + } + } + setCacheResult(cacheKey, &result) return &result, nil } // getRepositoryTags 获取仓库标签信息 func getRepositoryTags(ctx context.Context, namespace, name string) ([]TagInfo, error) { + if namespace == "" || name == "" { + return nil, fmt.Errorf("无效输入:命名空间和名称不能为空") + } + cacheKey := fmt.Sprintf("tags:%s:%s", namespace, name) if cached, ok := getCachedResult(cacheKey); ok { return cached.([]TagInfo), nil } // 构建API URL - var baseURL string - if namespace == "library" { - baseURL = fmt.Sprintf("https://registry.hub.docker.com/v2/repositories/library/%s/tags", name) - } else { - baseURL = fmt.Sprintf("https://registry.hub.docker.com/v2/repositories/%s/%s/tags", namespace, name) - } - + baseURL := fmt.Sprintf("https://registry.hub.docker.com/v2/repositories/%s/%s/tags", namespace, name) params := url.Values{} params.Set("page_size", "100") params.Set("ordering", "last_updated")