Skip to content

Instantly share code, notes, and snippets.

@nexpr
Created July 6, 2019 05:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nexpr/2b8baedaf9693fd17cec433703f9aeb9 to your computer and use it in GitHub Desktop.
Save nexpr/2b8baedaf9693fd17cec433703f9aeb9 to your computer and use it in GitHub Desktop.
github のユーザやグループのリポジトリリストをダイアログで一覧表示する/フォークは除去してスターの降順で並べる/このコードをユーザページで実行すれば使える/実行方法は直接でも拡張機能でもユーザスクリプトでも
async function getUserRepositories(username, force_all) {
const res = await fetch(`https://api.github.com/users/${username}/repos`)
if (!res.ok) {
throw { error: "invalid-username", username }
}
const repos = await res.json()
const link = res.headers.get("link")
if (link) {
const [, next_url, last_url] = link.match(/<(.*?)>; rel="next", <(.*?)>; rel="last"/) || []
const last_page = ~~new URL(last_url).searchParams.get("page")
if (!force_all && last_page > 10) {
throw { error: "many-page", last: last_page }
}
for (let page = 2; page < last_page; page++) {
await new Promise(r => setTimeout(r, 200))
const url = new URL(next_url)
url.searchParams.set("page", page)
const page_repos = await (await fetch(url)).json()
repos.push(...page_repos)
}
}
return repos
}
function show(repos) {
const div = document.createElement("div")
const sroot = div.attachShadow({ mode: "open" })
sroot.innerHTML = `
<style>
.bg {
position: fixed;
z-index: 999999;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background: #fffb;
display: flex;
}
.content {
display: flex;
flex-flow: column;
width: 60vw;
height: 60vh;
margin: auto;
border: 2px solid #ddd;
background: white;
border-radius: 20px;
padding: 20px;
}
.scroller {
flex: 1 1 auto;
overflow: auto;
}
h1 {
margin: 0 0 10px;
}
td {
padding: 2px 15px;
}
</style>
<div class="bg">
<div class="content">
<h1>Repository List (フォークなし/スター数降順)</h1>
<div class="scroller">
<table>
<thead>
<tr>
<th>Rank</th>
<th>Stars</th>
<th>name</th>
<th>Language</th>
<th>Description</th>
</tr>
</thead>
<tbody>
${repos
.map((e, i) => {
return `
<tr>
<td>${i + 1}</td>
<td>${e.stargazers_count}</td>
<td><a href="${e.html_url}">${e.full_name}</a></td>
<td>${e.language}</td>
<td>${esc(e.description)}</td>
</tr>
`
})
.join("")}
</tbody>
</table>
</div>
</div>
</div>
`
sroot.addEventListener("click", eve => eve.target.matches(".bg") && div.remove())
document.body.append(div)
}
function esc(s) {
const d = document.createElement("div")
d.textContent = s
return d.innerHTML
}
async function main(username, force_all) {
try {
const repos = await getUserRepositories(username, force_all)
const sorted_no_fork_repos = repos.filter(e => !e.fork).sort((a, b) => b.stargazers_count - a.stargazers_count)
show(sorted_no_fork_repos)
} catch (err) {
if (err.error === "invalid-username") {
alert(`${err.username} がみつかりません`)
} else if (err.error === "many-page") {
const will_continue = confirm(`リポジトリ数が多すぎます (${err.last}ページ)\n続行しますか?`)
if (will_continue) {
main(username, true)
}
} else {
throw err
}
}
}
const paths = location.pathname.split("/")
if (paths.length === 2 && paths[1] !== "") {
main(paths[1], false)
} else {
alert("このスクリプトはユーザページでのみ実行できます")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment