From d98bf86a97481e1770b2616cfa0b556a27bf506d Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 26 Jan 2026 23:37:39 +0000 Subject: [PATCH] feat: update gource script for 2014-2025+ visualization - Add community repos from awesome-activitywatch (awatcher, aw-watcher-enhanced, etc.) - Extend timeline captions to 2025 - Add color highlighting for Go, Kotlin, Java (community repos use these) - Add TODO for profile picture evolution feature (change avatars over time) - Improve error handling and progress output - Update title to reflect extended timeline Addresses Issue #11 --- video/gource-captions.txt | 6 ++ video/gource-output.sh | 130 +++++++++++++++++++++++++++++++------- 2 files changed, 114 insertions(+), 22 deletions(-) diff --git a/video/gource-captions.txt b/video/gource-captions.txt index e3b07b9..5ac2976 100644 --- a/video/gource-captions.txt +++ b/video/gource-captions.txt @@ -18,3 +18,9 @@ 1584918000|v0.9.2 released (2020-03-23) 1606172400|v0.10.0 released (2020-11-24) 1623794400|v0.11.0 released (2021-06-16) +1664841600|v0.12.0 released (2022-10-04) +1697500800|v0.12.3 released (2023-10-17) +1705190400|awatcher community watcher gains popularity (2024-01-14) +1714953600|aw-watcher-enhanced with OCR/LLM (2024-05-06) +1727740800|v0.13.0 released (2024-10-01) +1735689600|Community repos now included in visualization (2025-01-01) diff --git a/video/gource-output.sh b/video/gource-output.sh index a606b66..b53a923 100755 --- a/video/gource-output.sh +++ b/video/gource-output.sh @@ -1,15 +1,48 @@ #!/bin/bash +# ActivityWatch Gource Visualization Script +# Updated 2026-01 to include community repos and extend timeline 2014-2025+ set -e rootdir=../../../ tmpdir=.cache/gource +communitydir=.cache/community # Directory for community repos rm -rf $tmpdir mkdir -p $tmpdir +mkdir -p $communitydir + +echo "=== ActivityWatch Development Visualization ===" +echo "Building gource visualization with official + community repos" + +# Clone/update community repos (external contributors) +echo "" +echo "=== Fetching community repos ===" +community_repos=( + # Popular watchers from the community (awesome-activitywatch) + "2e3s/awatcher" # Popular Rust watcher for X11/Wayland + "kepptic/aw-watcher-enhanced" # Enhanced window watcher with OCR/LLM + "2e3s/aw-watcher-media-player" # Media playback tracking + "brayo-pip/aw-watcher-lastfm" # Last.fm scrobbles + "Otto-AA/aw-watcher-vscode" # VSCode extension + "OlivierMary/aw-watcher-jetbrains" # JetBrains extension + "NicoWeio/activitywatch-plasmoid" # KDE Plasma widget + "phrp720/aw-sync-suite" # Prometheus/Grafana sync +) -echo "Building stuff" +for repo in "${community_repos[@]}"; do + name=$(basename $repo) + if [ -d "$communitydir/$name" ]; then + echo "Updating $name..." + (cd "$communitydir/$name" && git pull --quiet) || echo " (pull failed, using cached)" + else + echo "Cloning $name..." + git clone --quiet "https://github.com/$repo.git" "$communitydir/$name" 2>/dev/null || echo " (clone failed, skipping)" + fi +done -# Bundle repo +# Bundle repo (official ActivityWatch) +echo "" +echo "=== Processing official repos ===" gource --output-custom-log $tmpdir/activitywatch.txt $rootdir modules=( @@ -17,17 +50,23 @@ modules=( # clients aw-client other/aw-client-js + other/aw-client-rust # server aw-server aw-server-rust # ui aw-server/aw-webui aw-qt - # watchers + aw-tauri + # watchers (official) aw-watcher-afk aw-watcher-window + aw-watcher-input + aw-watcher-spotify other/aw-watcher-web other/aw-watcher-window-wayland + # sync + aw-server-rust/aw-sync # website and docs other/activitywatch.github.io docs @@ -44,19 +83,35 @@ for path in "${modules[@]}"; do loc=$(echo $loc | sed -E "s#.+-client.*#clients/$name#g") loc=$(echo $loc | sed -E "s#.+-server.*#servers/$name#g") loc=$(echo $loc | sed -E "s#docs|activitywatch.github.io#website/$name#g") - echo $name $loc - gource --output-custom-log $tmpdir/$name.txt $rootdir/$path - sed -i -r "s#(.+)\\|#\\1|/$loc#" $tmpdir/$name.txt + echo " $name -> $loc" + if [ -d "$rootdir/$path" ]; then + gource --output-custom-log $tmpdir/$name.txt $rootdir/$path 2>/dev/null || echo " (skipped)" + sed -i -r "s#(.+)\\|#\\1|/$loc#" $tmpdir/$name.txt 2>/dev/null || true + fi +done + +# Process community repos +echo "" +echo "=== Processing community repos ===" +for repo in "${community_repos[@]}"; do + name=$(basename $repo) + if [ -d "$communitydir/$name" ]; then + echo " $name -> community/$name" + gource --output-custom-log $tmpdir/community-$name.txt $communitydir/$name 2>/dev/null || echo " (skipped)" + sed -i -r "s#(.+)\\|#\\1|/community/$name#" $tmpdir/community-$name.txt 2>/dev/null || true + fi done # Remove all files in activitywatch-old repo when rewrite began # TODO: Remove in a logical order (deepest first) -sed -E 's/.+[|](.+)[|].+[|](.+)/1461708000|\1|D|\2/g' $tmpdir/activitywatch-old.txt | uniq > $tmpdir/fixes.txt +if [ -f "$tmpdir/activitywatch-old.txt" ]; then + sed -E 's/.+[|](.+)[|].+[|](.+)/1461708000|\1|D|\2/g' $tmpdir/activitywatch-old.txt | uniq > $tmpdir/fixes.txt +fi gourcelog=$tmpdir/combined.gource # Combine all the logs into one log -cat $tmpdir/*.txt | sort -n > $gourcelog +cat $tmpdir/*.txt 2>/dev/null | sort -n > $gourcelog # Rename activitywatch-old so it behaves like top dir sed -i 's#activitywatch-old/##g' $gourcelog @@ -65,11 +120,14 @@ sed -i 's#activitywatch-old/##g' $gourcelog sed -i -E 's#.+/.github/##g' $gourcelog # Color certain file extensions a certain way -sed -i 's/[.]py/\0|4B8BBE/g' $gourcelog -sed -i 's/[.]rs$/\0|FFAA33/g' $gourcelog -sed -i 's/[.]js/\0|F0DB4F/g' $gourcelog -sed -i 's/[.]ts/\0|007ACC/g' $gourcelog -sed -i 's/[.]vue/\0|41B883/g' $gourcelog +sed -i 's/[.]py/\0|4B8BBE/g' $gourcelog # Python - blue +sed -i 's/[.]rs$/\0|FFAA33/g' $gourcelog # Rust - orange +sed -i 's/[.]js/\0|F0DB4F/g' $gourcelog # JavaScript - yellow +sed -i 's/[.]ts/\0|007ACC/g' $gourcelog # TypeScript - blue +sed -i 's/[.]vue/\0|41B883/g' $gourcelog # Vue - green +sed -i 's/[.]go$/\0|00ADD8/g' $gourcelog # Go - cyan (for awatcher) +sed -i 's/[.]kt$/\0|7F52FF/g' $gourcelog # Kotlin - purple (for JetBrains) +sed -i 's/[.]java$/\0|B07219/g' $gourcelog # Java - brown # Docs sed -i -E 's/[.](md|rst|txt)|LICENSE$/\0|FF5555/g' $gourcelog @@ -86,24 +144,48 @@ sed -i 's/johan-bjareholt/Johan Bjäreholt/g' $gourcelog sed -i -E 's/Erik Bj.{1,4}reholt/Erik Bjäreholt/g' $gourcelog sed -i 's/dependabot.+/dependabot/g' $gourcelog sed -i 's/Bill-linux/Bill Ang Li/g' $gourcelog +sed -i 's/2e3s/Dzmitry/g' $gourcelog # awatcher author # Remove names which have been spamming commits in CI (accidental bad CI config) sed -i 's/.*ErikBjare.*//g' $gourcelog # Prepare avatars # TODO: Doesn't fetch avatars from all repos (only the ones with most contributors) -# run for contributor-stats repo, initialized .git/avatars folder -if [ -x .git/avatars ]; then - perl fetch-avatars.pl +# TODO: Dynamic avatar evolution - change user avatars over time to reflect +# their profile picture at that point in history. This would require: +# 1. GitHub API to fetch historical avatar URLs (if available) or +# 2. Wayback Machine integration to get historical profile pictures +# 3. Gource custom avatar timeline support (may need patching gource) +# For now, avatars are static (most recent profile picture) +if [ -d ../.git/avatar ]; then + # run for contributor-stats repo + perl fetch-avatars.pl 2>/dev/null || echo "Avatar fetch skipped" # run for bundle repo, move avatars to local .git/avatars fetchsrc=$(realpath fetch-avatars.pl) - pushd $rootdir; perl $fetchsrc; popd; mv $rootdir/.git/avatar/* .git/avatar - pushd $rootdir/aw-server/aw-webui; perl $fetchsrc; popd; mv $rootdir/aw-server/aw-webui/.git/avatar/* .git/avatar - pushd $rootdir/docs; perl $fetchsrc; popd; mv $rootdir/docs/.git/avatar/* .git/avatar + if [ -d "$rootdir/.git" ]; then + pushd $rootdir > /dev/null; perl $fetchsrc 2>/dev/null || true; popd > /dev/null + [ -d "$rootdir/.git/avatar" ] && mv $rootdir/.git/avatar/* ../.git/avatar/ 2>/dev/null || true + fi + if [ -d "$rootdir/aw-server/aw-webui/.git" ]; then + pushd $rootdir/aw-server/aw-webui > /dev/null; perl $fetchsrc 2>/dev/null || true; popd > /dev/null + [ -d "$rootdir/aw-server/aw-webui/.git/avatar" ] && mv $rootdir/aw-server/aw-webui/.git/avatar/* ../.git/avatar/ 2>/dev/null || true + fi + if [ -d "$rootdir/docs/.git" ]; then + pushd $rootdir/docs > /dev/null; perl $fetchsrc 2>/dev/null || true; popd > /dev/null + [ -d "$rootdir/docs/.git/avatar" ] && mv $rootdir/docs/.git/avatar/* ../.git/avatar/ 2>/dev/null || true + fi + # Fetch avatars for community contributors + for repo in "${community_repos[@]}"; do + name=$(basename $repo) + if [ -d "$communitydir/$name/.git" ]; then + pushd $communitydir/$name > /dev/null; perl $fetchsrc 2>/dev/null || true; popd > /dev/null + [ -d "$communitydir/$name/.git/avatar" ] && mv $communitydir/$name/.git/avatar/* ../.git/avatar/ 2>/dev/null || true + fi + done fi # Rename avatars to suit committer name -cp ../.git/avatar/johan-bjareholt.png '../.git/avatar/Johan Bjäreholt.png' +[ -f "../.git/avatar/johan-bjareholt.png" ] && cp ../.git/avatar/johan-bjareholt.png '../.git/avatar/Johan Bjäreholt.png' 2>/dev/null || true # Resolutions: # - 2560x1440 (for upload) @@ -117,7 +199,7 @@ res_low=1280x720 # this would be nice, but unfortunately counts directories... # --file-extension-fallback gource_options=( - --title 'ActivityWatch (https://activitywatch.net)' + --title 'ActivityWatch Development 2014-2025+ (https://activitywatch.net)' --caption-file gource-captions.txt --user-image-dir ../.git/avatar/ --key --file-idle-time 0 @@ -141,8 +223,12 @@ gource_options=( $gourcelog ) -echo "Visualizing" +echo "" +echo "=== Visualizing ===" gource "${gource_options[@]}" # To render video +echo "" +echo "=== Rendering video ===" gource "${gource_options[@]}" -o - | ffmpeg -y -r 60 -f image2pipe -vcodec ppm -i - -vcodec libx264 -preset ultrafast -pix_fmt yuv420p -crf 1 -threads 0 -bf 0 gource.mp4 +echo "Done! Output: gource.mp4"