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 = `
@@ -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")