Add bundled default sound pack with auto-copy functionality
Features: - Complete default sound pack with 14 OGG audio files covering all Bifrost events - Auto-copy bundled pack to user data directory on first run (XDG compliant) - Graceful fallback if bundled pack is missing or copy fails - No network dependency for immediate audio feedback Sound Pack Contents: - Core sounds: startup, shutdown, success, error - Communication: private_message, mention, boost, reply, post_sent - Interface: timeline_update, notification - Interaction: autocomplete, autocomplete_end Technical Implementation: - Enhanced SoundManager.create_default_pack() to copy from bundled location - Smart path detection for bundled pack across different installation scenarios - Robust error handling with minimal fallback pack.json creation - Total pack size: ~260KB (suitable for regular Git without LFS) User Experience: - Immediate audio feedback from first application launch - No setup or configuration required - Sounds install to proper XDG data directory (~/.local/share/bifrost/sounds/) - Users can still customize or replace the default pack 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
BIN
sounds/default/autocomplete.ogg
Normal file
BIN
sounds/default/autocomplete.ogg
Normal file
Binary file not shown.
BIN
sounds/default/autocomplete_end.ogg
Normal file
BIN
sounds/default/autocomplete_end.ogg
Normal file
Binary file not shown.
BIN
sounds/default/boost.ogg
Normal file
BIN
sounds/default/boost.ogg
Normal file
Binary file not shown.
BIN
sounds/default/error.ogg
Normal file
BIN
sounds/default/error.ogg
Normal file
Binary file not shown.
BIN
sounds/default/mention.ogg
Normal file
BIN
sounds/default/mention.ogg
Normal file
Binary file not shown.
BIN
sounds/default/notification.ogg
Normal file
BIN
sounds/default/notification.ogg
Normal file
Binary file not shown.
21
sounds/default/pack.json
Normal file
21
sounds/default/pack.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Default",
|
||||
"description": "Clean, accessible default sounds for Bifrost",
|
||||
"author": "Bifrost Development Team",
|
||||
"version": "1.0",
|
||||
"sounds": {
|
||||
"private_message": "private_message.ogg",
|
||||
"mention": "mention.ogg",
|
||||
"boost": "boost.ogg",
|
||||
"reply": "reply.ogg",
|
||||
"post_sent": "post_sent.ogg",
|
||||
"timeline_update": "timeline_update.ogg",
|
||||
"notification": "notification.ogg",
|
||||
"autocomplete": "autocomplete.ogg",
|
||||
"autocomplete_end": "autocomplete_end.ogg",
|
||||
"startup": "startup.ogg",
|
||||
"shutdown": "shutdown.ogg",
|
||||
"success": "success.ogg",
|
||||
"error": "error.ogg"
|
||||
}
|
||||
}
|
BIN
sounds/default/post_sent.ogg
Normal file
BIN
sounds/default/post_sent.ogg
Normal file
Binary file not shown.
BIN
sounds/default/private_message.ogg
Normal file
BIN
sounds/default/private_message.ogg
Normal file
Binary file not shown.
BIN
sounds/default/reply.ogg
Normal file
BIN
sounds/default/reply.ogg
Normal file
Binary file not shown.
BIN
sounds/default/shutdown.ogg
Normal file
BIN
sounds/default/shutdown.ogg
Normal file
Binary file not shown.
BIN
sounds/default/startup.ogg
Normal file
BIN
sounds/default/startup.ogg
Normal file
Binary file not shown.
BIN
sounds/default/success.ogg
Normal file
BIN
sounds/default/success.ogg
Normal file
Binary file not shown.
BIN
sounds/default/timeline_update.ogg
Normal file
BIN
sounds/default/timeline_update.ogg
Normal file
Binary file not shown.
@@ -8,6 +8,7 @@ import json
|
||||
import wave
|
||||
import numpy as np
|
||||
import logging
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
from threading import Thread
|
||||
@@ -138,43 +139,73 @@ class SoundManager:
|
||||
self.sound_packs[pack_dir.name] = pack
|
||||
|
||||
def create_default_pack(self):
|
||||
"""Create default sound pack if it doesn't exist"""
|
||||
"""Create default sound pack if it doesn't exist by copying from bundled pack"""
|
||||
default_dir = self.settings.get_sounds_dir() / "default"
|
||||
default_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
pack_file = default_dir / "pack.json"
|
||||
if not pack_file.exists():
|
||||
# Try to copy from bundled default pack
|
||||
bundled_pack_dir = self._find_bundled_default_pack()
|
||||
if bundled_pack_dir and bundled_pack_dir.exists():
|
||||
self.logger.info(f"Copying bundled default sound pack from {bundled_pack_dir}")
|
||||
try:
|
||||
# Copy all files from bundled pack
|
||||
for file_path in bundled_pack_dir.iterdir():
|
||||
if file_path.is_file():
|
||||
shutil.copy2(file_path, default_dir / file_path.name)
|
||||
self.logger.info("Successfully copied bundled default sound pack")
|
||||
return
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Failed to copy bundled pack: {e}, creating minimal fallback")
|
||||
|
||||
# Fallback: create minimal pack.json (no actual sound files)
|
||||
self.logger.info("Creating minimal fallback default pack")
|
||||
pack_data = {
|
||||
"name": "Default",
|
||||
"description": "Default system sounds",
|
||||
"author": "Bifrost",
|
||||
"version": "1.0",
|
||||
"sounds": {
|
||||
"private_message": "private_message.wav",
|
||||
"direct_message": "direct_message.wav",
|
||||
"mention": "mention.wav",
|
||||
"boost": "boost.wav",
|
||||
"reply": "reply.wav",
|
||||
"favorite": "favorite.wav",
|
||||
"follow": "follow.wav",
|
||||
"unfollow": "unfollow.wav",
|
||||
"post_sent": "post_sent.wav",
|
||||
"post": "post.wav",
|
||||
"timeline_update": "timeline_update.wav",
|
||||
"notification": "notification.wav",
|
||||
"startup": "startup.wav",
|
||||
"shutdown": "shutdown.wav",
|
||||
"success": "success.wav",
|
||||
"error": "error.wav",
|
||||
"expand": "expand.wav",
|
||||
"collapse": "collapse.wav",
|
||||
"autocomplete": "autocomplete.wav",
|
||||
"autocomplete_end": "autocomplete_end.wav"
|
||||
"private_message": "private_message.ogg",
|
||||
"mention": "mention.ogg",
|
||||
"boost": "boost.ogg",
|
||||
"reply": "reply.ogg",
|
||||
"post_sent": "post_sent.ogg",
|
||||
"timeline_update": "timeline_update.ogg",
|
||||
"notification": "notification.ogg",
|
||||
"startup": "startup.ogg",
|
||||
"shutdown": "shutdown.ogg",
|
||||
"success": "success.ogg",
|
||||
"error": "error.ogg",
|
||||
"autocomplete": "autocomplete.ogg",
|
||||
"autocomplete_end": "autocomplete_end.ogg"
|
||||
}
|
||||
}
|
||||
|
||||
with open(pack_file, 'w') as f:
|
||||
json.dump(pack_data, f, indent=2)
|
||||
|
||||
def _find_bundled_default_pack(self) -> Optional[Path]:
|
||||
"""Find the bundled default sound pack directory"""
|
||||
# Look for bundled sounds relative to this file
|
||||
current_file = Path(__file__)
|
||||
|
||||
# Try different potential locations relative to the source
|
||||
potential_paths = [
|
||||
# From src/audio/sound_manager.py to sounds/default/
|
||||
current_file.parent.parent.parent / "sounds" / "default",
|
||||
# From installed location
|
||||
current_file.parent.parent / "sounds" / "default",
|
||||
# Current working directory
|
||||
Path.cwd() / "sounds" / "default"
|
||||
]
|
||||
|
||||
for path in potential_paths:
|
||||
if path.exists() and (path / "pack.json").exists():
|
||||
return path
|
||||
|
||||
return None
|
||||
|
||||
def load_current_pack(self):
|
||||
"""Load the currently selected sound pack"""
|
||||
|
Reference in New Issue
Block a user