ScrcpyにGUI付けただけのアプリを作った

## scrcpy
Android端末の画面や音声をパソコンに共有できるコマンドラインツールです。
去年のアップデートでカメラの映像も流せるようになりました。
## 作ったもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557115/12cfbc3b-16c9-f0e1-99e9-6ca55b5a1875.png)
↑こんな見た目です。ちょっと雑ですけど。
動作的には次のような感じ。

![Code_Iyo8VUzqJn.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557115/1c87a62a-8c66-6b60-a1c8-00c894862c74.gif)

## コード
:::note warn
注意
汚いコードに注意してください。またエラーハンドリングをしていないのでエラーが出たら自力で解決してください
:::

```python:app.py
import flet as ft
import subprocess
import get_devices as gd
import time

def main(page: ft.Page):
    page.title = "Scrcpy_GUI"
    page.padding = 24
    page.theme_mode = ft.ThemeMode.SYSTEM
    devices = []
    process = None
    connect = False

    def check_av(e):
        if noaudio.value == True:
            novideo.value = False
            novideo.update()
        elif novideo.value == True:
            noaudio.value = False
            noaudio.update()

    def load_device(e):
        connected_devices = gd.get_connected_devices()
        options = [ft.dropdown.Option(device['device_id']) for device in connected_devices]
        device_dd.options = options
        page.update()

    def start_scrcpy(e):
        nonlocal connect, process

        nv = novideo.value
        na = noaudio.value
        bt = bitrate.value
        audio_s = audiosource.value
        ab = audiobuffer.value
        db = displaybuffer.value

        device = str(device_dd.value)
        print(device)
        command = ['scrcpy', '-s', device]
        if device != "None":
            if nv == True:
                command.append('--no-video')
            if na == True:
                command.append('--no-audio')
            if bt:
                command += ['-b',f'{bt}M']
            if audio_s is None and audio_s == "内部音声":
                pass
            elif audio_s == "マイク":
                command.append('--audio-source=mic')
            if ab:
                command.append(f'--audio-buffer={ab}')
            if db:
                command.append(f'--display-buffer={db}')
            if connect:
                if process is not None or process.poll() is None:
                    print("プロセスを停止")
                    process.terminate()
                    connect_btn.icon = ft.icons.PLAY_ARROW
                    connect_btn.text = "接続"
                    connect_btn.update()
                connect = False
            else:
                print("プロセスを開始")
                process = subprocess.Popen(command)
                connect = True
                connect_btn.icon = ft.icons.STOP
                connect_btn.text = "切断"
                connect_btn.update()
        else:
            connect_btn.text = "デバイスを選択してください"
            connect_btn.icon = ft.icons.ERROR
            connect_btn.update()
            time.sleep(2)
            connect_btn.text = "接続"
            connect_btn.icon = ft.icons.PLAY_ARROW
            connect_btn.update()
    
    title = ft.Text("Scrcpy_GUI", style=ft.TextThemeStyle.TITLE_MEDIUM,size=32)
    device_dd = ft.Dropdown(label="デバイス", expand=True, options=[])
    connect_btn = ft.FloatingActionButton(icon=ft.icons.PLAY_ARROW, text="接続", on_click=start_scrcpy)
    select_device = ft.Row([
        device_dd,
        ft.FilledButton("読み込み", icon=ft.icons.REFRESH, on_click=load_device)
    ], expand=0)
    novideo = ft.Switch(label="画面をキャストしない",value=False,expand=True,on_change=check_av)
    noaudio = ft.Switch(label="音声をキャストしない",value=False,expand=True,on_change=check_av)
    nosource = ft.Row([novideo,noaudio])
    bitrate = ft.TextField(label="映像ビットレート(デフォルト:8)",suffix_text="Mbps")
    audiosource = ft.Dropdown(label="オーディオソース",options=[ft.dropdown.Option("内部音声"),ft.dropdown.Option("マイク")])
    audiobuffer = ft.TextField(label="オーディオバッファー(デフォルト:50)",suffix_text="ms",expand=True,hint_text="大きくすれば途切れにくくなりますが遅延が大きくなります")
    displaybuffer = ft.TextField(label="ディスプレイバッファー(デフォルト:0)",suffix_text="ms",expand=True,hint_text="大きくすれば途切れにくくなりますが遅延が大きくなります")
    buffers = ft.Row([audiobuffer,displaybuffer])
    options = ft.Column([
        nosource,bitrate,audiosource,buffers
    ],spacing=10)

    page.add(title, select_device, connect_btn,options)

if __name__ == "__main__":
    ft.app(main)

```
デバイス取得するコード
```python:get_device.py
import subprocess

def get_connected_devices():
    # adb devicesコマンドを実行して接続されているデバイスの一覧を取得
    result = subprocess.run(['adb', 'devices'], capture_output=True, text=True)
    
    # 出力からデバイスのリストを作成
    output_lines = result.stdout.splitlines()[1:]
    devices = [{'device_id': line.split('\t')[0]} for line in output_lines if len(line.split('\t')) == 2]
    return devices
```
## 使うには
- scrcpyのインストール
- `flet` のインストール

です。これをすれば動きます。

## 以上
以上です。複数デバイスでもちゃんと動いちゃった。