2016-02-13 17:06:36 -06:00
# -*- coding: utf-8 -*-
2018-12-03 15:55:55 -06:00
""" A buffer is a (virtual) list of items. All items belong to a category (wall posts, messages, persons...) """
2019-01-01 19:42:53 -06:00
from __future__ import unicode_literals
2018-12-09 11:26:21 -06:00
import random
2018-12-03 15:55:55 -06:00
import logging
import webbrowser
2016-06-05 14:15:40 -05:00
import arrow
2016-02-15 05:43:40 -06:00
import wx
2019-01-06 22:51:20 -06:00
import presenters
import views
import interactors
2018-12-03 15:55:55 -06:00
import languageHandler
2016-02-13 17:06:36 -06:00
import widgetUtils
2019-01-06 19:58:33 -06:00
from presenters import player
2016-03-27 00:11:52 -06:00
import output
2019-01-01 19:42:53 -06:00
from . import selector
from . import posts
2016-02-13 17:06:36 -06:00
from pubsub import pub
2018-12-09 05:21:52 -06:00
from vk_api . exceptions import VkApiError
2018-12-10 12:20:01 -06:00
from vk_api import upload
2018-12-18 05:32:41 -06:00
from requests . exceptions import ReadTimeout , ConnectionError
2018-12-03 15:55:55 -06:00
from wxUI . tabs import home
2018-12-06 17:56:22 -06:00
from sessionmanager import session , renderers , utils
2016-02-15 05:43:40 -06:00
from mysc . thread_utils import call_threaded
2016-06-08 05:45:03 -05:00
from wxUI import commonMessages , menus
2019-01-01 19:42:53 -06:00
from sessionmanager . renderers import add_attachment
2016-02-13 17:06:36 -06:00
2016-05-10 20:23:48 -05:00
log = logging . getLogger ( " controller.buffers " )
2016-02-13 17:06:36 -06:00
class baseBuffer ( object ) :
2018-12-03 15:55:55 -06:00
""" a basic representation of a buffer. Other buffers should be derived from this class. This buffer represents the " news feed " """
2016-06-08 05:45:03 -05:00
def get_post ( self ) :
2018-12-03 15:55:55 -06:00
""" Return the currently focused post. """
2018-12-16 02:06:36 -06:00
# Handle case where there are no items in the buffer.
if self . tab . list . get_count ( ) == 0 :
wx . Bell ( )
return None
2016-06-08 05:45:03 -05:00
return self . session . db [ self . name ] [ " items " ] [ self . tab . list . get_selected ( ) ]
2016-02-13 17:06:36 -06:00
def __init__ ( self , parent = None , name = " " , session = None , composefunc = None , * args , * * kwargs ) :
2018-01-14 14:55:53 -06:00
""" Constructor:
2018-12-03 15:55:55 -06:00
@parent wx . Treebook : parent for the buffer panel ,
@name str : Name for saving this buffer ' s data in the local storage variable,
@session sessionmanager . session . vkSession : Session for performing operations in the Vk API . This session should be logged in when this class is instanciated .
2018-12-30 10:41:47 -06:00
@composefunc str : This function will be called for composing the result which will be put in the listCtrl . Composefunc should exist in the sessionmanager . renderers module .
2018-12-03 15:55:55 -06:00
args and kwargs will be passed to get_items ( ) without any filtering . Be careful there .
"""
2016-02-13 17:06:36 -06:00
super ( baseBuffer , self ) . __init__ ( )
self . args = args
self . kwargs = kwargs
2018-01-14 14:55:53 -06:00
# Create GUI associated to this buffer.
2016-02-13 17:06:36 -06:00
self . create_tab ( parent )
2018-01-14 14:55:53 -06:00
# Add name to the new control so we could look for it when needed.
2016-02-13 17:06:36 -06:00
self . tab . name = name
self . session = session
self . compose_function = composefunc
2018-01-14 14:55:53 -06:00
#Update_function will be called every 3 minutes and it should be able to
# Get all new items in the buffer and sort them properly in the CtrlList.
# ToDo: Shall we allow dinamically set for update_function?
2016-02-13 17:06:36 -06:00
self . update_function = " get_page "
self . name = name
2018-01-14 14:55:53 -06:00
# Bind local events (they will respond to events happened in the buffer).
2016-02-13 17:06:36 -06:00
self . connect_events ( )
2018-01-14 14:55:53 -06:00
# source_key and post_key will point to the keys for sender and posts in VK API objects.
# They can be changed in the future for other item types in different buffers.
2016-06-08 05:45:03 -05:00
self . user_key = " source_id "
self . post_key = " post_id "
2018-01-14 14:55:53 -06:00
# When set to False, update_function won't be executed here.
2016-06-29 12:33:09 -05:00
self . can_get_items = True
2016-02-13 17:06:36 -06:00
def create_tab ( self , parent ) :
2018-12-03 15:55:55 -06:00
""" Create the Wx panel. """
2016-02-13 17:06:36 -06:00
self . tab = home . homeTab ( parent )
def insert ( self , item , reversed = False ) :
2018-12-30 10:41:47 -06:00
""" Add a new item to the list. Uses renderers.composefunc for parsing the dictionary and create a valid result for putting it in the list. """
2018-12-06 15:37:16 -06:00
item_ = getattr ( renderers , self . compose_function ) ( item , self . session )
2016-02-13 17:06:36 -06:00
self . tab . list . insert_item ( reversed , * item_ )
2016-02-23 17:49:55 -06:00
def get_items ( self , show_nextpage = False ) :
2018-12-03 15:55:55 -06:00
""" Retrieve items from the VK API. This function is called repeatedly by the main controller and users could call it implicitly as well with the update buffer option.
@show_nextpage boolean : If it ' s true, it will try to load previous results.
2016-04-13 17:45:05 -05:00
"""
2016-06-29 12:33:09 -05:00
if self . can_get_items == False : return
2016-04-13 17:45:05 -05:00
retrieved = True # Control variable for handling unauthorised/connection errors.
try :
num = getattr ( self . session , " get_newsfeed " ) ( show_nextpage = show_nextpage , name = self . name , * self . args , * * self . kwargs )
2018-12-09 05:21:52 -06:00
except VkApiError as err :
2019-01-01 19:42:53 -06:00
log . error ( " Error {0} : {1} " . format ( err . code , err . message ) )
2016-04-13 17:45:05 -05:00
retrieved = err . code
return retrieved
2019-01-01 19:42:53 -06:00
except ReadTimeout as ConnectionError :
2018-12-18 05:32:41 -06:00
log . exception ( " Connection error when updating buffer %s . Will try again in 2 minutes " % ( self . name , ) )
return False
2016-02-23 17:49:55 -06:00
if show_nextpage == False :
2016-02-13 17:06:36 -06:00
if self . tab . list . get_count ( ) > 0 and num > 0 :
2016-03-23 02:15:52 -06:00
v = [ i for i in self . session . db [ self . name ] [ " items " ] [ : num ] ]
v . reverse ( )
[ self . insert ( i , True ) for i in v ]
2016-02-13 17:06:36 -06:00
else :
[ self . insert ( i ) for i in self . session . db [ self . name ] [ " items " ] [ : num ] ]
2016-02-23 17:49:55 -06:00
else :
if num > 0 :
[ self . insert ( i , False ) for i in self . session . db [ self . name ] [ " items " ] [ : num ] ]
2016-04-13 17:45:05 -05:00
return retrieved
2016-02-23 17:49:55 -06:00
2016-03-31 10:33:02 -06:00
def get_more_items ( self ) :
2018-01-14 14:55:53 -06:00
""" Returns previous items in the buffer. """
2016-02-23 17:49:55 -06:00
self . get_items ( show_nextpage = True )
2016-02-13 17:06:36 -06:00
def post ( self , * args , * * kwargs ) :
2018-01-14 14:55:53 -06:00
""" 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 . """
2019-01-07 13:16:20 -06:00
p = presenters . postPresenter ( session = self . session , interactor = interactors . postInteractor ( ) , view = views . post ( title = _ ( " Write your post " ) , message = " " , text = " " ) )
if hasattr ( p , " text " ) or hasattr ( p , " privacy " ) :
2016-04-11 11:48:35 -05:00
call_threaded ( self . do_last , p = p )
2019-01-02 17:30:34 -06:00
def do_last ( self , p , parent_endpoint = " wall " , child_endpoint = " post " , * args , * * kwargs ) :
2018-01-14 14:55:53 -06:00
""" Second part of post function. Here everything is going to be sent to the API """
2019-01-07 13:16:20 -06:00
msg = p . text
privacy_opts = p . privacy
2016-04-11 11:48:35 -05:00
attachments = " "
if hasattr ( p , " attachments " ) :
attachments = self . upload_attachments ( p . attachments )
urls = utils . find_urls_in_text ( msg )
if len ( urls ) != 0 :
if len ( attachments ) == 0 : attachments = urls [ 0 ]
else : attachments + = urls [ 0 ]
msg = msg . replace ( urls [ 0 ] , " " )
2019-01-02 17:30:34 -06:00
# Determines the correct functions to call here.
parent_endpoint = getattr ( self . session . vk . client , parent_endpoint )
endpoint = getattr ( parent_endpoint , child_endpoint )
post = endpoint ( message = msg , friends_only = privacy_opts , attachments = attachments , * args , * * kwargs )
2016-04-11 11:48:35 -05:00
pub . sendMessage ( " posted " , buffer = self . name )
2016-02-23 05:48:05 -06:00
p . message . Destroy ( )
2016-02-13 17:06:36 -06:00
2016-04-11 11:48:35 -05:00
def upload_attachments ( self , attachments ) :
2018-01-14 14:55:53 -06:00
""" Upload attachments to VK before posting them.
Returns attachments formatted as string , as required by VK API .
2018-12-30 10:41:47 -06:00
Currently this function only supports photos and audios . """
2016-04-11 11:48:35 -05:00
# To do: Check the caption and description fields for this kind of attachments.
local_attachments = " "
2018-12-10 12:20:01 -06:00
uploader = upload . VkUpload ( self . session . vk . session_object )
2016-04-11 11:48:35 -05:00
for i in attachments :
2018-12-21 05:27:35 -06:00
if i [ " from " ] == " online " :
local_attachments + = " {0} {1} _ {2} , " . format ( i [ " type " ] , i [ " owner_id " ] , i [ " id " ] )
elif i [ " from " ] == " local " and i [ " type " ] == " photo " :
2016-04-11 11:48:35 -05:00
photos = i [ " file " ]
description = i [ " description " ]
r = uploader . photo_wall ( photos , caption = description )
id = r [ 0 ] [ " id " ]
owner_id = r [ 0 ] [ " owner_id " ]
local_attachments + = " photo {0} _ {1} , " . format ( owner_id , id )
2018-12-21 05:27:35 -06:00
elif i [ " from " ] == " local " and i [ " type " ] == " audio " :
2018-12-20 17:29:23 -06:00
audio = i [ " file " ]
2018-12-21 16:20:31 -06:00
title = " untitled "
artist = " unnamed "
if " artist " in i :
artist = i [ " artist " ]
if " title " in i :
title = i [ " title " ]
r = uploader . audio ( audio , title = title , artist = artist )
2018-12-20 17:29:23 -06:00
id = r [ " id " ]
owner_id = r [ " owner_id " ]
local_attachments + = " audio {0} _ {1} , " . format ( owner_id , id )
2016-04-11 11:48:35 -05:00
return local_attachments
2016-02-13 17:06:36 -06:00
def connect_events ( self ) :
2018-01-14 14:55:53 -06:00
""" Bind all events to this buffer """
2016-02-13 17:06:36 -06:00
widgetUtils . connect_event ( self . tab . post , widgetUtils . BUTTON_PRESSED , self . post )
2016-02-15 05:43:40 -06:00
widgetUtils . connect_event ( self . tab . list . list , widgetUtils . KEYPRESS , self . get_event )
2016-06-08 05:45:03 -05:00
widgetUtils . connect_event ( self . tab . list . list , wx . EVT_LIST_ITEM_RIGHT_CLICK , self . show_menu )
widgetUtils . connect_event ( self . tab . list . list , wx . EVT_LIST_KEY_DOWN , self . show_menu_by_key )
2016-06-05 14:15:40 -05:00
self . tab . set_focus_function ( self . onFocus )
2016-02-15 05:43:40 -06:00
2016-06-08 05:45:03 -05:00
def show_menu ( self , ev , pos = 0 , * args , * * kwargs ) :
2018-01-14 14:55:53 -06:00
""" Show contextual menu when pressing menu key or right mouse click in a list item. """
2016-06-08 05:45:03 -05:00
if self . tab . list . get_count ( ) == 0 : return
menu = self . get_menu ( )
if pos != 0 :
self . tab . PopupMenu ( menu , pos )
else :
2018-12-30 10:41:47 -06:00
self . tab . PopupMenu ( menu , self . tab . list . list . GetPosition ( ) )
2016-06-08 05:45:03 -05:00
def show_menu_by_key ( self , ev ) :
2018-01-14 14:55:53 -06:00
""" Show contextual menu when menu key is pressed """
2016-06-08 05:45:03 -05:00
if self . tab . list . get_count ( ) == 0 :
return
if ev . GetKeyCode ( ) == wx . WXK_WINDOWS_MENU :
self . show_menu ( widgetUtils . MENU , pos = self . tab . list . list . GetPosition ( ) )
def get_menu ( self ) :
2018-01-14 14:55:53 -06:00
""" Returns contextual menu options. They will change according to the focused item """
2016-06-08 05:45:03 -05:00
p = self . get_post ( )
2018-12-16 02:06:36 -06:00
if p == None :
return
2019-01-03 12:08:38 -06:00
# determine if the current user is able to delete the object.
if " can_delete " in p :
can_delete = True == p [ " can_delete " ]
else :
can_delete = False
m = menus . postMenu ( can_delete = can_delete )
2019-01-01 19:42:53 -06:00
if ( " likes " in p ) == False :
2016-06-08 05:45:03 -05:00
m . like . Enable ( False )
elif p [ " likes " ] [ " user_likes " ] == 1 :
m . like . Enable ( False )
m . dislike . Enable ( True )
2019-01-01 19:42:53 -06:00
if ( " comments " in p ) == False :
2016-06-08 05:45:03 -05:00
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 )
widgetUtils . connect_event ( m , widgetUtils . MENU , self . do_dislike , menuitem = m . dislike )
widgetUtils . connect_event ( m , widgetUtils . MENU , self . do_comment , menuitem = m . comment )
2019-01-03 12:08:38 -06:00
if hasattr ( m , " view_profile " ) :
widgetUtils . connect_event ( m , widgetUtils . MENU , self . open_person_profile , menuitem = m . view_profile )
2019-01-03 13:40:11 -06:00
if hasattr ( m , " delete " ) :
widgetUtils . connect_event ( m , widgetUtils . MENU , self . delete , menuitem = m . delete )
2016-06-08 05:45:03 -05:00
return m
def do_like ( self , * args , * * kwargs ) :
2018-01-14 14:55:53 -06:00
""" Set like in the currently focused post. """
2016-06-08 05:45:03 -05:00
post = self . get_post ( )
2018-12-16 02:06:36 -06:00
if post == None :
return
2016-06-08 05:45:03 -05:00
user = post [ self . user_key ]
id = post [ self . post_key ]
2019-01-01 19:42:53 -06:00
if " type " in post :
2016-06-08 05:45:03 -05:00
type_ = post [ " type " ]
else :
type_ = " post "
l = self . session . vk . client . likes . add ( owner_id = user , item_id = id , type = type_ )
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
2016-06-29 10:56:41 -05:00
# Translators: This will be used when user presses like.
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " You liked this " ) )
2016-06-08 05:45:03 -05:00
def do_dislike ( self , * args , * * kwargs ) :
2018-01-14 14:55:53 -06:00
""" Set dislike (undo like) in the currently focused post. """
2016-06-08 05:45:03 -05:00
post = self . get_post ( )
2018-12-16 02:06:36 -06:00
if post == None :
return
2016-06-08 05:45:03 -05:00
user = post [ self . user_key ]
id = post [ self . post_key ]
2019-01-01 19:42:53 -06:00
if " type " in post :
2016-06-08 05:45:03 -05:00
type_ = post [ " type " ]
else :
type_ = " post "
l = self . session . vk . client . likes . delete ( owner_id = user , item_id = id , type = type_ )
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
2016-06-29 10:56:41 -05:00
# Translators: This will be user in 'dislike'
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " You don ' t like this " ) )
2016-06-08 05:45:03 -05:00
def do_comment ( self , * args , * * kwargs ) :
2018-01-14 14:55:53 -06:00
""" Make a comment into the currently focused post. """
2018-12-16 02:06:36 -06:00
post = self . get_post ( )
if post == None :
return
2019-01-07 13:16:20 -06:00
comment = presenters . postPresenter ( session = self . session , interactor = interactors . postInteractor ( ) , view = views . post ( title = _ ( " Add a comment " ) , message = " " , text = " " , mode = " comment " ) )
if hasattr ( comment , " text " ) or hasattr ( comment , " privacy " ) :
msg = comment . text
2016-06-08 05:45:03 -05:00
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 )
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " You ' ve posted a comment " ) )
2016-06-08 05:45:03 -05:00
except Exception as msg :
2018-01-14 06:58:24 -06:00
log . error ( msg )
2016-06-08 05:45:03 -05:00
2019-01-03 13:40:11 -06:00
def delete ( self , * args , * * kwargs ) :
post = self . get_post ( )
if ( " type " in post and post [ " type " ] == " post " ) or self . name != " newsfeed " :
question = commonMessages . remove_post ( )
if question == widgetUtils . NO :
return
if " owner_id " in self . kwargs :
result = self . session . vk . client . wall . delete ( owner_id = self . kwargs [ " owner_id " ] , post_id = post [ self . post_key ] )
else :
result = self . session . vk . client . wall . delete ( post_id = post [ self . post_key ] )
pub . sendMessage ( " post_deleted " , post_id = post [ self . post_key ] )
self . session . db [ self . name ] [ " items " ] . pop ( self . tab . list . get_selected ( ) )
self . tab . list . remove_item ( self . tab . list . get_selected ( ) )
2016-02-15 05:43:40 -06:00
def get_event ( self , ev ) :
2018-01-14 14:55:53 -06:00
""" Parses keyboard input in the ListCtrl and executes the event associated with user keypresses. """
2016-02-19 17:36:19 -06:00
if ev . GetKeyCode ( ) == wx . WXK_RETURN and ev . ControlDown ( ) and ev . ShiftDown ( ) : event = " pause_audio "
2016-02-22 05:04:30 -06:00
elif ev . GetKeyCode ( ) == wx . WXK_RETURN and ev . ControlDown ( ) : event = " play_audio "
2016-02-15 15:09:33 -06:00
elif ev . GetKeyCode ( ) == wx . WXK_RETURN : event = " open_post "
2016-02-15 05:43:40 -06:00
elif ev . GetKeyCode ( ) == wx . WXK_F5 : event = " volume_down "
elif ev . GetKeyCode ( ) == wx . WXK_F6 : event = " volume_up "
else :
event = None
ev . Skip ( )
if event != None :
try :
getattr ( self , event ) ( )
2016-02-22 05:53:37 -06:00
except AttributeError :
2016-02-15 05:43:40 -06:00
pass
def volume_down ( self ) :
2018-01-14 14:55:53 -06:00
""" Decreases player volume by 5 % """
2016-02-15 05:43:40 -06:00
player . player . volume = player . player . volume - 5
def volume_up ( self ) :
2018-01-14 14:55:53 -06:00
""" Increases player volume by 5 % """
2016-02-15 05:43:40 -06:00
player . player . volume = player . player . volume + 5
2016-02-13 17:06:36 -06:00
2016-02-16 16:32:40 -06:00
def play_audio ( self , * args , * * kwargs ) :
2018-01-14 14:55:53 -06:00
""" Play audio in currently focused buffer, if possible. """
post = self . get_post ( )
2018-12-16 02:06:36 -06:00
if post == None :
return
2019-01-01 19:42:53 -06:00
if " type " in post and post [ " type " ] == " audio " :
2016-03-26 09:08:41 -06:00
pub . sendMessage ( " play-audio " , audio_object = post [ " audio " ] [ " items " ] [ 0 ] )
2016-07-18 17:34:37 -05:00
return True
2016-02-16 16:32:40 -06:00
2016-09-15 15:27:38 -05:00
def open_person_profile ( self , * args , * * kwargs ) :
2018-12-30 10:41:47 -06:00
""" Views someone ' s profile. """
2016-09-15 15:27:38 -05:00
selected = self . get_post ( )
2018-12-16 02:06:36 -06:00
if selected == None :
return
2018-01-14 14:55:53 -06:00
# Check all possible keys for an user object in VK API.
2016-09-21 13:54:52 -05:00
keys = [ " from_id " , " source_id " , " id " ]
2016-09-15 15:27:38 -05:00
for i in keys :
2019-01-01 19:42:53 -06:00
if i in selected :
2016-09-15 15:27:38 -05:00
pub . sendMessage ( " user-profile " , person = selected [ i ] )
2019-01-03 10:19:12 -06:00
break
2016-09-15 15:27:38 -05:00
2016-06-08 05:45:03 -05:00
def open_post ( self , * args , * * kwargs ) :
2018-01-14 14:55:53 -06:00
""" Opens the currently focused post. """
post = self . get_post ( )
2018-12-16 02:06:36 -06:00
if post == None :
return
2019-01-01 19:42:53 -06:00
if " type " in post and post [ " type " ] == " audio " :
2016-02-24 10:30:07 -06:00
a = posts . audio ( self . session , post [ " audio " ] [ " items " ] )
2016-02-17 17:37:57 -06:00
a . dialog . get_response ( )
2016-02-23 05:48:05 -06:00
a . dialog . Destroy ( )
2019-01-01 19:42:53 -06:00
elif " type " in post and post [ " type " ] == " friend " :
2016-02-17 17:37:57 -06:00
pub . sendMessage ( " open-post " , post_object = post , controller_ = " friendship " )
else :
pub . sendMessage ( " open-post " , post_object = post , controller_ = " postController " )
2016-02-19 17:36:19 -06:00
def pause_audio ( self , * args , * * kwargs ) :
2018-01-14 14:55:53 -06:00
""" pauses audio playback. """
2016-02-19 17:36:19 -06:00
player . player . pause ( )
2018-01-14 14:55:53 -06:00
def remove_buffer ( self , mandatory ) :
""" Function for removing a buffer. Returns True if removal is successful, False otherwise """
return False
2016-03-27 00:11:52 -06:00
2016-04-12 15:36:30 -05:00
def get_users ( self ) :
2018-01-14 14:55:53 -06:00
""" Returns source user in the post. """
post = self . get_post ( )
2018-12-16 02:06:36 -06:00
if post == None :
return
2019-01-01 19:42:53 -06:00
if ( " type " in post ) == False :
2016-04-15 09:06:18 -05:00
return [ post [ " from_id " ] ]
2016-04-12 15:36:30 -05:00
else :
return [ post [ " source_id " ] ]
2016-06-05 14:15:40 -05:00
def onFocus ( self , * args , * * kwargs ) :
""" Function executed when the item in a list is selected.
For this buffer it updates the date of posts in the list . """
2018-01-14 14:55:53 -06:00
post = self . get_post ( )
2018-12-16 02:06:36 -06:00
if post == None :
return
2016-06-05 14:15:40 -05:00
original_date = arrow . get ( post [ " date " ] )
2018-12-13 16:36:46 -06:00
created_at = original_date . humanize ( locale = languageHandler . curLang [ : 2 ] )
2018-09-03 08:33:05 -05:00
self . tab . list . list . SetItem ( self . tab . list . get_selected ( ) , 2 , created_at )
2016-06-05 14:15:40 -05:00
2016-02-13 17:06:36 -06:00
class feedBuffer ( baseBuffer ) :
2018-01-14 14:55:53 -06:00
""" This buffer represents an user ' s wall. It may be used either for the current user or someone else. """
2016-02-13 17:06:36 -06:00
2016-02-23 17:49:55 -06:00
def get_items ( self , show_nextpage = False ) :
2018-01-14 14:55:53 -06:00
""" Update buffer with newest items or get older items in the buffer. """
2016-06-29 12:33:09 -05:00
if self . can_get_items == False : return
2016-04-13 17:45:05 -05:00
retrieved = True
try :
num = getattr ( self . session , " get_page " ) ( show_nextpage = show_nextpage , name = self . name , * self . args , * * self . kwargs )
2018-12-18 05:32:41 -06:00
except VkApiError as err :
2019-01-01 19:42:53 -06:00
log . error ( " Error {0} : {1} " . format ( err . code , err . message ) )
2016-04-13 17:45:05 -05:00
retrieved = err . code
return retrieved
2019-01-01 19:42:53 -06:00
except ReadTimeout as ConnectionError :
2018-12-18 05:32:41 -06:00
log . exception ( " Connection error when updating buffer %s . Will try again in 2 minutes " % ( self . name , ) )
return False
2016-02-23 17:49:55 -06:00
if show_nextpage == False :
2016-02-13 17:06:36 -06:00
if self . tab . list . get_count ( ) > 0 and num > 0 :
2016-03-23 02:15:52 -06:00
v = [ i for i in self . session . db [ self . name ] [ " items " ] [ : num ] ]
v . reverse ( )
[ self . insert ( i , True ) for i in v ]
2016-02-13 17:06:36 -06:00
else :
[ self . insert ( i ) for i in self . session . db [ self . name ] [ " items " ] [ : num ] ]
2016-04-13 17:45:05 -05:00
return retrieved
2016-02-13 17:06:36 -06:00
2016-04-14 17:23:08 -05:00
def remove_buffer ( self , mandatory = False ) :
2018-01-14 14:55:53 -06:00
""" Remove buffer if the current buffer is not the logged user ' s wall. """
2016-04-14 17:23:08 -05:00
if " me_feed " == self . name :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " This buffer can ' t be deleted " ) )
2016-04-14 17:23:08 -05:00
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
2016-06-08 05:45:03 -05:00
def __init__ ( self , * args , * * kwargs ) :
super ( feedBuffer , self ) . __init__ ( * args , * * kwargs )
self . user_key = " from_id "
self . post_key = " id "
2019-01-02 17:46:01 -06:00
self . can_post = True
self . can_write_private_message = True
# if this is an user timeline we must check permissions to hide buttons when needed.
if " owner_id " in self . kwargs :
permissions = self . session . vk . client . users . get ( user_ids = self . kwargs [ " owner_id " ] , fields = " can_post, can_see_all_posts, can_write_private_message " )
self . can_post = permissions [ 0 ] [ " can_post " ]
self . can_see_all_posts = permissions [ 0 ] [ " can_see_all_posts " ]
self . can_write_private_message = permissions [ 0 ] [ " can_write_private_message " ]
if self . can_post == False :
self . tab . post . Enable ( False )
2016-06-08 05:45:03 -05:00
2019-01-02 17:30:34 -06:00
def post ( self , * args , * * kwargs ) :
""" Create a post in the wall for the specified user
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 . """
if " owner_id " not in self . kwargs :
return super ( feedBuffer , self ) . post ( )
owner_id = self . kwargs [ " owner_id " ]
user = self . session . get_user_name ( owner_id )
2019-01-07 13:16:20 -06:00
p = presenters . postPresenter ( session = self . session , interactor = interactors . postInteractor ( ) , view = views . post ( title = _ ( " Write your post " ) , message = " " , text = " " ) )
if hasattr ( p , " text " ) or hasattr ( p , " privacy " ) :
2019-01-02 17:30:34 -06:00
call_threaded ( self . do_last , p = p , owner_id = owner_id )
2018-12-30 10:41:47 -06:00
class communityBuffer ( feedBuffer ) :
def create_tab ( self , parent ) :
self . tab = home . communityTab ( parent )
def connect_events ( self ) :
super ( communityBuffer , self ) . connect_events ( )
widgetUtils . connect_event ( self . tab . load , widgetUtils . BUTTON_PRESSED , self . load_community )
def load_community ( self , * args , * * kwargs ) :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Loading community... " ) )
2018-12-30 10:41:47 -06:00
self . can_get_items = True
self . tab . load . Enable ( False )
wx . CallAfter ( self . get_items )
2016-02-13 17:06:36 -06:00
class audioBuffer ( feedBuffer ) :
2018-01-14 14:55:53 -06:00
""" this buffer was supposed to be used with audio elements
but is deprecated as VK removed its audio support for third party apps . """
2016-02-13 17:06:36 -06:00
def create_tab ( self , parent ) :
self . tab = home . audioTab ( parent )
2016-02-15 02:15:38 -06:00
def connect_events ( self ) :
widgetUtils . connect_event ( self . tab . play , widgetUtils . BUTTON_PRESSED , self . play_audio )
2016-03-23 08:17:45 -06:00
widgetUtils . connect_event ( self . tab . play_all , widgetUtils . BUTTON_PRESSED , self . play_all )
2016-02-15 05:43:40 -06:00
super ( audioBuffer , self ) . connect_events ( )
2016-02-15 02:15:38 -06:00
def play_audio ( self , * args , * * kwargs ) :
selected = self . tab . list . get_selected ( )
2016-07-18 17:34:37 -05:00
if selected == - 1 :
selected = 0
2016-03-26 09:08:41 -06:00
pub . sendMessage ( " play-audio " , audio_object = self . session . db [ self . name ] [ " items " ] [ selected ] )
2016-07-18 17:34:37 -05:00
return True
def play_next ( self , * args , * * kwargs ) :
selected = self . tab . list . get_selected ( )
2018-12-22 05:39:21 -06:00
if selected < 0 or selected == self . tab . list . get_count ( ) - 1 :
2016-07-18 17:34:37 -05:00
selected = 0
if self . tab . list . get_count ( ) < = selected + 1 :
newpos = 0
else :
newpos = selected + 1
self . tab . list . select_item ( newpos )
self . play_audio ( )
def play_previous ( self , * args , * * kwargs ) :
selected = self . tab . list . get_selected ( )
2018-12-22 05:39:21 -06:00
if selected < = 0 :
2016-07-18 17:34:37 -05:00
selected = self . tab . list . get_count ( )
newpos = selected - 1
self . tab . list . select_item ( newpos )
self . play_audio ( )
2016-02-15 02:15:38 -06:00
2016-06-08 05:45:03 -05:00
def open_post ( self , * args , * * kwargs ) :
2016-02-15 15:09:33 -06:00
selected = self . tab . list . get_selected ( )
2018-12-22 05:39:21 -06:00
if selected == - 1 :
2018-12-16 02:06:36 -06:00
return
2016-02-24 10:30:07 -06:00
audios = [ self . session . db [ self . name ] [ " items " ] [ selected ] ]
a = posts . audio ( self . session , audios )
2016-02-15 15:09:33 -06:00
a . dialog . get_response ( )
2016-02-23 05:48:05 -06:00
a . dialog . Destroy ( )
2016-03-22 02:10:59 -06:00
2016-03-23 08:17:45 -06:00
def play_all ( self , * args , * * kwargs ) :
selected = self . tab . list . get_selected ( )
2016-03-23 11:36:07 -06:00
if selected == - 1 :
selected = 0
2018-12-16 02:06:36 -06:00
if self . name not in self . session . db :
return
2016-03-26 09:08:41 -06:00
audios = [ i for i in self . session . db [ self . name ] [ " items " ] [ selected : ] ]
2016-03-23 08:57:16 -06:00
pub . sendMessage ( " play-audios " , audios = audios )
2016-07-18 17:34:37 -05:00
return True
2016-03-23 08:57:16 -06:00
2016-04-14 17:23:08 -05:00
def remove_buffer ( self , mandatory = False ) :
2016-03-27 00:11:52 -06:00
if " me_audio " == self . name or " popular_audio " == self . name or " recommended_audio " == self . name :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " This buffer can ' t be deleted " ) )
2016-03-27 00:11:52 -06:00
return False
else :
2016-04-13 17:45:05 -05:00
if mandatory == False :
dlg = commonMessages . remove_buffer ( )
else :
dlg = widgetUtils . YES
2016-03-27 00:11:52 -06:00
if dlg == widgetUtils . YES :
self . session . db . pop ( self . name )
return True
else :
return False
2016-03-31 10:33:02 -06:00
def get_more_items ( self , * args , * * kwargs ) :
2016-06-29 10:56:41 -05:00
# Translators: Some buffers can't use the get previous item feature due to API limitations.
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " This buffer doesn ' t support getting more items. " ) )
2016-03-31 10:33:02 -06:00
2016-06-05 14:15:40 -05:00
def onFocus ( self , * args , * * kwargs ) :
pass
2016-06-08 05:45:03 -05:00
def add_to_library ( self , * args , * * kwargs ) :
post = self . get_post ( )
2018-12-16 02:06:36 -06:00
if post == None :
return
2016-06-08 05:45:03 -05:00
args = { }
args [ " audio_id " ] = post [ " id " ]
2019-01-01 19:42:53 -06:00
if " album_id " in post :
2016-06-08 05:45:03 -05:00
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 :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Audio added to your library " ) )
2016-06-08 05:45:03 -05:00
def remove_from_library ( self , * args , * * kwargs ) :
post = self . get_post ( )
2018-12-16 02:06:36 -06:00
if post == None :
return
2016-06-08 05:45:03 -05:00
args = { }
args [ " audio_id " ] = post [ " id " ]
args [ " owner_id " ] = self . session . user_id
result = self . session . vk . client . audio . delete ( * * args )
if int ( result ) == 1 :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Removed audio from library " ) )
2016-07-12 05:00:07 -05:00
self . tab . list . remove_item ( self . tab . list . get_selected ( ) )
2016-06-08 05:45:03 -05:00
2016-06-29 04:08:37 -05:00
def move_to_album ( self , * args , * * kwargs ) :
2018-12-18 05:32:41 -06:00
if len ( self . session . audio_albums ) == 0 :
return commonMessages . no_audio_albums ( )
2018-12-16 02:06:36 -06:00
post = self . get_post ( )
if post == None :
return
2019-01-01 19:42:53 -06:00
album = selector . album ( _ ( " Select the album where you want to move this song " ) , self . session )
2016-06-29 04:08:37 -05:00
if album . item == None : return
2018-12-16 02:06:36 -06:00
id = post [ " id " ]
2016-06-29 04:08:37 -05:00
response = self . session . vk . client . audio . moveToAlbum ( album_id = album . item , audio_ids = id )
if response == 1 :
2016-06-29 10:56:41 -05:00
# Translators: Used when the user has moved an audio to an album.
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Moved " ) )
2016-06-29 04:08:37 -05:00
2016-06-08 05:45:03 -05:00
def get_menu ( self ) :
p = self . get_post ( )
2018-12-16 02:06:36 -06:00
if p == None :
return
2016-06-08 05:45:03 -05:00
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 )
2016-06-29 04:08:37 -05:00
widgetUtils . connect_event ( m , widgetUtils . MENU , self . move_to_album , menuitem = m . move )
2016-06-08 05:45:03 -05:00
# if owner_id is the current user, the audio is added to the user's audios.
if p [ " owner_id " ] == self . session . user_id :
2019-01-01 19:42:53 -06:00
m . library . SetItemLabel ( _ ( " &Remove from library " ) )
2016-06-08 05:45:03 -05:00
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
2016-06-29 12:33:09 -05:00
class audioAlbum ( audioBuffer ) :
2018-01-14 14:55:53 -06:00
""" this buffer was supposed to be used with audio albums
but is deprecated as VK removed its audio support for third party apps . """
2016-06-29 12:33:09 -05:00
def create_tab ( self , parent ) :
self . tab = home . audioAlbumTab ( parent )
2016-06-30 09:30:17 -05:00
self . tab . play . Enable ( False )
self . tab . play_all . Enable ( False )
2016-06-29 12:33:09 -05:00
def connect_events ( self ) :
super ( audioAlbum , self ) . connect_events ( )
widgetUtils . connect_event ( self . tab . load , widgetUtils . BUTTON_PRESSED , self . load_album )
def load_album ( self , * args , * * kwargs ) :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Loading album... " ) )
2016-06-29 12:33:09 -05:00
self . can_get_items = True
self . tab . load . Enable ( False )
wx . CallAfter ( self . get_items )
2016-06-30 09:30:17 -05:00
self . tab . play . Enable ( True )
self . tab . play_all . Enable ( True )
2016-06-29 12:33:09 -05:00
2016-08-14 07:46:41 -05:00
class videoBuffer ( feedBuffer ) :
2018-01-14 14:55:53 -06:00
""" This buffer represents video elements, and it can be used for showing videos for the logged user or someone else. """
2016-08-14 07:46:41 -05:00
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 ) :
2018-01-14 14:55:53 -06:00
""" Due to inheritance this method should be called play_audio, but play the currently focused video.
Opens a webbrowser pointing to the video ' s URL. " " "
2016-08-14 07:46:41 -05:00
selected = self . tab . list . get_selected ( )
2018-12-16 02:06:36 -06:00
if self . tab . list . get_count ( ) == 0 :
return
2016-08-14 07:46:41 -05:00
if selected == - 1 :
selected = 0
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Opening video in webbrowser... " ) )
2016-08-14 07:46:41 -05:00
webbrowser . open_new_tab ( self . session . db [ self . name ] [ " items " ] [ selected ] [ " player " ] )
2018-12-15 21:09:17 -06:00
# print self.session.db[self.name]["items"][selected]
2016-08-14 07:46:41 -05:00
return True
def open_post ( self , * args , * * kwargs ) :
2018-12-16 02:06:36 -06:00
pass
2016-08-14 07:46:41 -05:00
def remove_buffer ( self , mandatory = False ) :
if " me_video " == self . name :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " This buffer can ' t be deleted " ) )
2016-08-14 07:46:41 -05:00
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.
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " This buffer doesn ' t support getting more items. " ) )
2016-08-14 07:46:41 -05:00
def onFocus ( self , * args , * * kwargs ) :
pass
def add_to_library ( self , * args , * * kwargs ) :
post = self . get_post ( )
2018-12-16 02:06:36 -06:00
if post == None :
return
2016-08-14 07:46:41 -05:00
args = { }
args [ " video_id " ] = post [ " id " ]
2019-01-01 19:42:53 -06:00
if " album_id " in post :
2016-08-14 07:46:41 -05:00
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 :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Video added to your library " ) )
2016-08-14 07:46:41 -05:00
def remove_from_library ( self , * args , * * kwargs ) :
post = self . get_post ( )
2018-12-16 02:06:36 -06:00
if post == None :
return
2016-08-14 07:46:41 -05:00
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 :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Removed video from library " ) )
2016-08-14 07:46:41 -05:00
self . tab . list . remove_item ( self . tab . list . get_selected ( ) )
def move_to_album ( self , * args , * * kwargs ) :
2018-12-18 05:32:41 -06:00
if len ( self . session . video_albums ) == 0 :
return commonMessages . no_video_albums ( )
2018-12-16 02:06:36 -06:00
post = self . get_post ( )
if post == None :
return
2019-01-01 19:42:53 -06:00
album = selector . album ( _ ( " Select the album where you want to move this video " ) , self . session , " video_albums " )
2016-08-14 07:46:41 -05:00
if album . item == None : return
2018-12-16 02:06:36 -06:00
id = post [ " id " ]
2016-08-14 07:46:41 -05:00
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.
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Moved " ) )
2016-08-14 07:46:41 -05:00
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 ( )
2018-12-16 02:06:36 -06:00
if p == None :
return
2016-08-14 07:46:41 -05:00
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 :
2019-01-01 19:42:53 -06:00
m . library . SetItemLabel ( _ ( " &Remove from library " ) )
2016-08-14 07:46:41 -05:00
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 ) :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Loading album... " ) )
2016-08-14 07:46:41 -05:00
self . can_get_items = True
self . tab . load . Enable ( False )
wx . CallAfter ( self . get_items )
self . tab . play . Enable ( True )
2016-03-23 08:57:16 -06:00
class empty ( object ) :
def __init__ ( self , name = None , parent = None , * args , * * kwargs ) :
self . tab = home . empty ( parent = parent , name = name )
self . name = name
def get_items ( self , * args , * * kwargs ) :
pass
2016-03-31 10:33:02 -06:00
def get_more_items ( self , * args , * * kwargs ) :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " This buffer doesn ' t support getting more items. " ) )
2016-03-27 00:11:52 -06:00
2016-04-14 17:23:08 -05:00
def remove_buffer ( self , mandatory = False ) : return False
2016-05-17 12:46:57 -05:00
class chatBuffer ( baseBuffer ) :
2018-12-09 10:53:50 -06:00
2018-12-04 16:58:40 -06:00
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. """
2018-12-06 15:37:16 -06:00
item_ = getattr ( renderers , self . compose_function ) ( item , self . session )
2018-12-05 12:43:33 -06:00
# 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.
2018-12-04 17:53:10 -06:00
values = self . tab . add_message ( item_ [ 0 ] )
self . chats [ values ] = item [ " id " ]
def get_focused_post ( self ) :
2018-12-05 12:43:33 -06:00
""" Gets chat message currently in focus """
# this function replaces self.get_post for normal buffers, as we rely in a TextCtrl control for getting chats.
# Instead of the traditional method to do the trick.
# Get text position here.
2018-12-04 17:53:10 -06:00
position = self . tab . history . PositionToXY ( self . tab . history . GetInsertionPoint ( ) )
id_ = None
2019-01-01 19:42:53 -06:00
for i in list ( self . chats . keys ( ) ) :
2018-12-05 12:43:33 -06:00
# 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.
if position [ 2 ] + 1 > = i [ 0 ] and position [ 2 ] + 1 < i [ 1 ] :
2018-12-04 17:53:10 -06:00
id_ = self . chats [ i ]
2018-12-05 15:54:24 -06:00
# print i
2018-12-05 12:43:33 -06:00
break
# Retrieve here the object based in id_
2018-12-04 17:53:10 -06:00
if id_ != None :
for i in self . session . db [ self . name ] [ " items " ] :
if i [ " id " ] == id_ :
return i
return False
2018-12-04 16:58:40 -06:00
2018-12-04 17:53:10 -06:00
get_post = get_focused_post
def onFocus ( self , event , * args , * * kwargs ) :
2018-12-10 14:54:54 -06:00
if event . GetKeyCode ( ) == wx . WXK_UP or event . GetKeyCode ( ) == wx . WXK_DOWN or event . GetKeyCode ( ) == wx . WXK_START or event . GetKeyCode ( ) == wx . WXK_PAGEUP or event . GetKeyCode ( ) == wx . WXK_PAGEDOWN or event . GetKeyCode ( ) == wx . WXK_END :
2018-12-04 17:53:10 -06:00
msg = self . get_focused_post ( )
2018-12-05 12:43:33 -06:00
if msg == False : # Handle the case where the last line of the control cannot be matched to anything.
return
2019-01-01 19:42:53 -06:00
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 :
2018-12-16 00:41:47 -06:00
self . session . soundplayer . play ( " message_unread.ogg " )
2018-12-04 17:53:10 -06:00
self . reads . append ( msg [ " id " ] )
self . session . db [ self . name ] [ " items " ] [ - 1 ] [ " read_state " ] = 1
2018-12-05 12:43:33 -06:00
# print msg
2019-01-01 19:42:53 -06:00
if " attachments " in msg and len ( msg [ " attachments " ] ) > 0 :
2018-12-04 17:53:10 -06:00
self . tab . attachments . list . Enable ( True )
self . attachments = list ( )
2018-12-10 02:32:57 -06:00
self . tab . attachments . clear ( )
2018-12-04 17:53:10 -06:00
self . parse_attachments ( msg )
else :
self . tab . attachments . list . Enable ( False )
self . tab . attachments . clear ( )
event . Skip ( )
2016-06-06 04:27:07 -05:00
2016-05-17 12:46:57 -05:00
def create_tab ( self , parent ) :
self . tab = home . chatTab ( parent )
2016-09-25 14:24:40 -05:00
self . attachments = list ( )
2016-05-17 12:46:57 -05:00
def connect_events ( self ) :
widgetUtils . connect_event ( self . tab . send , widgetUtils . BUTTON_PRESSED , self . send_chat_to_user )
2017-03-13 02:16:34 -06:00
widgetUtils . connect_event ( self . tab . attachment , widgetUtils . BUTTON_PRESSED , self . add_attachment )
2018-12-11 09:26:14 -06:00
widgetUtils . connect_event ( self . tab . text , widgetUtils . KEYPRESS , self . catch_enter )
2018-12-04 17:53:10 -06:00
self . tab . set_focus_function ( self . onFocus )
2016-05-17 12:46:57 -05:00
2018-12-11 09:26:14 -06:00
def catch_enter ( self , event , * args , * * kwargs ) :
2018-12-19 04:32:47 -06:00
shift = event . ShiftDown ( )
if event . GetKeyCode ( ) == wx . WXK_RETURN and shift == False :
2018-12-25 19:08:36 -06:00
return self . send_chat_to_user ( )
2018-12-11 09:26:14 -06:00
event . Skip ( )
2018-12-16 00:41:47 -06:00
def get_items ( self , show_nextpage = False , unread = False ) :
2016-06-29 12:33:09 -05:00
if self . can_get_items == False : return
2016-05-17 12:46:57 -05:00
retrieved = True # Control variable for handling unauthorised/connection errors.
try :
num = getattr ( self . session , " get_messages " ) ( name = self . name , * self . args , * * self . kwargs )
2018-12-18 05:32:41 -06:00
except VkApiError as err :
2019-01-01 19:42:53 -06:00
log . error ( " Error {0} : {1} " . format ( err . code , err . message ) )
2016-05-17 12:46:57 -05:00
retrieved = err . code
return retrieved
2019-01-01 19:42:53 -06:00
except ReadTimeout as ConnectionError :
2018-12-18 05:32:41 -06:00
log . exception ( " Connection error when updating buffer %s . Will try again in 2 minutes " % ( self . name , ) )
return False
2016-05-17 12:46:57 -05:00
if show_nextpage == False :
2018-12-05 12:43:33 -06:00
if self . tab . history . GetValue ( ) != " " and num > 0 :
2016-05-17 12:46:57 -05:00
v = [ i for i in self . session . db [ self . name ] [ " items " ] [ : num ] ]
2018-12-05 12:43:33 -06:00
# v.reverse()
2016-08-14 07:46:41 -05:00
[ self . insert ( i , False ) for i in v ]
2016-05-17 12:46:57 -05:00
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 ] ]
2018-12-16 00:41:47 -06:00
if unread :
self . session . db [ self . name ] [ " items " ] [ - 1 ] . update ( read_state = 0 )
2016-05-17 12:46:57 -05:00
return retrieved
2017-03-13 02:16:34 -06:00
def add_attachment ( self , * args , * * kwargs ) :
2019-01-06 22:51:20 -06:00
a = presenters . attachPresenter ( session = self . session , view = views . attachDialog ( voice_messages = True ) , interactor = interactors . attachInteractor ( ) )
2018-12-21 05:54:52 -06:00
if len ( a . attachments ) != 0 :
self . attachments_to_be_sent = a . attachments
2017-03-13 02:16:34 -06:00
2016-05-17 12:46:57 -05:00
def send_chat_to_user ( self , * args , * * kwargs ) :
text = self . tab . text . GetValue ( )
2018-12-11 12:17:08 -06:00
if text == " " and not hasattr ( self , " attachments_to_be_sent " ) :
wx . Bell ( )
return
2018-12-24 12:52:58 -06:00
self . tab . text . SetValue ( " " )
2016-08-14 02:12:49 -05:00
call_threaded ( self . _send_message , text = text )
2018-12-21 05:54:52 -06:00
def upload_attachments ( self , attachments ) :
""" Upload attachments to VK before posting them.
Returns attachments formatted as string , as required by VK API .
"""
local_attachments = " "
uploader = upload . VkUpload ( self . session . vk . session_object )
for i in attachments :
if i [ " from " ] == " online " :
local_attachments + = " {0} {1} _ {2} , " . format ( i [ " type " ] , i [ " owner_id " ] , i [ " id " ] )
elif i [ " from " ] == " local " and i [ " type " ] == " photo " :
photos = i [ " file " ]
description = i [ " description " ]
r = uploader . photo_messages ( photos )
id = r [ 0 ] [ " id " ]
owner_id = r [ 0 ] [ " owner_id " ]
local_attachments + = " photo {0} _ {1} , " . format ( owner_id , id )
elif i [ " from " ] == " local " and i [ " type " ] == " audio " :
audio = i [ " file " ]
2018-12-21 16:20:31 -06:00
title = " untitled "
artist = " unnamed "
if " artist " in i :
artist = i [ " artist " ]
if " title " in i :
title = i [ " title " ]
r = uploader . audio ( audio , title = title , artist = artist )
2018-12-21 05:54:52 -06:00
id = r [ " id " ]
owner_id = r [ " owner_id " ]
local_attachments + = " audio {0} _ {1} , " . format ( owner_id , id )
2018-12-24 17:54:18 -06:00
elif i [ " from " ] == " local " and i [ " type " ] == " voice_message " :
r = uploader . audio_message ( i [ " file " ] , peer_id = self . kwargs [ " user_id " ] )
id = r [ " audio_message " ] [ " id " ]
owner_id = r [ " audio_message " ] [ " owner_id " ]
local_attachments + = " audio_message {0} _ {1} , " . format ( owner_id , id )
2018-12-21 05:54:52 -06:00
return local_attachments
def _send_message ( self , text , attachments = [ ] ) :
2018-12-21 08:18:39 -06:00
if hasattr ( self , " attachments_to_be_sent " ) :
self . attachments_to_be_sent = self . upload_attachments ( self . attachments_to_be_sent )
2018-12-09 11:26:21 -06:00
try :
2018-12-09 07:25:30 -06:00
# Let's take care about the random_id attribute.
# This should be unique per message and should be changed right after the message has been sent.
# If the message is tried to be sent twice this random_id should be the same for both copies.
# At the moment we just calculate len(text)_user_id, hope that will work.
2018-12-09 11:26:21 -06:00
random_id = random . randint ( 0 , 100000 )
if hasattr ( self , " attachments_to_be_sent " ) :
response = self . session . vk . client . messages . send ( user_id = self . kwargs [ " user_id " ] , message = text , attachment = self . attachments_to_be_sent , random_id = random_id )
else :
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 :
2019-01-01 19:42:53 -06:00
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. " ) )
2016-05-25 11:33:57 -05:00
2016-06-06 04:27:07 -05:00
def __init__ ( self , * args , * * kwargs ) :
super ( chatBuffer , self ) . __init__ ( * args , * * kwargs )
self . reads = [ ]
2018-12-04 17:53:10 -06:00
self . chats = dict ( )
2016-06-06 04:27:07 -05:00
2016-09-25 14:24:40 -05:00
def parse_attachments ( self , post ) :
attachments = [ ]
2017-03-13 02:16:34 -06:00
2019-01-01 19:42:53 -06:00
if " attachments " in post :
2016-09-25 14:24:40 -05:00
for i in post [ " attachments " ] :
# We don't need the photos_list attachment, so skip it.
if i [ " type " ] == " photos_list " :
continue
attachments . append ( add_attachment ( i ) )
self . attachments . append ( i )
self . tab . attachments . list . Bind ( wx . EVT_LIST_ITEM_ACTIVATED , self . open_attachment )
self . tab . insert_attachments ( attachments )
def open_attachment ( self , * args , * * kwargs ) :
index = self . tab . attachments . get_selected ( )
attachment = self . attachments [ index ]
if attachment [ " type " ] == " audio " :
a = posts . audio ( session = self . session , postObject = [ attachment [ " audio " ] ] )
a . dialog . get_response ( )
a . dialog . Destroy ( )
2018-12-13 11:48:17 -06:00
elif attachment [ " type " ] == " audio_message " :
link = attachment [ " audio_message " ] [ " link_mp3 " ]
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Playing... " ) )
2018-12-13 11:48:17 -06:00
player . player . play ( url = dict ( url = link ) , set_info = False )
elif attachment [ " type " ] == " link " :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Opening URL... " ) , True )
2016-09-25 14:24:40 -05:00
webbrowser . open_new_tab ( attachment [ " link " ] [ " url " ] )
elif attachment [ " type " ] == " doc " :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Opening document in web browser... " ) )
2018-12-13 11:48:17 -06:00
webbrowser . open ( attachment [ " doc " ] [ " url " ] )
2016-09-25 14:24:40 -05:00
elif attachment [ " type " ] == " video " :
# it seems VK doesn't like to attach video links as normal URLS, so we'll have to
# get the full video object and use its "player" key which will open a webbrowser in their site with a player for the video.
# see https://vk.com/dev/attachments_w and and https://vk.com/dev/video.get
# However, the flash player isn't good for visually impaired people (when you press play you won't be able to close the window with alt+f4), so it could be good to use the HTML5 player.
# For firefox, see https://addons.mozilla.org/ru/firefox/addon/force-html5-video-player-at-vk/
# May be I could use a dialogue here for inviting people to use this addon in firefox. It seems it isn't possible to use this html5 player from the player URL.
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 ]
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Opening video in web browser... " ) , True )
2016-09-25 14:24:40 -05:00
webbrowser . open_new_tab ( video_object [ " player " ] )
elif attachment [ " type " ] == " photo " :
2019-01-01 19:42:53 -06:00
output . speak ( _ ( " Opening photo in web browser... " ) , True )
2016-09-25 14:24:40 -05:00
# 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 :
2019-01-01 19:42:53 -06:00
if " photo_ {0} " . format ( i , ) in attachment [ " photo " ] :
2016-09-25 14:24:40 -05:00
url = attachment [ " photo " ] [ " photo_ {0} " . format ( i , ) ]
break
if url != " " :
webbrowser . open_new_tab ( url )
else :
log . debug ( " Unhandled attachment: %r " % ( attachment , ) )
2018-12-20 15:36:32 -06:00
def clear_reads ( self ) :
for i in self . session . db [ self . name ] [ " items " ] :
if " read_state " in i and i [ " read_state " ] == 0 :
i [ " read_state " ] = 1
2016-05-25 11:33:57 -05:00
class peopleBuffer ( feedBuffer ) :
def create_tab ( self , parent ) :
self . tab = home . peopleTab ( parent )
def connect_events ( self ) :
super ( peopleBuffer , self ) . connect_events ( )
widgetUtils . connect_event ( self . tab . new_chat , widgetUtils . BUTTON_PRESSED , self . new_chat )
def new_chat ( self , * args , * * kwargs ) :
2018-12-16 02:06:36 -06:00
user = self . get_post ( )
if user == None :
return
user_id = user [ " id " ]
2016-06-05 14:15:40 -05:00
pub . sendMessage ( " new-chat " , user_id = user_id )
def onFocus ( self , * args , * * kwargs ) :
2018-12-16 02:06:36 -06:00
post = self . get_post ( )
if post == None :
return
2019-01-01 19:42:53 -06:00
if ( " last_seen " in post ) == False : return
2016-06-05 14:15:40 -05:00
original_date = arrow . get ( post [ " last_seen " ] [ " time " ] )
2018-12-13 16:36:46 -06:00
created_at = original_date . humanize ( locale = languageHandler . curLang [ : 2 ] )
2018-09-03 08:33:05 -05:00
self . tab . list . list . SetItem ( self . tab . list . get_selected ( ) , 1 , created_at )
2016-06-08 05:45:03 -05:00
def open_timeline ( self , * args , * * kwargs ) :
pass
def get_menu ( self , * args , * * kwargs ) :
2018-12-10 17:35:36 -06:00
""" display menu for people buffers (friends and requests) """
# If this is an incoming requests buffer, there is a flag in the peopleMenu that shows a few new options.
# So let's make sure we call it accordingly.
if self . name == " friend_requests " :
m = menus . peopleMenu ( is_request = True )
# Connect the accept and decline methods from here.
widgetUtils . connect_event ( m , widgetUtils . MENU , self . accept_friendship , menuitem = m . accept )
widgetUtils . connect_event ( m , widgetUtils . MENU , self . decline_friendship , menuitem = m . decline )
2018-12-10 17:52:01 -06:00
widgetUtils . connect_event ( m , widgetUtils . MENU , self . keep_as_follower , menuitem = m . keep_as_follower )
2018-12-10 17:35:36 -06:00
else :
m = menus . peopleMenu ( is_request = False )
# It is not allowed to send messages to people who is not your friends, so let's disble it if we're in a pending or outgoing requests folder.
if " friend_requests " in self . name :
m . message . Enable ( False )
2016-06-08 05:45:03 -05:00
widgetUtils . connect_event ( m , widgetUtils . MENU , self . new_chat , menuitem = m . message )
widgetUtils . connect_event ( m , widgetUtils . MENU , self . open_timeline , menuitem = m . timeline )
2016-09-21 13:54:52 -05:00
widgetUtils . connect_event ( m , widgetUtils . MENU , self . open_person_profile , menuitem = m . view_profile )
2016-07-08 16:34:28 -05:00
return m
def open_post ( self , * args , * * kwargs ) : pass
2016-07-18 17:34:37 -05:00
def play_audio ( self , * args , * * kwargs ) : return False
2016-07-08 16:34:28 -05:00
def pause_audio ( self , * args , * * kwargs ) : pass
2018-12-10 17:35:36 -06:00
def accept_friendship ( self , * args , * * kwargs ) :
pass
def decline_friendship ( self , * args , * * kwargs ) :
pass
2018-12-10 17:52:01 -06:00
def keep_as_follower ( self , * args , * * kwargs ) :
pass
2016-08-02 10:38:10 -05:00
class requestsBuffer ( peopleBuffer ) :
def get_items ( self , show_nextpage = False ) :
if self . can_get_items == False : return
retrieved = True
try :
ids = self . session . vk . client . friends . getRequests ( * self . args , * * self . kwargs )
2018-12-18 05:32:41 -06:00
except VkApiError as err :
2019-01-01 19:42:53 -06:00
log . error ( " Error {0} : {1} " . format ( err . code , err . message ) )
2016-08-02 10:38:10 -05:00
retrieved = err . code
return retrieved
2019-01-01 19:42:53 -06:00
except ReadTimeout as ConnectionError :
2018-12-18 05:32:41 -06:00
log . exception ( " Connection error when updating buffer %s . Will try again in 2 minutes " % ( self . name , ) )
return False
2016-08-02 10:38:10 -05:00
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 " )
if show_nextpage == False :
if self . tab . list . get_count ( ) > 0 and num > 0 :
v = [ i for i in self . session . db [ self . name ] [ " items " ] [ : num ] ]
v . reverse ( )
[ self . insert ( i , True ) for i in v ]
else :
[ self . insert ( i ) for i in self . session . db [ self . name ] [ " items " ] [ : num ] ]
return retrieved
2018-12-10 17:35:36 -06:00
def accept_friendship ( self , * args , * * kwargs ) :
2018-12-10 17:52:01 -06:00
""" Adds a person to a list of friends. This method is done for accepting someone else ' s friend request.
https : / / vk . com / dev / friends . add
"""
2018-12-10 17:35:36 -06:00
person = self . get_post ( )
2018-12-16 02:06:36 -06:00
if person == None :
return
2018-12-10 17:35:36 -06:00
result = self . session . vk . client . friends . add ( user_id = person [ " id " ] )
if result == 2 :
2019-01-01 19:42:53 -06:00
msg = _ ( " {0} {1} now is your friend. " ) . format ( person [ " first_name " ] , person [ " last_name " ] )
2018-12-10 17:35:36 -06:00
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 ( ) )
def decline_friendship ( self , * args , * * kwargs ) :
2018-12-10 17:52:01 -06:00
""" Declines a freind request.
https : / / vk . com / dev / friends . delete
"""
2018-12-10 17:35:36 -06:00
person = self . get_post ( )
2018-12-16 02:06:36 -06:00
if person == None :
return
2018-12-10 17:35:36 -06:00
result = self . session . vk . client . friends . delete ( user_id = person [ " id " ] )
if " out_request_deleted " in result :
2019-01-01 19:42:53 -06:00
msg = _ ( " You ' ve deleted the friends request to {0} {1} . " ) . format ( person [ " first_name " ] , person [ " last_name " ] )
2018-12-10 17:35:36 -06:00
elif " in_request_deleted " in result :
2019-01-01 19:42:53 -06:00
msg = _ ( " You ' ve declined the friend request of {0} {1} . " ) . format ( person [ " first_name " ] , person [ " last_name " ] )
2018-12-10 17:35:36 -06:00
pub . sendMessage ( " notify " , message = msg )
self . session . db [ self . name ] [ " items " ] . pop ( self . tab . list . get_selected ( ) )
2018-12-10 17:52:01 -06:00
self . tab . list . remove_item ( self . tab . list . get_selected ( ) )
def keep_as_follower ( self , * args , * * kwargs ) :
""" Adds a person to The followers list of the current user.
https : / / vk . com / dev / friends . add
"""
person = self . get_post ( )
2018-12-16 02:06:36 -06:00
if person == None :
return
2018-12-10 17:52:01 -06:00
result = self . session . vk . client . friends . add ( user_id = person [ " id " ] , follow = 1 )
if result == 2 :
2019-01-01 19:42:53 -06:00
msg = _ ( " {0} {1} is following you. " ) . format ( person [ " first_name " ] , person [ " last_name " ] )
2018-12-10 17:52:01 -06:00
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 ( ) )