-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdaw_tracker.py
More file actions
172 lines (150 loc) · 8.61 KB
/
daw_tracker.py
File metadata and controls
172 lines (150 loc) · 8.61 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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import psutil
import time
import mido
import threading
from datetime import datetime, timedelta
# Импортируем наш новый модуль для работы с БД
import database
import site_blocker # Импортируем модуль блокировки
# Список исполняемых файлов DAW, которые мы хотим отслеживать.
# Названия могут отличаться в зависимости от версии и ОС.
# ❗️ВАЖНО: Добавьте сюда имя процесса вашей DAW, если его нет в списке.
# Используйте find_processes.py, чтобы узнать точное имя.
# Все имена должны быть в НИЖНЕМ РЕГИСТРЕ.
DAW_PROCESS_NAMES = [
"ableton live 12 lite.exe", # <- Привел к нижнему регистру для корректной работы
"ableton live 11 suite.exe",
"fl64.exe",
"bitwigstudio.exe",
"reaper.exe",
"studio one.exe",
]
IDLE_THRESHOLD_SECONDS = 60 # Порог неактивности в секундах
TARGET_SECONDS_PER_DAY = 30 * 60 # Цель на день: 30 минут
LOOP_INTERVAL = 5 # Интервал проверки в секундах
def is_daw_running():
"""
Проверяет, запущен ли какой-либо из указанных DAW-процессов.
Возвращает имя процесса, если он найден, иначе None.
"""
for proc in psutil.process_iter(['name']):
# Сравниваем в нижнем регистре для надежности
if proc.info['name'].lower() in DAW_PROCESS_NAMES:
return proc.info['name'] # Возвращаем оригинальное имя для вывода
return None
def monitor_midi_activity(stop_event, last_midi_activity_ref):
"""
Эта функция запускается в отдельном потоке, слушает MIDI-события
и обновляет время последней активности.
"""
try:
# mido.open_input() без аргументов открывает первый доступный порт
with mido.open_input() as port:
print(f"🎧 Слушаем MIDI-порт: {port.name}")
# Обновляем время, чтобы сессия сразу считалась активной
last_midi_activity_ref[0] = datetime.now()
while not stop_event.is_set():
# Проверяем наличие сообщений без блокировки
if port.poll():
last_midi_activity_ref[0] = datetime.now()
time.sleep(0.1) # Небольшая пауза, чтобы не грузить CPU
except (IOError, OSError):
print("⚠️ MIDI-устройства не найдены. Отслеживание будет только по факту запуска DAW.")
# В этом случае мы просто обновляем время, пока DAW открыт
while not stop_event.is_set():
last_midi_activity_ref[0] = datetime.now()
time.sleep(1)
class CineBlockerTracker:
def __init__(self):
# --- Состояние трекера ---
self.total_today_seconds = 0
self.session_active = False
self.sites_are_blocked = None
self.is_idle = False
self.daw_process_name = None
self.status_text = "Инициализация..."
self.time_text = "00:00 / 30:00"
# --- Управление потоками ---
self.last_midi_activity = [None] # В списке для передачи по ссылке
self.midi_thread = None
self.stop_midi_thread_event = threading.Event()
self._stop_main_loop_event = threading.Event()
def _update_time_text(self):
"""Форматирует строку времени для GUI."""
done_mins, done_secs = divmod(self.total_today_seconds, 60)
target_mins, _ = divmod(TARGET_SECONDS_PER_DAY, 60)
self.time_text = f"{done_mins:02d}:{done_secs:02d} / {target_mins:02d}:00"
def run(self):
"""Основной цикл трекера. Запускается в отдельном потоке."""
print("🚀 Трекер запущен...")
database.init_db()
self.total_today_seconds = database.get_today_activity()
self._update_time_text()
# Начальная проверка и установка блокировки
if self.total_today_seconds < TARGET_SECONDS_PER_DAY:
self.sites_are_blocked = site_blocker.block_sites()
else:
if site_blocker.unblock_sites():
self.sites_are_blocked = False
while not self._stop_main_loop_event.is_set():
running_daw = is_daw_running()
if running_daw and not self.session_active:
# Начало сессии
self.session_active = True
self.daw_process_name = running_daw
self.status_text = f"✅ Обнаружен DAW: {self.daw_process_name}"
self.stop_midi_thread_event.clear()
self.midi_thread = threading.Thread(
target=monitor_midi_activity,
args=(self.stop_midi_thread_event, self.last_midi_activity),
daemon=True
)
self.midi_thread.start()
elif running_daw and self.session_active:
# Сессия активна
self.is_idle = self.last_midi_activity[0] and \
(datetime.now() - self.last_midi_activity[0]) > timedelta(seconds=IDLE_THRESHOLD_SECONDS)
if self.is_idle:
self.status_text = "😴 Пользователь неактивен, таймер на паузе..."
else:
self.status_text = "🎶 Сессия активна, время идет!"
self.total_today_seconds += LOOP_INTERVAL
self._update_time_text()
if self.sites_are_blocked and self.total_today_seconds >= TARGET_SECONDS_PER_DAY:
print("\n🎉 Поздравляем! Цель достигнута!")
database.save_today_activity(self.total_today_seconds)
if site_blocker.unblock_sites():
self.sites_are_blocked = False
self.status_text = f"✅ Цель достигнута! Наслаждайтесь отдыхом."
elif not running_daw and self.session_active:
# Завершение сессии
self.status_text = "🛑 DAW закрыт. Сессия завершена."
database.save_today_activity(self.total_today_seconds)
self.session_active = False
self.stop_midi_thread_event.set()
if self.midi_thread:
self.midi_thread.join()
self.last_midi_activity[0] = None
else:
# Ожидание
if self.total_today_seconds < TARGET_SECONDS_PER_DAY:
self.status_text = "...Ожидаем запуска DAW. Сайты заблокированы."
else:
self.status_text = "...Ожидаем запуска DAW. Цель на день выполнена."
time.sleep(LOOP_INTERVAL)
self._shutdown()
def stop(self):
"""Сигнализирует основному циклу и потокам о необходимости остановиться."""
print("Получен сигнал на остановку трекера...")
self._stop_main_loop_event.set()
self.stop_midi_thread_event.set()
def _shutdown(self):
"""Выполняет чистое завершение работы: сохраняет данные, снимает блокировку."""
print("Трекер завершает работу, сохраняем данные...")
database.save_today_activity(self.total_today_seconds)
if self.sites_are_blocked:
print("Снимаем блокировку сайтов перед выходом...")
site_blocker.unblock_sites()
if self.midi_thread and self.midi_thread.is_alive():
self.midi_thread.join()
print("👋 Трекер полностью остановлен.")