2016-02-13 17:06:36 -06:00
# -*- coding: utf-8 -*-
2016-02-14 17:39:56 -06:00
import time
2016-02-13 17:06:36 -06:00
import arrow
import languageHandler
import paths
import vkSessionHandler
import logging
import utils
2016-05-24 17:48:22 -05:00
import sound
2016-02-13 17:06:36 -06:00
from config_utils import Configuration , ConfigurationResetException
2016-06-06 03:53:55 -05:00
from pubsub import pub
2018-09-03 09:15:52 -05:00
from vk . exceptions import VkAPIError
2016-06-06 03:53:55 -05:00
2016-05-10 20:23:48 -05:00
log = logging . getLogger ( " session " )
2016-02-13 17:06:36 -06:00
sessions = { }
2016-02-17 08:11:47 -06:00
# Saves possible set of identifier keys for VK'S data types
# see https://vk.com/dev/datatypes for more information.
2016-05-10 20:23:48 -05:00
# I've added the Date identifier (this is a field in unix time format), for special objects (like friendship indicators) because these objects doesn't have an own identifier.
identifiers = [ " aid " , " gid " , " uid " , " pid " , " id " , " post_id " , " nid " , " date " ]
2016-02-17 08:11:47 -06:00
def find_item ( list , item ) :
""" Finds an item in a list by taking an identifier """
# determines the kind of identifier that we are using
global identifiers
2016-05-10 20:23:48 -05:00
identifier = None
for i in identifiers :
if item . has_key ( i ) :
identifier = i
break
2016-02-17 08:11:47 -06:00
if identifier == None :
2016-02-17 09:18:36 -06:00
# if there are objects that can't be processed by lack of identifier, let's print keys for finding one.
2016-05-10 20:23:48 -05:00
log . exception ( " Can ' t find an identifier for the following object: %r " % ( item . keys ( ) , ) )
2016-02-17 08:11:47 -06:00
for i in list :
if i . has_key ( identifier ) and i [ identifier ] == item [ identifier ] :
return True
return False
2016-02-13 17:06:36 -06:00
def add_attachment ( attachment ) :
2016-05-10 20:23:48 -05:00
""" Adds information about attachment files in posts. It only adds the text, I mean, no attachment file is added here.
2016-02-13 17:06:36 -06:00
This will produce a result like ' Title of a web page: http://url.xxx ' , etc . """
msg = u " "
if attachment [ " type " ] == " link " :
msg = u " {0} : {1} " . format ( attachment [ " link " ] [ " title " ] , attachment [ " link " ] [ " url " ] )
elif attachment [ " type " ] == " photo " :
msg = attachment [ " photo " ] [ " text " ]
if msg == " " :
2016-07-08 16:40:34 -05:00
return _ ( u " photo with no description available " )
2016-02-13 17:06:36 -06:00
elif attachment [ " type " ] == " video " :
2016-07-08 16:40:34 -05:00
msg = _ ( u " video: {0} " ) . format ( attachment [ " video " ] [ " title " ] , )
2016-02-13 17:06:36 -06:00
return msg
def add_text ( status ) :
""" This shorts the text to 140 characters for displaying it in the list control. """
message = " "
2016-03-23 17:28:40 -06:00
if status . has_key ( " copy_history " ) :
txt = status [ " copy_history " ] [ 0 ] [ " text " ]
else :
txt = status [ " text " ]
if len ( txt ) < 140 :
message = utils . clean_text ( txt )
else :
message = utils . clean_text ( txt [ : 139 ] )
2016-02-13 17:06:36 -06:00
return message
2016-05-25 11:33:57 -05:00
def compose_person ( status , session ) :
2016-06-02 13:11:42 -05:00
if status . has_key ( " last_seen " ) :
original_date = arrow . get ( status [ " last_seen " ] [ " time " ] )
2016-06-29 10:56:41 -05:00
# Translators: This is the date of last seen
2016-06-02 13:11:42 -05:00
last_seen = _ ( u " {0} " ) . format ( original_date . humanize ( locale = languageHandler . getLanguage ( ) ) , )
elif status . has_key ( " last_seen " ) == False and status . has_key ( " deactivated " ) :
last_seen = _ ( u " Account deactivated " )
2016-05-25 11:33:57 -05:00
return [ u " {0} {1} " . format ( status [ " first_name " ] , status [ " last_name " ] ) , last_seen ]
2016-02-13 17:06:36 -06:00
def compose_new ( status , session ) :
""" This method is used to compose an item of the news feed. """
2016-07-07 10:20:03 -05:00
user = session . get_user_name ( status [ " source_id " ] , case_name = " nom " )
2016-03-23 17:28:40 -06:00
if status . has_key ( " copy_history " ) :
user = _ ( u " {0} has shared the {1} ' s post " ) . format ( user , session . get_user_name ( status [ " copy_history " ] [ 0 ] [ " owner_id " ] ) )
2016-02-13 17:06:36 -06:00
message = " "
original_date = arrow . get ( status [ " date " ] )
created_at = original_date . humanize ( locale = languageHandler . getLanguage ( ) )
if status [ " type " ] == " post " :
message + = add_text ( status )
if status . has_key ( " attachment " ) and len ( status [ " attachment " ] ) > 0 :
message + = add_attachment ( status [ " attachment " ] )
if message == " " :
message = " no description available "
elif status [ " type " ] == " audio " :
2016-06-02 13:11:42 -05:00
# removes deleted audios.
status [ " audio " ] = clean_audio ( status [ " audio " ] )
2016-02-23 17:49:55 -06:00
if status [ " audio " ] [ " count " ] == 1 :
message = _ ( u " {0} has added an audio: {1} " ) . format ( user , u " , " . join ( compose_audio ( status [ " audio " ] [ " items " ] [ 0 ] , session ) ) , )
else :
prem = " "
for i in xrange ( 0 , status [ " audio " ] [ " count " ] ) :
composed_audio = compose_audio ( status [ " audio " ] [ " items " ] [ i ] , session )
prem + = u " {0} - {1} , " . format ( composed_audio [ 0 ] , composed_audio [ 1 ] )
2016-02-25 05:08:56 -06:00
message = _ ( u " {0} has added {1} audios: {2} " ) . format ( user , status [ " audio " ] [ " count " ] , prem )
2016-02-13 17:06:36 -06:00
elif status [ " type " ] == " friend " :
msg_users = u " "
2016-08-10 12:58:11 -05:00
if status . has_key ( " friends " ) :
for i in status [ " friends " ] [ " items " ] :
msg_users = msg_users + u " {0} , " . format ( session . get_user_name ( i [ " user_id " ] , " nom " ) )
else :
print status . keys ( )
2016-02-17 08:11:47 -06:00
message = _ ( u " {0} hadded friends: {1} " ) . format ( user , msg_users )
2016-03-23 12:03:39 -06:00
elif status [ " type " ] == " video " :
if status [ " video " ] [ " count " ] == 1 :
message = _ ( u " {0} has added a video: {1} " ) . format ( user , u " , " . join ( compose_video ( status [ " video " ] [ " items " ] [ 0 ] , session ) ) , )
else :
prem = " "
for i in xrange ( 0 , status [ " video " ] [ " count " ] ) :
composed_video = compose_video ( status [ " video " ] [ " items " ] [ i ] , session )
prem + = u " {0} - {1} , " . format ( composed_video [ 0 ] , composed_video [ 1 ] )
message = _ ( u " {0} has added {1} videos: {2} " ) . format ( user , status [ " video " ] [ " count " ] , prem )
2016-02-13 17:06:36 -06:00
else :
2016-03-23 12:03:39 -06:00
if status [ " type " ] != " post " : print status
2016-02-13 17:06:36 -06:00
return [ user , message , created_at ]
2016-06-02 13:11:42 -05:00
def clean_audio ( audio ) :
for i in audio [ " items " ] [ : ] :
if type ( i ) == bool :
audio [ " items " ] . remove ( i )
audio [ " count " ] = audio [ " count " ] - 1
return audio
2016-05-17 12:46:57 -05:00
def compose_message ( message , session ) :
2016-07-07 10:20:03 -05:00
user = session . get_user_name ( message [ " from_id " ] , " nom " )
2016-05-17 12:46:57 -05:00
original_date = arrow . get ( message [ " date " ] )
created_at = original_date . format ( _ ( u " dddd, MMMM D, YYYY H:m:s " ) , locale = languageHandler . getLanguage ( ) )
body = message [ " body " ]
return [ u " {2} , {0} {1} " . format ( body , created_at , user ) ]
2016-02-13 17:06:36 -06:00
def compose_status ( status , session ) :
2016-07-07 10:20:03 -05:00
user = session . get_user_name ( status [ " from_id " ] , " nom " )
2016-03-30 16:27:37 -06:00
if status . has_key ( " copy_history " ) :
user = _ ( u " {0} has shared the {1} ' s post " ) . format ( user , session . get_user_name ( status [ " copy_history " ] [ 0 ] [ " owner_id " ] ) )
2016-02-13 17:06:36 -06:00
message = " "
original_date = arrow . get ( status [ " date " ] )
created_at = original_date . humanize ( locale = languageHandler . getLanguage ( ) )
2016-02-22 05:53:37 -06:00
if status . has_key ( " copy_owner_id " ) :
user = _ ( u " {0} has shared the {1} ' s post " ) . format ( user , session . get_user_name ( status [ " copy_owner_id " ] ) )
if status [ " post_type " ] == " post " or status [ " post_type " ] == " copy " :
2016-02-13 17:06:36 -06:00
message + = add_text ( status )
if status . has_key ( " attachment " ) and len ( status [ " attachment " ] ) > 0 :
message + = add_attachment ( status [ " attachment " ] )
if message == " " :
message = " no description available "
return [ user , message , created_at ]
2016-04-04 03:40:42 -05:00
def compose_audio ( audio , session = None ) :
2016-02-19 17:30:11 -06:00
if audio == False : return [ _ ( u " Audio removed from library " ) , " " , " " ]
2016-02-13 17:06:36 -06:00
return [ audio [ " title " ] , audio [ " artist " ] , utils . seconds_to_string ( audio [ " duration " ] ) ]
2016-04-04 03:40:42 -05:00
def compose_video ( video , session = None ) :
2016-03-23 12:03:39 -06:00
if video == False : return [ _ ( u " Audio removed from library " ) , " " , " " ]
2016-08-14 07:46:41 -05:00
return [ video [ " title " ] , video [ " description " ] , utils . seconds_to_string ( video [ " duration " ] ) ]
2016-03-23 12:03:39 -06:00
2016-02-13 17:06:36 -06:00
class vkSession ( object ) :
2016-02-23 17:49:55 -06:00
def order_buffer ( self , name , data , show_nextpage ) :
2016-02-13 17:06:36 -06:00
2016-02-17 08:11:47 -06:00
""" Put new items on the local database. Useful for cursored buffers
2016-02-13 17:06:36 -06:00
name str : The name for the buffer stored in the dictionary .
data list : A list with items and some information about cursors .
returns the number of items that has been added in this execution """
2016-02-17 08:11:47 -06:00
first_addition = False
2016-02-13 17:06:36 -06:00
num = 0
if self . db . has_key ( name ) == False :
self . db [ name ] = { }
self . db [ name ] [ " items " ] = [ ]
2016-02-17 08:11:47 -06:00
first_addition = True
2016-02-13 17:06:36 -06:00
for i in data :
2016-05-17 12:46:57 -05:00
if i . has_key ( " type " ) and ( i [ " type " ] == " wall_photo " or i [ " type " ] == " photo_tag " or i [ " type " ] == " photo " ) :
2016-05-10 20:23:48 -05:00
log . debug ( " Skipping unsupported item... %r " % ( i , ) )
continue
2016-02-17 08:11:47 -06:00
if find_item ( self . db [ name ] [ " items " ] , i ) == False :
# if i not in self.db[name]["items"]:
2016-02-25 04:52:02 -06:00
if first_addition == True or show_nextpage == True :
2016-02-17 08:11:47 -06:00
if self . settings [ " general " ] [ " reverse_timelines " ] == False : self . db [ name ] [ " items " ] . append ( i )
else : self . db [ name ] [ " items " ] . insert ( 0 , i )
else :
if self . settings [ " general " ] [ " reverse_timelines " ] == False : self . db [ name ] [ " items " ] . insert ( 0 , i )
else : self . db [ name ] [ " items " ] . append ( i )
2016-02-13 17:06:36 -06:00
num = num + 1
2016-05-10 20:23:48 -05:00
log . debug ( " There are %d items in the %s buffer " % ( len ( self . db [ name ] [ " items " ] ) , name ) )
2016-02-13 17:06:36 -06:00
return num
def __init__ ( self , session_id ) :
self . session_id = session_id
self . logged = False
self . settings = None
self . vk = vkSessionHandler . vkObject ( )
self . db = { }
self . db [ " users " ] = { }
self . db [ " groups " ] = { }
@property
def is_logged ( self ) :
return self . logged
def get_configuration ( self ) :
""" Gets settings for a session. """
file_ = " %s /session.conf " % ( self . session_id , )
# try:
log . debug ( " Creating config file %s " % ( file_ , ) )
self . settings = Configuration ( paths . config_path ( file_ ) , paths . app_path ( " session.defaults " ) )
2016-05-24 17:48:22 -05:00
self . soundplayer = sound . soundSystem ( self . settings [ " sound " ] )
2016-02-13 17:06:36 -06:00
# except:
# log.exception("The session configuration has failed.")
def login ( self ) :
""" Login using credentials from settings.
2016-02-17 08:11:47 -06:00
if the user account isn ' t authorised, it ' ll call self . authorise ( ) before login .
If the access_token has expired , it will call authorise ( ) too , for getting a new access token . """
2016-02-13 17:06:36 -06:00
if self . settings [ " vk " ] [ " token " ] != None :
2018-09-03 09:18:32 -05:00
# Handle special case where you get identical access tokens for two IP addresses.
# See https://github.com/manuelcortez/socializer/issues/11
2018-09-03 09:15:52 -05:00
try :
result = self . vk . login_access_token ( self . settings [ " vk " ] [ " token " ] )
self . logged = True
log . debug ( " Logged. " )
if result == False :
self . authorise ( )
except VkAPIError as err :
if err . code == 5 :
self . authorise ( )
2016-02-13 17:06:36 -06:00
else :
2016-02-14 18:46:23 -06:00
self . authorise ( )
2016-02-19 17:30:11 -06:00
self . get_my_data ( )
2016-02-13 17:06:36 -06:00
def authorise ( self ) :
2016-06-06 03:53:55 -05:00
try :
self . vk . login ( self . settings [ " vk " ] [ " user " ] , self . settings [ " vk " ] [ " password " ] )
self . settings [ " vk " ] [ " token " ] = self . vk . client . _session . access_token
self . settings . write ( )
except :
self . settings [ " vk " ] [ " user " ] = " "
self . settings [ " vk " ] [ " password " ] = " "
self . settings . write ( )
pub . sendMessage ( " authorisation-failed " )
2016-02-13 17:06:36 -06:00
def post_wall_status ( self , message , * args , * * kwargs ) :
2016-02-17 08:11:47 -06:00
""" Sends a post to an user, group or community wall. """
2016-05-10 20:23:48 -05:00
log . debug ( " Making a post to the user ' s wall with the following params: %r " % ( kwargs , ) )
2016-02-13 17:06:36 -06:00
response = self . vk . client . wall . post ( message = message , * args , * * kwargs )
2016-02-23 17:49:55 -06:00
def get_newsfeed ( self , name = " newsfeed " , show_nextpage = False , endpoint = " " , * args , * * kwargs ) :
2016-05-10 20:23:48 -05:00
log . debug ( " Updating news feed... " )
2016-03-28 05:19:08 -06:00
if show_nextpage == True and self . db [ name ] . has_key ( " cursor " ) :
2016-05-10 20:23:48 -05:00
log . debug ( " user has requested previous items " )
2016-02-23 17:49:55 -06:00
kwargs [ " start_from " ] = self . db [ name ] [ " cursor " ]
2016-05-10 20:23:48 -05:00
log . debug ( " Params for sending to vk: %r " % ( kwargs , ) )
2016-02-13 17:06:36 -06:00
data = getattr ( self . vk . client . newsfeed , " get " ) ( * args , * * kwargs )
if data != None :
2016-02-23 17:49:55 -06:00
if show_nextpage == False :
self . process_usernames ( data )
2016-02-25 04:52:02 -06:00
# else:
# print data.keys(), len(data["items"]), data["next_from"]
num = self . order_buffer ( name , data [ " items " ] , show_nextpage )
2016-05-10 20:23:48 -05:00
log . debug ( " Keys of the returned data for debug purposes: %r " % ( data . keys ( ) , ) )
2016-03-28 05:19:08 -06:00
if data . has_key ( " next_from " ) :
self . db [ name ] [ " cursor " ] = data [ " next_from " ]
2016-02-13 17:06:36 -06:00
return num
2016-02-23 17:49:55 -06:00
def get_page ( self , name = " " , show_nextpage = False , endpoint = " " , * args , * * kwargs ) :
2016-02-13 17:06:36 -06:00
data = None
if kwargs . has_key ( " parent_endpoint " ) :
p = kwargs [ " parent_endpoint " ]
kwargs . pop ( " parent_endpoint " )
p = getattr ( self . vk . client , p )
2016-05-10 20:23:48 -05:00
log . debug ( " Calling endpoint %s with params %r " % ( p , kwargs , ) )
2016-02-13 17:06:36 -06:00
data = getattr ( p , endpoint ) ( * args , * * kwargs )
if data != None :
2016-03-22 02:59:31 -06:00
if type ( data ) == dict :
num = self . order_buffer ( name , data [ " items " ] , show_nextpage )
2016-06-19 12:25:06 -05:00
if len ( data [ " items " ] ) > 0 and data [ " items " ] [ 0 ] . has_key ( " first_name " ) :
2016-07-07 10:20:03 -05:00
data2 = { " profiles " : [ ] , " groups " : [ ] }
2016-05-25 11:33:57 -05:00
for i in data [ " items " ] :
2016-07-07 10:20:03 -05:00
data2 [ " profiles " ] . append ( i )
2016-07-07 13:23:49 -05:00
self . process_usernames ( data2 )
2016-03-30 16:27:37 -06:00
if data . has_key ( " profiles " ) and data . has_key ( " groups " ) :
self . process_usernames ( data )
2016-03-22 02:59:31 -06:00
else :
num = self . order_buffer ( name , data , show_nextpage )
2016-02-13 17:06:36 -06:00
return num
2016-05-17 12:46:57 -05:00
def get_messages ( self , name = " " , * args , * * kwargs ) :
data = self . vk . client . messages . getHistory ( * args , * * kwargs )
if data != None :
num = self . order_buffer ( name , data [ " items " ] , False )
return num
2016-07-07 10:20:03 -05:00
def get_user_name ( self , user_id , case_name = " gen " ) :
2016-02-13 17:06:36 -06:00
if user_id > 0 :
if self . db [ " users " ] . has_key ( user_id ) :
2016-07-07 10:20:03 -05:00
if self . db [ " users " ] [ user_id ] . has_key ( case_name ) :
return self . db [ " users " ] [ user_id ] [ case_name ]
else :
return self . db [ " users " ] [ user_id ] [ " nom " ]
2016-02-13 17:06:36 -06:00
else :
return " no specified user "
else :
if self . db [ " groups " ] . has_key ( abs ( user_id ) ) :
2016-07-07 10:20:03 -05:00
return self . db [ " groups " ] [ abs ( user_id ) ] [ " nom " ]
2016-02-13 17:06:36 -06:00
else :
return " no specified community "
def get_users ( self , user_ids = None , group_ids = None ) :
2016-05-10 20:23:48 -05:00
log . debug ( " Getting user information from the VK servers " )
2016-02-13 17:06:36 -06:00
if user_ids != None :
u = self . vk . client . users . get ( user_ids = user_ids , fields = " uid, first_name, last_name " )
for i in u :
2016-02-23 17:49:55 -06:00
self . db [ " users " ] [ i [ " id " ] ] = u " {0} {1} " . format ( i [ " first_name " ] , i [ " last_name " ] )
2016-02-13 17:06:36 -06:00
if group_ids != None :
g = self . vk . client . groups . getById ( group_ids = group_ids , fields = " name " )
for i in g :
2016-02-23 17:49:55 -06:00
self . db [ " groups " ] [ i [ " id " ] ] = i [ " name " ]
2016-02-17 09:18:36 -06:00
def process_usernames ( self , data ) :
2016-07-07 10:20:03 -05:00
""" processes user IDS and saves them in a local storage system.
Every function wich needs to convert from an ID to user or community name will have to call the get_user_name function in this session object .
Every function that needs to save a set ot user ids for a future use needs to pass a data dictionary with a profiles key being a list of user objects .
For russian , it gets the genitive case of every name for future use . """
2016-05-10 20:23:48 -05:00
log . debug ( " Adding usernames to the local database... " )
2016-07-07 10:20:03 -05:00
ids = " "
2016-02-17 09:18:36 -06:00
for i in data [ " profiles " ] :
2016-07-07 10:20:03 -05:00
if self . db [ " users " ] . has_key ( i [ " id " ] ) == False :
self . db [ " users " ] [ i [ " id " ] ] = dict ( nom = u " {0} {1} " . format ( i [ " first_name " ] , i [ " last_name " ] ) )
ids = ids + " {0} , " . format ( i [ " id " ] , )
gids = " "
2016-02-17 09:18:36 -06:00
for i in data [ " groups " ] :
2016-07-07 10:20:03 -05:00
self . db [ " groups " ] [ i [ " id " ] ] = dict ( nom = i [ " name " ] )
gids = " {0} , " . format ( i [ " id " ] , )
if not " ru " in languageHandler . getLanguage ( ) :
return
2016-07-10 22:51:06 -05:00
if ids != " " :
users_genitive = self . vk . client . users . get ( user_ids = ids , fields = " first_name, last_name " , name_case = " gen " )
users_instrumental = self . vk . client . users . get ( user_ids = ids , fields = " first_name, last_name " , name_case = " ins " )
for i in users_genitive :
if self . db [ " users " ] . has_key ( i [ " id " ] ) :
self . db [ " users " ] [ i [ " id " ] ] [ " gen " ] = u " {0} {1} " . format ( i [ " first_name " ] , i [ " last_name " ] )
for i in users_instrumental :
if self . db [ " users " ] . has_key ( i [ " id " ] ) :
self . db [ " users " ] [ i [ " id " ] ] [ " ins " ] = u " {0} {1} " . format ( i [ " first_name " ] , i [ " last_name " ] )
2016-02-19 17:30:11 -06:00
def get_my_data ( self ) :
2016-05-10 20:23:48 -05:00
log . debug ( " Getting user identifier... " )
2016-03-14 16:07:44 -06:00
user = self . vk . client . users . get ( fields = " uid, first_name, last_name " )
self . user_id = user [ 0 ] [ " id " ]
2016-07-07 10:20:03 -05:00
# self.db["users"][self.user_id] = u"{0} {1}".format(user[0]["first_name"], user[0]["last_name"])