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
|
import glob
import json
import os
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
def update_ytdl(parent_win):
try:
youtube_dl_found = subprocess.run(['where', 'youtube-dl'], stdout=subprocess.PIPE, text=True)
except FileNotFoundError:
youtube_dl_found = subprocess.run(['which', 'youtube-dl'], stdout=subprocess.PIPE, text=True)
if youtube_dl_found.returncode != 0:
def poll():
answer = wx.MessageBox("Could not find youtube-dl. Open vidslice README?", "Error", wx.YES_NO, parent_win)
if answer == wx.YES:
import webbrowser
webbrowser.open("https://github.com/boringcactus/vidslice/blob/master/README.md")
return
wx.CallAfter(poll)
youtube_dl_path = youtube_dl_found.stdout.split("\n")[0]
old_mtime = os.stat(youtube_dl_path).st_mtime
proc = subprocess.run(["youtube-dl", "-U"], stdout=subprocess.PIPE, text=True)
if not proc.stdout.startswith("youtube-dl is up-to-date"):
while os.stat(youtube_dl_path).st_mtime == old_mtime:
from time import sleep
sleep(0.25)
wx.CallAfter(lambda: wx.MessageBox("Updated youtube-dl successfully", "Complete", wx.OK, parent_win))
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()
|