Jake Spurlock

15 Followers
71 Following
36 Posts
Baseball, WordPress, and bikes.
Websitehttps://jakespurlock.com

Little League Season Prep 2026

It’s that time of year again — fields are getting lined, equipment bags are coming out of garages, and coaches everywhere are scrambling to get organized before opening day.

Over the years, I’ve built a few tools to make my own coaching life easier. Here’s the stack I’m using for 2026:

The Lineup Spreadsheet

Still my most-shared resource. A simple Google Sheets template that lets you plan defensive positions, track pitching innings, and print out dugout-ready lineup cards.

Get the free lineup spreadsheet →

WalkUp DJ

New this year. Walk-up music for every kid — because that moment when they step up to bat should feel special. Apple Music integration, custom audio files, AirPlay support, and optional announcer voice intros.

Download WalkUp DJ on the App Store →

Draft Night

If your league does a player draft, this app handles the whole process — snake drafts, keeper rules, the works. I built it for Walnut Creek Little League and it’s been used by leagues across the country.

Check out Draft Night →

Good luck this season. Play ball. ⚾

#apps #Baseball #DraftNight #Drafts #Lineups #LittleLeague #Softball #Spreadsheet #WalkUpDJ

After 10 years of volunteering with Little League, I built the app I always wanted.

WalkUp DJ — walk-up music for youth baseball and softball.

Pick songs from Apple Music. Set the start time so the drop hits first. Tap to play when your kid steps up to bat.

AI announcer intros. AirPlay to the PA. Runs on iPhone, iPad, Mac, and Vision Pro.

Free tier gets you started. Spring season is here.

jakespurlock.com/2026/02/announcing-walkup-dj/

Announcing WalkUp DJ

WalkUp DJ is now available on the App Store.

It’s a walk-up music app for baseball and softball teams. Create your roster, assign each player a song, and play their entrance music with a single tap during games.

Download WalkUp DJ →

Features

Apple Music Integration — Search millions of songs, preview before you pick, set custom start times so the best part plays first.

Custom Audio — No Apple Music? Upload your own MP3s or M4As. Works with any audio file.

AI Announcer Intros — Generate stadium-style announcements: “Now batting… number 12… SARAH MARTINEZ!” Plays automatically before the walk-up song.

Game Mode — Full-screen batter cards, one-tap play, on-deck preview. Big buttons designed for the dugout.

Game Lineups — Build your batting order, drag to reorder, swap in substitutes mid-game.

Pitcher Warmup Music — Separate warmup songs for pitchers, accessible from a quick panel in Game Mode.

AirPlay Support — Send audio to a Bluetooth speaker, PA system, or any AirPlay device.

iCloud Sync — Keep your teams synced across all your devices.

Share Rosters — Export teams via QR code, file, or link. Import from other coaches instantly.

Pricing

The free tier includes one team with up to 12 players, full Apple Music integration, and Game Mode with auto-stop.

Pro ($9.99/year) unlocks unlimited teams, custom audio uploads, announcer intros, iCloud sync, and export.

Team Pack ($29.99 one-time) includes everything in Pro, forever, with no ads.

Platforms

WalkUp DJ runs on iPhone, iPad, Mac (Apple Silicon), and Vision Pro.

Spring season is here. Give your players the big league experience.

Download WalkUp DJ →

#AI #app #AppDevelopment #Apple #apps #development #iOS #MacIS #MacOS #NerdyStuff #Swift
@siracusa Not sure I agree, but I am obviously biased here. 😀

@siracusa comment caught me off guard, haha.

Former WIRED engineer here.

@brentsimmons this is kinda unreal for me to have you posting about my little app. Thanks for the ❤️.

Check out the iOS app too. It came first.

@siracusa Wired.com is WIRED magazine. Has been for 15ish years.

Built my own iMessage Wrapped in 30 minutes after my daughter said "I bet Dad could write this"

~100 lines of Python, your data never leaves your machine

Blog post + script: jakespurlock.com/2026/02/i-built-my-own-imessage-wrapped-and-so-can-you/

I Built My Own iMessage Wrapped (And So Can You)

My daughter was joking that someone should build a Spotify Wrapped, but for iMessage — your year in emoji and reactions. My wife said my brother-in-law should build it since he works at Apple. (Every Apple problem is his fault in our house.)

From the other room, my daughter yelled: “I bet Dad could write this!”

Challenge accepted.

The Result

Thirty minutes later, I had a working script. Here’s my 2025:

🎁 iMessage Wrapped 2025 📱 Messages Total: 35,768 Sent: 12,191 Received: 23,577 💬 Reactions Given: 1,974 Received: 5,014 🏆 Your Reaction Style 👍 982 ❤️ 398 😂 275 ‼️ 126 ❓ 19 👎 16 📈 Messages by Month Jan ███████████████ 3,052 Feb █████████████ 2,621 Mar █████████████████ 3,422 Apr ██████████████████ 3,696 May ██████████████████ 3,640 Jun ████████████████████ 3,904 Jul █████████████ 2,561 Aug ████████████ 2,448 Sep ██████████████ 2,790 Oct █████████████████ 3,466 Nov ███████████ 2,206 Dec ██████████ 1,962

Some things I learned about myself:

  • I’m a listener. I receive almost 2x as many messages as I send.
  • People love reacting to me. 5,014 reactions received vs 1,974 given.
  • I’m a thumbs-up guy. 👍 accounts for half my reactions. Apparently I’m very agreeable.
  • June was my chattiest month. December was quietest (holiday break mode).

