Fix AttributeError when saving data from the alternative tokens method

This commit is contained in:
2019-04-11 05:29:42 -05:00
8 changed files with 112 additions and 68 deletions

View File

@@ -911,10 +911,11 @@ class chatBuffer(baseBuffer):
def insert(self, item, reversed=False):
""" Add a new item to the list. Uses session.composefunc for parsing the dictionary and create a valid result for putting it in the list."""
# as this tab is based in a text control, we have to overwrite the defaults.
item_ = getattr(renderers, self.compose_function)(item, self.session)
# the self.chat dictionary will have (first_line, last_line) as keys and message ID as a value for looking into it when needed.
# Here we will get first and last line of a chat message appended to the history.
values = self.tab.add_message(item_[0])
values = self.tab.add_message(item_[0], reverse=reversed)
self.chats[values] = item["id"]
def get_focused_post(self):
@@ -930,7 +931,6 @@ class chatBuffer(baseBuffer):
# position[2]+1 is added because line may start with 0, while in wx.TextCtrl.GetNumberLines() that is not possible.
if position[2]+1 >= i[0] and position[2]+1 < i[1]:
id_ = self.chats[i]
# print i
break
# Retrieve here the object based in id_
if id_ != None:
@@ -946,9 +946,10 @@ class chatBuffer(baseBuffer):
msg = self.get_focused_post()
if msg == False: # Handle the case where the last line of the control cannot be matched to anything.
return
if "read_state" in msg and msg["read_state"] == 0 and msg["id"] not in self.reads and "out" in msg and msg["out"] == 0:
# Mark unread conversations as read.
if "read_state" in msg and msg["read_state"] == 0 and "out" in msg and msg["out"] == 0:
self.session.soundplayer.play("message_unread.ogg")
self.reads.append(msg["id"])
call_threaded(self.session.vk.client.messages.markAsRead, peer_id=self.kwargs["peer_id"])
self.session.db[self.name]["items"][-1]["read_state"] = 1
if "attachments" in msg and len(msg["attachments"]) > 0:
self.tab.attachments.list.Enable(True)
@@ -985,10 +986,11 @@ class chatBuffer(baseBuffer):
event.Skip()
def get_items(self, show_nextpage=False):
""" Update buffer with newest items or get older items in the buffer."""
if self.can_get_items == False: return
retrieved = True # Control variable for handling unauthorised/connection errors.
retrieved = True
try:
num = getattr(self.session, "get_messages")(name=self.name, *self.args, **self.kwargs)
num = getattr(self.session, "get_page")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs)
except VkApiError as err:
log.error("Error {0}: {1}".format(err.code, err.error))
retrieved = err.code
@@ -1001,20 +1003,38 @@ class chatBuffer(baseBuffer):
self.create_tab(self.parent)
# Add name to the new control so we could look for it when needed.
self.tab.name = self.name
if show_nextpage == False:
if self.tab.history.GetValue() != "" and num > 0:
v = [i for i in self.session.db[self.name]["items"][:num]]
# v.reverse()
[self.insert(i, False) for i in v]
else:
[self.insert(i) for i in self.session.db[self.name]["items"][:num]]
else:
if num > 0:
[self.insert(i, False) for i in self.session.db[self.name]["items"][:num]]
# At this point we save more CPU and mathematical work if we just delete everything in the chat history and readd all messages.
# Otherwise we'd have to insert new lines at the top and recalculate positions everywhere else.
# Firstly, we'd have to save the current focused object so we will place the user in the right part of the text after loading everything again.
focused_post = self.get_post()
self.chats = dict()
self.tab.history.SetValue("")
v = [i for i in self.session.db[self.name]["items"]]
[self.insert(i) for i in v]
# Now it's time to set back the focus in the post.
for i in self.chats.keys():
if self.chats[i] == focused_post["id"]:
line = i[0]
self.tab.history.SetInsertionPoint(self.tab.history.XYToPosition(0, line))
output.speak(_("Items loaded"))
break
if self.unread == True and num > 0:
self.session.db[self.name]["items"][-1].update(read_state=0)
return retrieved
def get_more_items(self):
output.speak(_("Getting more items..."))
call_threaded(self.get_items, show_nextpage=True)
def add_attachment(self, *args, **kwargs):
a = presenters.attachPresenter(session=self.session, view=views.attachDialog(voice_messages=True), interactor=interactors.attachInteractor())
if len(a.attachments) != 0:
@@ -1093,7 +1113,6 @@ class chatBuffer(baseBuffer):
def __init__(self, unread=False, *args, **kwargs):
super(chatBuffer, self).__init__(*args, **kwargs)
self.unread = unread
self.reads = []
self.chats = dict()
self.peer_typing = 0
self.last_keypress = time.time()

