From d307ca1784b6992717c593ac36563a84b76b8bd8 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 26 Jan 2018 12:56:50 -0600 Subject: [PATCH] Added context menu for tracks and file downloads --- src/controller/mainController.py | 28 ++++++++++++++++++++++++++-- src/utils.py | 20 ++++++++++++++++++++ src/wxUI/mainWindow.py | 8 +++++++- src/wxUI/menus.py | 10 ++++++++++ 4 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 src/wxUI/menus.py diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 1d63afb..c3e76e3 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -5,7 +5,7 @@ import logging import widgetUtils import utils from pubsub import pub -from wxUI import mainWindow +from wxUI import mainWindow, menus from extractors import zaycev from . import player @@ -56,6 +56,9 @@ class Controller(object): widgetUtils.connect_event(self.window, widgetUtils.MENU, self.on_volume_up, menuitem=self.window.player_volume_up) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.on_mute, menuitem=self.window.player_mute) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.on_shuffle, menuitem=self.window.player_shuffle) + self.window.list.Bind(wx.EVT_LISTBOX_DCLICK, self.on_play) + self.window.list.Bind(wx.EVT_CONTEXT_MENU, self.on_context) + pub.subscribe(self.change_status, "change_status") # Event functions. These functions will call other functions in a thread and are bound to widget events. @@ -114,6 +117,26 @@ class Controller(object): def on_shuffle(self, *args, **kwargs): player.player.shuffle = self.window.player_shuffle.IsChecked() + def on_context(self, *args, **kwargs): + item = self.window.get_item() + if item == -1: + return wx.Bell() + menu = menus.contextMenu() + widgetUtils.connect_event(menu, widgetUtils.MENU, self.on_play, menuitem=menu.play) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.on_download, menuitem=menu.download) + self.window.PopupMenu(menu, wx.GetMousePosition()) + menu.Destroy() + + def on_download(self, *args, **kwargs): + item = self.results[self.window.get_item()] + f = "{0}.mp3".format(item.title) + if item.download_url == "": + item.get_download_url() + path = self.window.get_destination_path(f) + if path != None: + log.debug("downloading %s URL to %s filename" % (item.download_url, path,)) + utils.call_threaded(utils.download_file, item.download_url, path) + def change_status(self, status): """ Function used for changing the status bar from outside the main controller module.""" self.window.change_status("{0} {1}".format(status, self.get_status_info())) @@ -129,4 +152,5 @@ class Controller(object): self.results = self.extractor.results for i in self.results: self.window.list.Append(i.format_track()) - self.change_status("") \ No newline at end of file + self.change_status("") + diff --git a/src/utils.py b/src/utils.py index 6a6b2d4..05577b0 100644 --- a/src/utils.py +++ b/src/utils.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- +import os +import requests import threading import logging +from pubsub import pub log = logging.getLogger("utils") @@ -44,3 +47,20 @@ class RepeatingTimer(threading.Thread): self.function(*self.args, **self.kwargs) except: log.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs)) + +def download_file(url, local_filename): + r = requests.get(url, stream=True) + pub.sendMessage("change_status", status=_(u"Downloading {0}.").format(local_filename,)) + total_length = r.headers.get("content-length") + dl = 0 + total_length = int(total_length) + with open(local_filename, 'wb') as f: + for chunk in r.iter_content(chunk_size=64): + if chunk: # filter out keep-alive new chunks + dl += len(chunk) + f.write(chunk) + done = int(100 * dl / total_length) + msg = _(u"Downloading {0} ({1}%).").format(os.path.basename(local_filename), done) + pub.sendMessage("change_status", status=msg) + pub.sendMessage("change_status", status="") + return local_filename diff --git a/src/wxUI/mainWindow.py b/src/wxUI/mainWindow.py index 5d5ee8c..864196b 100644 --- a/src/wxUI/mainWindow.py +++ b/src/wxUI/mainWindow.py @@ -69,4 +69,10 @@ class mainWindow(wx.Frame): return t def get_item(self): - return self.list.GetSelection() \ No newline at end of file + return self.list.GetSelection() + + def get_destination_path(self, filename): + saveFileDialog = wx.FileDialog(self, _(u"Save this file"), "", filename, _(u"Audio Files(*.mp3)|*.mp3"), wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) + if saveFileDialog.ShowModal() == wx.ID_OK: + return saveFileDialog.GetPath() + saveFileDialog.Destroy() \ No newline at end of file diff --git a/src/wxUI/menus.py b/src/wxUI/menus.py new file mode 100644 index 0000000..27efa3b --- /dev/null +++ b/src/wxUI/menus.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +import wx + +class contextMenu(wx.Menu): + def __init__(self, *args, **kwargs): + super(contextMenu, self).__init__(*args, **kwargs) + self.play = wx.MenuItem(self, wx.NewId(), _("Play")) + self.AppendItem(self.play) + self.download = wx.MenuItem(self, wx.NewId(), _("Download")) + self.AppendItem(self.download)