2 changed files with 172 additions and 0 deletions
@ -0,0 +1,153 @@ |
|||
#!/usr/bin/env python3 |
|||
# coding: utf-8 |
|||
# vim:et:sta:sts=4:sw=4:ts=8:tw=79: |
|||
|
|||
import gi |
|||
|
|||
gi.require_version("Gtk", "3.0") |
|||
from gi.repository import Gtk |
|||
|
|||
import shlex, subprocess |
|||
import yt_dlp |
|||
|
|||
class wnd(Gtk.Window): |
|||
def __init__(self): |
|||
super().__init__( |
|||
border_width = 20, |
|||
default_height = 240, |
|||
default_width = 480, |
|||
icon_name = "youtube", |
|||
resizable = False, |
|||
title = "yt-dlp GUI", |
|||
window_position = Gtk.WindowPosition.CENTER, |
|||
) |
|||
|
|||
self.controls = { |
|||
'url' : { 'e':Gtk.Entry(hexpand = True), |
|||
'l':Gtk.Label(label = "Video URL:", xalign = 0), |
|||
'w':2 }, |
|||
'title' : { 'e':Gtk.Entry(editable = False, hexpand = True), |
|||
'l':Gtk.Label(label = "Title:", xalign = 0), |
|||
'w':3 }, |
|||
'resolution' : { 'e':Gtk.ComboBoxText(), |
|||
'l':Gtk.Label(label = "Resolution:", xalign = 0), |
|||
'w':1 }, |
|||
'scale' : { 'e':Gtk.ComboBoxText(), |
|||
'l':Gtk.Label(label = "Scale:", xalign = 0), |
|||
'w':1 } |
|||
} |
|||
|
|||
self.chk = [ |
|||
{ 'e':Gtk.CheckButton(label = "On-Top"), |
|||
'opt':' --ontop' }, |
|||
{ 'e':Gtk.CheckButton(label = "Without borders"), |
|||
'opt':' --no-border' }, |
|||
{ 'e':Gtk.CheckButton(label = "On all workspaces"), |
|||
'opt':' --on-all-workspaces' } |
|||
] |
|||
|
|||
self.url = "" |
|||
|
|||
vbox = Gtk.Box(orientation = Gtk.Orientation.VERTICAL, spacing = 8) |
|||
self.add(vbox) |
|||
|
|||
g_main = Gtk.Grid(column_spacing = 8, row_spacing = 8, hexpand = True) |
|||
vbox.pack_start(g_main, True, True, 0) |
|||
|
|||
g_buttons = Gtk.Grid(column_spacing = 8, row_spacing = 8, |
|||
halign = Gtk.Align.END, valign = Gtk.Align.END) |
|||
vbox.pack_start(g_buttons, True, True, 0) |
|||
|
|||
for k in self.controls.keys(): |
|||
g_main.attach_next_to(self.controls[k]['l'], None, |
|||
Gtk.PositionType.BOTTOM, 1, 1) |
|||
g_main.attach_next_to(self.controls[k]['e'], |
|||
self.controls[k]['l'], |
|||
Gtk.PositionType.RIGHT, |
|||
self.controls[k]['w'], 1) |
|||
|
|||
b_get_info = Gtk.Button(image = Gtk.Image.new_from_icon_name( |
|||
"gtk-find", Gtk.IconSize.BUTTON)) |
|||
g_main.attach_next_to(b_get_info, self.controls['url']['e'], |
|||
Gtk.PositionType.RIGHT, 1, 1) |
|||
|
|||
g_checkboxes = Gtk.Grid(column_spacing = 8, row_spacing = 8, |
|||
hexpand = True) |
|||
g_main.attach(g_checkboxes, 2, 2, 1, 4) |
|||
|
|||
for c in self.chk: |
|||
g_checkboxes.attach_next_to(c['e'], None, |
|||
Gtk.PositionType.BOTTOM, 1, 1) |
|||
|
|||
b_ok = Gtk.Button(label = "Ok", |
|||
image = Gtk.Image.new_from_icon_name( |
|||
"gtk-ok", Gtk.IconSize.BUTTON)) |
|||
b_cancel = Gtk.Button(label = "Cancel", |
|||
image = Gtk.Image.new_from_icon_name( |
|||
"gtk-cancel", Gtk.IconSize.BUTTON)) |
|||
|
|||
g_buttons.attach(b_ok, 0, 0, 1, 1) |
|||
g_buttons.attach(b_cancel, 1, 0, 1, 1) |
|||
|
|||
for s in ["x0.5", "x1", "x2"]: |
|||
self.controls['scale']['e'].append_text(s) |
|||
|
|||
self.controls['scale']['e'].set_active(1) |
|||
|
|||
b_cancel.connect("clicked", self.on_cancel_clicked) |
|||
b_ok.connect("clicked", self.on_ok_clicked) |
|||
b_get_info.connect("clicked", self.get_info) |
|||
|
|||
def on_cancel_clicked(self, button): |
|||
self.destroy() |
|||
|
|||
def on_ok_clicked(self, button): |
|||
cmd = "mpv --no-terminal" |
|||
|
|||
for c in self.chk: |
|||
if c['e'].get_active(): |
|||
cmd += c['opt'] |
|||
|
|||
cmd += " --window-scale=" |
|||
cmd += self.controls['scale']['e'].get_active_text()[1:] |
|||
cmd += " --ytdl-format=\"bv*[height<=" |
|||
cmd += self.controls['resolution']['e'].get_active_text()[0:-1] |
|||
cmd += "]+ba/b[height<=" |
|||
cmd += self.controls['resolution']['e'].get_active_text()[0:-1] |
|||
cmd += "] / wv*+ba/w\" " |
|||
cmd += self.url |
|||
|
|||
args = shlex.split(cmd) |
|||
|
|||
p = subprocess.Popen(args, |
|||
stdin = subprocess.DEVNULL, |
|||
stdout = subprocess.DEVNULL, |
|||
stderr = subprocess.DEVNULL) |
|||
|
|||
self.destroy() |
|||
|
|||
def get_info(self, button): |
|||
self.url = self.controls['url']['e'].get_text() |
|||
|
|||
if self.url: |
|||
ydl_opts = { 'quiet': True, 'no-warnings': True } |
|||
with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
|||
info = ydl.extract_info(self.url, download = False) |
|||
self.controls['title']['e'].set_text(info['title']) |
|||
|
|||
h = [] |
|||
for f in info['formats']: |
|||
if f['vcodec'] != "none" and f['height'] not in h: |
|||
h.append(f['height']) |
|||
self.controls['resolution']['e'].append_text( |
|||
"{}p".format(f['height'])) |
|||
|
|||
self.controls['resolution']['e'].set_active(0) |
|||
else: |
|||
self.controls['title']['e'].set_text("Error: Empty url.") |
|||
|
|||
win = wnd() |
|||
win.connect("destroy", Gtk.main_quit) |
|||
win.show_all() |
|||
Gtk.main() |
|||
|
Loading…
Reference in new issue