Skip to content

Add onSessionStart and duringSession hooks#24

Open
ayrtmn wants to merge 12 commits intoBahaaio:mainfrom
ayrtmn:main
Open

Add onSessionStart and duringSession hooks#24
ayrtmn wants to merge 12 commits intoBahaaio:mainfrom
ayrtmn:main

Conversation

@ayrtmn
Copy link

@ayrtmn ayrtmn commented Mar 17, 2026

Summary

This PR adds comprehensive sound support to pomo with seamless audio playback inspired by TomatoBar:

1. New Hooks: onSessionStart and duringSession

Two new hook types for audio feedback:

  • onSessionStart: Play sound when session starts (windup.wav)
  • duringSession: Loop ambient sound during session (ticking.wav at 80% volume)

Both global (top-level) and per-task hooks are supported. Per-task hooks override global hooks.

2. Gapless Audio Playback

Uses mpv with --gapless-audio flag for seamless looping without gaps between iterations. Volume defaulted to 80% for better focus.

3. Audio Controls

  • Space bar: Pauses/resumes both timer AND audio together
  • "a" key: Toggles audio independently while timer keeps running
  • Audio mute state persists - pressing space after muting via "a" only resumes timer
  • "a" button disabled when session is paused

4. Command-line Audio Override

New --url / -u flag to override duringSession audio URL without editing config:

pomo -u "https://youtube.com/watch?v=..."  # Custom YouTube/Spotify audio

5. Timer Accuracy Fixes

Fixed timer drift issues when pausing/resuming multiple times by properly tracking elapsed time with pausedElapsed field.

Configuration

# Global hooks (defaults)
onSessionEnd: "ask"

onSessionStart:
  - [afplay, ~/sounds/windup.wav]

duringSession:
  - ["mpv", "--no-video", "--gapless-audio", "--loop-file=inf", "--volume=80", "~/sounds/ticking.wav"]

# Per-task hooks (override global)
work:
  duration: 25m
  onStart:
    - [afplay, ~/sounds/work-start.wav]  # overrides global
  during:
    - ["mpv", "--no-video", "--volume=80", "~/sounds/other.wav"]  # overrides global
  then:
    - [afplay, ~/sounds/ding.wav]

break:
  duration: 5m
  then:
    - [afplay, ~/sounds/ding.wav]

# Command-line override
# pomo -u "https://youtube.com/watch?v=..."

Sound Files

Copy sound files from TomatoBar or use your own:

mkdir -p ~/sounds
# Recommended from TomatoBar:
# - windup.wav (session start)
# - ticking.wav (during session - gapless loop)
# - ding.wav (session complete)

Key Bindings

Key Action
Space Pause/Resume timer AND audio together
a Toggle audio only (timer keeps running)
p Same as Space (pause/resume)
q Quit session
s Skip to next session
+ / Up Increase duration
- / Down Decrease duration
r Reset session

Implementation

  • config/config.go: Added OnSessionStart, DuringSession fields with mpv defaults
  • sound/sound.go: Enhanced PlayCommandLoop to support both afplay and mpv with IPC for pause/resume
  • ui/model.go: Audio state tracking (audioMuted, pausedElapsed)
  • ui/handlers.go: Integrated hooks with proper cleanup, pause/resume synchronization
  • cmd/root.go: Added --url flag
  • cmd/runner.go: URL override logic

Testing

  • Start sound (windup.wav) plays on session begin
  • Ambient sound (ticking.wav) loops gapless during session at 80% volume
  • Sounds properly cancelled on session end/quit
  • Space pauses both timer and audio synchronously
  • "a" toggles audio independently
  • Audio mute persists across space presses
  • "a" disabled when session is paused
  • Timer remains accurate through multiple pause/resume cycles
  • --url flag overrides config audio for YouTube/Spotify streams

ayrtmn and others added 12 commits March 17, 2026 09:44
Add two new hook types to the configuration system:
- onSessionStart: Run commands when a session starts (e.g., play start sound)
- duringSession: Run ambient sounds during session (e.g., rain, ticking)

Both global (top-level) and per-task hooks are supported.
Per-task hooks override global hooks when specified.

Example config:
  onSessionStart:
    - [afplay, ~/sounds/start.wav]
  duringSession:
    - [afplay, ~/sounds/rain.mp3]
  work:
    onStart: [...]  # overrides global
    during: [...]   # overrides global
Remove debug logging added during development.
Bug fix: commands are stored as [command, file, ...] so we need to pass
cmd[1] (the file path) instead of cmd[0] (the command itself) to the
sound player.
Add PlayCommandLoop and PlayCommandOnce to support commands with
multiple arguments like:
  - [mpv, --no-video, --loop, https://youtube.com/watch?v=...]

This enables YouTube audio streams and other complex audio sources
for gapless ambient sound playback.
Add Pause() and Resume() methods to sound.Player using mpv IPC socket.
When user pauses the timer, mpv playback is also paused. When resumed,
playback continues from the same position.

Config example:
  duringSession:
    - ["mpv", "--no-video", "https://youtube.com/watch?v=..."]

Press 'p' to pause - both timer and YouTube audio will pause.
Press 'p' again to resume - both resume from where they left off.
New key binding:
- "a" - Toggle during-session audio on/off without pausing timer

Workflow:
- Space - Pause timer AND audio together
- "a" - Toggle audio only (timer keeps running)

This allows muting the background music/rain sounds while keeping
the timer running, useful when you need silence temporarily.

Also fixes mpv IPC socket tracking for reliable pause/resume.
- Add --url (-u) flag to override duringSession audio URL from command line
- Fix timer accuracy issues when pausing/resume multiple times
- Add pausedElapsed field to track elapsed time during pause
- Update help text with --url flag example

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant