Port socializer to Python 3. #16

This commit is contained in:
Manuel Cortez 2019-01-02 04:42:53 +03:00
parent 1aeab0aef5
commit 4442931dd4
68 changed files with 967 additions and 1006 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
*.py.bak
*.pyc
*~
src/config/

View File

@ -1,14 +1,16 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
name = "Socializer"
version = "0.17"
author = u"Manuel Cortez"
author = "Manuel Cortez"
authorEmail = "manuel@manuelcortez.net"
copyright = u"Copyright (C) 2016-2018, Manuel Cortez"
description = unicode(name+" Is an accessible VK client for Windows.")
copyright = "Copyright (C) 2016-2018, Manuel Cortez"
description = name+" Is an accessible VK client for Windows."
url = "https://manuelcortez.net/socializer"
# The short name will be used for detecting translation files. See languageHandler for more details.
short_name = "socializer"
translators = [u"Darya Ratnikova (Russian)", u"Manuel Cortez (Spanish)"]
translators = ["Darya Ratnikova (Russian)", "Manuel Cortez (Spanish)"]
bts_name = "socializer"
bts_access_token = "U29jaWFsaXplcg"
bts_url = "https://issues.manuelcortez.net"

View File

@ -45,7 +45,7 @@ def hist(keys):
def find_problems(hist):
"Takes a histogram and returns a list of items occurring more than once."
res=[]
for k,v in hist.items():
for k,v in list(hist.items()):
if v>1:
res.append(k)
return res

View File

