Spaces:
Sleeping
Sleeping
| """ | |
| FocusTrack - Main Entry Point | |
| Starts the tracker service and optionally the dashboard. | |
| """ | |
| import sys | |
| import os | |
| import argparse | |
| import threading | |
| import subprocess | |
| import logging | |
| from pathlib import Path | |
| # Add project root to path | |
| ROOT = Path(__file__).parent | |
| sys.path.insert(0, str(ROOT)) | |
| # ββ Create required directories BEFORE logging setup ββββββββββββββββββββββββββ | |
| (ROOT / "logs").mkdir(exist_ok=True) | |
| (ROOT / "data").mkdir(exist_ok=True) | |
| from tracker import ActivityTracker | |
| from database import Database | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", | |
| handlers=[ | |
| logging.FileHandler(ROOT / "logs" / "focustrack.log"), | |
| logging.StreamHandler(), | |
| ], | |
| ) | |
| logger = logging.getLogger("focustrack.main") | |
| def start_dashboard(): | |
| """Launch the Streamlit dashboard in a subprocess.""" | |
| ui_path = Path(__file__).parent / "app.py" | |
| cmd = [sys.executable, "-m", "streamlit", "run", str(ui_path), | |
| "--server.port", "8501", | |
| "--server.headless", "true", | |
| "--server.address", "localhost", | |
| "--browser.gatherUsageStats", "false"] | |
| logger.info("Starting FocusTrack Dashboard at http://localhost:8501") | |
| proc = subprocess.Popen(cmd) | |
| return proc | |
| def start_tray(tracker: ActivityTracker): | |
| """Start system tray icon (optional, graceful fallback).""" | |
| try: | |
| from tray import TrayApp | |
| tray = TrayApp(tracker) | |
| tray.run() | |
| except Exception as e: | |
| logger.warning(f"System tray unavailable: {e}. Running headless.") | |
| def main(): | |
| parser = argparse.ArgumentParser(description="FocusTrack - Local Activity Tracker") | |
| parser.add_argument("--no-tray", action="store_true", help="Disable system tray") | |
| parser.add_argument("--no-dashboard", action="store_true", help="Don't open browser dashboard") | |
| parser.add_argument("--tracker-only", action="store_true", help="Run tracker without dashboard") | |
| args = parser.parse_args() | |
| # Initialize database | |
| db = Database() | |
| db.initialize() | |
| logger.info("Database initialized") | |
| # Start tracker | |
| tracker = ActivityTracker(db) | |
| tracker_thread = threading.Thread(target=tracker.run, daemon=True) | |
| tracker_thread.start() | |
| logger.info("Activity tracker started") | |
| # Start dashboard | |
| dashboard_proc = None | |
| if not args.tracker_only and not args.no_dashboard: | |
| dashboard_proc = start_dashboard() | |
| # Start tray | |
| if not args.no_tray: | |
| tray_thread = threading.Thread(target=start_tray, args=(tracker,), daemon=True) | |
| tray_thread.start() | |
| logger.info("FocusTrack is running. Press Ctrl+C to stop.") | |
| try: | |
| tracker_thread.join() | |
| except KeyboardInterrupt: | |
| logger.info("Shutting down FocusTrack...") | |
| tracker.stop() | |
| if dashboard_proc: | |
| dashboard_proc.terminate() | |
| sys.exit(0) | |
| if __name__ == "__main__": | |
| main() | |