javascript:(async () => { /* Ensure the script is run on a valid GitHub repository page */ const ensureForksPage = () => { const match = window.location.href.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+)(\/forks\/?)?/); if (!match) { alert('Run this from a GitHub repository page.'); throw new Error('Not on a valid GitHub repository page.'); } if (!match[3]) { window.location.href = `https://github.com/${match[1]}/${match[2]}/forks`; throw new Error('Redirecting to the forks page.'); } return { user: match[1], repo: match[2] }; }; /* Fetch the default branch of a repository */ const getDefaultBranch = async (user, repo) => { let token = prompt("Insert your GITHUB_TOKEN. It won't be saved"); const res = await fetch(`https://api.github.com/repos/${user}/${repo}`, { headers: { accept: 'application/json', authorization: `Bearer ${token}` } }); if (!res.ok) throw new Error(`Failed to fetch default branch for ${user}/${repo}`); return (await res.json()).default_branch; }; /* Fetch branch information */ const fetchBranchInfo = async (user, repo, branch) => { try { const res = await fetch(`https://github.com/${user}/${repo}/branch-infobar/${branch}`, { headers: { accept: 'application/json' } }); if (res.ok) return (await res.json()).refComparison; } catch (e) { console.error(`Error fetching branch info for ${user}/${repo}:`, e); } return null; }; try { /* Ensure on the forks page and get main repository details */ const { user: mainUser, repo: mainRepo } = ensureForksPage(); const defaultBranch = await getDefaultBranch(mainUser, mainRepo); /* Process fork links */ const forks = [...document.querySelectorAll('ul[data-view-component="true"] > li')]; for (const fork of forks) { const repoLink = fork.querySelector('a[href*="/"]:nth-of-type(2)'); const match = repoLink?.href.match(/github\.com\/([^/]+)\/([^/]+)/); if (!match) continue; const [_, user, repo] = match; let branchInfo = await fetchBranchInfo(user, repo, defaultBranch); if (!branchInfo) branchInfo = await fetchBranchInfo(user, repo, await getDefaultBranch(user, repo)); if (branchInfo) { const { ahead, behind } = branchInfo; const info = `Ahead: ${ahead}, Behind: ${behind}`; const infoDiv = document.createElement('div'); infoDiv.innerHTML = info; infoDiv.style.marginTop = '10px'; infoDiv.style.fontSize = 'small'; fork.appendChild(infoDiv); if (ahead === 0) fork.style.display = 'none'; } } } catch (e) { console.error('Error in bookmarklet execution:', e); } })();