@ -2,10 +2,11 @@
""" Attachment controller for different kind of posts in VK.
this controller will take care of preparing data structures to be uploaded later, when the user decides to start the upload process by sending the post.
"""
from __future__ import unicode_literals
import os
import logging
import widgetUtils
import audioRecorder
from . import audioRecorder
from mutagen.id3 import ID3
from sessionmanager.utils import seconds_to_string
from wxUI.dialogs import attach as gui
@ -63,7 +64,7 @@ class attach(object):
imageInfo = {"type": "photo", "file": image, "description": description, "from": "local"}
self.attachments.append(imageInfo)
# Translators: This is the text displayed in the attachments dialog, when the user adds a photo.
info = [_(u"Photo"), description]
info = [_("Photo"), description]
self.dialog.attachments.insert_item(False, *info)
self.dialog.remove.Enable(True)
@ -77,15 +78,15 @@ class attach(object):
if "TIT2" in audio_tags:
title = audio_tags["TIT2"].text[0]
else:
title = _(u"Untitled")
title = _("Untitled")
if "TPE1" in audio_tags:
artist = audio_tags["TPE1"].text[0]
else:
artist = _(u"Unknown artist")
artist = _("Unknown artist")
audioInfo = {"type": "audio", "file": audio, "from": "local", "title": title, "artist": artist}
self.attachments.append(audioInfo)
# Translators: This is the text displayed in the attachments dialog, when the user adds an audio file.
info = [_(u"Audio file"), u"{title} - {artist}".format(title=title, artist=artist)]
info = [_("Audio file"), "{title} - {artist}".format(title=title, artist=artist)]
self.dialog.attachments.insert_item(False, *info)
self.dialog.remove.Enable(True)
@ -95,7 +96,7 @@ class attach(object):
audioInfo = {"type": "voice_message", "file": a.file, "from": "local"}
self.attachments.append(audioInfo)
# Translators: This is the text displayed in the attachments dialog, when the user adds an audio file.
info = [_(u"Voice message"), seconds_to_string(a.duration,)]
info = [_("Voice message"), seconds_to_string(a.duration,)]
self.dialog.attachments.insert_item(False, *info)
self.dialog.remove.Enable(True)
@ -105,8 +106,8 @@ class attach(object):
list_of_audios = self.session.db["me_audio"]["items"]
audios = []
for i in list_of_audios:
audios.append(u"{0}, {1}".format(i["title"], i["artist"]))
select = selector.selectAttachment(_(u"Select the audio files you want to send"), audios)
audios.append("{0}, {1}".format(i["title"], i["artist"]))
select = selector.selectAttachment(_("Select the audio files you want to send"), audios)
if select.get_response() == widgetUtils.OK and select.attachments.GetCount() > 0:
attachments = select.get_all_attachments()
for i in attachments:
@ -114,7 +115,7 @@ class attach(object):
info["from"] = "online"
self.attachments.append(info)
# Translators: This is the text displayed in the attachments dialog, when the user adds an audio file.
info2 = [_(u"Audio file"), u"{0} - {1}".format(list_of_audios[i]["title"], list_of_audios[i]["artist"])]
info2 = [_("Audio file"), "{0} - {1}".format(list_of_audios[i]["title"], list_of_audios[i]["artist"])]
self.dialog.attachments.insert_item(False, *info2)
self.check_remove_status()

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import time
import os
import tempfile
@ -24,12 +25,12 @@ class audioRecorder(object):
self.postprocess()
def on_pause(self, *args, **kwargs):
if self.dialog.get("pause") == _(u"Pause"):
if self.dialog.get("pause") == _("Pause"):
self.recording.pause()
self.dialog.set("pause", _(u"&Resume"))
elif self.dialog.get("pause") == _(u"Resume"):
self.dialog.set("pause", _("&Resume"))
elif self.dialog.get("pause") == _("Resume"):
self.recording.play()
self.dialog.set("pause", _(U"&Pause"))
self.dialog.set("pause", _("&Pause"))
def on_record(self, *args, **kwargs):
if self.recording != None:
@ -45,20 +46,20 @@ class audioRecorder(object):
self.recording = sound.get_recording(self.file)
self.duration = time.time()
self.recording.play()
self.dialog.set("record", _(u"&Stop"))
output.speak(_(u"Recording"))
self.dialog.set("record", _("&Stop"))
output.speak(_("Recording"))
def stop_recording(self):
self.recording.stop()
self.duration = int(time.time()-self.duration)
self.recording.free()
output.speak(_(u"Stopped"))
output.speak(_("Stopped"))
self.recorded = True
self.dialog.set("record", _(u"&Record"))
self.dialog.set("record", _("&Record"))
self.file_attached()
def file_attached(self):
self.dialog.set("pause", _(u"&Pause"))
self.dialog.set("pause", _("&Pause"))
self.dialog.disable_control("record")
self.dialog.enable_control("play")
self.dialog.enable_control("discard")
@ -79,7 +80,7 @@ class audioRecorder(object):
self.dialog.record.SetFocus()
self.dialog.disable_control("discard")
self.recording = None
output.speak(_(u"Discarded"))
output.speak(_("Discarded"))
def on_play(self, *args, **kwargs):
if not self.playing:
@ -88,30 +89,30 @@ class audioRecorder(object):
self._stop()
def _play(self):
output.speak(_(u"Playing..."))
output.speak(_("Playing..."))
# try:
self.playing = sound_lib.stream.FileStream(file=unicode(self.file), flags=sound_lib.stream.BASS_UNICODE)
self.playing = sound_lib.stream.FileStream(file=str(self.file), flags=sound_lib.stream.BASS_UNICODE)
self.playing.play()
self.dialog.set("play", _(u"&Stop"))
self.dialog.set("play", _("&Stop"))
try:
while self.playing.is_playing:
pass
self.dialog.set("play", _(u"&Play"))
self.dialog.set("play", _("&Play"))
self.playing.free()
self.playing = None
except:
pass
def _stop(self):
output.speak(_(u"Stopped"))
output.speak(_("Stopped"))
self.playing.stop()
self.playing.free()
self.dialog.set("play", _(u"&Play"))
self.dialog.set("play", _("&Play"))
self.playing = None
def postprocess(self):
if self.file.lower().endswith('.wav'):
output.speak(_(u"Recoding audio..."))
output.speak(_("Recoding audio..."))
sound.recode_audio(self.file)
self.wav_file = self.file
self.file = '%s.ogg' % self.file[:-4]

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
""" A buffer is a (virtual) list of items. All items belong to a category (wall posts, messages, persons...)"""
from __future__ import unicode_literals
import random
import logging
import webbrowser
@ -7,12 +8,12 @@ import arrow
import wx
import languageHandler
import widgetUtils
import messages
import player
from . import messages
from . import player
import output
import selector
import posts
import attach
from . import selector
from . import posts
from . import attach
from pubsub import pub
from vk_api.exceptions import VkApiError
from vk_api import upload
@ -21,7 +22,7 @@ from wxUI.tabs import home
from sessionmanager import session, renderers, utils
from mysc.thread_utils import call_threaded
from wxUI import commonMessages, menus
from sessionmanager.utils import add_attachment
from sessionmanager.renderers import add_attachment
log = logging.getLogger("controller.buffers")
@ -85,10 +86,10 @@ class baseBuffer(object):
try:
num = getattr(self.session, "get_newsfeed")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs)
except VkApiError as err:
log.error(u"Error {0}: {1}".format(err.code, err.message))
log.error("Error {0}: {1}".format(err.code, err.message))
retrieved = err.code
return retrieved
except ReadTimeout, ConnectionError:
except ReadTimeout as ConnectionError:
log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,))
return False
if show_nextpage == False:
@ -111,7 +112,7 @@ class baseBuffer(object):
""" Create a post in the current user's wall.
This process is handled in two parts. This is the first part, where the GUI is created and user can send the post.
During the second part (threaded), the post will be sent to the API."""
p = messages.post(session=self.session, title=_(u"Write your post"), caption="", text="")
p = messages.post(session=self.session, title=_("Write your post"), caption="", text="")
if p.message.get_response() == widgetUtils.OK:
call_threaded(self.do_last, p=p)
@ -192,12 +193,12 @@ class baseBuffer(object):
p = self.get_post()
if p == None:
return
if p.has_key("likes") == False:
if ("likes" in p) == False:
m.like.Enable(False)
elif p["likes"]["user_likes"] == 1:
m.like.Enable(False)
m.dislike.Enable(True)
if p.has_key("comments") == False:
if ("comments" in p) == False:
m.comment.Enable(False)
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_post, menuitem=m.open)
widgetUtils.connect_event(m, widgetUtils.MENU, self.do_like, menuitem=m.like)
@ -213,7 +214,7 @@ class baseBuffer(object):
return
user = post[self.user_key]
id = post[self.post_key]
if post.has_key("type"):
if "type" in post:
type_ = post["type"]
else:
type_ = "post"
@ -221,7 +222,7 @@ class baseBuffer(object):
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["count"] = l["likes"]
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["user_likes"] = 1
# Translators: This will be used when user presses like.
output.speak(_(u"You liked this"))
output.speak(_("You liked this"))
def do_dislike(self, *args, **kwargs):
""" Set dislike (undo like) in the currently focused post."""
@ -230,7 +231,7 @@ class baseBuffer(object):
return
user = post[self.user_key]
id = post[self.post_key]
if post.has_key("type"):
if "type" in post:
type_ = post["type"]
else:
type_ = "post"
@ -238,21 +239,21 @@ class baseBuffer(object):
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["count"] = l["likes"]
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["user_likes"] = 2
# Translators: This will be user in 'dislike'
output.speak(_(u"You don't like this"))
output.speak(_("You don't like this"))
def do_comment(self, *args, **kwargs):
""" Make a comment into the currently focused post."""
post = self.get_post()
if post == None:
return
comment = messages.comment(title=_(u"Add a comment"), caption="", text="")
comment = messages.comment(title=_("Add a comment"), caption="", text="")
if comment.message.get_response() == widgetUtils.OK:
msg = comment.message.get_text().encode("utf-8")
try:
user = post[self.user_key]
id = post[self.post_key]
self.session.vk.client.wall.addComment(owner_id=user, post_id=id, text=msg)
output.speak(_(u"You've posted a comment"))
output.speak(_("You've posted a comment"))
except Exception as msg:
log.error(msg)
@ -285,7 +286,7 @@ class baseBuffer(object):
post = self.get_post()
if post == None:
return
if post.has_key("type") and post["type"] == "audio":
if "type" in post and post["type"] == "audio":
pub.sendMessage("play-audio", audio_object=post["audio"]["items"][0])
return True
@ -297,7 +298,7 @@ class baseBuffer(object):
# Check all possible keys for an user object in VK API.
keys = ["from_id", "source_id", "id"]
for i in keys:
if selected.has_key(i):
if i in selected:
pub.sendMessage("user-profile", person=selected[i])
def open_post(self, *args, **kwargs):
@ -305,11 +306,11 @@ class baseBuffer(object):
post = self.get_post()
if post == None:
return
if post.has_key("type") and post["type"] == "audio":
if "type" in post and post["type"] == "audio":
a = posts.audio(self.session, post["audio"]["items"])
a.dialog.get_response()
a.dialog.Destroy()
elif post.has_key("type") and post["type"] == "friend":
elif "type" in post and post["type"] == "friend":
pub.sendMessage("open-post", post_object=post, controller_="friendship")
else:
pub.sendMessage("open-post", post_object=post, controller_="postController")
@ -327,7 +328,7 @@ class baseBuffer(object):
post = self.get_post()
if post == None:
return
if post.has_key("type") == False:
if ("type" in post) == False:
return [post["from_id"]]
else:
return [post["source_id"]]
@ -352,10 +353,10 @@ class feedBuffer(baseBuffer):
try:
num = getattr(self.session, "get_page")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs)
except VkApiError as err:
log.error(u"Error {0}: {1}".format(err.code, err.message))
log.error("Error {0}: {1}".format(err.code, err.message))
retrieved = err.code
return retrieved
except ReadTimeout, ConnectionError:
except ReadTimeout as ConnectionError:
log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,))
return False
if show_nextpage == False:
@ -370,7 +371,7 @@ class feedBuffer(baseBuffer):
def remove_buffer(self, mandatory=False):
""" Remove buffer if the current buffer is not the logged user's wall."""
if "me_feed" == self.name:
output.speak(_(u"This buffer can't be deleted"))
output.speak(_("This buffer can't be deleted"))
return False
else:
if mandatory == False:
@ -398,7 +399,7 @@ class communityBuffer(feedBuffer):
widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_community)
def load_community(self, *args, **kwargs):
output.speak(_(u"Loading community..."))
output.speak(_("Loading community..."))
self.can_get_items = True
self.tab.load.Enable(False)
wx.CallAfter(self.get_items)
@ -462,7 +463,7 @@ class audioBuffer(feedBuffer):
def remove_buffer(self, mandatory=False):
if "me_audio" == self.name or "popular_audio" == self.name or "recommended_audio" == self.name:
output.speak(_(u"This buffer can't be deleted"))
output.speak(_("This buffer can't be deleted"))
return False
else:
if mandatory == False:
@ -477,7 +478,7 @@ class audioBuffer(feedBuffer):
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."))
output.speak(_("This buffer doesn't support getting more items."))
def onFocus(self, *args, **kwargs):
pass
@ -488,12 +489,12 @@ class audioBuffer(feedBuffer):
return
args = {}
args["audio_id"] = post["id"]
if post.has_key("album_id"):
if "album_id" in post:
args["album_id"] = post["album_id"]
args["owner_id"] = post["owner_id"]
audio = self.session.vk.client.audio.add(**args)
if audio != None and int(audio) > 21:
output.speak(_(u"Audio added to your library"))
output.speak(_("Audio added to your library"))
def remove_from_library(self, *args, **kwargs):
post = self.get_post()
@ -504,7 +505,7 @@ class audioBuffer(feedBuffer):
args["owner_id"] = self.session.user_id
result = self.session.vk.client.audio.delete(**args)
if int(result) == 1:
output.speak(_(u"Removed audio from library"))
output.speak(_("Removed audio from library"))
self.tab.list.remove_item(self.tab.list.get_selected())
def move_to_album(self, *args, **kwargs):
@ -513,13 +514,13 @@ class audioBuffer(feedBuffer):
post = self.get_post()
if post == None:
return
album = selector.album(_(u"Select the album where you want to move this song"), self.session)
album = selector.album(_("Select the album where you want to move this song"), self.session)
if album.item == None: return
id = post["id"]
response = self.session.vk.client.audio.moveToAlbum(album_id=album.item, audio_ids=id)
if response == 1:
# Translators: Used when the user has moved an audio to an album.
output.speak(_(u"Moved"))
output.speak(_("Moved"))
def get_menu(self):
p = self.get_post()
@ -531,7 +532,7 @@ class audioBuffer(feedBuffer):
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"))
m.library.SetItemLabel(_("&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)
@ -551,7 +552,7 @@ class audioAlbum(audioBuffer):
widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_album)
def load_album(self, *args, **kwargs):
output.speak(_(u"Loading album..."))
output.speak(_("Loading album..."))
self.can_get_items = True
self.tab.load.Enable(False)
wx.CallAfter(self.get_items)
@ -576,7 +577,7 @@ class videoBuffer(feedBuffer):
return
if selected == -1:
selected = 0
output.speak(_(u"Opening video in webbrowser..."))
output.speak(_("Opening video in webbrowser..."))
webbrowser.open_new_tab(self.session.db[self.name]["items"][selected]["player"])
# print self.session.db[self.name]["items"][selected]
return True
@ -586,7 +587,7 @@ class videoBuffer(feedBuffer):
def remove_buffer(self, mandatory=False):
if "me_video" == self.name:
output.speak(_(u"This buffer can't be deleted"))
output.speak(_("This buffer can't be deleted"))
return False
else:
if mandatory == False:
@ -601,7 +602,7 @@ class videoBuffer(feedBuffer):
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."))
output.speak(_("This buffer doesn't support getting more items."))
def onFocus(self, *args, **kwargs):
pass
@ -612,12 +613,12 @@ class videoBuffer(feedBuffer):
return
args = {}
args["video_id"] = post["id"]
if post.has_key("album_id"):
if "album_id" in post:
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"))
output.speak(_("Video added to your library"))
def remove_from_library(self, *args, **kwargs):
post = self.get_post()
@ -628,7 +629,7 @@ class videoBuffer(feedBuffer):
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"))
output.speak(_("Removed video from library"))
self.tab.list.remove_item(self.tab.list.get_selected())
def move_to_album(self, *args, **kwargs):
@ -637,13 +638,13 @@ class videoBuffer(feedBuffer):
post= self.get_post()
if post == None:
return
album = selector.album(_(u"Select the album where you want to move this video"), self.session, "video_albums")
album = selector.album(_("Select the album where you want to move this video"), self.session, "video_albums")
if album.item == None: return
id = 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"))
output.speak(_("Moved"))
def get_menu(self):
""" We'll use the same menu that is used for audio items, as the options are exactly the same"""
@ -656,7 +657,7 @@ class videoBuffer(feedBuffer):
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"))
m.library.SetItemLabel(_("&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)
@ -673,7 +674,7 @@ class videoAlbum(videoBuffer):
widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_album)
def load_album(self, *args, **kwargs):
output.speak(_(u"Loading album..."))
output.speak(_("Loading album..."))
self.can_get_items = True
self.tab.load.Enable(False)
wx.CallAfter(self.get_items)
@ -689,7 +690,7 @@ class empty(object):
pass
def get_more_items(self, *args, **kwargs):
output.speak(_(u"This buffer doesn't support getting more items."))
output.speak(_("This buffer doesn't support getting more items."))
def remove_buffer(self, mandatory=False): return False
@ -710,7 +711,7 @@ class chatBuffer(baseBuffer):
# Get text position here.
position = self.tab.history.PositionToXY(self.tab.history.GetInsertionPoint())
id_ = None
for i in self.chats.keys():
for i in list(self.chats.keys()):
# Check if position[2] (line position) matches with something in self.chats
# (All messages, except the last one, should be able to be matched here).
# position[2]+1 is added because line may start with 0, while in wx.TextCtrl.GetNumberLines() that is not possible.
@ -733,12 +734,12 @@ 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 msg.has_key("read_state") and msg["read_state"] == 0 and msg["id"] not in self.reads and msg.has_key("out") and msg["out"] == 0:
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:
self.session.soundplayer.play("message_unread.ogg")
self.reads.append(msg["id"])
self.session.db[self.name]["items"][-1]["read_state"] = 1
# print msg
if msg.has_key("attachments") and len(msg["attachments"]) > 0:
if "attachments" in msg and len(msg["attachments"]) > 0:
self.tab.attachments.list.Enable(True)
self.attachments = list()
self.tab.attachments.clear()
@ -770,10 +771,10 @@ class chatBuffer(baseBuffer):
try:
num = getattr(self.session, "get_messages")(name=self.name, *self.args, **self.kwargs)
except VkApiError as err:
log.error(u"Error {0}: {1}".format(err.code, err.message))
log.error("Error {0}: {1}".format(err.code, err.message))
retrieved = err.code
return retrieved
except ReadTimeout, ConnectionError:
except ReadTimeout as ConnectionError:
log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,))
return False
if show_nextpage == False:
@ -853,7 +854,7 @@ class chatBuffer(baseBuffer):
response = self.session.vk.client.messages.send(user_id=self.kwargs["user_id"], message=text, random_id=random_id)
except ValueError as ex:
if ex.code == 9:
output.speak(_(u"You have been sending a message that is already sent. Try to update the buffer if you can't see the new message in the history."))
output.speak(_("You have been sending a message that is already sent. Try to update the buffer if you can't see the new message in the history."))
def __init__(self, *args, **kwargs):
super(chatBuffer, self).__init__(*args, **kwargs)
@ -863,7 +864,7 @@ class chatBuffer(baseBuffer):
def parse_attachments(self, post):
attachments = []
if post.has_key("attachments"):
if "attachments" in post:
for i in post["attachments"]:
# We don't need the photos_list attachment, so skip it.
if i["type"] == "photos_list":
@ -882,13 +883,13 @@ class chatBuffer(baseBuffer):
a.dialog.Destroy()
elif attachment["type"] == "audio_message":
link = attachment["audio_message"]["link_mp3"]
output.speak(_(u"Playing..."))
output.speak(_("Playing..."))
player.player.play(url=dict(url=link), set_info=False)
elif attachment["type"] == "link":
output.speak(_(u"Opening URL..."), True)
output.speak(_("Opening URL..."), True)
webbrowser.open_new_tab(attachment["link"]["url"])
elif attachment["type"] == "doc":
output.speak(_(u"Opening document in web browser..."))
output.speak(_("Opening document in web browser..."))
webbrowser.open(attachment["doc"]["url"])
elif attachment["type"] == "video":
# it seems VK doesn't like to attach video links as normal URLS, so we'll have to
@ -900,15 +901,15 @@ class chatBuffer(baseBuffer):
object_id = "{0}_{1}".format(attachment["video"]["owner_id"], attachment["video"]["id"])
video_object = self.session.vk.client.video.get(owner_id=attachment["video"]["owner_id"], videos=object_id)
video_object = video_object["items"][0]
output.speak(_(u"Opening video in web browser..."), True)
output.speak(_("Opening video in web browser..."), True)
webbrowser.open_new_tab(video_object["player"])
elif attachment["type"] == "photo":
output.speak(_(u"Opening photo in web browser..."), True)
output.speak(_("Opening photo in web browser..."), True)
# Possible photo sizes for looking in the attachment information. Try to use the biggest photo available.
possible_sizes = [1280, 604, 130, 75]
url = ""
for i in possible_sizes:
if attachment["photo"].has_key("photo_{0}".format(i,)):
if "photo_{0}".format(i,) in attachment["photo"]:
url = attachment["photo"]["photo_{0}".format(i,)]
break
if url != "":
@ -941,7 +942,7 @@ class peopleBuffer(feedBuffer):
post = self.get_post()
if post == None:
return
if post.has_key("last_seen") == False: return
if ("last_seen" in post) == False: return
original_date = arrow.get(post["last_seen"]["time"])
created_at = original_date.humanize(locale=languageHandler.curLang[:2])
self.tab.list.list.SetItem(self.tab.list.get_selected(), 1, created_at)
@ -992,10 +993,10 @@ class requestsBuffer(peopleBuffer):
try:
ids = self.session.vk.client.friends.getRequests(*self.args, **self.kwargs)
except VkApiError as err:
log.error(u"Error {0}: {1}".format(err.code, err.message))
log.error("Error {0}: {1}".format(err.code, err.message))
retrieved = err.code
return retrieved
except ReadTimeout, ConnectionError:
except ReadTimeout as ConnectionError:
log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,))
return False
num = self.session.get_page(name=self.name, show_nextpage=show_nextpage, endpoint="get", parent_endpoint="users", count=1000, user_ids=", ".join([str(i) for i in ids["items"]]), fields="uid, first_name, last_name, last_seen")
@ -1017,7 +1018,7 @@ class requestsBuffer(peopleBuffer):
return
result = self.session.vk.client.friends.add(user_id=person["id"])
if result == 2:
msg = _(u"{0} {1} now is your friend.").format(person["first_name"], person["last_name"])
msg = _("{0} {1} now is your friend.").format(person["first_name"], person["last_name"])
pub.sendMessage("notify", message=msg)
self.session.db[self.name]["items"].pop(self.tab.list.get_selected())
self.tab.list.remove_item(self.tab.list.get_selected())
@ -1031,9 +1032,9 @@ class requestsBuffer(peopleBuffer):
return
result = self.session.vk.client.friends.delete(user_id=person["id"])
if "out_request_deleted" in result:
msg = _(u"You've deleted the friends request to {0} {1}.").format(person["first_name"], person["last_name"])
msg = _("You've deleted the friends request to {0} {1}.").format(person["first_name"], person["last_name"])
elif "in_request_deleted" in result:
msg = _(u"You've declined the friend request of {0} {1}.").format(person["first_name"], person["last_name"])
msg = _("You've declined the friend request of {0} {1}.").format(person["first_name"], person["last_name"])
pub.sendMessage("notify", message=msg)
self.session.db[self.name]["items"].pop(self.tab.list.get_selected())
self.tab.list.remove_item(self.tab.list.get_selected())
@ -1047,7 +1048,7 @@ class requestsBuffer(peopleBuffer):
return
result = self.session.vk.client.friends.add(user_id=person["id"], follow=1)
if result == 2:
msg = _(u"{0} {1} is following you.").format(person["first_name"], person["last_name"])
msg = _("{0} {1} is following you.").format(person["first_name"], person["last_name"])
pub.sendMessage("notify", message=msg)
self.session.db[self.name]["items"].pop(self.tab.list.get_selected())
self.tab.list.remove_item(self.tab.list.get_selected())

