aboutsummaryrefslogtreecommitdiff
path: root/sources.py
blob: f15f3b3c6ea1fe5edb943bf02b5ae93a3d05173d (plain)
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
import glob
import json
import subprocess
import tempfile
import threading

import wx


def has_ytdl():
    try:
        subprocess.run(["youtube-dl", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        return True
    except FileNotFoundError:
        return False


class SourcesPanel(wx.Panel):
    """
    A Panel representing source info
    """

    def __init__(self, *args, **kw):
        super(SourcesPanel, self).__init__(*args, **kw)
        self.update_listeners = []

        root_sizer = wx.StaticBoxSizer(wx.VERTICAL, self, label="Sources")
        self.SetSizer(root_sizer)
        main = wx.Panel(self)
        root_sizer.Add(main, proportion=1, flag=wx.EXPAND, border=5)
        main_sizer = wx.GridBagSizer(5, 5)
        main.SetSizer(main_sizer)

        if has_ytdl():
            main_sizer.Add(wx.StaticText(main, label="URL"), wx.GBPosition(0, 0), flag=wx.EXPAND)
            self.url_text = wx.TextCtrl(main)
            main_sizer.Add(self.url_text, wx.GBPosition(0, 1), flag=wx.EXPAND)
            self.url_download_button = wx.Button(main, label="Download")
            self.url_download_button.Bind(wx.EVT_BUTTON, self.handle_url_download_pressed)
            main_sizer.Add(self.url_download_button, wx.GBPosition(0, 2), flag=wx.EXPAND)
        else:
            no_ytdl_label = wx.StaticText(main, label="Could not find youtube-dl, can't download videos automatically")
            main_sizer.Add(no_ytdl_label, wx.GBPosition(0, 0), wx.GBSpan(1, 3), flag=wx.EXPAND)

        main_sizer.Add(wx.StaticText(main, label="File"), wx.GBPosition(1, 0), flag=wx.EXPAND)
        self.file_text = wx.TextCtrl(main)
        self.file_text.Bind(wx.EVT_TEXT, self.handle_file_changed)
        main_sizer.Add(self.file_text, wx.GBPosition(1, 1), flag=wx.EXPAND)
        self.file_browse_button = wx.Button(main, label="Browse")
        self.file_browse_button.Bind(wx.EVT_BUTTON, self.handle_file_browse_pressed)
        main_sizer.Add(self.file_browse_button, wx.GBPosition(1, 2), flag=wx.EXPAND)

        self.status_label = wx.StaticText(main, label="Status: Select a file")
        main_sizer.Add(self.status_label, wx.GBPosition(2, 0), wx.GBSpan(1, 3))

        main_sizer.AddGrowableCol(1, proportion=1)

    def set_status(self, text):
        self.status_label.SetLabel("Status: " + text)

    def handle_url_download_pressed(self, _):
        self.set_status("Downloading...")

        def download():
            file = tempfile.NamedTemporaryFile(delete=False)
            # noinspection PyArgumentList
            proc = subprocess.Popen([
                'youtube-dl', '-o', file.name + '.%(ext)s', self.url_text.GetValue()
            ], stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            while proc.poll() is None:
                out_data = proc.stdout.readline()
                if out_data != '':
                    wx.CallAfter(lambda: self.set_status("Downloading: " + out_data.strip()))
            if proc.returncode == 0:
                output_file = glob.glob(glob.escape(file.name) + '.*')[0]
                wx.CallAfter(lambda: self.set_status("Downloaded!"))
                wx.CallAfter(lambda: self.file_text.SetValue(output_file))
            else:
                error = ''.join(proc.stderr.readlines()).strip()
                wx.CallAfter(lambda: self.set_status("Couldn't download: " + error))

        threading.Thread(target=download).start()

    def handle_file_browse_pressed(self, _):
        dialog = wx.FileDialog(self, style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
        if dialog.ShowModal() == wx.ID_OK:
            self.file_text.SetValue(dialog.GetPath())

    def handle_file_changed(self, _event):
        result = subprocess.run([
            'ffprobe', '-v', 'error', '-of', 'json',
            '-show_entries', 'format=start_time,duration:stream=index,codec_type,avg_frame_rate,width,height',
            self.file_text.GetValue()
        ], capture_output=True, text=True)
        if result.returncode == 0:
            ffprobe_data = json.loads(result.stdout)
            self.set_status("Successfully loaded media info")
            for listener in self.update_listeners:
                listener(ffprobe_data)
        else:
            self.set_status("Failed to load media info: " + result.stderr)
            for listener in self.update_listeners:
                listener(None)

    def on_update(self, callback):
        self.update_listeners.append(callback)

    def get_file(self):
        return self.file_text.GetValue()