Initial commit: phonestream project

This commit is contained in:
Nikolay
2026-07-03 16:08:02 +03:00
commit 7858eaeb2c
5 changed files with 920 additions and 0 deletions
+132
View File
@@ -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()