View File

@ -1,40 +1,41 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import widgetUtils
from wxUI.dialogs import configuration as configurationUI
class configuration(object):
def get_notification_type(self, value):
if value == _(u"Native"):
if value == _("Native"):
return "native"
else:
return "custom"
def get_notification_label(self, value):
if value == "native":
return _(u"Native")
return _("Native")
else:
return _(u"Custom")
return _("Custom")
def get_update_channel_type(self, value):
if value == _(u"Stable"):
if value == _("Stable"):
return "stable"
elif value == _(u"Weekly"):
elif value == _("Weekly"):
return "weekly"
else:
return "alpha"
def get_update_channel_label(self, value):
if value == "stable":
return _(u"Stable")
return _("Stable")
elif value == "weekly":
return _(u"Weekly")
return _("Weekly")
else:
return _(u"Alpha")
return _("Alpha")
def __init__(self, session):
self.session = session
self.dialog = configurationUI.configurationDialog(_(u"Preferences"))
self.dialog = configurationUI.configurationDialog(_("Preferences"))
self.create_config()
def create_config(self):

View File

@ -1,19 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from builtins import range
import time
import os
import wx
import widgetUtils
import messages
import buffers
import configuration
import player
import posts
import profiles
from . import messages
from . import buffers
from . import configuration
from . import player
from . import posts
from . import profiles
import webbrowser
import logging
import output
import longpollthread
import selector
from . import longpollthread
from . import selector
from vk_api.exceptions import LoginRequired, VkApiError
from requests.exceptions import ConnectionError
from pubsub import pub
@ -32,7 +34,7 @@ log = logging.getLogger("controller.main")
class Controller(object):
def search(self, tab_name):
for i in xrange(0, len(self.buffers)):
for i in range(0, len(self.buffers)):
if self.buffers[i].name == tab_name:
return self.buffers[i]
return False
@ -51,8 +53,8 @@ class Controller(object):
player.setup()
self.window = mainWindow.mainWindow()
log.debug("Main window created")
self.window.change_status(_(u"Ready"))
self.session = session.sessions[session.sessions.keys()[0]]
self.window.change_status(_("Ready"))
self.session = session.sessions[list(session.sessions.keys())[0]]
self.create_controls()
self.window.Show()
self.connect_events()
@ -63,11 +65,11 @@ class Controller(object):
posts_ = buffers.empty(parent=self.window.tb, name="posts")
self.buffers.append(posts_)
# Translators: Name for the posts tab in the tree view.
self.window.add_buffer(posts_.tab, _(u"Posts"))
self.window.add_buffer(posts_.tab, _("Posts"))
home = buffers.baseBuffer(parent=self.window.tb, name="home_timeline", session=self.session, composefunc="render_newsfeed_item", endpoint="newsfeed", count=self.session.settings["buffers"]["count_for_wall_buffers"])
self.buffers.append(home)
# Translators: Newsfeed's name in the tree view.
self.window.insert_buffer(home.tab, _(u"Home"), self.window.search("posts"))
self.window.insert_buffer(home.tab, _("Home"), self.window.search("posts"))
self.repeatedUpdate = RepeatingTimer(120, self.update_all_buffers)
self.repeatedUpdate.start()
self.readMarker = RepeatingTimer(60, self.mark_as_read)
@ -75,60 +77,60 @@ class Controller(object):
feed = buffers.feedBuffer(parent=self.window.tb, name="me_feed", composefunc="render_status", session=self.session, endpoint="get", parent_endpoint="wall", extended=1, count=self.session.settings["buffers"]["count_for_wall_buffers"])
self.buffers.append(feed)
# Translators: Own user's wall name in the tree view.
self.window.insert_buffer(feed.tab, _(u"My wall"), self.window.search("posts"))
self.window.insert_buffer(feed.tab, _("My wall"), self.window.search("posts"))
audios = buffers.empty(parent=self.window.tb, name="audios")
self.buffers.append(audios)
# Translators: name for the music category in the tree view.
self.window.add_buffer(audios.tab, _(u"Music"))
self.window.add_buffer(audios.tab, _("Music"))
audio = buffers.audioBuffer(parent=self.window.tb, name="me_audio", composefunc="render_audio", session=self.session, endpoint="get", parent_endpoint="audio")
self.buffers.append(audio)
self.window.insert_buffer(audio.tab, _(u"My audios"), self.window.search("audios"))
self.window.insert_buffer(audio.tab, _("My audios"), self.window.search("audios"))
if self.session.settings["vk"]["use_alternative_tokens"] == False:
p_audio = buffers.audioBuffer(parent=self.window.tb, name="popular_audio", composefunc="render_audio", session=self.session, endpoint="getPopular", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"])
self.buffers.append(p_audio)
self.window.insert_buffer(p_audio.tab, _(u"Populars"), self.window.search("audios"))
self.window.insert_buffer(p_audio.tab, _("Populars"), self.window.search("audios"))
r_audio = buffers.audioBuffer(parent=self.window.tb, name="recommended_audio", composefunc="render_audio", session=self.session, endpoint="getRecommendations", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"])
self.buffers.append(r_audio)
self.window.insert_buffer(r_audio.tab, _(u"Recommendations"), self.window.search("audios"))
self.window.insert_buffer(r_audio.tab, _("Recommendations"), self.window.search("audios"))
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"))
self.window.insert_buffer(albums.tab, _("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"))
self.window.add_buffer(videos.tab, _("Video"))
my_videos = buffers.videoBuffer(parent=self.window.tb, name="me_video", composefunc="render_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"))
self.window.insert_buffer(my_videos.tab, _("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"))
self.window.insert_buffer(video_albums.tab, _("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"))
self.window.add_buffer(people.tab, _("People"))
friends = buffers.peopleBuffer(parent=self.window.tb, name="friends_", composefunc="render_person", session=self.session, endpoint="get", parent_endpoint="friends", count=5000, fields="uid, first_name, last_name, last_seen")
self.buffers.append(friends)
self.window.insert_buffer(friends.tab, _(u"Friends"), self.window.search("people"))
self.window.insert_buffer(friends.tab, _("Friends"), self.window.search("people"))
requests_ = buffers.empty(parent=self.window.tb, name="requests")
self.buffers.append(requests_)
self.window.insert_buffer(requests_.tab, _(u"Friendship requests"), self.window.search("people"))
self.window.insert_buffer(requests_.tab, _("Friendship requests"), self.window.search("people"))
incoming_requests = buffers.requestsBuffer(parent=self.window.tb, name="friend_requests", composefunc="render_person", session=self.session, count=1000)
self.buffers.append(incoming_requests)
self.window.insert_buffer(incoming_requests.tab, _(u"Pending requests"), self.window.search("requests"))
self.window.insert_buffer(incoming_requests.tab, _("Pending requests"), self.window.search("requests"))
outgoing_requests = buffers.requestsBuffer(parent=self.window.tb, name="friend_requests_sent", composefunc="render_person", session=self.session, count=1000, out=1)
self.buffers.append(outgoing_requests)
self.window.insert_buffer(outgoing_requests.tab, _(u"I follow"), self.window.search("requests"))
# communities= buffers.empty(parent=self.window.tb, name="communities")
# self.buffers.append(communities)
self.window.insert_buffer(outgoing_requests.tab, _("I follow"), self.window.search("requests"))
communities= buffers.empty(parent=self.window.tb, name="communities")
self.buffers.append(communities)
# Translators: name for the videos category in the tree view.
# self.window.add_buffer(communities.tab, _(u"Communities"))
self.window.add_buffer(communities.tab, _("Communities"))
chats = buffers.empty(parent=self.window.tb, name="chats")
self.buffers.append(chats)
self.window.add_buffer(chats.tab, _(u"Chats"))
self.window.add_buffer(chats.tab, _("Chats"))
timelines = buffers.empty(parent=self.window.tb, name="timelines")
self.buffers.append(timelines)
self.window.add_buffer(timelines.tab, _(u"Timelines"))
self.window.add_buffer(timelines.tab, _("Timelines"))
self.window.realize()
def connect_events(self):
@ -193,15 +195,15 @@ class Controller(object):
commonMessages.bad_authorisation()
def login(self):
self.window.change_status(_(u"Logging in VK"))
self.window.change_status(_("Logging in VK"))
self.session.login()
self.window.change_status(_(u"Ready"))
self.window.change_status(_("Ready"))
for i in self.buffers:
if hasattr(i, "get_items"):
# Translators: {0} will be replaced with the name of a buffer.
self.window.change_status(_(u"Loading items for {0}").format(i.name,))
self.window.change_status(_("Loading items for {0}").format(i.name,))
i.get_items()
self.window.change_status(_(u"Ready"))
self.window.change_status(_("Ready"))
self.create_longpoll_thread()
self.status_setter = RepeatingTimer(280, self.set_online)
self.status_setter.start()
@ -216,7 +218,7 @@ class Controller(object):
self.longpoll = longpollthread.worker(self.session)
self.longpoll.start()
if notify:
self.notify(message=_(u"Chat server reconnected"))
self.notify(message=_("Chat server reconnected"))
except ConnectionError:
pub.sendMessage("longpoll-read-timeout")
@ -233,17 +235,17 @@ class Controller(object):
for i in self.buffers:
if hasattr(i, "get_items"):
i.get_items()
log.debug(u"Updated %s" % (i.name))
log.debug("Updated %s" % (i.name))
def download(self, url, filename):
log.debug(u"downloading %s URL to %s filename" % (url, filename,))
log.debug("downloading %s URL to %s filename" % (url, filename,))
call_threaded(utils.download_file, url, filename, self.window)
def play_audio(self, audio_object):
# Restricted audios does not include an URL paramether.
# Restriction can be due to licensed content to unauthorized countries.
if "url" in audio_object and audio_object["url"] =="":
self.notify(message=_(u"This file could not be played because it is not allowed in your country"))
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)
@ -279,11 +281,11 @@ class Controller(object):
dlg = searchDialogs.searchAudioDialog()
if dlg.get_response() == widgetUtils.OK:
q = dlg.get("term").encode("utf-8")
newbuff = buffers.audioBuffer(parent=self.window.tb, name=u"{0}_audiosearch".format(q.decode("utf-8"),), session=self.session, composefunc="render_audio", parent_endpoint="audio", endpoint="search", q=q)
newbuff = buffers.audioBuffer(parent=self.window.tb, name="{0}_audiosearch".format(q,), session=self.session, composefunc="render_audio", parent_endpoint="audio", endpoint="search", q=q)
self.buffers.append(newbuff)
call_threaded(newbuff.get_items)
# Translators: {0} will be replaced with the search term.
self.window.insert_buffer(newbuff.tab, _(u"Search for {0}").format(q.decode("utf-8"),), self.window.search("audios"))
self.window.insert_buffer(newbuff.tab, _("Search for {0}").format(q,), self.window.search("audios"))
def search_videos(self, *args, **kwargs):
dlg = searchDialogs.searchVideoDialog()
@ -297,11 +299,11 @@ class Controller(object):
params["adult"] = dlg.get_checkable("safe_search")
params["sort"] = dlg.get_sort_order()
params["filters"] = "youtube, vimeo, short, long"
newbuff = buffers.videoBuffer(parent=self.window.tb, name=u"{0}_videosearch".format(params["q"].decode("utf-8"),), session=self.session, composefunc="render_video", parent_endpoint="video", endpoint="search", **params)
newbuff = buffers.videoBuffer(parent=self.window.tb, name="{0}_videosearch".format(params["q"],), session=self.session, composefunc="render_video", parent_endpoint="video", endpoint="search", **params)
self.buffers.append(newbuff)
call_threaded(newbuff.get_items)
# Translators: {0} will be replaced with the search term.
self.window.insert_buffer(newbuff.tab, _(u"Search for {0}").format(params["q"].decode("utf-8"),), self.window.search("videos"))
self.window.insert_buffer(newbuff.tab, _("Search for {0}").format(params["q"],), self.window.search("videos"))
def update_status_bar(self, status):
self.window.change_status(status)
@ -350,15 +352,15 @@ class Controller(object):
if buffertype == "audio":
buffer = buffers.audioBuffer(parent=self.window.tb, name="{0}_audio".format(user_id,), composefunc="render_audio", session=self.session, endpoint="get", parent_endpoint="audio", owner_id=user_id)
# Translators: {0} will be replaced with an user.
name_ = _(u"{0}'s audios").format(self.session.get_user_name(user_id, "gen"),)
name_ = _("{0}'s audios").format(self.session.get_user_name(user_id, "gen"),)
elif buffertype == "wall":
buffer = buffers.feedBuffer(parent=self.window.tb, name="{0}_feed".format(user_id,), composefunc="render_status", session=self.session, endpoint="get", parent_endpoint="wall", extended=1, count=self.session.settings["buffers"]["count_for_wall_buffers"], owner_id=user_id)
# Translators: {0} will be replaced with an user.
name_ = _(u"{0}'s wall posts").format(self.session.get_user_name(user_id, "gen"),)
name_ = _("{0}'s wall posts").format(self.session.get_user_name(user_id, "gen"),)
elif buffertype == "friends":
buffer = buffers.peopleBuffer(parent=self.window.tb, name="friends_{0}".format(user_id,), composefunc="render_person", session=self.session, endpoint="get", parent_endpoint="friends", count=5000, fields="uid, first_name, last_name, last_seen", user_id=user_id)
# Translators: {0} will be replaced with an user.
name_ = _(u"{0}'s friends").format(self.session.get_user_name(user_id, "friends"),)
name_ = _("{0}'s friends").format(self.session.get_user_name(user_id, "friends"),)
self.buffers.append(buffer)
call_threaded(self.complete_buffer_creation, buffer=buffer, name_=name_, position=self.window.search("timelines"))
@ -374,7 +376,7 @@ class Controller(object):
def search_chat_buffer(self, user_id):
for i in self.buffers:
if "_messages" in i.name:
if i.kwargs.has_key("user_id") and i.kwargs["user_id"] == user_id: return i
if "user_id" in i.kwargs and i.kwargs["user_id"] == user_id: return i
return None
def chat_from_id(self, user_id, setfocus=True, unread=False):
@ -388,7 +390,7 @@ class Controller(object):
buffer = buffers.chatBuffer(parent=self.window.tb, name="{0}_messages".format(user_id,), composefunc="render_message", session=self.session, count=200, user_id=user_id, rev=0, extended=True, fields="id, user_id, date, read_state, out, body, attachments, deleted")
self.buffers.append(buffer)
# Translators: {0} will be replaced with an user.
self.window.insert_buffer(buffer.tab, _(u"Chat with {0}").format(self.session.get_user_name(user_id, "ins")), self.window.search("chats"))
self.window.insert_buffer(buffer.tab, _("Chat with {0}").format(self.session.get_user_name(user_id, "ins")), self.window.search("chats"))
if setfocus:
pos = self.window.search(buffer.name)
self.window.change_buffer(pos)
@ -400,7 +402,7 @@ class Controller(object):
if self.session.settings["chat"]["notify_online"] == False:
return
user_name = self.session.get_user_name(event.user_id, "nom")
msg = _(u"{0} is online.").format(user_name,)
msg = _("{0} is online.").format(user_name,)
sound = "friend_online.ogg"
self.notify(msg, sound, self.session.settings["chat"]["notifications"])
@ -408,7 +410,7 @@ class Controller(object):
if self.session.settings["chat"]["notify_offline"] == False:
return
user_name = self.session.get_user_name(event.user_id, "nom")
msg = _(u"{0} is offline.").format(user_name,)
msg = _("{0} is offline.").format(user_name,)
sound = "friend_offline.ogg"
self.notify(msg, sound, self.session.settings["chat"]["notifications"])
@ -503,7 +505,7 @@ class Controller(object):
buffer = buffers.audioAlbum(parent=self.window.tb, name="{0}_audio_album".format(i["id"],), composefunc="render_audio", session=