Skip to content

Instantly share code, notes, and snippets.

@mkoertgen
Last active June 28, 2024 15:32
Show Gist options
  • Save mkoertgen/61ef2e75e3e09659791b77d7f63f67aa to your computer and use it in GitHub Desktop.
Save mkoertgen/61ef2e75e3e09659791b77d7f63f67aa to your computer and use it in GitHub Desktop.
Gource automation

Gource Automation

Watch the video

Example for rendering a Gource video from a Git repository between two dates corresponding to two tags:

# List tag dates in ISO format
$ git for-each-ref --format="%(refname:short) | %(creatordate:iso)" "refs/tags/*"
...
1.220.0 | 2024-05-14 12:26:53 +0200
1.222.0 | 2024-06-20 17:25:44 +0200
...
# Using gravatar images with user-image-dir
# Gource Automation https://gist.github.com/mkoertgen/61ef2e75e3e09659791b77d7f63f67aa
$ gource --user-image-dir .git/avatar/

# Interactive
$ gource --start-date "2024-05-14" --stop-date "2024-06-20"

# Show all options
$ gource -H

# Render video
$ gource --start-date "2024-05-14" --stop-date "2024-06-20" -o gource.ppm
# Convert to mp4 (should be good compression)
$ ffmpeg -y -r 60 -f image2pipe -vcodec ppm -i gource.ppm -vcodec libx264 -preset medium -pix_fmt yuv420p -f mp4 gource.mp4
# Add music
$ ffmpeg -i gource.mp4 -i music.mp3 -c:v copy -c:a aac -strict experimental gource-music.mp4
# Convert to webm
$ ffmpeg -i gource.mp4 -c:v libvpx -b:v 1M -c:a libvorbis gource.webm

Automation Examples

import os
import hashlib
import requests
import subprocess
# Ported from Perl: https://github.com/acaudwell/Gource/wiki/Gravatar-Example
# Configuration
size = 90
output_dir = '.git/avatar'
# Check for .git/ directory
if not os.path.isdir('.git'):
raise Exception("no .git/ directory found in current path")
# Create output directory if it doesn't exist
os.makedirs(output_dir, exist_ok=True)
# Execute git log command and get output
git_log_output = subprocess.check_output(
['git', 'log', '--pretty=format:%ae|%an'],
encoding='utf-8',
universal_newlines=True
)
processed_authors = set()
for line in git_log_output.splitlines():
email, author = line.split('|', 1)
# Skip if author has already been processed
if author in processed_authors:
continue
processed_authors.add(author)
author_image_file = os.path.join(output_dir, f'{author}.png')
# Skip if image already exists
if os.path.exists(author_image_file):
continue
# Generate Gravatar URL
email_hash = hashlib.md5(email.lower().encode('utf-8')).hexdigest()
grav_url = f"http://www.gravatar.com/avatar/{email_hash}?d=404&size={size}"
print(f"fetching image for '{author}' {email} ({grav_url})...")
# Fetch and save the image
response = requests.get(grav_url)
if response.status_code == 200:
with open(author_image_file, 'wb') as f:
f.write(response.content)
# Sleep to avoid hammering the server
#time.sleep(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment