跳到主要内容

2 篇博文 含有标签「github」

查看所有标签

获取 winget 的软件清单

· 阅读需 4 分钟
1adybug
子虚伊人

winget 的所有软件清单都保存在 manifests 目录中。下一层的目录便是软件作者名称的首字母,比如 Google.Chrome 便是保存在 manifests/g 目录中 接下来使用 GitHub REST API 获取目录即可:

import fetch from "node-fetch"
import YAML from "yaml"

export namespace Winget {
export interface Package {
PackageIdentifier: string
PackageVersion: string
InstallerType: string
InstallModes: string[]
InstallerSwitches: InstallerSwitches
ExpectedReturnCodes: ExpectedReturnCode[]
UpgradeBehavior: string
Protocols: string[]
FileExtensions: string[]
AppsAndFeaturesEntries: AppsAndFeaturesEntry[]
Installers: Installer[]
ManifestType: string
ManifestVersion: string
}

export interface Installer {
Architecture: string
Scope: string
InstallerUrl: string
InstallerSha256: string
InstallerSwitches: InstallerSwitches2
ProductCode: string
}

export interface InstallerSwitches2 {
Custom: string
}

export interface AppsAndFeaturesEntry {
UpgradeCode: string
InstallerType: string
}

export interface ExpectedReturnCode {
InstallerReturnCode: number
ReturnResponse: string
}

export interface InstallerSwitches {
Log: string
}
}

export type WingetDownloadInfo = {
name: string
id: string
dir: string
architecture?: "x64" | "x86" | "all"
}

export interface GithubContent {
name: string
path: string
sha: string
size: number
url: string
html_url: string
git_url: string
download_url?: string | null
type: string
_links: Links
}

export interface Links {
self: string
git: string
html: string
}

export type WingetItem = {
filename: string
version: string
ext: string
architecture: string
}

export async function downloadFromWinget({ name, id, dir, architecture = "x64" }: WingetDownloadInfo) {
const firstLetter = id[0].toLowerCase()
const path = id.replace(/\./g, "/")
const response = await fetch(`https://api.github.com/repos/microsoft/winget-pkgs/contents/manifests/${firstLetter}/${path}`, { agent })
const data: GithubContent[] = (await response.json()) as any
const reg2 = /^\d+(\.\d+?)*$/
const stables = data.filter(item => reg2.test(item.name))

stables.sort((a, b) => {
const avs = a.name.split(".")
const bvs = b.name.split(".")
const max = Math.max(avs.length, bvs.length)

for (let i = 0; i < max; i++) {
const av = avs[i] ? parseInt(avs[i]) : 0
const bv = bvs[i] ? parseInt(bvs[i]) : 0
if (av < bv) return 1
if (av > bv) return -1
}

return 0
})

const response2 = await fetch(
`https://raw.githubusercontent.com/microsoft/winget-pkgs/master/manifests/${firstLetter}/${path}/${stables[0].name}/${id}.installer.yaml`,
{ agent },
)
const yaml = await response2.text()
const pkg: Winget.Package = YAML.parse(yaml)

const installers = pkg.Installers.filter((item, index) => {
if (item.Architecture !== "x64" && item.Architecture !== "x86") return false
if (architecture !== "all" && item.Architecture !== architecture) return false
if (!item.InstallerUrl.endsWith(".exe") && !item.InstallerUrl.endsWith(".msi")) return false
if (item.InstallerUrl.endsWith(".msi") && pkg.Installers.some(item2 => item2.Architecture === item.Architecture && item2.InstallerUrl.endsWith(".exe")))
return false
if (pkg.Installers.findIndex(item2 => item2.Architecture === item.Architecture) !== index) return false
return true
})

const result: WingetItem[] = []

for (const { InstallerUrl, Architecture } of installers) {
if (Architecture !== "x64" && Architecture !== "x86") continue
const filename = await download(InstallerUrl, dir)

result.push({
filename,
version: pkg.PackageVersion,
ext: InstallerUrl.endsWith(".exe") ? "exe" : "msi",
architecture: Architecture,
})
}

for (const { version, filename, architecture, ext } of result) {
await sleep(100)
await rename(join(dir, filename), join(dir, `${name}_${version}_${architecture}.${ext}`))
}
}
提示
  • 使用 YAML 来将 YAML 文件格式化为 JSON
  • InstallerScope 字段有两个可能的值:usermachine
    • user:当 Scope 被设置为 user 时,意味着安装操作仅针对当前用户进行。安装的程序或者应用将仅对当前用户可用,安装的结果(如程序文件和快捷方式)将被存储在用户的个人目录下(例如,在 Windows 系统中可能是 C:\Users\[用户名]\ 下的某个目录),并且只有当前用户有权限运行或修改。这种安装方式不需要管理员权限,但安装的程序只能由安装它的用户使用。
    • machine:当 Scope 被设置为 machine 时,表明安装是针对整个系统进行的,安装的程序或应用将对所有用户可用。这通常意味着程序会被安装在系统级的目录下(例如,在 Windows 系统中可能是 C:\Program Files\),并且安装、运行或修改程序可能需要管理员权限。这种安装方式确保了所有使用该机器的用户都可以访问到安装的程序。
注意
  • 由于国内的网络环境限制,可能需要为 fetch 配置代理
  • 示例函数对于版本号使用了 ^\d+(\.\d+?)*$ 正则表达式进行了过滤,也就是只接受 数字.数字.数字... 形式的版本
  • 示例函数的返回结果并不一定严格符合 Winget.Package 类型,只是以 Google.Chrome 为例

使用接口的方式获取 Github 项目的目录

· 阅读需 2 分钟
1adybug
子虚伊人

要使用 API 的方式获取 GitHub 地址中某个特定目录的内容,可以通过 GitHub 的 REST API 实现。下面是一个基本的步骤指南:

获取仓库内容:使用 GitHub REST API 的 /repos/{owner}/{repo}/contents/{path} 可以获取仓库中特定路径的内容。这里的 {owner} 是仓库拥有者的用户名,{repo} 是仓库名,而 {path} 是你想要获取内容的目录路径。

认证:对于公共仓库,你可能不需要认证就可以请求这个 API。但是,对于私有仓库,你需要使用 OAuth token 或者其他形式的认证。

解析响应:API 的响应将以 JSON 格式返回,包含目录下的文件和子目录列表。你可以解析这个 JSON 来获取你需要的信息。

示例:

假设我们想要获取 GitHub 上 octocat/Hello-World 仓库根目录下的 lib 目录的内容。使用 curl 命令,请求看起来可能像这样:

curl https://api.github.com/repos/octocat/Hello-World/contents/lib

如果需要认证,可以在请求中添加 HTTP 头 Authorization: token YOUR_TOKEN,如下所示:

curl -H "Authorization: token YOUR_TOKEN" https://api.github.com/repos/octocat/Hello-World/contents/lib
注意
  • 确保替换 YOUR_TOKEN 为你的实际 GitHub 访问令牌。
  • 如果目录很大或有很多文件,GitHub 的 API 可能会进行分页处理。这种情况下,你可能需要处理分页逻辑,通过检查响应头中的 Link 字段来获取下一页数据。
  • 为了避免过度使用 API 并受到限制,注意检查并遵守 GitHub 的速率限制政策。

通过这种方式,你可以轻松地编程访问 GitHub 上任何公开或私有仓库的目录和文件内容。