How It Works

Your iMessage history lives in a SQLite database at ~/Library/Messages/chat.db. It’s just sitting there, queryable.

The tricky bits:

  • Dates are weird. Apple stores timestamps as nanoseconds since January 1, 2001 (because of course they do).
  • Reactions are messages. When you tapback a ❤️, it’s stored as a separate message with associated_message_type set to a magic number (2000 = loved, 2001 = liked, etc.).
  • Custom emoji reactions landed in iOS 17 and are stored in associated_message_emoji.
  • Once you know the schema, it’s just SQL.

    The Script

    Here’s the full thing — about 100 lines of Python, no dependencies beyond the standard library:

    #!/usr/bin/env python3 """ iMessage Wrapped — Your year in emoji and reactions Usage: python3 imessage-wrapped.py [year] Requires: Full Disk Access for Terminal """ import sqlite3 import os import sys from datetime import datetime from pathlib import Path YEAR = int(sys.argv[1]) if len(sys.argv) > 1 else 2025 DB_PATH = Path.home() / "Library/Messages/chat.db" APPLE_EPOCH_OFFSET = 978307200 TAPBACKS = { 2000: "❤️", # Loved 2001: "👍", # Liked 2002: "👎", # Disliked 2003: "😂", # Laughed 2004: "‼️", # Emphasized 2005: "❓", # Questioned } def get_db(): if not DB_PATH.exists(): print(f"❌ Database not found at {DB_PATH}") sys.exit(1) return sqlite3.connect(f"file:{DB_PATH}?mode=ro", uri=True) def date_filter(year): return f""" datetime(date/1000000000 + {APPLE_EPOCH_OFFSET}, 'unixepoch') >= '{year}-01-01' AND datetime(date/1000000000 + {APPLE_EPOCH_OFFSET}, 'unixepoch') < '{year + 1}-01-01' """ def main(): print(f"\n🎁 iMessage Wrapped {YEAR}\n") db = get_db() cur = db.cursor() # Message counts cur.execute(f""" SELECT COUNT(*), SUM(CASE WHEN is_from_me = 1 THEN 1 ELSE 0 END), SUM(CASE WHEN is_from_me = 0 THEN 1 ELSE 0 END) FROM message WHERE {date_filter(YEAR)} AND associated_message_type = 0 """) total, sent, received = cur.fetchone() print(f"📱 Messages: {total:,} ({sent:,} sent, {received:,} received)") # Reaction counts cur.execute(f""" SELECT SUM(CASE WHEN is_from_me = 1 THEN 1 ELSE 0 END), SUM(CASE WHEN is_from_me = 0 THEN 1 ELSE 0 END) FROM message WHERE {date_filter(YEAR)} AND associated_message_type >= 2000 """) given, got = cur.fetchone() print(f"💬 Reactions: {given + got:,} ({given:,} given, {got:,} received)") # Your tapback style print(f"\n🏆 Your Reaction Style") cur.execute(f""" SELECT associated_message_type, COUNT(*) FROM message WHERE {date_filter(YEAR)} AND associated_message_type BETWEEN 2000 AND 2005 AND is_from_me = 1 GROUP BY associated_message_type ORDER BY COUNT(*) DESC """) for type_id, cnt in cur.fetchall(): print(f" {TAPBACKS.get(type_id, '?')} {cnt:,}") # Custom emoji cur.execute(f""" SELECT associated_message_emoji, COUNT(*) FROM message WHERE {date_filter(YEAR)} AND associated_message_emoji IS NOT NULL AND is_from_me = 1 GROUP BY associated_message_emoji ORDER BY COUNT(*) DESC LIMIT 5 """) customs = cur.fetchall() if customs: print(f"\n🎯 Custom Reactions: {', '.join(f'{e} ({c})' for e, c in customs)}") # Monthly volume print(f"\n📈 By Month") cur.execute(f""" SELECT strftime('%m', datetime(date/1000000000 + {APPLE_EPOCH_OFFSET}, 'unixepoch')), COUNT(*) FROM message WHERE {date_filter(YEAR)} AND associated_message_type = 0 GROUP BY 1 ORDER BY 1 """) months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] data = {row[0]: row[1] for row in cur.fetchall()} max_cnt = max(data.values()) if data else 1 for i, name in enumerate(months, 1): cnt = data.get(f"{i:02d}", 0) bar = "█" * int(20 * cnt / max_cnt) print(f" {name} {bar} {cnt:,}") db.close() if __name__ == "__main__": main()

    Running It

  • Save the script as imessage-wrapped.py
  • Grant Full Disk Access to your terminal (System Settings → Privacy & Security → Full Disk Access)
  • Run it:
  • python3 imessage-wrapped.py # defaults to 2025 python3 imessage-wrapped.py 2024 # or any year

    That’s it. Your data never leaves your machine.

    What I’d Add Next

    If I turn this into a proper app:

    • Shareable cards — export your stats as an image
    • Conversation breakdown — who do you text the most?
    • Time of day patterns — are you a morning texter or a midnight scroller?
    • Streak tracking — longest daily conversation streak

    But honestly? The script is fun enough. Sometimes a quick hack that makes your daughter laugh is the whole point.

    The script and a slightly more polished version are on GitHub if you want to grab it.

    #Apple #iMessage #Messages #NerdyStuff #Python