Initial commit: phonestream project
This commit is contained in:
Executable
+132
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
PhoneStream Tray — иконка в системном трее.
|
||||
Запуск: python3 phonestream-tray.py
|
||||
Зависимости: gir1.2-appindicator3-0.1 (sudo apt install gir1.2-appindicator3-0.1)
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import threading
|
||||
import signal
|
||||
import gi
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('AppIndicator3', '0.1')
|
||||
|
||||
from gi.repository import Gtk, GLib
|
||||
from gi.repository import AppIndicator3 as AppIndicator
|
||||
|
||||
SCRIPT = "/home/nikolas/bin/phonestream/phonestream.sh"
|
||||
PHONE_ID = "c3c2c293"
|
||||
|
||||
PROFILES = [
|
||||
(0, "▶ Максимум (5MP 4:3)", "start", "0"),
|
||||
(1, "▶ Широкий (4MP 16:9)", "start", "1"),
|
||||
(2, "▶ 2.5K (5MP 4:3)", "start", "2"),
|
||||
(3, "▶ Full HD", "start", "3"),
|
||||
(4, "▶ Full HD 60fps", "start", "4"),
|
||||
(5, "▶ HD 120fps (slow-mo)", "start", "5"),
|
||||
(6, "▶ HD 240fps (slow-mo)", "start", "6"),
|
||||
]
|
||||
|
||||
|
||||
def is_stream_active():
|
||||
try:
|
||||
r = subprocess.run(["pgrep", "-f", "scrcpy.*v4l2-sink"],
|
||||
capture_output=True, text=True, timeout=2)
|
||||
return r.returncode == 0
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def is_phone_connected():
|
||||
try:
|
||||
r = subprocess.run(["adb", "devices"],
|
||||
capture_output=True, text=True, timeout=3)
|
||||
return PHONE_ID in r.stdout
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def run_script(args):
|
||||
def _run():
|
||||
try:
|
||||
subprocess.run([SCRIPT] + args, capture_output=True, text=True, timeout=15)
|
||||
except Exception:
|
||||
pass
|
||||
threading.Thread(target=_run, daemon=True).start()
|
||||
|
||||
|
||||
def make_menu():
|
||||
phone_ok = is_phone_connected()
|
||||
stream_active = is_stream_active()
|
||||
|
||||
menu = Gtk.Menu()
|
||||
|
||||
# Статус
|
||||
phone_item = Gtk.MenuItem(label=f"📱 Телефон: {'Подключён' if phone_ok else 'Нет'}")
|
||||
phone_item.set_sensitive(False)
|
||||
menu.append(phone_item)
|
||||
|
||||
stream_item = Gtk.MenuItem(label=f"📷 Стрим: {'Активен ●' if stream_active else 'Стоп ○'}")
|
||||
stream_item.set_sensitive(False)
|
||||
menu.append(stream_item)
|
||||
|
||||
menu.append(Gtk.SeparatorMenuItem())
|
||||
|
||||
if not stream_active:
|
||||
# Запуск с профилем
|
||||
for idx, label, action, profile_idx in PROFILES:
|
||||
item = Gtk.MenuItem(label=label)
|
||||
item.connect("activate", lambda i, p=profile_idx: run_script(["start", p]))
|
||||
menu.append(item)
|
||||
else:
|
||||
# Остановка
|
||||
stop_item = Gtk.MenuItem(label="⏹ Остановить")
|
||||
stop_item.connect("activate", lambda i: run_script(["stop"]))
|
||||
menu.append(stop_item)
|
||||
|
||||
# Перезапуск
|
||||
menu.append(Gtk.SeparatorMenuItem())
|
||||
for idx, label, action, profile_idx in PROFILES:
|
||||
restart_label = label.replace("▶", "🔄")
|
||||
item = Gtk.MenuItem(label=restart_label)
|
||||
item.connect("activate", lambda i, p=profile_idx: run_script(["restart", p]))
|
||||
menu.append(item)
|
||||
|
||||
menu.append(Gtk.SeparatorMenuItem())
|
||||
|
||||
status_item = Gtk.MenuItem(label="📊 Статус")
|
||||
status_item.connect("activate", lambda i: run_script(["status"]))
|
||||
menu.append(status_item)
|
||||
|
||||
quit_item = Gtk.MenuItem(label="✕ Выход из трея")
|
||||
quit_item.connect("activate", lambda i: Gtk.main_quit())
|
||||
menu.append(quit_item)
|
||||
|
||||
menu.show_all()
|
||||
return menu
|
||||
|
||||
|
||||
def main():
|
||||
indicator = AppIndicator.Indicator.new(
|
||||
"phonestream",
|
||||
"camera-web",
|
||||
AppIndicator.IndicatorCategory.HARDWARE
|
||||
)
|
||||
indicator.set_status(AppIndicator.IndicatorStatus.ACTIVE)
|
||||
indicator.set_title("PhoneStream")
|
||||
indicator.set_menu(make_menu())
|
||||
|
||||
# Обновление меню каждые 3 сек
|
||||
def refresh(ind):
|
||||
ind.set_menu(make_menu())
|
||||
return True
|
||||
|
||||
GLib.timeout_add_seconds(3, refresh, indicator)
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
Gtk.main()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user