diff --git a/changelog.md b/changelog.md index 1474162..8f6b4b3 100644 --- a/changelog.md +++ b/changelog.md @@ -5,7 +5,7 @@ * Added a new menu in the menu bar that allows you to control the audio playback. For some actions (like play, next and back), if you are not focusing an audio buffer, the program will take the song from the "my audios" buffer. * Added two more buffers: "Followers" and "I follow", located in the people buffer, under "friendship requests". * Added an experimental photo viewer. Will show options for see the next and previous photo if the current post contains multiple images. -* Improved chats, now they should be more stable. +* Improved chats, now they should be more stable. Also you will be able to send the message by pressing enter in the text box. If you are trying to send the same message multiple times, you will be warned. ## Changes in build 2016.07.08 (08/07/2016) diff --git a/src/controller/buffers.py b/src/controller/buffers.py index 2fb74f8..846fce3 100644 --- a/src/controller/buffers.py +++ b/src/controller/buffers.py @@ -10,6 +10,7 @@ import player import output import logging import selector +import webbrowser from wxUI.tabs import home from pubsub import pub from sessionmanager import session @@ -395,7 +396,7 @@ class audioBuffer(feedBuffer): self.tab.list.remove_item(self.tab.list.get_selected()) def move_to_album(self, *args, **kwargs): - album = selector.audioAlbum(_(u"Select the album where you want to move this song"), self.session) + album = selector.album(_(u"Select the album where you want to move this song"), self.session) if album.item == None: return id = self.get_post()["id"] response = self.session.vk.client.audio.moveToAlbum(album_id=album.item, audio_ids=id) @@ -436,6 +437,113 @@ class audioAlbum(audioBuffer): self.tab.play.Enable(True) self.tab.play_all.Enable(True) +class videoBuffer(feedBuffer): + def create_tab(self, parent): + self.tab = home.videoTab(parent) + + def connect_events(self): + widgetUtils.connect_event(self.tab.play, widgetUtils.BUTTON_PRESSED, self.play_audio) + super(videoBuffer, self).connect_events() + + def play_audio(self, *args, **kwargs): + selected = self.tab.list.get_selected() + if selected == -1: + selected = 0 + output.speak(_(u"Opening video in webbrowser...")) + webbrowser.open_new_tab(self.session.db[self.name]["items"][selected]["player"]) + return True + + def open_post(self, *args, **kwargs): + selected = self.tab.list.get_selected() + audios = [self.session.db[self.name]["items"][selected]] + a = posts.audio(self.session, audios) + a.dialog.get_response() + a.dialog.Destroy() + + def remove_buffer(self, mandatory=False): + if "me_video" == self.name: + output.speak(_(u"This buffer can't be deleted")) + return False + else: + if mandatory == False: + dlg = commonMessages.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + self.session.db.pop(self.name) + return True + else: + return False + + def get_more_items(self, *args, **kwargs): + # Translators: Some buffers can't use the get previous item feature due to API limitations. + output.speak(_(u"This buffer doesn't support getting more items.")) + + def onFocus(self, *args, **kwargs): + pass + + def add_to_library(self, *args, **kwargs): + post = self.get_post() + args = {} + args["video_id"] = post["id"] + if post.has_key("album_id"): + args["album_id"] = post["album_id"] + args["owner_id"] = post["owner_id"] + video = self.session.vk.client.video.add(**args) + if video != None and int(video) > 21: + output.speak(_(u"Video added to your library")) + + def remove_from_library(self, *args, **kwargs): + post = self.get_post() + args = {} + args["video_id"] = post["id"] + args["owner_id"] = self.session.user_id + result = self.session.vk.client.video.delete(**args) + if int(result) == 1: + output.speak(_(u"Removed video from library")) + self.tab.list.remove_item(self.tab.list.get_selected()) + + def move_to_album(self, *args, **kwargs): + album = selector.album(_(u"Select the album where you want to move this video"), self.session, "video_albums") + if album.item == None: return + id = self.get_post()["id"] + response = self.session.vk.client.video.addToAlbum(album_ids=album.item, video_id=id, target_id=self.session.user_id, owner_id=self.get_post()["owner_id"]) + if response == 1: + # Translators: Used when the user has moved an video to an album. + output.speak(_(u"Moved")) + + def get_menu(self): + """ We'll use the same menu that is used for audio items, as the options are exactly the same""" + p = self.get_post() + m = menus.audioMenu() +# widgetUtils.connect_event(m, widgetUtils.MENU, self.open_post, menuitem=m.open) +# widgetUtils.connect_event(m, widgetUtils.MENU, self.play_audio, menuitem=m.play) + widgetUtils.connect_event(m, widgetUtils.MENU, self.move_to_album, menuitem=m.move) + # if owner_id is the current user, the audio is added to the user's audios. + if p["owner_id"] == self.session.user_id: + m.library.SetItemLabel(_(u"&Remove from library")) + widgetUtils.connect_event(m, widgetUtils.MENU, self.remove_from_library, menuitem=m.library) + else: + widgetUtils.connect_event(m, widgetUtils.MENU, self.add_to_library, menuitem=m.library) + return m + +class videoAlbum(videoBuffer): + + def create_tab(self, parent): + self.tab = home.videoAlbumTab(parent) + self.tab.play.Enable(False) + + def connect_events(self): + super(videoAlbum, self).connect_events() + widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_album) + + def load_album(self, *args, **kwargs): + output.speak(_(u"Loading album...")) + self.can_get_items = True + self.tab.load.Enable(False) + wx.CallAfter(self.get_items) + self.tab.play.Enable(True) + class empty(object): def __init__(self, name=None, parent=None, *args, **kwargs): @@ -479,7 +587,7 @@ class chatBuffer(baseBuffer): print "inserting a value" v = [i for i in self.session.db[self.name]["items"][:num]] v.reverse() - [self.insert(i, True) for i in v] + [self.insert(i, False) for i in v] else: [self.insert(i) for i in self.session.db[self.name]["items"][:num]] else: diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 7ef7842..902840c 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -92,6 +92,18 @@ class Controller(object): albums = buffers.empty(parent=self.window.tb, name="albums") self.buffers.append(albums) self.window.insert_buffer(albums.tab, _(u"Albums"), self.window.search("audios")) + + videos = buffers.empty(parent=self.window.tb, name="videos") + self.buffers.append(videos) + # Translators: name for the videos category in the tree view. + self.window.add_buffer(videos.tab, _(u"Video")) + my_videos = buffers.videoBuffer(parent=self.window.tb, name="me_video", composefunc="compose_video", session=self.session, endpoint="get", parent_endpoint="video", count=self.session.settings["buffers"]["count_for_video_buffers"]) + self.buffers.append(my_videos) + self.window.insert_buffer(my_videos.tab, _(u"My videos"), self.window.search("videos")) + video_albums = buffers.empty(parent=self.window.tb, name="video_albums") + self.buffers.append(video_albums) + self.window.insert_buffer(video_albums.tab, _(u"Albums"), self.window.search("videos")) + people = buffers.empty(parent=self.window.tb, name="people") self.buffers.append(people) self.window.add_buffer(people.tab, _(u"People")) @@ -139,6 +151,8 @@ class Controller(object): widgetUtils.connect_event(self.window, widgetUtils.MENU, self.new_timeline, menuitem=self.window.timeline) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.create_audio_album, menuitem=self.window.audio_album) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.delete_audio_album, menuitem=self.window.delete_audio_album) + widgetUtils.connect_event(self.window, widgetUtils.MENU, self.create_video_album, menuitem=self.window.video_album) + widgetUtils.connect_event(self.window, widgetUtils.MENU, self.delete_video_album, menuitem=self.window.delete_video_album) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.check_documentation, menuitem=self.window.documentation) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.menu_play_pause, menuitem=self.window.player_play) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.menu_play_next, menuitem=self.window.player_next) @@ -180,6 +194,7 @@ class Controller(object): self.set_online() self.create_unread_messages() wx.CallAfter(self.get_audio_albums, self.session.user_id) + wx.CallAfter(self.get_video_albums, self.session.user_id) def in_post(self, buffer): buffer = self.search(buffer) @@ -411,6 +426,27 @@ class Controller(object): # inserts a pause of 1 second here, so we'll avoid errors 6 in VK. time.sleep(0.3) + def get_video_albums(self, user_id=None): + try: + log.debug("Create video albums...") + albums = self.session.vk.client.video.getAlbums(owner_id=user_id) + except VkAPIMethodError as ex: + if ex.code == 6: + log.exception("Something went wrong when getting albums. Waiting a second to retry") + time.sleep(2) + return self.get_audio_albums(user_id=user_id) + self.session.video_albums = albums["items"] + for i in albums["items"]: + buffer = buffers.videoAlbum(parent=self.window.tb, name="{0}_video_album".format(i["id"],), composefunc="compose_video", session=self.session, endpoint="get", parent_endpoint="video", count=self.session.settings["buffers"]["count_for_video_buffers"], user_id=user_id, album_id=i["id"]) + buffer.can_get_items = False + # Translators: {0} Will be replaced with a video album's title. + name_ = _(u"Album: {0}").format(i["title"],) + self.buffers.append(buffer) + self.window.insert_buffer(buffer.tab, name_, self.window.search("video_albums")) + buffer.get_items() + # inserts a pause of 1 second here, so we'll avoid errors 6 in VK. + time.sleep(0.3) + def create_audio_album(self, *args, **kwargs): d = creation.audio_album() if d.get_response() == widgetUtils.OK and d.get("title") != "": @@ -427,7 +463,7 @@ class Controller(object): self.session.audio_albums = self.session.vk.client.audio.getAlbums(owner_id=self.session.user_id)["items"] def delete_audio_album(self, *args, **kwargs): - answer = selector.audioAlbum(_(u"Select the album you want to delete"), self.session) + answer = selector.album(_(u"Select the album you want to delete"), self.session) if answer.item == None: return response = commonMessages.delete_audio_album() @@ -440,6 +476,35 @@ class Controller(object): del buffer self.session.audio_albums = self.session.vk.client.audio.getAlbums(owner_id=self.session.user_id)["items"] + def create_video_album(self, *args, **kwargs): + d = creation.audio_album() + if d.get_response() == widgetUtils.OK and d.get("title") != "": + response = self.session.vk.client.video.addAlbum(title=d.get("title")) + if response.has_key("album_id") == False: return + album_id = response["album_id"] + buffer = buffers.videoAlbum(parent=self.window.tb, name="{0}_video_album".format(album_id,), composefunc="compose_video", session=self.session, endpoint="get", parent_endpoint="video", count=self.session.settings["buffers"]["count_for_video_buffers"], user_id=self.session.user_id, album_id=album_id) + buffer.can_get_items = False + # Translators: {0} will be replaced with a video album's title. + name_ = _(u"Album: {0}").format(d.get("title"),) + self.buffers.append(buffer) + self.window.insert_buffer(buffer.tab, name_, self.window.search("video_albums")) + buffer.get_items() + self.session.video_albums = self.session.vk.client.video.getAlbums(owner_id=self.session.user_id)["items"] + + def delete_video_album(self, *args, **kwargs): + answer = selector.album(_(u"Select the album you want to delete"), self.session, "video_albums") + if answer.item == None: + return + response = commonMessages.delete_audio_album() + if response != widgetUtils.YES: return + removal = self.session.vk.client.video.deleteAlbum(album_id=answer.item) + buffer = self.search("{0}_video_album".format(answer.item,)) + buff = self.window.search(buffer.name) + self.window.remove_buffer(buff) + self.buffers.remove(buffer) + del buffer + self.session.video_albums = self.session.vk.client.video.getAlbums(owner_id=self.session.user_id)["items"] + def check_documentation(self, *args, **kwargs): lang = localization.get("documentation") os.chdir("documentation/%s" % (lang,)) diff --git a/src/controller/selector.py b/src/controller/selector.py index 904d722..daec451 100644 --- a/src/controller/selector.py +++ b/src/controller/selector.py @@ -2,22 +2,26 @@ import widgetUtils from wxUI.dialogs import selector as gui -class audioAlbum(object): +class album(object): - def __init__(self, title, session): - super(audioAlbum, self).__init__() + def __init__(self, title, session, album_type="audio_albums"): + super(album, self).__init__() self.item = None self.session = session + if not hasattr(self.session, album_type): + return + self.albums = getattr(self.session, album_type) self.dialog = gui.selectAlbum(title=title, albums=self.get_albums_as_string()) response = self.dialog.get_response() if response == widgetUtils.OK: self.item = self.search_item(self.dialog.get_string()) def get_albums_as_string(self): - return [i["title"] for i in self.session.audio_albums] + return [i["title"] for i in self.albums] def search_item(self, item): - for i in self.session.audio_albums: + for i in self.albums: if i["title"] == item: return i["id"] return None + diff --git a/src/session.defaults b/src/session.defaults index 6b0daae..e6e53fa 100644 --- a/src/session.defaults +++ b/src/session.defaults @@ -8,6 +8,7 @@ reverse_timelines = boolean(default=False) [buffers] count_for_audio_buffers = integer(default=100) count_for_wall_buffers = integer(default=100) +count_for_video_buffers = integer(default=200) [sound] volume = float(default=1.0) diff --git a/src/sessionmanager/session.py b/src/sessionmanager/session.py index 7e7683d..5c041bc 100644 --- a/src/sessionmanager/session.py +++ b/src/sessionmanager/session.py @@ -155,7 +155,7 @@ def compose_audio(audio, session=None): def compose_video(video, session=None): if video == False: return [_(u"Audio removed from library"), "", ""] - return [video["title"], utils.seconds_to_string(video["duration"])] + return [video["title"], video["description"], utils.seconds_to_string(video["duration"])] class vkSession(object): diff --git a/src/wxUI/mainWindow.py b/src/wxUI/mainWindow.py index bace8df..f8e3d11 100644 --- a/src/wxUI/mainWindow.py +++ b/src/wxUI/mainWindow.py @@ -8,9 +8,11 @@ class mainWindow(wx.Frame): app_ = wx.Menu() create = wx.Menu() self.audio_album = create.Append(wx.NewId(), _(u"Audio album")) + self.video_album = create.Append(wx.NewId(), _(u"Video album")) app_.AppendMenu(wx.NewId(), _(u"Create"), create) delete = wx.Menu() self.delete_audio_album = delete.Append(wx.NewId(), _(u"Audio album")) + self.delete_video_album = delete.Append(wx.NewId(), _(u"Video album")) app_.AppendMenu(wx.NewId(), _(u"Delete"), delete) self.settings_dialog = app_.Append(wx.NewId(), _(u"Preferences")) buffer = wx.Menu() diff --git a/src/wxUI/tabs/home.py b/src/wxUI/tabs/home.py index 2b64c0a..3a81f79 100644 --- a/src/wxUI/tabs/home.py +++ b/src/wxUI/tabs/home.py @@ -175,3 +175,30 @@ class peopleTab(homeTab): self.postBox = wx.BoxSizer(wx.HORIZONTAL) self.postBox.Add(self.post, 0, wx.ALL, 5) self.postBox.Add(self.new_chat, 0, wx.ALL, 5) + +class videoTab(homeTab): + def create_list(self): + self.lbl = wx.StaticText(self, wx.NewId(), _(u"Video&s")) + self.list = widgetUtils.list(self, *[_(u"Title"), _(u"Description"), _(u"Duration")], style=wx.LC_REPORT) + self.list.set_windows_size(0, 160) + self.list.set_windows_size(1, 380) + self.list.set_windows_size(2, 80) + self.list.set_size() + self.list.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnKeyDown) + + def create_post_buttons(self): + self.post = wx.Button(self, -1, _(u"&Post")) + self.play = wx.Button(self, -1, _(u"P&lay")) + self.postBox = wx.BoxSizer(wx.HORIZONTAL) + self.postBox.Add(self.post, 0, wx.ALL, 5) + self.postBox.Add(self.play, 0, wx.ALL, 5) + +class videoAlbumTab(videoTab): + + def create_post_buttons(self): + self.load = wx.Button(self, wx.NewId(), _(u"Load album")) + self.post = wx.Button(self, -1, _(u"&Post")) + self.play = wx.Button(self, -1, _(u"P&lay")) + self.postBox = wx.BoxSizer(wx.HORIZONTAL) + self.postBox.Add(self.post, 0, wx.ALL, 5) + self.postBox.Add(self.play, 0, wx.ALL, 5)