aardio 文档
aardio 范例: GitHub API
import win.ui;
import fonts.fontAwesome;
import web.rest.github;
import web.form.simpleMarkdown;
/*DSG{{*/
var winform = win.form(text="GitHub 助手";right=1000;bottom=680;bgcolor=0xFAFAFA;border="none")
winform.add(
btnQuery={cls="plus";text='\uF002 查询';left=770;top=78;right=920;bottom=118;bgcolor=0x4FA42E;border={radius=8};color=0xFFFFFF;dr=1;dt=1;font=LOGFONT(h=-15;name='FontAwesome';weight=600);notify=1;z=6};
cmbMirrors={cls="combobox";left=110;top=135;right=561;bottom=161;dl=1;dt=1;edge=1;font=LOGFONT(h=-14);hscroll=1;items={};mode="dropdown";vscroll=1;z=8};
custom={cls="custom";left=20;top=180;right=980;bottom=660;bgcolor=0xFFFFFF;db=1;dl=1;dr=1;dt=1;z=10};
editUrl={cls="plus";left=110;top=78;right=750;bottom=118;align="left";bgcolor=0xFFFFFF;border={color=0xD0D0D0;radius=8;width=1};dl=1;dr=1;dt=1;editable=1;font=LOGFONT(h=-14);iconColor=0x969696;iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome');padding={left=10}};iconText='\uF002';textPadding={left=40;top=10;right=12;bottom=10};z=5};
iconGithub={cls="bkplus";text='\uF09B';left=20;top=12;right=52;bottom=44;color=0xFFFFFF;dl=1;dt=1;font=LOGFONT(h=-24;name='FontAwesome');z=2};
lblMirrors={cls="plus";text="优选镜像:";left=20;top=135;right=105;bottom=161;align="right";color=0x505050;dl=1;dt=1;font=LOGFONT(h=-13;weight=600);z=7};
lblUrl={cls="plus";text="项目地址:";left=20;top=78;right=105;bottom=118;align="right";color=0x505050;dl=1;dt=1;font=LOGFONT(h=-13;weight=600);z=4};
mirrorStatus={cls="plus";left=589;top=133;right=918;bottom=159;align="left";color=0x808080;dl=1;dr=1;dt=1;font=LOGFONT(h=-14);iconStyle={align="left";font=LOGFONT(name='FontAwesome')};textPadding={left=21};z=9};
titleBar={cls="bkplus";left=0;top=0;right=1002;bottom=60;bgcolor=0x3D2817;dl=1;dr=1;dt=1;z=1};
titleText={cls="bkplus";text="GitHub 助手";left=56;top=16;right=300;bottom=44;align="left";color=0xFFFFFF;dl=1;dt=1;font=LOGFONT(h=-20;weight=700);z=3}
)
/*}}*/
var wb = web.form.simpleMarkdown(winform.custom)
wb.translate = function( url ){
if(!string.find(url,"<releases/download>|<\.zip!>|<\.gz!>|<\.7z!>")){
return url;
}
var mirrorUrl = winform.cmbMirrors.selText || "";
if(#mirrorUrl) return mirrorUrl + "/" + url;
}
// 添加无边框窗口的标题栏按钮
import win.ui.simpleWindow;
win.ui.simpleWindow(winform);
winform.show();
// 格式化日期
var formatDate = function(dateStr) {
if(!dateStr) return "未知";
var y, m, d, h, mi, s = string.match(dateStr, "(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)");
if(y) return string.format("%s-%s-%s %s:%s:%s", y, m, d, h, mi, s);
return dateStr;
}
winform.editUrl.setCueBannerText("请输入 用户名/项目名 或 GitHub 项目或文件网址");
// 支持回车查询
winform.editUrl.editBox.onOk = function(ctrl,alt,shift){
winform.btnQuery.oncommand();
return true;
}
// 生成 Markdown
var generateMarkdown = function(info) {
var md = {};
table.push(md, "# 📦 " + info.fullName);
table.push(md, "");
if(info.description) {
table.push(md, "> " + info.description);
table.push(md, "");
}
table.push(md, "---");
table.push(md, "");
// 基本统计
table.push(md, "## 📊 项目统计");
table.push(md, "");
table.push(md, "| 指标 | 数值 | 指标 | 数值 |");
table.push(md, "|:----:|:----:|:----:|:----:|");
table.push(md, "| ⭐ Stars | **" + tostring(info.stars) + "** | 🍴 Forks | **" + tostring(info.forks) + "** |");
table.push(md, "| 👀 Watchers | **" + tostring(info.watchers) + "** | 🐛 Issues | **" + tostring(info.openIssues) + "** |");
table.push(md, "| 👥 Contributors | **" + tostring(info.contributorCount) + "** | 📦 Size | **" + string.format("%.2f MB", info.size/1024) + "** |");
table.push(md, "");
// 项目详情
table.push(md, "## 📋 项目详情");
table.push(md, "");
table.push(md, "| 属性 | 信息 |");
table.push(md, "|------|------|");
table.push(md, "| 📜 开源协议 | " + info.license + " |");
table.push(md, "| 🌿 默认分支 | `" + info.defaultBranch + "` |");
if(info.language) table.push(md, "| 🔤 主要语言 | " + info.language + " |");
if(info.homepage && #info.homepage) {
table.push(md, "| 🏠 项目主页 | [" + info.homepage + "](" + info.homepage + ") |");
}
table.push(md, "| 🔗 GitHub | [" + info.htmlUrl + "](" + info.htmlUrl + ") |");
table.push(md, "");
if(info.fork) {
table.push(md, "> ⚠️ 这是一个 Fork 项目");
table.push(md, "");
}
if(info.archived) {
table.push(md, "> 📦 该项目已归档(只读)");
table.push(md, "");
}
// 标签
if(info.topics && #info.topics > 0) {
table.push(md, "## 🏷️ 标签");
table.push(md, "");
var topicStr = "";
for(i, topic in info.topics) {
topicStr = topicStr + "`" + topic + "` ";
}
table.push(md, topicStr);
table.push(md, "");
}
// 语言统计
if(info.languages && table.count(info.languages) > 0) {
table.push(md, "## 💻 编程语言占比");
table.push(md, "");
var total = 0;
for(lang, bytes in info.languages) {
total = total + bytes;
}
var langs = {};
for(lang, bytes in info.languages) {
table.push(langs, { name = lang; bytes = bytes; percent = bytes / total * 100 });
}
table.sort(langs, function(next) { return owner.bytes > next.bytes; });
table.push(md, "| 语言 | 占比 | 语言 | 占比 |");
table.push(md, "|:----:|:----:|:----:|:----:|");
for(i = 1; #langs; 2) {
var l1 = langs[i];
var l2 = langs[i + 1];
var row = "| " + l1.name + " | " + string.format("%.1f%%", l1.percent) + " |";
if(l2) {
row = row + " " + l2.name + " | " + string.format("%.1f%%", l2.percent) + " |";
} else {
row = row + " - | - |";
}
table.push(md, row);
}
table.push(md, "");
}
// 时间信息
table.push(md, "## 📅 时间线");
table.push(md, "");
table.push(md, "| 事件 | 时间 |");
table.push(md, "|------|------|");
table.push(md, "| 🎉 仓库创建 | " + formatDate(info.createdAt) + " |");
if(info.firstCommit) {
table.push(md, "| 📝 首次提交 | " + formatDate(info.firstCommit.date)
+ "[`" + string.left(info.firstCommit.sha, 7) + "` " + info.firstCommit.author + "](" + (info.htmlUrl + "/commit/" + info.firstCommit.sha) + ") |");
table.push(md, "| 📊 总提交数 | **" + tostring(info.firstCommit.totalCommits) + "** 次 |");
}
table.push(md, "| 🔄 最后更新 | " + formatDate(info.updatedAt) + " |");
table.push(md, "| 🚀 最后推送 | " + formatDate(info.pushedAt) + " |");
table.push(md, "");
// Star 历史图
table.push(md, "## ⭐ Star 历史趋势");
table.push(md, "");
table.push(md, "");
table.push(md, "");
// 下载链接
table.push(md, "## 📥 下载");
table.push(md, "");
table.push(md, "### 源码下载");
table.push(md, "");
table.push(md, "| 格式 | 链接 |");
table.push(md, "|------|------|");
table.push(md, "| 📦 ZIP | [" + info.repo + "-" + info.defaultBranch + ".zip](" + info.zipUrl + ") |");
table.push(md, "");
// 最新 Release
if(info.latestRelease) {
table.push(md, "### 🎉 最新发布: " + info.latestRelease.tagName);
table.push(md, "");
if(info.latestRelease.name) {
table.push(md, "**" + info.latestRelease.name + "**");
table.push(md, "");
}
table.push(md, "- 📅 发布时间: " + formatDate(info.latestRelease.publishedAt));
table.push(md, "- 🔗 [查看发布页面](" + info.latestRelease.htmlUrl + ")");
table.push(md, "");
// Release 附件下载
if(info.latestRelease.assets && #info.latestRelease.assets > 0) {
table.push(md, "**📎 附件下载:**");
table.push(md, "");
table.push(md, "| 文件名 | 大小 | 下载次数 |");
table.push(md, "|--------|------|----------|");
for(i, asset in info.latestRelease.assets) {
var sizeStr = asset.size > 1048576
? string.format("%.2f MB", asset.size / 1048576)
: string.format("%.2f KB", asset.size / 1024);
table.push(md, "| [" + asset.name + "](" + asset.downloadUrl + ") | " + sizeStr + " | " + tostring(asset.downloadCount) + " |");
}
table.push(md, "");
} else {
// 没有附件时显示源码包
table.push(md, "**📎 源码包:**");
table.push(md, "");
table.push(md, "- [下载 ZIP](https://github.com/"+info.user+"/"+info.repo+"/archive/refs/tags/"+info.latestRelease.tagName+".zip)");
table.push(md, "");
}
} else {
table.push(md, "> ℹ️ 该项目暂无发布版本");
table.push(md, "");
}
return string.join(md, '\n');
}
// 创建线程命令监听
winform.onQueryResult = function(info, err) {
winform.btnQuery.disabledText = null;
if(info) {
var md = generateMarkdown(info);
wb.setMarkdown(md);
} else {
wb.showError('❌ 获取失败:' + (err || "未知错误,请检查项目地址是否正确"));
}
}
winform.btnQuery.oncommand = function(id, event) {
var url = string.trim(winform.editUrl.text);
if(!#url) {
winform.msgbox("请输入 GitHub 项目地址", "提示");
winform.editUrl.setFocus();
return;
}
winform.btnQuery.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250']
wb.setMarkdown("");
wb.showLoading(" 请稍候,正在从 GitHub 获取数据...")
thread.invoke(
function(winform,url) {
import web.rest.github;
// 获取首次提交
var getFirstCommit = function(user, repo, defaultBranch) {
var client = web.rest.github();
var repoApi = client.api().repos[user][repo];
var totalCommits = 1;
client.afterSend = function(statusCode, contentLength) {
var linkHeader = client.readHeader("Link");
if(linkHeader) {
totalCommits = tonumber(string.match(linkHeader, `\&page\=(\d+)\>\;\s*rel\=\"last\"`)) : 1;
}
}
var commitsApi = repoApi.commits;
commitsApi.get({ sha = defaultBranch; per_page = 1 });
client.afterSend = null;
var firstCommitData = commitsApi.get({
sha = defaultBranch;
per_page = 1;
page = totalCommits;
});
client.close();
if(firstCommitData && #firstCommitData) {
var first = firstCommitData[1];
return {
sha = first.sha;
author = first.commit.author.name;
date = first.commit.author.date;
message = first.commit.message;
totalCommits = totalCommits;
};
}
return null;
}
// 获取仓库接口
var repoApi,repoUrl;
repoApi,user,repo,repoUrl = web.rest.github.repo(url)
if(!repoApi){
winform.onQueryResult(null, user || "无效的项目地址格式");
return;
}
winform.editUrl.text = repoUrl;
var restClient = repoApi.getRestClient();
var repoInfo,err = repoApi.get();
if(!repoInfo) {
restClient.close();
winform.onQueryResult(null, err || "无法获取仓库信息,请检查项目是否存在");
return;
}
// 获取语言统计
var languages = repoApi.languages.get();
// 获取贡献者数量
var contributorCount = 1;
restClient.afterSend = function() {
var linkHeader = restClient.readHeader("Link");
if(linkHeader) {
contributorCount = tonumber(string.match(linkHeader, `\&page\=(\d+)\>\;\s*rel\=\"last\"`)) : 1;
}
}
repoApi.contributors.get({ per_page = 1 });
// 获取最新 Release
var latestRelease = null;
var releaseData = repoApi.releases.latest.get();
if(releaseData && releaseData.tag_name) {
latestRelease = {
tagName = releaseData.tag_name;
name = releaseData.name;
publishedAt = releaseData.published_at;
htmlUrl = releaseData.html_url;
zipballUrl = releaseData.zipball_url;
tarballUrl = releaseData.tarball_url;
assets = {};
};
// 获取所有附件下载链接
if(releaseData.assets && #releaseData.assets) {
for(i, asset in releaseData.assets) {
table.push(latestRelease.assets, {
name = asset.name;
size = asset.size;
downloadUrl = asset.browser_download_url;
downloadCount = asset.download_count;
});
}
}
}
restClient.close();
// 获取首次提交
var firstCommit = getFirstCommit(user, repo, repoInfo.default_branch);
var info = {
user = user;
repo = repo;
fullName = repoInfo.full_name;
description = repoInfo.description;
stars = repoInfo.stargazers_count;
forks = repoInfo.forks_count;
watchers = repoInfo.watchers_count;
openIssues = repoInfo.open_issues_count;
language = repoInfo.language;
languages = languages;
license = repoInfo.license ? repoInfo.license.name : "未指定";
defaultBranch = repoInfo.default_branch;
createdAt = repoInfo.created_at;
updatedAt = repoInfo.updated_at;
pushedAt = repoInfo.pushed_at;
homepage = repoInfo.homepage;
htmlUrl = repoInfo.html_url;
topics = repoInfo.topics;
contributorCount = contributorCount;
firstCommit = firstCommit;
size = repoInfo.size;
archived = repoInfo.archived;
fork = repoInfo.fork;
latestRelease = latestRelease;
zipUrl = "https://github.com/" + user + "/" + repo + "/archive/refs/heads/" + repoInfo.default_branch + ".zip";
};
winform.onQueryResult(info);
},winform,url
)
}
wb.setMarkdown(`# 🔍 GitHub 助手
## ✨ 功能特性
- 📊 显示项目基本统计(Stars、Forks、Issues 等)
- 📋 展示项目详情(语言、协议、标签等)
- 📅 时间线信息(创建时间、首次提交、最后更新)
- 📈 Star 历史趋势图
- 📥 源码与 Release 下载链接
- 🚀 多线程自动获取可用镜像服务器(点击下载链接时自动转换)
> GitHub 接口如果调用次数过多时会失败,可更换 IP 再试
`);
winform.mirrorStatus.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250',text=' 正在检测镜像...']
import web.rest.githubMirrors;
var gitMirrors = web.rest.githubMirrors();
if(gitMirrors){
var first;
winform.setInterval(
function(){
while(var url = gitMirrors.pop(1)){
if(url){
winform.cmbMirrors.add(url);
if(!first){
winform.cmbMirrors.selIndex = 1;
first = 1;
}
}
}
if(!gitMirrors.busy()){
winform.mirrorStatus.disabledText = null;
winform.mirrorStatus.argbColor = 0xFF2EA44F;
winform.mirrorStatus.text = '镜像就绪,请点击下载链接';
winform.mirrorStatus.iconText = '\uF00C';
return false;
}
},1000
)
}
else{
winform.mirrorStatus.argbColor = 0xFFFE0505;
winform.mirrorStatus.text = '访问接口失败,请更换 IP 或稍后再试';
winform.mirrorStatus.iconText = '\uF00D';
}
winform.editUrl.editBox.enablePopMenu()
// 查询按钮样式
winform.btnQuery.background = 0xFF2EA44F; // GitHub 绿色
winform.btnQuery.skin({
background={
default=0xFF2EA44F;
hover=0xFF3FB950;
active=0xFF238636;
disabled=0xFFAAAAAA
};
color={
default=0xFFFFFFFF
};
border={
default={radius=8;width=0}
}
})
// 输入框悬停效果
winform.editUrl.skin({
border={
default={color=0xFFD0D0D0;radius=8;width=1};
hover={color=0xFF2EA44F;radius=8;width=2};
focus={color=0xFF2EA44F;radius=8;width=2}
}
})
win.loopMessage();
Markdown 格式