if you’ve downloaded your glitch stuff (Get_my_glitch_stuff.sh), here’s some files to generate something like that grid of green squares they have on GitHub to show which days you did stuff. except it’s using data from Glitch’s rewind system.
first, there’s this extract_rewind_timestamps.sh
. run this to create rewind_timestamps.txt
#!/bin/sh -eu
project_domains() {
tail -n+2 projects.txt | cut -d' ' -f1
}
if [ ! -e user_id.txt ]; then
snail whoami -n >user_id.txt
fi
user_id=$(cat user_id.txt)
mkdir -p /tmp/inspectgit
project_domains | while read -r domain; do
rm -rf /tmp/inspectgit/app
echo >&2 "reading $domain"
tar -xf "projects/$domain/app.tar.gz" -C /tmp/inspectgit app/.git || continue
git -C /tmp/inspectgit/app/.git log --branches --author=Glitch --grep=":$user_id/" --format="%H %at" || true
done | sort -k1,1 -u >rewind_timestamps.txt
rm -rf /tmp/inspectgit
then there’s this render_rewind_timestamps.html
to total up the per-day rewind checkpoints and draw the squares.
<!doctype html>
<style>
body {
font-family: sans-serif;
}
.year-label {
margin: 1rem 0rem 0rem;
font-weight: normal;
}
.squares {
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-content: flex-start;
height: 91px;
}
.day {
display: block;
margin: 0px 3px 3px 0px;
border-radius: 2px;
width: 10px;
height: 10px;
}
.zero {
border: 1px solid hsl(0 0% 90%);
width: 8px;
height: 8px;
}
</style>
<form id="timestamps_form"><input id="timestamps_input" type="file"> <input type="submit" value="render"></form>
<p id="out"></p>
<script>
function dayFromTimestamp(/** @type {number} */ timestamp) {
const d = new Date(timestamp * 1000);
d.setHours(12, 0, 0, 0);
return Math.round(d.getTime() / 86400000);
}
function dateFromDay(/** @type {number} */ day) {
return new Date(day * 86400000);
}
const /** @type {HTMLFormElement} */ timestampsForm = document.getElementById('timestamps_form');
const /** @type {HTMLInputElement} */ timestampsInput = document.getElementById('timestamps_input');
const /** @type {HTMLParagraphElement} */ out = document.getElementById('out');
timestampsForm.onsubmit = (e) => {
e.preventDefault();
out.innerHTML = '';
if (!timestampsInput.files.length) return;
(async () => {
try {
const timestampsStr = await timestampsInput.files[0].text();
let /** @type {number | null} */ earliestDay = null;
let /** @type {number | null} */ latestDay = null;
const countByDay = {};
for (const line of timestampsStr.split('\n')) {
if (!line.trim()) continue;
const [hash, timestampStr] = line.split(' ');
const timestamp = +timestampStr;
const day = dayFromTimestamp(timestamp);
if (earliestDay === null || day < earliestDay) {
earliestDay = day;
}
if (latestDay === null || day > latestDay) {
latestDay = day;
}
if (day in countByDay) {
countByDay[day]++;
} else {
countByDay[day] = 1;
}
}
let maxCount = 0;
for (const day in countByDay) {
if (countByDay[day] > maxCount) {
maxCount = countByDay[day];
}
}
let /** @type {number | null} */ year = null;
let /** @type {HTMLDivElement | null} */ squaresDiv = null;
for (let day = earliestDay; day <= latestDay; day++) {
const d = dateFromDay(day);
const dayYear = d.getFullYear();
if (year === null || dayYear !== year) {
year = dayYear;
const yearDiv = document.createElement('div');
yearDiv.className = 'year';
const yearLabelHeading = document.createElement('h2');
yearLabelHeading.className = 'year-label';
yearLabelHeading.textContent = year;
yearDiv.appendChild(yearLabelHeading);
squaresDiv = document.createElement('div');
squaresDiv.className = 'squares';
yearDiv.appendChild(squaresDiv);
out.appendChild(yearDiv);
const firstDateOfYear = new Date(dayYear, 0, 1, 12);
const firstDayOfWeek = firstDateOfYear.getDay();
for (let i = 0; i < firstDayOfWeek; i++) {
const daySpan = document.createElement('span');
daySpan.className = 'day padding';
squaresDiv.appendChild(daySpan);
}
const skippedDays = Math.round((d.getTime() - firstDateOfYear.getTime()) / 86400000);
for (let i = 0; i < skippedDays; i++) {
const daySpan = document.createElement('span');
daySpan.className = 'day zero';
squaresDiv.appendChild(daySpan);
}
}
const count = day in countByDay ? countByDay[day] : 0;
const l = count ? 85 - 60 * (count / maxCount) : 100;
const daySpan = document.createElement('span');
daySpan.className = count ? 'day' : 'day zero';
daySpan.title = `${count} ${count === 1 ? 'checkpoint' : 'checkpoints'} on ${d.toDateString()}`;
daySpan.style.backgroundColor = `hsl(135 70% ${l}%)`;
squaresDiv.appendChild(daySpan);
}
if (year !== null) {
for (let day = latestDay + 1; true; day++) {
const d = dateFromDay(day);
if (d.getFullYear() !== year) break;
const daySpan = document.createElement('span');
daySpan.className = 'day zero';
squaresDiv.appendChild(daySpan);
}
}
} catch (e) {
reportError(e);
}
})();
};
</script>
here’s mine