灵猴市集Linghou Market

Gitee 仓库搜索

码云gitee-repo-search

用途 在 Gitee 上按关键词搜索公开仓库,返回仓库名称、所属用户或组织、语言、星标数、Fork 数、简介、最近推送时间和仓库链接。 执行前提 请在 gitee.com 或 so.gitee.com 页面执行。脚本使用搜索页公开 JSON 路径读取结果,不需要登录。 如果当前浏览器页面被 so.gitee.com 的安全验证码拦截,页面内容可能无法正常读…

搜索仓库开发者
版本1.0.0
扫描passed
更新2026-06-28
超时30000ms

匹配范围

*://*.gitee.com/**://so.gitee.com/*

排除范围

未声明

能力声明

dom.read

代码

源码已展开
1return await (async () => {2  const input = params && typeof params === "object" ? params : {};3  const rawQuery = input.query ?? input.keyword;4  const query = typeof rawQuery === "string" ? rawQuery.trim() : String(rawQuery ?? "").trim();5 6  if (!query) {7    throw new Error("参数 query 必填,也兼容 keyword。");8  }9 10  const rawLimit = Number(input.limit ?? 10);11  const limit = Number.isFinite(rawLimit) ? Math.min(Math.max(Math.trunc(rawLimit), 1), 50) : 10;12  const endpoint = new URL("https://api.indexea.com/v1/search/widget/wong1slagnlmzwvsu5ya");13  endpoint.searchParams.set("q", query);14  endpoint.searchParams.set("from", "0");15  endpoint.searchParams.set("size", String(limit));16 17  const response = await fetch(endpoint.toString(), {18    method: "GET",19    headers: { Accept: "application/json" },20    credentials: "omit",21  });22 23  if (!response.ok) {24    throw new Error(`Gitee 搜索接口请求失败:${response.status} ${response.statusText}。如当前页面处于安全验证码或风控策略下,请先用浏览器内执行验证确认接口可读。`);25  }26 27  const payload = await response.json();28  const hits = Array.isArray(payload?.hits?.hits) ? payload.hits.hits : [];29 30  const toList = (value) => {31    if (Array.isArray(value)) return value.map((item) => String(item ?? "").trim()).filter(Boolean);32    if (value === undefined || value === null) return [];33    const text = String(value).trim();34    return text ? [text] : [];35  };36 37  const firstText = (value) => toList(value)[0] ?? "";38  const firstNumber = (value) => {39    const text = firstText(value);40    if (!text) return 0;41    const number = Number(text);42    return Number.isFinite(number) ? number : 0;43  };44 45  const parseRepoUrl = (value) => {46    const text = firstText(value);47    if (!text) return null;48 49    try {50      const url = new URL(text);51      if (url.hostname !== "gitee.com") return null;52 53      const parts = url.pathname.split("/").map((part) => part.trim()).filter(Boolean);54      if (parts.length !== 2) return null;55 56      const owner = decodeURIComponent(parts[0]);57      const repo = decodeURIComponent(parts[1]).replace(/\.git$/i, "");58      if (!owner || !repo) return null;59 60      return {61        owner,62        repo,63        url: `https://gitee.com/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`,64      };65    } catch {66      return null;67    }68  };69 70  return hits71    .map((hit) => hit?.fields ?? {})72    .map((fields) => {73      const repoUrl = parseRepoUrl(fields.url);74      if (!repoUrl) return null;75 76      return {77        name: firstText(fields.title) || `${repoUrl.owner}/${repoUrl.repo}`,78        owner: repoUrl.owner,79        repo: repoUrl.repo,80        language: toList(fields.langs).join(", "),81        stars: firstNumber(fields["count.star"]),82        forks: firstNumber(fields["count.fork"] ?? fields.fork),83        description: firstText(fields.description),84        last_push_at: firstText(fields.last_push_at),85        url: repoUrl.url,86      };87    })88    .filter(Boolean)89    .map((item, index) => ({90      rank: index + 1,91      ...item,92    }));93})();