Skip to content

Instantly share code, notes, and snippets.

@Dobby233Liu
Last active December 27, 2025 17:03
Show Gist options
  • Select an option

  • Save Dobby233Liu/c55c1e9c816facd153eeb19e386f53fd to your computer and use it in GitHub Desktop.

Select an option

Save Dobby233Liu/c55c1e9c816facd153eeb19e386f53fd to your computer and use it in GitHub Desktop.
Froyocomb Helper: Tool for speeding up the process of finding commits from before a specific date (i.e. included with a specific build). Developed for Froyocomb, the Android pre-release source reconstruction project.
// ==UserScript==
// @name Froyocomb Helper
// @namespace https://dobby233liu.neocities.org
// @version v1.1.10
// @description Tool for speeding up the process of finding commits from before a specific date (i.e. included with a specific build). Developed for Froyocomb, the Android pre-release source reconstruction project.
// @author Liu Wenyuan
// @match https://android.googlesource.com/*
// @match https://chromium.googlesource.com/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @run-at document-end
// @downloadURL https://gist.github.com/Dobby233Liu/c55c1e9c816facd153eeb19e386f53fd/raw/Froyocomb Helper.user.js
// @updateURL https://gist.github.com/Dobby233Liu/c55c1e9c816facd153eeb19e386f53fd/raw/Froyocomb Helper.user.js
// @supportURL https://gist.github.com/Dobby233Liu/c55c1e9c816facd153eeb19e386f53fd#comments
// ==/UserScript==
"use strict";
const SITE = location.hostname.split(".").reverse()[2];
// JANK
function getForCurrentSite(config, defaultValue) {
return GM_getValue(SITE + "." + config, defaultValue);
}
function setForCurrentSite(config, value) {
return GM_setValue(SITE + "." + config, value);
}
if (!getForCurrentSite("referenceTag"))
setForCurrentSite("referenceTag", SITE == "android" ? GM_getValue("referenceTag", "android-4.0.1_r1") : "TAG");
if (!getForCurrentSite("referenceBranch"))
setForCurrentSite("referenceBranch", SITE == "android" ? GM_getValue("referenceBranch", "ics-mr0-release") : "main");
if (!getForCurrentSite("referenceTime"))
setForCurrentSite("referenceTime", (SITE == "android" ? GM_getValue("referenceTime") : null) ?? +(new Date("0")));
if (SITE == "android") {
GM_deleteValue("referenceTag");
GM_deleteValue("referenceBranch");
GM_deleteValue("referenceTime");
}
const createElement = document.createElement.bind(document);
let floatingPanelStylesPresent = false;
function createFloatingPanel(variant) {
if (!floatingPanelStylesPresent) {
GM_addStyle(`
.fch-FloatingPanel {
position: fixed;
padding: 8px;
background: #ffdb00ee;
}
.fch-FloatingPanel-bottom {
left: 50%; bottom: 0;
transform: translate3d(-50%, 0, 0);
}
.fch-FloatingPanel-right {
right: 0; top: 3em;
transform: translate3d(0, 0, 0);
}
.fch-FloatingPanel button {
font: inherit;
}
`);
floatingPanelStylesPresent = true;
}
const panel = document.body.insertAdjacentElement("afterBegin", createElement("div"));
panel.classList.add("fch-FloatingPanel");
panel.classList.add("fch-FloatingPanel-" + (variant ?? "bottom"));
panel.tabindex = 0;
return panel;
}
function addListItem(list, content) {
const item = list.appendChild(createElement("li"));
if (content)
item.appendChild(content);
return content;
}
function generateButton(text, onClick) {
const button = createElement("button");
button.type = "button";
button.innerText = text;
if (onClick)
button.addEventListener("click", onClick);
return button;
}
let copyButtonStylePresent = false;
function createCopyButtonFactory(title) {
if (!copyButtonStylePresent) {
GM_addStyle(`
.fch-CopyButton {
font: inherit;
position: relative;
margin-left: 2px;
margin-right: 3px;
}
@keyframes fch-CopyButton-Toast-Anim {
from, 33.333% {
opacity: 1;
}
to {
opacity: 0;
bottom: calc(100% + 1em);
}
}
.fch-CopyButton-Toast {
position: absolute;
left: 50%;
transform: translate3d(-50%, 0, 0);
bottom: calc(100% + 0.3em);
z-index: 10;
width: max-content;
padding: 2px 6px;
background: #ffdb00f0;
border: #ffe54755 2px solid;
border-radius: 6px;
opacity: 0;
}
.fch-CopyButton-Toast > * {
pointer-events: none;
}
.fch-CopyButton-Toast-Done, .fch-CopyButton-Toast-Error {
animation: fch-CopyButton-Toast-Anim 1s ease-in-out;
}
.fch-CopyButton-Toast-Error {
background-color: #ff0004f0;
border-color: #ff474755;
}
`);
copyButtonStylePresent = true;
}
const button = generateButton("\u{1F4CB}");
button.classList.add("fch-CopyButton");
button.title = title ? title : "Copy";
const toast = button.appendChild(createElement("div"));
toast.classList.add("fch-CopyButton-Toast");
toast.style.display = "none";
return function(text, copyCb) {
const newButton = button.cloneNode(true);
const newToast = newButton.querySelector(".fch-CopyButton-Toast");
newToast.addEventListener("animationend", function(ev) {
if (ev.animationName == "fch-CopyButton-Toast-Anim")
ev.target.style.display = "none";
});
newToast.addEventListener("click", function(ev) {
// prevent toast from triggering copy
ev.stopPropagation();
});
newButton.addEventListener("click", function(ev) {
(async function(ev) {
let ok = true;
try {
await navigator.clipboard.writeText(text);
} catch (ex) {
console.error("[FCH] Copy to clipboard failed", ex);
ok = false;
}
if (typeof copyCb == "function")
copyCb(text);
if (!newToast) return;
newToast.classList.remove("fch-CopyButton-Toast-Done");
newToast.classList.remove("fch-CopyButton-Toast-Error");
requestAnimationFrame(() => {
newToast.style.display = "";
void(newToast.offsetWidth); // crime
if (ok) {
newToast.classList.add("fch-CopyButton-Toast-Done");
newToast.innerText = "Copied!";
} else {
newToast.classList.add("fch-CopyButton-Toast-Error");
newToast.innerText = "Copy failed!";
}
});
})();
});
return newButton;
}
}
function getRepoHomePath(pathname) {
const i = pathname.indexOf("/+");
if (i >= 0)
return pathname.substring(0, i);
return pathname.replace(/\/+$/, "");
}
function formatRef(refType, refName) {
if (refType == "" || refType == "commit")
return refName;
return `refs/${refType}/${refName}`;
}
function getPathToRef(homePath, ref, viewType="") {
return homePath + `/+${viewType}/` + ref;
}
function parseGitilesJson(rawJson) {
// TODO: what is Gitiles smoking
return JSON.parse(rawJson.replace(/^\)\]\}'\n/, ""));
}
// if author email in a commit doesn't match one of these patterns, the commit potentially comes from upstream,
// or is likely a partner/AOSP ext contribution that probably got merged in by Google later
const AUTHOR_ALLOWLIST = (function(site) {
// from inside google (mostly)
// note that this implictly includes corp-partner.google.com which might be undesirable, but since we haven't/won't get to the point
// where we'd need to mark those, we'll see
let authorAllowlist = [
/@(?:|[A-Za-z0-9\-\.]+?\.)google\.com/, // look idk
/%(?:|[A-Za-z0-9\-\.]+?\.)google\.com@gtempaccount\.com/
];
if (site == "android") {
authorAllowlist = authorAllowlist.concat([ // from inside android
/@(?:|[A-Za-z0-9\-\.]+?\.)android\.com/,
/%(?:|[A-Za-z0-9\-\.]+?\.)android\.com@gtempaccount\.com/,
/@android$/,
/@android@[a-f0-9\-]+$/,
]);
}
if (
site == "chromium"
// idk
// normally during 4.4 chromium-automerger@android is SLIGHTLY more reliable
|| (site == "android" && getRepoHomePath(location.pathname).includes("/platform/external/chromium_org"))
) {
authorAllowlist = authorAllowlist.concat([
/@(?:|[A-Za-z0-9\-\.]+?\.)chromium\.org/
]);
}
return authorAllowlist;
})(SITE);
// usually signs that may indicate a upstream commit
const ALERTABLE_COMMENT_MESSAGE_PATTERNS = (function(site){
let patterns = [
"\ngit-svn-id: "
];
if (site == "android") {
patterns = patterns.concat([
/\nReview URL: http(?:s)?:\/\/codereview\.chromium\.org\//,
/\nReview URL: http(?:s)?:\/\/chromiumcodereview\.appspot\.com\//,
/\nReviewed-on: http(?:s)?:\/\/chromium-review\.googlesource\.com\//
]);
}
return patterns;
})(SITE);
function matchesPatterns(str, pats) {
return pats.some(i => i instanceof RegExp ? !!str.match(i) : str.includes(i));
}
(function() {
const headerMenu = document.querySelector(".Site-header .Header-menu");
if (!headerMenu) return;
for (const i of headerMenu.querySelectorAll(".Header-menuItem")) {
if (i.tagName == "A" && i.href.startsWith("https://accounts.google.com/AccountChooser") && i.innerText == "Sign in") {
GM_addStyle(`
.fch-LoginHint {
color: #ff2f00;
text-decoration: underline dotted; /* TODO: use abbr instead? */
}
`);
const loginHint = i.appendChild(createElement("span"));
loginHint.innerText = " (recommended)";
loginHint.title = "Log in for more lenient rate limits";
loginHint.classList.add("fch-LoginHint");
break;
}
}
})();
if (document.querySelector(".RepoShortlog")) {
// This part is almost useless outside of android
(function() {
const panel = createFloatingPanel();
const list = panel.appendChild(createElement("ul"));
function updateRefLink(link, refType, refName, viewType) {
const ref = formatRef(refType, refName);
link.href = getPathToRef(getRepoHomePath(location.pathname), ref, viewType);
link.innerText = "Go to " + viewType + " of " + ref;
return link;
}
const refTagContainer = addListItem(list, createElement("span"));
const refTagLink = refTagContainer.appendChild(createElement("a"));
function updateRefTagLink() {
updateRefLink(refTagLink, "tags", getForCurrentSite("referenceTag"), "log");
}
updateRefTagLink();
refTagContainer.appendChild(document.createTextNode(" "));
refTagContainer.appendChild(generateButton("Set", function() {
const val = prompt("Set reference tag to:", getForCurrentSite("referenceTag")).trim();
if (!val || val === "") return;
setForCurrentSite("referenceTag", val);
updateRefTagLink();
}));
const refBranchContainer = addListItem(list, createElement("span"));
const refBranchLink = refBranchContainer.appendChild(createElement("a"));
function updateRefBranchLink() {
updateRefLink(refBranchLink, "heads", getForCurrentSite("referenceBranch"), "log");
}
updateRefBranchLink();
refBranchContainer.appendChild(document.createTextNode(" "));
refBranchContainer.appendChild(generateButton("Set", function() {
const val = prompt("Set reference branch to:", getForCurrentSite("referenceBranch")).trim();
if (!val || val === "") return;
setForCurrentSite("referenceBranch", val);
updateRefBranchLink();
}));
})();
} else if (document.querySelector(".CommitLog")) {
(function() {
GM_addStyle(`
.fch-LightEmUp-Message-Container {
display: flex;
flex-flow: row wrap;
gap: 8px;
align-items: center;
margin-bottom: 2px;
}
.fch-LightEmUp-Message {
flex: 1 1;
}
.fch-LightEmUp-RefTime-Entry, .fch-LightEmUp-RefTimeSetter-Entry {
text-align: center;
}
.fch-LightEmUp-RefTime-Entry {
font-size: 13px;
}
.fch-LightEmUp-RefTimeSetter-Entry {
font-size: 12px;
}
.CommitLog-item--fch-lightedUp {
background: #ffff00;
}
.CommitLog-item--fch-lightedUp-exact {
background: #ffa400;
}
.CommitLog-item--fch-lightedUp-lesser {
background: #eeee0040;
}
`);
function filterCommits(commits, dateBefore) {
const result = {};
for (const commit of commits) {
const authorEmail = commit.querySelector(":scope > .CommitLog-author").title;
const lesser = !matchesPatterns(authorEmail, AUTHOR_ALLOWLIST);
const time = new Date(commit.querySelector(":scope > .CommitLog-time").title);
if (isNaN(+time))
continue;
if (time <= dateBefore)
result[commit.querySelector(":scope > .CommitLog-sha1").href] = lesser ? "-lesser" : (time >= dateBefore ? "-exact" : "");
}
return result;
}
// strange feature per Mainnn's request
//let markAsVisitedIframe = undefined;
function markAsVisited(url) {
/*
if (markAsVisitedIframe === undefined) {
markAsVisitedIframe = document.body.appendChild(createElement("iframe"));
markAsVisitedIframe.name = "fch-markAsVisited";
markAsVisitedIframe.src = blankPage;
markAsVisitedIframe.style.display = "none";
console.log(markAsVisitedIframe);
}
*/
const wnd = window; // markAsVisitedIframe.contentWindow;
const oldHref = wnd.location.href;
wnd.history.replaceState({}, "", url);
wnd.history.replaceState({}, "", oldHref);
}
const commits = Array.from(document.querySelectorAll(".Site-content > .Container > .CommitLog > .CommitLog-item"));
const createCopyButton = createCopyButtonFactory("Copy hash");
for (const commit of commits) {
const hashEl = commit.querySelector(".CommitLog-sha1");
if (!hashEl) continue;
const hash = new URL(hashEl.href).pathname.split("/").reverse()[0];
if (!(hash.length == 40 && hash.startsWith(hashEl.innerText))) {
console.warn("[FCH] Hash extraction failed, sha1 link element:", hashEl);
continue;
}
hashEl.parentNode.insertBefore(createCopyButton(hash, (_) => {
try {
markAsVisited(hashEl.href);
} catch (ex) {
console.warn("[FCH] markAsVisited failed", ex);
}
}), hashEl.nextSibling);
}
const panel = createFloatingPanel();
const lightedUpClz = "CommitLog-item--fch-lightedUp";
const lightedUpExactClz = "CommitLog-item--fch-lightedUp-exact";
const lightedUpLesserClz = "CommitLog-item--fch-lightedUp-lesser";
const firstId = "fch-lightedUp-First";
const list = panel.appendChild(createElement("ul"));
const lightEmUpEntry = list.appendChild(createElement("li"));
const messageContainerEl = lightEmUpEntry.appendChild(createElement("div"));
messageContainerEl.classList.add("fch-LightEmUp-Message-Container");
const lightEmUpBtn = messageContainerEl.appendChild(generateButton("Light 'em up!"));
lightEmUpBtn.accessKey = "z";
lightEmUpBtn.title = "[alt+z]";
const messageEl = messageContainerEl.appendChild(createElement("span"));
messageEl.classList.add("fch-LightEmUp-Message");
const jumpToFirst = messageContainerEl.appendChild(createElement("a"));
jumpToFirst.classList.add("fch-lightedUp-JumpToFirst");
jumpToFirst.innerText = "(first)";
jumpToFirst.href = "#" + firstId;
jumpToFirst.style.display = "none";
jumpToFirst.accessKey = "v";
jumpToFirst.title = "[alt+v]";
lightEmUpBtn.addEventListener("click", function() {
const time = new Date(getForCurrentSite("referenceTime"));
const filtered = filterCommits(commits, time);
let firstFound = false;
for (const commit of commits) {
commit.classList.remove(lightedUpClz);
commit.classList.remove(lightedUpExactClz);
commit.classList.remove(lightedUpLesserClz);
const found = filtered[commit.querySelector(":scope > .CommitLog-sha1").href];
if (found === undefined) {
if (commit.id == firstId)
delete commit.id;
} else {
commit.classList.add(lightedUpClz + found);
if (!firstFound) {
commit.id = firstId;
firstFound = true;
} else if (commit.id == firstId) {
delete commit.id;
}
}
}
const filteredCount = Object.keys(filtered).length;
messageEl.innerText = `${filteredCount} found`;
messageEl.title = `(before ${time.toISOString()})`;
jumpToFirst.style.display = filteredCount > 0 ? "" : "none";
});
const nextButtonOrig = document.querySelector(".LogNav-next");
const prevButtonOrig = document.querySelector(".LogNav-prev");
if (nextButtonOrig || prevButtonOrig) {
messageContainerEl.appendChild(document.createTextNode("|"));
if (prevButtonOrig) {
const prevButton = messageContainerEl.appendChild(prevButtonOrig.cloneNode());
prevButton.innerText = "<< Prev";
prevButton.accessKey = "a";
prevButton.title = "[alt+a]";
}
if (nextButtonOrig) {
const nextButton = messageContainerEl.appendChild(nextButtonOrig.cloneNode());
nextButton.innerText = "Next >>";
nextButton.accessKey = "s";
nextButton.title = "[alt+s]";
}
}
const refTimeEntry = list.appendChild(createElement("li"));
refTimeEntry.classList.add("fch-LightEmUp-RefTime-Entry");
const refTimeContainer = refTimeEntry.appendChild(createElement("span"));
const refTimePrefix = refTimeContainer.appendChild(document.createTextNode("Highlight commits from before "));
const refTimeDisp = refTimeContainer.appendChild(createElement("strong"));
function updateRefTimeDisp() {
refTimeDisp.innerText = new Date(getForCurrentSite("referenceTime")).toISOString();
}
updateRefTimeDisp();
const refTimeSetterEntry = list.appendChild(createElement("li"));
refTimeSetterEntry.classList.add("fch-LightEmUp-RefTimeSetter-Entry");
const refTimeSetterContainer = refTimeSetterEntry.appendChild(createElement("span"));
refTimeSetterContainer.appendChild(document.createTextNode("(Set "));
refTimeSetterContainer.appendChild(generateButton("by datetime", function() {
const val = prompt("Set reference time by datetime string:", new Date(getForCurrentSite("referenceTime")).toISOString()).trim();
if (!val || val === "") return;
const ts = +(new Date(val));
if (isNaN(ts)) {
alert("Invalid date");
return;
}
setForCurrentSite("referenceTime", ts);
updateRefTimeDisp();
}));
refTimeSetterContainer.appendChild(generateButton("by timestamp", function() {
const val = prompt("Set reference time by timestamp:", getForCurrentSite("referenceTime")).trim();
if (!val || val === "") return;
const ts = +(new Date(parseInt(val)));
if (isNaN(ts)) {
alert("Invalid date");
return;
}
setForCurrentSite("referenceTime", ts);
updateRefTimeDisp();
}));
function rtsTerminateQuote() {
refTimeSetterContainer.appendChild(document.createTextNode(")"));
}
if (SITE == "android") {
const setByCommitBtn = refTimeSetterContainer.appendChild(generateButton("by tag commit"));
rtsTerminateQuote();
const setByCommitWorkingEl = refTimeSetterContainer.appendChild(createElement("span"));
setByCommitWorkingEl.innerText = " (working...)";
setByCommitWorkingEl.style.display = "none";
async function setByCommitBtnOnClickReal() {
const hash = prompt("Please input the full hash of the commit modifying build/(make/)core/build_id.mk that you have in mind").trim();
if (hash.search(/^[0-9a-f]{40}$/) == -1) { // technically an arbitary limitation but idk
alert("Invalid hash");
return;
}
const url = new URL(getPathToRef("/platform/build", formatRef("commit", hash)), location.origin);
url.searchParams.set("format", "JSON");
const response = await fetch(url.href);
if (!response.ok) {
const errMsg = await response.text();
console.error("[FCH] platform/build commit request error", new Error(errMsg));
alert("Status: " + response.status + "\n\n" + errMsg.trim());
return;
}
const body = parseGitilesJson(await response.text());
const commitMsg = (body.message ?? "").split("\n")[0];
let commitDate = new Date(body.committer.time);
if (isNaN(+commitDate)) {
alert("Invalid date");
return;
}
if (confirm(
`Message: ${commitMsg}
Authored by: ${body.author.name} <${body.author.email}>
Committed by: ${body.committer.name} <${body.committer.email}>
Commit date: ${commitDate.toISOString()}
Does this seem correct?`)) {
if (body.committer.email == "initial-contribution@android.com"
&& (commitMsg.startsWith("auto import from ") || commitMsg.startsWith("Automated import from ")
|| commitMsg.includes("Code drop from //branches/")
|| (body.message ?? "").includes("Automated import of CL "))) {
if (confirm("This commit appears to be a import from Perforce (or SVN?) (commonly seen pre-Dount).\n"
+ "Each import commit's dates appear to be seconds apart, which may cause detection inaccuracy.\n\n"
+ "Adjust reference time by 5 minutes for safety?"))
commitDate = new Date(commitDate.getTime() + 5*60000);
}
setForCurrentSite("referenceTime", +commitDate);
updateRefTimeDisp();
}
}
setByCommitBtn.addEventListener("click", async function() {
setByCommitWorkingEl.style.display = "";
try {
await setByCommitBtnOnClickReal();
} catch (ex) {
console.error("[FCH] setByCommitBtnOnClickReal error", ex);
alert(ex.stack);
}
setByCommitWorkingEl.style.display = "none";
});
} else {
rtsTerminateQuote();
}
const panelRight = createFloatingPanel("right");
panelRight.appendChild(generateButton("Locate", function() {
const newLoc = new URL(location);
const start = prompt("Commit to locate in this log:", newLoc.searchParams.get("s") || "").trim();
if (!start || start === "") return;
newLoc.searchParams.set("s", start);
location.href = newLoc.href;
}));
})();
} else if (document.querySelector(".TreeDetail") || document.querySelector(".Diff")) {
(function() {
const commitRow = document.querySelector(".Metadata > table > tbody > tr:nth-child(1)");
if (commitRow.querySelector(":scope > .Metadata-title").innerText == "commit") {
const commitEl = commitRow.querySelector(":scope > td:nth-child(2)");
const commit = commitEl.innerText;
commitEl.appendChild(createCopyButtonFactory("Copy hash")(commit));
const dLog = commitRow.querySelector(":scope > td:nth-child(3)");
const headLogUrl = new URL(getPathToRef(getRepoHomePath(location.pathname), "HEAD", "log"), location.origin);
headLogUrl.searchParams.set("s", commit);
dLog.appendChild(document.createTextNode(" "));
const headLogLinkContainer = dLog.appendChild(createElement("span"));
headLogLinkContainer.appendChild(document.createTextNode("["));
const headLogLink = headLogLinkContainer.appendChild(createElement("a"));
headLogLink.href = headLogUrl.href;
headLogLink.innerText = "log@HEAD";
headLogLinkContainer.appendChild(document.createTextNode("]"));
}
const committerRow = document.querySelector(".Metadata > table > tbody > tr:nth-child(3)");
if (committerRow.querySelector(":scope > .Metadata-title").innerText == "committer") {
const committerEl = committerRow.querySelector(":scope > td:nth-child(2)");
const committerEmailMatch = committerEl.innerText.match("<([^<>]+?)>$");
// TODO: more specific patterns to match expected committers
if (committerEmailMatch && matchesPatterns(committerEmailMatch[1], AUTHOR_ALLOWLIST))
committerEl.style.backgroundColor = "#ffee3366";
const refTime = new Date(getForCurrentSite("referenceTime"));
const commitTimeEl = committerRow.querySelector(":scope > td:nth-child(3)");
const commitTime = new Date(commitTimeEl.innerText);
const commitMsg = document.body.querySelector(".Container > .MetadataMessage")?.innerText;
const lesser = commitMsg ? matchesPatterns(commitMsg, ALERTABLE_COMMENT_MESSAGE_PATTERNS) : false;
if (!isNaN(+commitTime) && commitTime <= refTime) {
// <arbitary color> or .CommitLog-item--fch-lightedUp
// TODO: do I use CSS for this?
commitTimeEl.style.backgroundColor = lesser ? "#aadfff77" : "#ffff00";
}
}
})();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment