-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun.py
More file actions
133 lines (114 loc) · 4.27 KB
/
run.py
File metadata and controls
133 lines (114 loc) · 4.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python3
"""
Navidrome → Discord Rich Presence with Imgur caching
Entry point for the navrpc package.
"""
import sys
import argparse
import threading
import logging
from navrpc.config import load_config
from navrpc.core import main_loop
from navrpc.validation import validate_configuration
from navrpc.logger import setup_logger, get_logger
def parse_args():
"""Parse command-line arguments."""
parser = argparse.ArgumentParser(
description="NavRPC - Navidrome Discord Rich Presence",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python run.py Run NavRPC
python run.py --debug Run with debug logging enabled
python run.py --validate-only Validate configuration and exit
"""
)
parser.add_argument(
'--debug',
action='store_true',
help='Enable debug logging'
)
parser.add_argument(
'--no-log-file',
action='store_true',
help='Disable logging to file'
)
parser.add_argument(
'--validate-only',
action='store_true',
help='Validate configuration and exit'
)
return parser.parse_args()
def main():
args = parse_args()
# Setup logging
log_level = logging.DEBUG if args.debug else logging.INFO
log_file = None if args.no_log_file else "navrpc.log"
setup_logger(level=log_level, log_file=log_file)
logger = get_logger()
try:
# Load and validate settings from config.yaml
logger.info("=" * 60)
logger.info("NavRPC - Navidrome Discord Rich Presence")
logger.info("=" * 60)
settings = load_config()
# Validate configuration
if not validate_configuration(settings):
logger.error("Configuration validation failed. Please fix errors and try again.")
sys.exit(1)
# Exit if validation-only mode
if args.validate_only:
logger.info("Validation complete. Exiting.")
sys.exit(0)
# Run with system tray UI
try:
from navrpc.tray import TrayIcon
logger.info("Starting NavRPC...")
logger.info("Right-click the tray icon to access menu options")
# Shared state for restart/reconnect
restart_event = threading.Event()
reconnect_event = threading.Event()
main_thread = None
def restart_app():
"""Restart the entire application."""
logger.info("Restarting application...")
import os
os.execv(sys.executable, [sys.executable] + sys.argv)
def reconnect_discord():
"""Signal to reconnect Discord RPC."""
logger.info("Reconnecting Discord RPC...")
reconnect_event.set()
# Create tray icon with callbacks
tray_icon = TrayIcon(
on_exit=lambda: sys.exit(0),
on_restart=restart_app,
on_reconnect=reconnect_discord
)
# Start main loop in background thread
main_thread = threading.Thread(
target=main_loop,
args=(settings, tray_icon),
daemon=True
)
main_thread.start()
# Run tray icon (blocking)
tray_icon.start()
except ImportError as e:
logger.error(f"System tray requires pystray: {e}")
logger.error("Install with: pip install pystray")
sys.exit(1)
except Exception as e:
logger.exception(f"Failed to start: {e}")
sys.exit(1)
except FileNotFoundError as e:
logger.error(f"Error: {e}")
logger.error("Please copy 'config.yaml.example' to 'config.yaml' and configure it.")
sys.exit(1)
except KeyboardInterrupt:
logger.info("Shutting down...")
sys.exit(0)
except Exception as e:
logger.exception(f"FATAL ERROR: {e}")
sys.exit(1)
if __name__ == "__main__":
main()