View File

@@ -114,8 +114,6 @@ class Controller(object):
self.window.realize()
self.repeatedUpdate = RepeatingTimer(120, self.update_all_buffers)
self.repeatedUpdate.start()
self.readMarker = RepeatingTimer(60, self.mark_as_read)
self.readMarker.start()
def complete_buffer_creation(self, buffer, name_, position):
answer = buffer.get_items()
@@ -158,14 +156,6 @@ class Controller(object):
call_threaded(self.chat_from_id, i["last_message"]["peer_id"], setfocus=False, unread=False)
time.sleep(0.6)
def mark_as_read(self):
for i in self.buffers:
if hasattr(i, "reads") and len(i.reads) != 0:
response = self.session.vk.client.messages.markAsRead(peer_id=i.kwargs["peer_id"])
i.clear_reads()
i.reads = []
time.sleep(1)
def get_audio_albums(self, user_id=None, create_buffers=True, force_action=False):
if self.session.settings["load_at_startup"]["audio_albums"] == False and force_action == False:
return
@@ -350,13 +340,13 @@ class Controller(object):
if "url" in audio_object and audio_object["url"] =="":
self.notify(message=_("This file could not be played because it is not allowed in your country"))
return
call_threaded(player.player.play, audio_object, fresh=True)
pub.sendMessage("play", object=audio_object, fresh=True)
def play_audios(self, audios):
""" Play all audios passed in alist, putting the audio in a queue of the media player.
@audios list: A list of Vk audio objects.
"""
player.player.play_all(audios, shuffle=self.window.player_shuffle.IsChecked())
pub.sendMessage("play_all", list_of_songs=audios, shuffle=self.window.player_shuffle.IsChecked())
def view_post(self, post_object, controller_):
""" Display the passed post in the passed post presenter.
@@ -392,7 +382,7 @@ class Controller(object):
elif user_id > 2000000000:
chat = self.session.vk.client.messages.getChat(chat_id=user_id-2000000000)
name = chat["title"]
wx.CallAfter(pub.sendMessage, "create_buffer", buffer_type="chatBuffer", buffer_title=name, parent_tab="chats", get_items=True, kwargs=dict(parent=self.window.tb, name="{0}_messages".format(user_id,), composefunc="render_message", session=self.session, unread=unread, count=200, peer_id=user_id, rev=0, extended=True, fields="id, user_id, date, read_state, out, body, attachments, deleted"))
wx.CallAfter(pub.sendMessage, "create_buffer", buffer_type="chatBuffer", buffer_title=name, parent_tab="chats", get_items=True, kwargs=dict(parent=self.window.tb, name="{0}_messages".format(user_id,), composefunc="render_message", parent_endpoint="messages", endpoint="getHistory", session=self.session, unread=unread, count=200, peer_id=user_id, rev=0, extended=True, fields="id, user_id, date, read_state, out, body, attachments, deleted"))
# if setfocus:
# pos = self.window.search(buffer.name)
# self.window.change_buffer(pos)
@@ -538,7 +528,7 @@ class Controller(object):
data = [message]
# Let's add this to the buffer.
# ToDo: Clean this code and test how is the database working with this set to True.
num = self.session.order_buffer(buffer.name, data, True)
buffer.session.db[buffer.name]["items"].append(message)
buffer.insert(self.session.db[buffer.name]["items"][-1], False)
self.session.soundplayer.play("message_received.ogg")
wx.CallAfter(self.reorder_buffer, buffer)
@@ -883,6 +873,7 @@ class Controller(object):
else:
option = menu.Append(wx.NewId(), _("Discard groups"))
widgetUtils.connect_event(menu, widgetUtils.MENU, self.unload_community_buffers, menuitem=option)
# Deal with video and audio albums' sections.
elif current_buffer.name == "audio_albums":
menu = wx.Menu()
if self.session.settings["load_at_startup"]["audio_albums"] == False and not hasattr(self.session, "audio_albums"):
@@ -899,6 +890,9 @@ class Controller(object):
else:
option = menu.Append(wx.NewId(), _("Discard video albums"))
widgetUtils.connect_event(menu, widgetUtils.MENU, self.unload_video_album_buffers, menuitem=option)
elif current_buffer.name.endswith("_messages"):
menu = menus.conversationBufferMenu()
widgetUtils.connect_event(menu, widgetUtils.MENU, self.delete_conversation, menuitem=menu.delete)
if menu != None:
self.window.PopupMenu(menu, self.window.FindFocus().GetPosition())
@@ -1000,4 +994,13 @@ class Controller(object):
buff = self.window.search(buffer.name)
self.window.remove_buffer(buff)
self.buffers.remove(buffer)
del self.session.video_albums
del self.session.video_albums
def delete_conversation(self, *args, **kwargs):
current_buffer = self.get_current_buffer()
d = commonMessages.delete_conversation()
if d == widgetUtils.YES:
results = self.session.vk.client.messages.deleteConversation(peer_id=current_buffer.kwargs["peer_id"])
buff = self.window.search(current_buffer.name)
self.window.remove_buffer(buff)
self.buffers.remove(current_buffer)

View File

@@ -1,40 +1,62 @@
# -*- coding: utf-8 -*-
""" Audio player module for socializer.
As this player does not have (still) an associated GUI, I have decided to place here the code for the interactor, which connects a bunch of pubsub events, and the presenter itself.
"""
import sys
import random
import output
import sound_lib
import logging
import sound_lib
import output
import config
from sound_lib.config import BassConfig
from sound_lib.stream import URLStream
from sound_lib.main import BassError
from mysc.repeating_timer import RepeatingTimer
from pubsub import pub
from mysc.repeating_timer import RepeatingTimer
player = None
log = logging.getLogger("player")
# This function will be deprecated when the player works with pubsub events, as will no longer be needed to instantiate and import the player directly.
def setup():
global player
if player == None:
player = audioPlayer()
class audioPlayer(object):
""" A media player which will play all passed URLS."""
def __init__(self):
# control variable for checking if another file has been sent to the player before,
# thus avoiding double file playback and other oddities happening in sound_lib from time to time.
self.is_playing = False
# This will be the URLStream handler
self.stream = None
self.vol = config.app["sound"]["volume"]
# this variable is set to true when the URLPlayer is decoding something, thus it will block other calls to the play method.
self.is_working = False
# Playback queue.
self.queue = []
# Index of the currently playing track.
self.playing_track = 0
# Status of the player.
self.stopped = True
# Modify some default settings present in Bass so it will increase timeout connection, thus causing less "connection timed out" errors when playing.
bassconfig = BassConfig()
# Set timeout connection to 30 seconds.
bassconfig["net_timeout"] = 30000
pub.subscribe(self.play, "play")
pub.subscribe(self.play_all, "play_all")
pub.subscribe(self.pause, "pause")
pub.subscribe(self.stop, "stop")
pub.subscribe(self.play_next, "play_next")
pub.subscribe(self.play_previous, "play_previous")
def play(self, url, set_info=True, fresh=False):
def play(self, object, set_info=True, fresh=False):
""" Play an URl Stream.
@object dict: typically an audio object as returned by VK, with a "url" component which must be a valid URL to a media file.
@set_info bool: If true, will set information about the currently playing audio in the application status bar.
@fresh bool: If True, will remove everything playing in the queue and start this file only. otherwise it will play the new file but not remove the current queue."""
if self.stream != None and self.stream.is_playing == True:
try:
self.stream.stop()
@@ -50,19 +72,15 @@ class audioPlayer(object):
if self.is_working == False:
self.is_working = True
# Let's encode the URL as bytes if on Python 3
if sys.version[0] == "3":
url_ = bytes(url["url"], "utf-8")
else:
url_ = url["url"]
url_ = bytes(object["url"], "utf-8")
try:
self.stream = URLStream(url=url_)
except IndexError:
log.error("Unable to play URL")
log.error(url_)
log.error("Unable to play URL %s" % (url_))
return
# Translators: {0} will be replaced with a song's title and {1} with the artist.
if set_info:
msg = _("Playing {0} by {1}").format(url["title"], url["artist"])
msg = _("Playing {0} by {1}").format(object["title"], object["artist"])
pub.sendMessage("update-status-bar", status=msg)
self.stream.volume = self.vol/100.0
self.stream.play()
@@ -70,6 +88,7 @@ class audioPlayer(object):
self.is_working = False
def stop(self):
""" Stop audio playback. """
if self.stream != None and self.stream.is_playing == True:
self.stream.stop()
self.stopped = True
@@ -79,6 +98,7 @@ class audioPlayer(object):
self.queue = []
def pause(self):
""" pause the current playback, without destroying the queue or the current stream. If the stream is already paused this function will resume the playback. """
if self.stream != None:
if self.stream.is_playing == True:
self.stream.pause()
@@ -105,11 +125,14 @@ class audioPlayer(object):
if self.stream != None:
self.stream.volume = self.vol/100.0
def play_all(self, list_of_urls, shuffle=False):
def play_all(self, list_of_songs, shuffle=False):
""" Play all passed songs and adds all of those to the queue.
@list_of_songs list: A list of audio objects returned by VK.
@shuffle bool: If True, the files will be played randomly."""
self.playing_track = 0
self.stop()
# Skip all country restricted tracks as they are not playable here.
self.queue = [i for i in list_of_urls if i["url"] != ""]
self.queue = [i for i in list_of_songs if i["url"] != ""]
if shuffle:
random.shuffle(self.queue)
self.play(self.queue[self.playing_track])
@@ -117,6 +140,7 @@ class audioPlayer(object):
self.worker.start()
def player_function(self):
""" Check if the stream has reached the end of the file so it will play the next song. """
if self.stream != None and self.stream.is_playing == False and self.stopped == False and len(self.stream) == self.stream.position:
if len(self.queue) == 0 or self.playing_track >= len(self.queue):
self.worker.cancel()
@@ -126,6 +150,7 @@ class audioPlayer(object):
self.play(self.queue[self.playing_track])
def play_next(self):
""" Play the next song in the queue. """
if len(self.queue) == 0:
return
if self.playing_track < len(self.queue)-1:
@@ -135,6 +160,7 @@ class audioPlayer(object):
self.play(self.queue[self.playing_track])
def play_previous(self):
""" Play the previous song in the queue. """
if len(self.queue) == 0:
return
if self.playing_track <= 0:
@@ -144,6 +170,7 @@ class audioPlayer(object):
self.play(self.queue[self.playing_track])
def check_is_playing(self):
""" check if the player is already playing a stream. """
if self.stream == None:
return False
if self.stream != None and self.stream.is_playing == False:

View File

@@ -66,6 +66,9 @@ class vkSession(object):
self.db[name] = {}
self.db[name]["items"] = []
first_addition = True
# Handles chat messages case, as the buffer is inverted
if name.endswith("_messages") and show_nextpage == True:
show_nextpage = False
for i in data:
if "type" in i and not isinstance(i["type"], int) and (i["type"] == "wall_photo" or i["type"] == "photo_tag" or i["type"] == "photo"):
log.debug("Skipping unsupported item... %r" % (i,))
@@ -124,8 +127,11 @@ class vkSession(object):
config_filename = os.path.join(paths.config_path(), self.session_id, "vkconfig.json")
self.vk.login(self.settings["vk"]["user"], self.settings["vk"]["password"], token=self.settings["vk"]["token"], secret=self.settings["vk"]["secret"], device_id=self.settings["vk"]["device_id"], alt_token=self.settings["vk"]["use_alternative_tokens"], filename=config_filename)
self.settings["vk"]["token"] = self.vk.session_object.token["access_token"]
self.settings["vk"]["secret"] = self.vk.session_object.secret
self.settings["vk"]["device_id"] = self.vk.session_object.device_id
try:
self.settings["vk"]["secret"] = self.vk.session_object.secret
self.settings["vk"]["device_id"] = self.vk.session_object.device_id
except AttributeError:
pass
self.settings.write()
self.logged = True
self.get_my_data()
@@ -192,6 +198,10 @@ class vkSession(object):
if data != None:
if "count" not in kwargs:
kwargs["count"] = 100
# Let's handle a little exception when dealing with conversation buffers.
# the first results of the query should be reversed before being sent to order_buffer.
if type(data) == dict and "items" in data and endpoint == "getHistory" and kwargs["offset"] == 0:
data["items"].reverse()
if type(data) == dict:
num = self.order_buffer(name, data["items"], show_nextpage)
self.db[name]["offset"] = kwargs["offset"]+kwargs["count"]

View File

@@ -63,4 +63,7 @@ def restart_program():
return wx.MessageDialog(None, _("In order to apply the changes you requested, you must restart the program. Do you want to restart Socializer now?"), _("Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal()
def community_no_items():
return wx.MessageDialog(None, _("There are 0 items for this community."), _("Error"), wx.ICON_ERROR).ShowModal()
return wx.MessageDialog(None, _("There are 0 items for this community."), _("Error"), wx.ICON_ERROR).ShowModal()
def delete_conversation():
return wx.MessageDialog(None, _("do you really want to delete all messages of this conversation in VK?"), _("Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal()

View File

@@ -124,4 +124,9 @@ class communityBufferMenu(wx.Menu):
self.load_audios = load.Append(wx.NewId(), _("Load audios"))
self.load_videos = load.Append(wx.NewId(), _("Load videos"))
self.load_documents = load.Append(wx.NewId(), _("Load documents"))
self.Append(wx.NewId(), _("Load"), load)
self.Append(wx.NewId(), _("Load"), load)
class conversationBufferMenu(wx.Menu):
def __init__(self):
super(conversationBufferMenu, self).__init__()
self.delete = self.Append(wx.NewId(), _("Delete conversation"))