Skip to content

Commit f29914e

Browse files
committed
Merge branch 'dev'
2 parents 5c7dab5 + 9291b7f commit f29914e

6 files changed

Lines changed: 85 additions & 26 deletions

File tree

jconfig/jconfig.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,19 @@ def __init__(self, section, filename='.jconfig'):
2222
def __getattr__(self, name):
2323
return self._settings[self._section].get(name)
2424

25+
def __getitem__(self, key):
26+
return self.__getattr__(key)
27+
2528
def __setattr__(self, name, value):
2629
if name.startswith('_'):
2730
super(Config, self).__setattr__(name, value)
2831
return
2932

3033
self._settings[self._section][name] = value
3134

35+
def __setitem__(self, key, value):
36+
return self.__setattr__(key, value)
37+
3238
def clear_section(self):
3339
self._settings[self._section] = {}
3440

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
setup(
1616
name='vk_api',
17-
version='7.0',
17+
version='7.1',
1818
author='Kirill Python',
1919
author_email='python273@ya.ru',
2020
url='https://github.com/python273/vk_api',

vk_api/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"""
1010

1111
__author__ = 'Kirill Python'
12-
__version__ = '7.0'
12+
__version__ = '7.1'
1313
__email__ = 'python273@ya.ru'
1414
__contact__ = 'https://vk.com/python273'
1515

vk_api/vk_api.py

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import re
1212
import time
13+
import threading
1314

1415
import requests
1516

@@ -39,7 +40,7 @@ def __init__(self, login=None, password=None, number=None, sec_number=None,
3940
proxies=None,
4041
auth_handler=None, captcha_handler=None,
4142
config_filename='vk_config.json',
42-
api_version='5.44', app_id=2895443, scope=33554431,
43+
api_version='5.52', app_id=2895443, scope=33554431,
4344
client_secret=None):
4445
"""
4546
:param login: Логин ВКонтакте
@@ -56,8 +57,9 @@ def __init__(self, login=None, password=None, number=None, sec_number=None,
5657
{'http': 'http://127.0.0.1:8888/',
5758
'https': 'https://127.0.0.1:8888/'}
5859
:param auth_handler: Функция для обработки двухфакторной аутентификации,
59-
обязана возвращать строку с кодом для
60-
прохождения аутентификации
60+
обязана возвращать строку с кодом и булевое значение,
61+
означающее, стоит ли вк запомнить это устройство, для
62+
прохождения аутентификации.
6163
:param captcha_handler: Функция для обработки капчи
6264
:param config_filename: Расположение config файла
6365
@@ -85,10 +87,10 @@ def __init__(self, login=None, password=None, number=None, sec_number=None,
8587

8688
self.http = requests.Session()
8789
self.http.proxies = proxies # Ставим прокси
88-
self.http.headers = { # Притворимся браузером
90+
self.http.headers.update({ # Притворимся браузером
8991
'User-agent': 'Mozilla/5.0 (Windows NT 6.1; rv:40.0) '
9092
'Gecko/20100101 Firefox/40.0'
91-
}
93+
})
9294

9395
self.last_request = 0.0
9496

@@ -99,10 +101,12 @@ def __init__(self, login=None, password=None, number=None, sec_number=None,
99101
TWOFACTOR_CODE: auth_handler or self.auth_handler
100102
}
101103

104+
self.lock = threading.Lock()
105+
102106
def authorization(self, reauth=False):
103107
""" Полная авторизация с получением токена
104108
105-
:param reauth: Позволяет переавторизиваться, игнорируя сохраненные
109+
:param reauth: Позволяет переавторизиваться, игнорируя сохраненные
106110
куки и токен
107111
"""
108112

@@ -148,8 +152,8 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
148152
remixsid = None
149153

150154
if 'act=authcheck' in response.url:
151-
code = self.error_handlers[TWOFACTOR_CODE]()
152-
response = self.twofactor(response, code)
155+
code, remember_device = self.error_handlers[TWOFACTOR_CODE]()
156+
response = self.twofactor(response, code, remember_device)
153157

154158
if 'remixsid' in self.http.cookies:
155159
remixsid = self.http.cookies['remixsid']
@@ -188,21 +192,27 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
188192
if 'act=blocked' in response.url:
189193
raise AccountBlocked('Account is blocked')
190194

191-
def twofactor(self, response, code):
195+
def twofactor(self, response, code, remember_device=False):
192196
""" Двухфакторная аутентификация
193197
:param reponse: запрос, содержащий страницу с приглашением к аутентификации
194198
:param code: код, который необходимо ввести для успешной аутентификации
199+
:param remember_device: параметр, означающий,
200+
стоит ли запоминать это устройство в целях
201+
избежания повторного ввода кода(default: False)
195202
"""
196-
assert code != None, "Empty code doesn't acceptable"
197-
assert len(code) == 6, "Length of code cannot be other than 6."
203+
204+
if code == None:
205+
raise TwoFactorError("Empty code doesn't acceptable")
206+
if len(code) != 6:
207+
raise TwoFactorError("Length of code cannot be other than 6.")
198208

199209
auth_hash = search_re(RE_AUTH_HASH, response.text)
200210
url = 'https://vk.com/al_login.php'
201211
if auth_hash:
202212
values = {
203213
'act': 'a_authcheck_code',
204214
'code': code,
205-
'remember': 0, # TODO: Fix me(device remembering)
215+
'remember': int(remember_device),
206216
'hash': auth_hash,
207217
}
208218
response = self.http.post(url, values, cookies=response.cookies)
@@ -383,14 +393,15 @@ def method(self, method, values=None, captcha_sid=None, captcha_key=None):
383393
'captcha_key': captcha_key
384394
})
385395

386-
# Ограничение 3 запроса в секунду
387-
delay = DELAY - (time.time() - self.last_request)
396+
with self.lock:
397+
# Ограничение 3 запроса в секунду
398+
delay = DELAY - (time.time() - self.last_request)
388399

389-
if delay > 0:
390-
time.sleep(delay)
400+
if delay > 0:
401+
time.sleep(delay)
391402

392-
response = self.http.post(url, values)
393-
self.last_request = time.time()
403+
response = self.http.post(url, values)
404+
self.last_request = time.time()
394405

395406
if response.ok:
396407
response = response.json()
@@ -574,6 +585,7 @@ def __init__(self, vk, captcha_sid,
574585

575586
self.key = None
576587
self.url = url
588+
self.image = None
577589

578590
def get_url(self):
579591
""" Возвращает ссылку на изображение капчи
@@ -585,6 +597,14 @@ def get_url(self):
585597

586598
return self.url
587599

600+
def get_image(self):
601+
""" Возвращает бинарное изображение капчи, получаемое по get_url()
602+
"""
603+
604+
if not self.image:
605+
self.image = self.vk.http.get(self.get_url()).content
606+
return self.image
607+
588608
def try_again(self, key):
589609
""" Отправляет запрос заново с ответом капчи
590610

vk_api/vk_tools.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def get_all(self, method, max_count, values=None, key='items', limit=None):
5252

5353
while True:
5454
run_code = code_get_all_items % (
55-
max_count, offset, key, json.dumps(values, ensure_ascii=False),
55+
max_count, offset, key, sjson_dumps(values),
5656
method, method
5757
)
5858

@@ -187,7 +187,7 @@ def gen_code_one_method(self, pool):
187187
method = pool[0][0]
188188

189189
list_values = [i[1] for i in pool]
190-
json_list_values = json.dumps(list_values, separators=(',', ':'))
190+
json_list_values = sjson_dumps(list_values)
191191
run_code = code_requestspoll_one_method % (
192192
json_list_values, method
193193
)
@@ -199,8 +199,8 @@ def gen_code_one_param(self, pool):
199199
(если в пулле запросы к одному методу, с одним меняющеися параметром)
200200
"""
201201
run_code = code_requestspoll_one_param % (
202-
json.dumps(self.one_param['default'], separators=(',', ':')),
203-
json.dumps(pool, separators=(',', ':')),
202+
sjson_dumps(self.one_param['default']),
203+
sjson_dumps(pool),
204204
self.one_param['key'],
205205
self.one_param['method']
206206
)
@@ -212,7 +212,7 @@ def gen_code_one_param(self, pool):
212212
def gen_code_many_methods(self, pool):
213213
""" Генерирует код для нескольких методов """
214214
reqs = ','.join(
215-
'API.{}({})'.format(i[0], json.dumps(i[1]), separators=(',', ':'))
215+
'API.{}({})'.format(i[0], sjson_dumps(i[1]))
216216
for i in pool
217217
)
218218
run_code = 'return [{}];'.format(reqs)
@@ -239,9 +239,18 @@ def execute(self):
239239
if self.one_param:
240240
self.one_param['return'][cur_pool[x]] = response[x]
241241
else:
242-
self.pool[i + x][2].update(response[x])
242+
if response[x] is False:
243+
self.pool[i + x][2].update({'_error': True})
244+
else:
245+
self.pool[i + x][2].update(response[x])
243246

244247

248+
def sjson_dumps(*args, **kwargs):
249+
kwargs['ensure_ascii'] = False
250+
kwargs['separators'] = (',', ':')
251+
252+
return json.dumps(*args, **kwargs)
253+
245254
# Полный код в файле vk_procedures
246255
code_get_all_items = """
247256
var m=%s,n=%s,b="%s",v=n;var c={count:m,offset:v}+%s;var r=API.%s(c),k=r.count,

vk_api/vk_upload.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,30 @@ def photo_wall(self, photos, user_id=None, group_id=None):
112112

113113
return response
114114

115+
def audio(self, file_path, artist, title):
116+
""" Загрузка аудио
117+
118+
:param file_path: путь к аудиофайлу
119+
:param artist: исполнитель
120+
:param title: название
121+
"""
122+
123+
url = self.vk.method('audio.getUploadServer')['upload_url']
124+
125+
filetype = file_path.split('.')[-1]
126+
audio_file = [(('file', ( 'file.' + filetype, open(file_path, 'rb'))))]
127+
128+
response = self.vk.http.post(url, files=audio_file).json()
129+
130+
response.update({
131+
'artist': artist,
132+
'title': title
133+
})
134+
135+
response = self.vk.method('audio.save', response)
136+
137+
return response
138+
115139
def document(self, file_path, title=None, tags=None, group_id=None):
116140
""" Загрузка документа
117141

0 commit comments

Comments
 (0)