# Gtk imports import gi, faulthandler, signal gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import GLib from gi.repository.GdkPixbuf import Pixbuf # Python imports import threading, subprocess, os, requests from setproctitle import setproctitle # Application imports def threaded(fn): def wrapper(*args, **kwargs): threading.Thread(target=fn, args=args, kwargs=kwargs).start() return wrapper class Controller: def __init__(self, settings): setproctitle('Media Downloader') GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, Gtk.main_quit) faulthandler.enable() # For better debug info self.settings = settings self.builder = self.settings.returnBuilder() self.downloadTypes = self.builder.get_object("downloadTypes") self.urlEntry = self.builder.get_object("urlEntry") self.downloadButton = self.builder.get_object("downloadButton") self.thumbnail = self.builder.get_object("thumbnailImg") self.selected = None def updateYoutubeDl(self, widget): pass def paste(self, widget): entry = self.getClipboardData() self.urlEntry.set_text(entry) @threaded def urlChanged(self, widget): # This also gets called by paste entry = widget.get_text().strip() size = len(entry) thumbUrl = "https://img.youtube.com/vi/" + entry[(size - 11): size] + "/hqdefault.jpg" self.setThumbnail(thumbUrl) self.downloadButton.set_sensitive(False) self.downloadTypes.clear() if entry: if len(entry) in [28, 43]: if "youtu.be" in entry or "watch?v=" in entry: self.showDownloadTypes() def showDownloadTypes(self): lines = self.getFormatData().split("\n") # Remove pre format strings i = 0 while i <= 3: del lines[0] i += 1 for line in lines: parts = line.split() while len(parts) != 4: parts.append("NO DATA") if parts[3][len(parts[3]) - 1] == ",": parts[3] = parts[3][0:len(parts[3]) - 1] self.downloadTypes.append(parts) @threaded def download(self, widget): url = self.urlEntry.get_text() dlComm = ["youtube-dl", "--no-playlist", "-o", "~/Downloads/%(title)s.%(ext)s", "-f", self.selected, url] proc = subprocess.Popen(dlComm, stdout=subprocess.PIPE) # Gets formats while True: line = proc.stdout.readline() if not line: break print(line.decode("utf-8").rstrip()) def setSelected(self, widget, row, col): model = widget.get_model() self.selected = model[row][0] self.downloadButton.set_sensitive(True) @threaded def setThumbnail(self, url): fname = "/tmp/thumbnail-hqdefault.jpg" r = requests.get(url, allow_redirects=True) open(fname, 'wb').write(r.content) self.thumbnail.set_from_pixbuf(Pixbuf.new_from_file(fname)) def getFormatData(self): url = self.urlEntry.get_text() dlComm = ["youtube-dl", "-F", url] awkComm = ["awk", "{ print $1, $2, $3, $11 }"] proc = subprocess.Popen(dlComm, stdout=subprocess.PIPE) # Gets formats proc.wait() data = subprocess.check_output(awkComm, stdin=proc.stdout) # "Piping" to awk to get columns return data.decode("utf-8").strip() def getClipboardData(self): proc = subprocess.Popen(['xclip','-selection', 'clipboard', '-o'], stdout=subprocess.PIPE) retcode = proc.wait() data = proc.stdout.read() return data.decode("utf-8").strip() def setClipboardData(self, data): proc = subprocess.Popen(['xclip','-selection','clipboard'], stdin=subprocess.PIPE) proc.stdin.write(data) proc.stdin.close() retcode = proc.wait()