Sergey Kiselev
5 months ago
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