A home photo and video management system

I want some tools to help me manage my photos and videos, conforming to some of my particular requirements.

I've already begun tinkering on some of my own, but with every line of code I think, "surely, someone must have done this already." Have you?


  • Backup. I have a local fileserver, but I want offsite backup too. Backblaze B2 looks cheapest but I also already have a DreamObjects account.
  • A thing to make it effortless to get photos off devices and into long-term storage.
def envbool(key, default=False, unknown=True):
"""Return a boolean value based on that of an environment variable.
Environment variables have no native boolean type. They are always strings, and may be empty or
unset (which differs from empty.) Furthermore, notions of what is "truthy" in shell script
differ from that of python.
This function converts environment variables to python boolean True or False in
case-insensitive, expected ways to avoid pitfalls:

Refactoring from an overuse of **kwargs


def a(**kwargs):
  if 'A' not in kwargs:
    kwargs['A'] = 1
  if 'B' not in kwargs:
    kwargs['B'] = 2
  success, result = b(**kwargs)

Basic Workflow


Different uses of git will have a different optimal workflow. This document describes a git workflow with the following characteristics:

  • It is a centralized workflow, meaning multiple developers all push to a shared repository. (As opposed to a fork-and-pull-request Github-style workflow.)
  • It is safe to use when collaborating on a feature branch with others, but requires no workflow changes when working alone. (So there's only one set of steps to remember.)
  • Some git users rely heavily on rebases, using them for any and all conflicts. This is an unhealthy coping mechanism born of past git merge trauma. This workflow relies heavily on merges, using rebase only when it is safe to do so (with commits that have yet to be pushed).
  • push --force is never needed (and may be disallowed by the remote repository.)
View WaitingProcessMonitor.tac
When you issue a SIGINT or SIGTERM to
twisted.runner.procmon.ProcessMonitor, its child processes get signalled
but it immediately disconnects from them and exits, even if they haven't
exited. This causes problems when we're trying to monitor a process that
has critical on-exit cleanup code.
This is a subclass modifying ProcessMonitor in such a way that it will
View definedoc.scm
; an imaginary syntax for docstrings. Goals:
; - runtime introspectable
; - DRY including explicit docs for each procedure
; argument, and its return value
; - hyperlinks in docstrings
; - executable code examples (doctests)
; - docstrings are rewrapped/formatted and docs for args
; and return value are formatted and appended for
; (procedure-documentation <proc>)
"If I had a filesystem that did blockwise deduplication with variable
block sizes (using Rabin-Karp rolling hash), how much space would I
Recursively reads all files under the current directory, printing
filenames as it goes, along with occasional cumulative statistics.
View .gitignore
# a stupid irc bot for demonstration of
# Copyright 2015 Michael F. Lamb <>
# License: AGPLv3+
while read prefix command arg0 arg1 args; do
case "$prefix" in
PING) echo PONG; continue ;;
case "$command $arg0 $arg1" in
"PRIVMSG $nickname :reload") exec "$0" "$@" ;;
"You can't spell 'skateboarding' without d-a-t-a-g-r-o-k."
Usage: python3 WORD
Prints all the words in its dictionary that contain at least all the
letters given in WORD
Copyright 2015 Michael F. Lamb <>