kodi-vk.inpos.ru/default.py

1162 lines
48 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals
import sys, os, vk, time, pickle, binascii
from vk.exceptions import VkAPIError
from vk.api import Session, AuthSession
from math import ceil
import xbmc, xbmcplugin, xbmcaddon, xbmcgui
import urllib.parse
import urllib.request, urllib.error, urllib.parse
from urllib.parse import urlencode
from urllib.request import urlopen
import simplejson as json
import re
2018-05-24 20:40:56 +03:00
_VERSION = '1.2.5'
_ADDON_NAME = 'kodi-vk.inpos.ru'
_addon = xbmcaddon.Addon(id=_ADDON_NAME)
_addon_id = int(sys.argv[1])
_addon_url = sys.argv[0]
_addon_path = _addon.getAddonInfo('path')
_APP_ID = '4353740'
_APP_SEC = 'GRDdDhHJ8qzyPQczrwqC'
_SCOPE = 'friends,photos,audio,video,groups,messages,offline'
_SETTINGS_ID_TOKEN = 'vk_token'
_SETTINGS_ID_MAX_RES = 'video_resolution'
_SETTINGS_ID_LIST_LEN = 'list_len'
_SETTINGS_ID_VIDEO_SEARCH_SORT = 'v_search_sort'
_SETTINGS_ID_VIDEO_SEARCH_HD = 'search_hd_video'
_SETTINGS_ID_VIDEO_SEARCH_ADULT = 'dont_search_adult_video'
_SETTINGS_BOOL = {'true': 1, 'false': 0}
_SETTINGS_INV_BOOL = {'true': 0, 'false': 1}
_SETTINGS_PAGE_ITEMS = int(_addon.getSetting(_SETTINGS_ID_LIST_LEN))
# _SETTINGS_PAGE_ITEMS = 50
_SETTINGS_MAX_RES = int(_addon.getSetting(_SETTINGS_ID_MAX_RES))
# _SETTINGS_MAX_RES = 1080
_SETTINGS_VIDEO_SEARCH_SORT = int(_addon.getSetting(_SETTINGS_ID_VIDEO_SEARCH_SORT))
# _SETTINGS_VIDEO_SEARCH_SORT = 0
_SETTINGS_VIDEO_SEARCH_HD = _SETTINGS_BOOL[_addon.getSetting(_SETTINGS_ID_VIDEO_SEARCH_HD)]
# _SETTINGS_VIDEO_SEARCH_HD = False
_SETTINGS_VIDEO_SEARCH_ADULT = _SETTINGS_INV_BOOL[_addon.getSetting(_SETTINGS_ID_VIDEO_SEARCH_ADULT)]
# _SETTINGS_VIDEO_SEARCH_ADULT = True
_FILE_VIDEO_SEARCH_HISTORY = _ADDON_NAME + '_vsh.pkl'
_FILE_GROUP_SEARCH_HISTORY = _ADDON_NAME + '_gsh.pkl'
_FILE_USER_SEARCH_HISTORY = _ADDON_NAME + '_ush.pkl'
_USERNAME = 'vk_username'
_LOGIN_RETRY = 3
_VK_API_VERSION = '5.95'
_PHOTO_THUMB_KEY = 'photo_130'
_CTYPE_VIDEO = 'video'
_CTYPE_AUDIO = 'audio'
_CTYPE_IMAGE = 'image'
_DO_HOME = 'home'
_DO_MAIN_VIDEO = 'main_video'
_DO_VIDEO = 'video'
_DO_VIDEO_ALBUMS = 'video_albums'
_DO_MAIN_VIDEO_SEARCH = 'main_video_search'
_DO_VIDEO_SEARCH = 'video_search'
_DO_PLAY_VIDEO = 'play_video'
_DO_MAIN_AUDIO = 'main_audio'
_DO_MAIN_PHOTO = 'main_photo'
_DO_PHOTO = 'photo'
_DO_PHOTO_ALBUMS = 'photo_albums'
_DO_FRIENDS = 'friends'
_DO_GROUPS = 'groups'
_DO_MAIN_GROUP_SEARCH = 'main_group_search'
_DO_GROUP_SEARCH = 'group_search'
_DO_MEMBERS = 'members'
_DO_MAIN_USER_SEARCH = 'main_user_search'
_DO_USER_SEARCH = 'user_search'
_DO_MAIN_FAVE = 'main_fave'
_DO_FAVE_VIDEO = 'fave_video'
_DO_FAVE_PHOTO = 'fave_photo'
_DO_FAVE_GROUPS = 'fave_groups'
_DO_FAVE_USERS = 'fave_users'
_DO_LOGOUT = 'logout'
_NO_OWNER = '__no_owner__'
_VK_VIDEO_SOURCE = 'vk_video'
_YOUTUBE_VIDEO_SOURCE = 'youtube_video'
_UNKNOWN_VIDEO_SOURCE = 'unknown_video'
DELAY = 1.0 / 3 # 3 запроса в секунду
# Служебные классы
class APIMethod(object):
__slots__ = ['conn', '_method_name']
def __init__(self, conn, method_name):
self.conn = conn
self._method_name = method_name
def __getattr__(self, method_name):
return APIMethod(self.conn, self._method_name + '.' + method_name)
def __call__(self, **method_kwargs):
return self.conn(self._method_name, **method_kwargs)
class Connection(object):
"""Соединяемся с сайтом"""
def __init__(self, app_id, username=None, password=None, access_token=None, scope=''):
if access_token is not None:
session = Session(access_token=access_token)
else:
session = AuthSession(app_id, username, password, scope=scope)
self.conn = vk.API(session)
self.last_request = 0.0
def __getattr__(self, method_name):
return APIMethod(self, method_name)
def __call__(self, method_name, **method_kwargs):
# Ограничение 3 запроса в секунду
delay = DELAY - (time.time() - self.last_request)
if delay > 0:
time.sleep(delay)
if 'v' not in method_kwargs: method_kwargs['v'] = _VK_API_VERSION
res = self.conn(method_name, **method_kwargs)
self.last_request = time.time()
return res
class Group(object):
"""Группа"""
def __init__(self, gid, conn):
self.conn = conn
self.id = gid
self.info = {}
def set_info(self):
self.info = self.conn.groups.getById(group_id=int(self.id) * -1)[0]
def members(self, page_items=_SETTINGS_PAGE_ITEMS, page=1):
m = self.conn.groups.getMembers(group_id=self.id,
offset=((page_items * page) - page_items),
fields='first_name,last_name,photo_50,photo_100,photo_200',
count=page_items)
count = m['count']
pages = ceil(float(count) / float(page_items))
l = []
for i in m['items']:
member = User(i['id'], self.conn)
member.info = i
l.append(member)
return {'pages': pages, 'total': count, 'items': l}
# Благодарю автора статьи https://habrahabr.ru/post/193374/
def switch_view():
skin_used = xbmc.getSkinDir()
if skin_used == 'skin.confluence':
xbmc.executebuiltin('Container.SetViewMode(500)') # Вид "Эскизы".
elif skin_used == 'skin.aeon.nox':
xbmc.executebuiltin('Container.SetViewMode(512)') # Вид "Инфо-стена"
def get_search_history(h_file_name):
path = os.path.join(xbmc.translatePath('special://temp/'), h_file_name)
if not os.path.exists(path):
return []
with open(path, 'rb') as f:
history = pickle.load(f)
return history
def put_search_history(history, h_file_name):
path = os.path.join(xbmc.translatePath('special://temp/'), h_file_name)
with open(path, 'wb') as f:
pickle.dump(history, f, -1)
def media_entries(e_method, conn, oid, **kwargs):
page_items = kwargs.pop('page_items', _SETTINGS_PAGE_ITEMS)
page = kwargs.pop('page', 1)
album = kwargs.pop('album', None)
kwargs.update({
'offset': ((page_items * page) - page_items),
'count': page_items
})
if oid != _NO_OWNER:
kwargs['owner_id'] = oid
if album:
kwargs['album_id'] = album
try:
entries = getattr(conn, e_method)(**kwargs)
except VkAPIError as exc:
if exc.code == 15 or (200 <= exc.code < 300):
entries = {'count': 0, 'items': []}
else:
raise
2017-01-29 11:41:57 +03:00
count = entries['count']
pages = int(ceil(count / float(page_items)))
l = []
2017-01-29 11:41:57 +03:00
for i in entries['items']:
if e_method.split('.')[-1] in ['getAlbums', 'getUsers', 'getLinks']:
entry_id = str(i['id'])
else:
entry_id = str(i['owner_id']) + '_' + str(i['id'])
ent = Entry(e_method, entry_id, conn)
ent.info = i
l.append(ent)
del entries['count']
del entries['items']
res = {'pages': pages, 'total': count, 'items': l}
for k in list(entries.keys()):
res[k] = entries[k]
return res
2017-01-29 11:41:57 +03:00
class Entry(object):
def __init__(self, e_method, eid, conn):
self.method = e_method
2017-01-29 11:41:57 +03:00
self.id = eid
self.conn = conn
self.info = {}
def set_info(self):
if self.method == 'video.get':
self.info = self.conn.video.get(videos=self.id)['items'][0]
elif self.method == 'audio.get':
self.info = self.conn.audio.getById(audios=self.id)['items'][0]
elif self.method == 'photos.get':
self.info = self.conn.photos.getById(photos=self.id)['items'][0]
class User(object):
"""Этот класс описывает свойства и методы пользователя."""
def __init__(self, uid, conn):
self.conn = conn
self.id = uid
self.info = {}
def set_info(self):
self.info = self.conn.users.get(user_id=self.id, fields='first_name,last_name,photo_50,photo_100,photo_200')[0]
def friends(self, page_items=_SETTINGS_PAGE_ITEMS, page=1, order='hints'):
f = self.conn.friends.get(user_id=self.id,
offset=((page_items * page) - page_items),
count=page_items,
fields='first_name,last_name,photo_50,photo_100,photo_200',
order=order)
count = f['count']
pages = ceil(float(count) / float(page_items))
l = []
for i in f['items']:
u = User(i['id'], self.conn)
u.info = i
l.append(u)
return {'pages': pages, 'total': count, 'items': l}
def user_search(self, q='', page_items=_SETTINGS_PAGE_ITEMS, page=1):
usr = self.conn.users.search(q=q,
offset=((page_items * page) - page_items),
count=page_items,
fields='first_name,last_name,photo_50,photo_100,photo_200')
count = usr['count']
pages = ceil(float(count) / float(page_items))
l = []
for i in usr['items']:
u = User(i['id'], self.conn)
u.info = i
l.append(u)
return {'pages': pages, 'total': count, 'items': l}
def groups(self, page_items=_SETTINGS_PAGE_ITEMS, page=1):
gr = self.conn.groups.get(user_id=self.id,
offset=((page_items * page) - page_items),
count=page_items,
extended=1)
count = gr['count']
pages = ceil(float(count) / float(page_items))
l = []
for i in gr['items']:
if i['is_closed'] > 0 and i['is_member'] == 0: continue
g = Group(i['id'], self.conn)
g.info = i
l.append(g)
return {'pages': pages, 'total': count, 'items': l}
def group_search(self, q='', page_items=_SETTINGS_PAGE_ITEMS, page=1):
gr = self.conn.groups.search(q=q,
offset=((page_items * page) - page_items),
count=page_items)
count = gr['count']
pages = ceil(float(count) / float(page_items))
l = []
for i in gr['items']:
if i['is_closed'] > 0 and i['is_member'] == 0: continue
g = Group(i['id'], self.conn)
g.info = i
l.append(g)
return {'pages': pages, 'total': count, 'items': l}
class KodiVKGUIFave(object):
def __init__(self, root):
self.root = root
def m_main_fave(self):
if self.root.c_type == _CTYPE_VIDEO:
self.root.add_folder(self.root.gui.m_string(400502), {'do': _DO_FAVE_VIDEO, 'page': 1})
elif self.root.c_type == _CTYPE_IMAGE:
self.root.add_folder(self.root.gui.m_string(400504), {'do': _DO_FAVE_PHOTO, 'page': 1})
self.root.add_folder(self.root.gui.m_string(400513), {'do': _DO_FAVE_USERS, 'page': 1})
self.root.add_folder(self.root.gui.m_string(400506), {'do': _DO_FAVE_GROUPS, 'page': 1})
xbmcplugin.endOfDirectory(_addon_id)
def m_video(self):
page = int(self.root.params['page'])
kwargs = {'page': page, 'extended': 1}
vids = media_entries('fave.getVideos', self.root.conn, _NO_OWNER, **kwargs)
if page < vids['pages']:
params = {'do': _DO_FAVE_VIDEO, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
for v in vids['items']:
list_item = xbmcgui.ListItem(v.info['title'])
list_item.setInfo('video', {
'title': v.info['title'],
'duration': int(v.info['duration']),
'plot': v.info['description']
}
)
p_key = 'photo_%d' % (
max([int(x.split('_')[1]) for x in [x for x in list(v.info.keys()) if x.startswith('photo_')]]),)
list_item.setArt({'thumb': v.info['photo_130'], 'icon': v.info['photo_130'], 'fanart': v.info[p_key]})
list_item.setProperty('IsPlayable', 'true')
if 'files' in list(v.info.keys()):
if 'external' in v.info['files']:
v_source = self.root.gui.videos.m_get_video_source(v.info['files']['external'])
else:
v_source = _VK_VIDEO_SOURCE
else:
v_source = self.root.gui.videos.m_get_video_source(v.info['player'])
if v_source == _VK_VIDEO_SOURCE:
params = {'do': _DO_PLAY_VIDEO, 'vid': v.id, 'source': _VK_VIDEO_SOURCE}
url = self.root.url(**params)
elif v_source == _YOUTUBE_VIDEO_SOURCE:
if 'files' in list(v.info.keys()):
y_url = v.info['files']['external']
else:
y_url = v.info['player']
s = re.compile('^http.*youtube.*(v=|\/embed\/)([^\?\&]+)[\?\&]?.*$')
sr = s.findall(y_url)
if len(sr) < 0:
xbmc.log('WARN: Unknown youtube url: %s' % (y_url,))
continue
y_id = sr[0][1]
url = 'plugin://plugin.video.youtube/?action=play_video&videoid=' + y_id
else:
continue
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=False)
if page < vids['pages']:
params = {'do': _DO_FAVE_VIDEO, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
def m_photo(self):
page = int(self.root.params['page'])
kwargs = {'page': page}
photos = media_entries('photos.getAll', self.root.conn, _NO_OWNER, **kwargs)
if page < photos['pages']:
params = {'do': _DO_FAVE_PHOTO, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
for index in range(len(photos['items'])):
p = photos['items'][index]
num = (_SETTINGS_PAGE_ITEMS * page) + index + 1
list_item = xbmcgui.ListItem('%04d' % (num,))
p_info = {
'title': '%04d' % (num,),
'tagline': p.info['text']
}
if 'width' in list(p.info.keys()): p_info['exif:resolution'] = '%d,%d' % (p.info['width'], p.info['height'])
list_item.setInfo('pictures', p_info)
list_item.setArt({'thumb': p.info['photo_130'], 'icon': p.info['photo_75']})
r = [int(x.split('_')[1]) for x in [x for x in list(p.info.keys()) if x.startswith('photo_')]]
### Здесь надо подумать над настройкой
url_key = max(r)
url = p.info['photo_%d' % (url_key,)]
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=False)
if page < photos['pages']:
params = {'do': _DO_FAVE_PHOTO, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
switch_view()
def m_users(self):
page = int(self.root.params['page'])
users = media_entries('fave.getUsers', self.root.conn, _NO_OWNER, page=page)
if page < users['pages']:
params = {'do': _DO_FAVE_USERS, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
for u in users['items']:
list_item = xbmcgui.ListItem('%s %s' % (u.info['last_name'], u.info['first_name']))
# p_key = 'photo_%d' % (max(map(lambda x: int(x.split('_')[1]), filter(lambda x: x.startswith('photo_'), m.info.keys()))),)
# list_item.setArt({'thumb': m.info[p_key], 'icon': m.info[p_key]})
params = {'do': _DO_HOME, 'oid': u.id}
url = self.root.url(**params)
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=True)
if page < users['pages']:
params = {'do': _DO_FAVE_USERS, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
def m_groups(self):
page = int(self.root.params['page'])
links = media_entries('fave.getLinks', self.root.conn, _NO_OWNER, page=page)
if page < links['pages']:
params = {'do': _DO_FAVE_GROUPS, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
for l in links['items']:
l_id = l.info['id'].split('_')
if l_id[0] == '2':
list_item = xbmcgui.ListItem(l.info['title'])
p_key = 'photo_%d' % (
max([int(x.split('_')[1]) for x in [x for x in list(l.info.keys()) if x.startswith('photo_')]]),)
list_item.setArt({'thumb': l.info[p_key], 'icon': l.info[p_key]})
params = {'do': _DO_HOME, 'oid': -int(l_id[-1])}
url = self.root.url(**params)
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=True)
if page < links['pages']:
params = {'do': _DO_FAVE_GROUPS, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
class KodiVKGUIPhotos(object):
def __init__(self, root):
self.root = root
def m_main_photo(self):
oid = self.root.params['oid']
self.root.add_folder(self.root.gui.m_string(400508), {'do': _DO_PHOTO, 'oid': oid, 'page': 1})
self.root.add_folder(self.root.gui.m_string(400511), {'do': _DO_PHOTO_ALBUMS, 'oid': oid, 'page': 1})
xbmcplugin.endOfDirectory(_addon_id)
def m_photo_albums(self):
page = int(self.root.params['page'])
oid = self.root.params['oid']
kwargs = {'page': page, 'need_covers': 1, 'need_system': 1}
albums = media_entries('photos.getAlbums', self.root.conn, oid, **kwargs)
if page < albums['pages']:
params = {'do': _DO_PHOTO_ALBUMS, 'oid': oid, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
for a in albums['items']:
list_item = xbmcgui.ListItem(a.info['title'])
list_item.setInfo('pictures', {'title': a.info['title']})
list_item.setArt({'thumb': a.info['thumb_src'], 'icon': a.info['thumb_src']})
params = {'do': _DO_PHOTO, 'oid': oid, 'album': a.id, 'page': 1}
url = self.root.url(**params)
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=True)
if page < albums['pages']:
params = {'do': _DO_PHOTO_ALBUMS, 'oid': oid, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
switch_view()
def m_photo(self):
page = int(self.root.params['page'])
oid = self.root.params['oid']
album = self.root.params.get('album', None)
kwargs = {'page': page}
if album:
kwargs['album'] = album
photos = media_entries('photos.get', self.root.conn, oid, **kwargs)
else:
photos = media_entries('photos.getAll', self.root.conn, oid, **kwargs)
if page < photos['pages']:
params = {'do': _DO_PHOTO, 'oid': oid, 'page': page + 1}
if album: params['album'] = album
self.root.add_folder(self.root.gui.m_string(400602), params)
for index in range(len(photos['items'])):
p = photos['items'][index]
num = (_SETTINGS_PAGE_ITEMS * (page - 1)) + index + 1
list_item = xbmcgui.ListItem('%04d' % (num,))
p_info = {
'title': '%04d' % (num,),
'tagline': p.info['text']
}
if 'width' in list(p.info.keys()): p_info['exif:resolution'] = '%d,%d' % (p.info['width'], p.info['height'])
list_item.setInfo('pictures', p_info)
list_item.setArt({'thumb': p.info['photo_130'], 'icon': p.info['photo_75']})
r = [int(x.split('_')[1]) for x in [x for x in list(p.info.keys()) if x.startswith('photo_')]]
# Здесь надо подумать над настройкой
url_key = max(r)
url = p.info['photo_%d' % (url_key,)]
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=False)
if page < photos['pages']:
params = {'do': _DO_PHOTO, 'oid': oid, 'page': page + 1}
if album: params['album'] = album
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
switch_view()
class KodiVKGUIVideos(object):
def __init__(self, root):
self.root = root
def m_get_video_source(self, v_url):
is_vk_url_re = re.compile('https?\:\/\/[^\/]*vk.com\/.*')
is_youtube_url_re = re.compile('https\:\/\/www.youtube.com\/.*')
if len(is_vk_url_re.findall(v_url)) > 0: return _VK_VIDEO_SOURCE
if len(is_youtube_url_re.findall(v_url)) > 0: return _YOUTUBE_VIDEO_SOURCE
return _UNKNOWN_VIDEO_SOURCE
def m_main_video_search(self):
page = int(self.root.params['page'])
self.root.add_folder(self.root.gui.m_string(400516), {'do': _DO_VIDEO_SEARCH, 'q': 'none', 'page': 1})
history = get_search_history(_FILE_VIDEO_SEARCH_HISTORY)
count = len(history)
pages = int(ceil(count / float(_SETTINGS_PAGE_ITEMS)))
if page < pages:
params = {'do': _DO_MAIN_VIDEO_SEARCH, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
h_start = _SETTINGS_PAGE_ITEMS * (page - 1)
h_end = h_start + _SETTINGS_PAGE_ITEMS
history = history[h_start:h_end]
for h in history:
query_hex = binascii.hexlify(pickle.dumps(h, -1))
list_item = xbmcgui.ListItem(h)
params = {'do': _DO_VIDEO_SEARCH, 'q': query_hex, 'page': 1}
url = self.root.url(**params)
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=True)
if page < pages:
params = {'do': _DO_MAIN_VIDEO_SEARCH, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
def m_video_search(self):
page = int(self.root.params['page'])
q = self.root.params['q']
if q == 'none':
s_win = xbmc.Keyboard()
s_win.setHeading(self.root.gui.m_string(400515))
s_win.setHiddenInput(False)
s_win.doModal()
if s_win.isConfirmed():
q = s_win.getText()
else:
self.root.gui.notify(self.root.gui.m_string(400525), '')
return
else:
q = pickle.loads(binascii.unhexlify(q))
history = get_search_history(_FILE_VIDEO_SEARCH_HISTORY)
try:
del history[history.index(q)]
except ValueError:
pass
history = [q] + history
put_search_history(history, _FILE_VIDEO_SEARCH_HISTORY)
query_hex = binascii.hexlify(pickle.dumps(q, -1))
kwargs = {
'page': page,
'sort': _SETTINGS_VIDEO_SEARCH_SORT,
'hd': _SETTINGS_VIDEO_SEARCH_HD,
'adult': _SETTINGS_VIDEO_SEARCH_ADULT,
'q': q,
'extended': 1
}
search_res = media_entries('video.search', self.root.conn, _NO_OWNER, **kwargs)
if page < search_res['pages']:
params = {'do': _DO_VIDEO_SEARCH, 'q': query_hex, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
self.m__create_video_list_(search_res)
if page < search_res['pages']:
params = {'do': _DO_VIDEO_SEARCH, 'q': query_hex, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
def m_main_video(self):
oid = self.root.params['oid']
self.root.add_folder(self.root.gui.m_string(400509), {'do': _DO_VIDEO, 'oid': oid, 'page': 1})
self.root.add_folder(self.root.gui.m_string(400510), {'do': _DO_VIDEO_ALBUMS, 'oid': oid, 'page': 1})
if int(oid) == self.root.u.id:
self.root.add_folder(self.root.gui.m_string(400515), {'do': _DO_MAIN_VIDEO_SEARCH, 'page': 1})
xbmcplugin.endOfDirectory(_addon_id)
def m__create_video_list_(self, vids):
for v in vids['items']:
list_item = xbmcgui.ListItem(v.info['title'])
oid = v.info['owner_id']
if int(oid) < 0:
gid = oid * -1
g = [x for x in vids['groups'] if x['id'] == gid][0]
cm_title = '%s [I]%s[/I]' % (self.root.gui.m_string(400604), g['name'])
else:
u = [x for x in vids['profiles'] if x['id'] == oid][0]
cm_title = '%s [I]%s %s[/I]' % (self.root.gui.m_string(400603), u['last_name'], u['first_name'])
cm_params = {'do': _DO_HOME, 'oid': oid}
cm_url = self.root.url(**cm_params)
list_item.addContextMenuItems([(cm_title, 'xbmc.Container.update(%s)' % (cm_url,))])
list_item.setInfo('video', {
'title': v.info['title'],
'duration': int(v.info['duration']),
'plot': v.info['description']
}
)
p_key = 'photo_%d' % (max([int(x.split('_')[1]) for x in [x for x in list(v.info.keys()) if x.startswith('photo_')]]),)
2017-01-30 23:16:23 +03:00
list_item.setArt({'thumb': v.info['photo_130'], 'icon': v.info['photo_130'], 'fanart': v.info[p_key]})
list_item.setProperty('IsPlayable', 'true')
if 'files' in list(v.info.keys()):
if 'external' in v.info['files']:
v_source = self.m_get_video_source(v.info['files']['external'])
else:
v_source = _VK_VIDEO_SOURCE
else:
v_source = self.m_get_video_source(v.info['player'])
if v_source == _VK_VIDEO_SOURCE:
params = {'do': _DO_PLAY_VIDEO, 'vid': v.id, 'source': _VK_VIDEO_SOURCE}
url = self.root.url(**params)
2017-01-30 23:16:23 +03:00
elif v_source == _YOUTUBE_VIDEO_SOURCE:
if 'files' in list(v.info.keys()):
y_url = v.info['files']['external']
else:
y_url = v.info['player']
s = re.compile('^http.*youtube.*(v=|\/embed\/)([^\?\&]+)[\?\&]?.*$')
sr = s.findall(y_url)
if len(sr) < 0:
xbmc.log('WARN: Unknown youtube url: %s' % (y_url,))
continue
y_id = sr[0][1]
url = 'plugin://plugin.video.youtube/?action=play_video&videoid=' + y_id
else:
continue
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=False)
def m_video_albums(self):
page = int(self.root.params['page'])
oid = self.root.params['oid']
kwargs = {
'page': page,
'extended': 1
}
albums = media_entries('video.getAlbums', self.root.conn, oid, **kwargs)
if page < albums['pages']:
params = {'do': _DO_VIDEO_ALBUMS, 'oid': oid, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
for a in albums['items']:
list_item = xbmcgui.ListItem(a.info['title'])
list_item.setInfo('video', {'title': a.info['title']})
if 'photo_320' in list(a.info.keys()):
list_item.setArt(
{'thumb': a.info['photo_160'], 'icon': a.info['photo_160'], 'fanart': a.info['photo_320']})
params = {'do': _DO_VIDEO, 'oid': oid, 'album': a.id, 'page': 1}
url = self.root.url(**params)
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=True)
if page < albums['pages']:
params = {'do': _DO_VIDEO_ALBUMS, 'oid': oid, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
def m_video(self):
page = int(self.root.params['page'])
oid = self.root.params['oid']
album = self.root.params.get('album', None)
kwargs = {'page': page, 'extended': 1}
if album: kwargs['album'] = album
vids = media_entries('video.get', self.root.conn, oid, **kwargs)
if page < vids['pages']:
params = {'do': _DO_VIDEO, 'oid': oid, 'page': page + 1}
if album: params['album'] = album
self.root.add_folder(self.root.gui.m_string(400602), params)
self.m__create_video_list_(vids)
if page < vids['pages']:
params = {'do': _DO_VIDEO, 'oid': oid, 'page': page + 1}
if album: params['album'] = album
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
def m_play_video(self):
vid = self.root.params['vid']
src = self.root.params['source']
v = Entry('video.get', vid, self.root.conn)
try:
v.set_info()
except:
self.root.gui.notify(self.root.gui.m_string(400524), '')
return
if 'files' in list(v.info.keys()):
2017-01-29 11:41:57 +03:00
paths = {}
if src == _VK_VIDEO_SOURCE:
for k in list(v.info['files'].keys()):
if '_' not in k:
try:
local_idx = int(k)
except:
continue
else:
local_idx = int(k.split('_')[1])
paths[local_idx] = v.info['files'][k]
2017-01-29 11:41:57 +03:00
else:
v_url = v.info['player']
if src == _VK_VIDEO_SOURCE:
paths = self.root.parse_vk_player_html(v_url)
# Здесь должно браться разрешение из настроек
k = max([x for x in list(paths.keys()) if x <= _SETTINGS_MAX_RES])
path = paths[k]
play_item = xbmcgui.ListItem(path=path)
xbmcplugin.setResolvedUrl(_addon_id, True, listitem=play_item)
class KodiVkGUI:
"""Окошки, диалоги, сообщения"""
def __init__(self, root):
self.root = root
self.photos = KodiVKGUIPhotos(self.root)
self.videos = KodiVKGUIVideos(self.root)
self.faves = KodiVKGUIFave(self.root)
def notify(self, title, msg):
dialog = xbmcgui.Dialog()
dialog.notification(title, msg,
xbmcgui.NOTIFICATION_WARNING, 3000)
def m_string(self, string_id):
return _addon.getLocalizedString(string_id)
def m_login_form(self):
login_window = xbmc.Keyboard()
login_window.setHeading(self.m_string(400500))
login_window.setHiddenInput(False)
login_window.setDefault(_addon.getSetting(_USERNAME))
login_window.doModal()
if login_window.isConfirmed():
username = login_window.getText()
password_window = xbmc.Keyboard()
password_window.setHeading(self.m_string(400501))
password_window.setHiddenInput(True)
password_window.doModal()
if password_window.isConfirmed():
return username, password_window.getText()
else:
raise Exception("Password input was cancelled.")
else:
raise Exception("Login input was cancelled.")
def m_home(self):
c_type = self.root.params.get('content_type', None)
oid = self.root.params['oid']
if not c_type:
xbmc.log('No content_type')
return
if int(oid) < 0:
g = Group(oid, self.root.conn)
g.set_info()
header_string = '%s [I]%s[/I]' % (self.m_string(400604), g.info['name'])
p_key = 'photo_%d' % (
max([int(x.split('_')[1]) for x in [x for x in list(g.info.keys()) if x.startswith('photo_')]]),)
2017-01-30 23:16:23 +03:00
thumb_url = g.info[p_key]
icon_url = g.info[p_key]
else:
u = User(oid, self.root.conn)
u.set_info()
header_string = '%s [I]%s %s[/I]' % (self.m_string(400603), u.info['last_name'], u.info['first_name'])
p_key = 'photo_%d' % (max([int(x.split('_')[1]) for x in [x for x in list(u.info.keys()) if x.startswith('photo_')]]),)
2017-01-30 23:16:23 +03:00
thumb_url = u.info[p_key]
icon_url = u.info[p_key]
list_item = xbmcgui.ListItem(header_string)
list_item.setArt({'thumb': thumb_url, 'icon': icon_url})
h_url = self.root.url({'do': _DO_HOME, 'oid': oid})
xbmcplugin.addDirectoryItem(_addon_id, h_url, list_item, isFolder=True)
if c_type == _CTYPE_VIDEO:
self.root.add_folder(self.m_string(400502), {'do': _DO_MAIN_VIDEO, 'oid': oid})
# elif c_type == _CTYPE_AUDIO:
# self.root.add_folder(self._string(400503), {'do': _DO_MAIN_AUDIO, 'oid': oid})
elif c_type == _CTYPE_IMAGE:
self.root.add_folder(self.m_string(400504), {'do': _DO_MAIN_PHOTO, 'oid': oid})
else:
xbmc.log('Unknown content_type: %s' % (c_type,))
return
if int(oid) > 0:
self.root.add_folder(self.m_string(400505), {'do': _DO_FRIENDS, 'oid': oid, 'page': 1})
self.root.add_folder(self.m_string(400506), {'do': _DO_GROUPS, 'oid': oid, 'page': 1})
else:
self.root.add_folder(self.m_string(400512), {'do': _DO_MEMBERS, 'oid': -int(oid), 'page': 1})
if oid == self.root.u.id:
self.root.add_folder(self.m_string(400514), {'do': _DO_MAIN_FAVE})
xbmcplugin.addDirectoryItem(_addon_id, '', xbmcgui.ListItem(''), isFolder=False)
xbmcplugin.addDirectoryItem(_addon_id, '', xbmcgui.ListItem(''), isFolder=False)
xbmcplugin.addDirectoryItem(_addon_id, '', xbmcgui.ListItem(''), isFolder=False)
self.root.add_folder(self.m_string(400526), {'do': _DO_LOGOUT})
xbmcplugin.endOfDirectory(_addon_id)
def m__create_group_list_(self, groups):
for g in groups['items']:
list_item = xbmcgui.ListItem(g.info['name'])
p_key = 'photo_%d' % (
max([int(x.split('_')[1]) for x in [x for x in list(g.info.keys()) if x.startswith('photo_')]]),)
list_item.setArt({'thumb': g.info[p_key], 'icon': g.info[p_key]})
params = {'do': _DO_HOME, 'oid': -g.id}
url = self.root.url(**params)
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=True)
def m_groups(self):
oid = self.root.params['oid']
page = int(self.root.params['page'])
if int(oid) == self.root.u.id:
self.root.add_folder(self.root.gui.m_string(400515), {'do': _DO_MAIN_GROUP_SEARCH, 'page': 1})
user = User(oid, self.root.conn)
groups = user.groups(page=page)
if page < groups['pages']:
params = {'do': _DO_GROUPS, 'oid': oid, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
self.m__create_group_list_(groups)
if page < groups['pages']:
params = {'do': _DO_GROUPS, 'oid': oid, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
def m__create_user_list_(self, users):
for f in users['items']:
list_item = xbmcgui.ListItem('%s %s' % (f.info['last_name'], f.info['first_name']))
p_key = 'photo_%d' % (max([int(x.split('_')[1]) for x in [x for x in list(f.info.keys()) if x.startswith('photo_')]]),)
list_item.setArt({'thumb': f.info[p_key], 'icon': f.info[p_key]})
params = {'do': _DO_HOME, 'oid': f.id}
url = self.root.url(**params)
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=True)
def m_friends(self):
2017-01-30 23:16:23 +03:00
oid = self.root.params['oid']
page = int(self.root.params['page'])
if int(oid) == self.root.u.id:
self.root.add_folder(self.root.gui.m_string(400515), {'do': _DO_MAIN_USER_SEARCH, 'page': 1})
2017-01-30 23:16:23 +03:00
user = User(oid, self.root.conn)
friends = user.friends(page=page)
2017-01-30 23:16:23 +03:00
if page < friends['pages']:
params = {'do': _DO_FRIENDS, 'oid': oid, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
self.m__create_user_list_(friends)
2017-01-30 23:16:23 +03:00
if page < friends['pages']:
params = {'do': _DO_FRIENDS, 'oid': oid, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
2017-01-30 23:16:23 +03:00
xbmcplugin.endOfDirectory(_addon_id)
def m_members(self):
2017-01-30 23:16:23 +03:00
oid = self.root.params['oid']
page = int(self.root.params['page'])
group = Group(oid, self.root.conn)
members = group.members(page=page)
2017-01-30 23:16:23 +03:00
if page < members['pages']:
params = {'do': _DO_MEMBERS, 'oid': oid, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
2017-01-30 23:16:23 +03:00
for m in members['items']:
list_item = xbmcgui.ListItem('%s %s' % (m.info['last_name'], m.info['first_name']))
p_key = 'photo_%d' % (
max([int(x.split('_')[1]) for x in [x for x in list(m.info.keys()) if x.startswith('photo_')]]),)
2017-01-30 23:16:23 +03:00
list_item.setArt({'thumb': m.info[p_key], 'icon': m.info[p_key]})
params = {'do': _DO_HOME, 'oid': m.id}
url = self.root.url(**params)
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=True)
2017-01-30 23:16:23 +03:00
if page < members['pages']:
params = {'do': _DO_MEMBERS, 'oid': oid, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
2017-01-30 23:16:23 +03:00
xbmcplugin.endOfDirectory(_addon_id)
def m__create_user_group_search_page_(self, do_current, do_target, h_file):
page = int(self.root.params['page'])
self.root.add_folder(self.root.gui.m_string(400516), {'do': do_target, 'q': 'none', 'page': 1})
history = get_search_history(h_file)
count = len(history)
pages = int(ceil(count / float(_SETTINGS_PAGE_ITEMS)))
if page < pages:
params = {'do': do_current, 'page': page + 1}
self.root.add_folder(self.m_string(400602), params)
h_start = _SETTINGS_PAGE_ITEMS * (page - 1)
h_end = h_start + _SETTINGS_PAGE_ITEMS
history = history[h_start:h_end]
for h in history:
query_hex = binascii.hexlify(pickle.dumps(h, -1))
list_item = xbmcgui.ListItem(h)
params = {'do': do_target, 'q': query_hex, 'page': 1}
url = self.root.url(**params)
xbmcplugin.addDirectoryItem(_addon_id, url, list_item, isFolder=True)
if page < pages:
params = {'do': do_current, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
def m_main_group_search(self):
self.m__create_user_group_search_page_(_DO_MAIN_GROUP_SEARCH, _DO_GROUP_SEARCH, _FILE_GROUP_SEARCH_HISTORY)
def m_group_search(self):
page = int(self.root.params['page'])
q = self.root.params['q']
if q == 'none':
s_win = xbmc.Keyboard()
s_win.setHeading(self.m_string(400515))
s_win.setHiddenInput(False)
s_win.doModal()
if s_win.isConfirmed():
q = s_win.getText()
else:
self.notify(self.m_string(400525), '')
return
else:
q = pickle.loads(binascii.unhexlify(q))
history = get_search_history(_FILE_GROUP_SEARCH_HISTORY)
try:
del history[history.index(q)]
except ValueError:
pass
history = [q] + history
put_search_history(history, _FILE_GROUP_SEARCH_HISTORY)
query_hex = binascii.hexlify(pickle.dumps(q, -1))
kwargs = {
'page': page,
'q': q
}
u = User(self.root.u.id, self.root.conn)
search_res = u.group_search(**kwargs)
if page < search_res['pages']:
2018-05-24 20:40:56 +03:00
params = {'do': _DO_GROUP_SEARCH, 'q': query_hex, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
self.m__create_group_list_(search_res)
if page < search_res['pages']:
2018-05-24 20:40:56 +03:00
params = {'do': _DO_GROUP_SEARCH, 'q': query_hex, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
def m_main_user_search(self):
self.m__create_user_group_search_page_(_DO_MAIN_USER_SEARCH, _DO_USER_SEARCH, _FILE_USER_SEARCH_HISTORY)
def m_user_search(self):
page = int(self.root.params['page'])
q = self.root.params['q']
if q == 'none':
s_win = xbmc.Keyboard()
s_win.setHeading(self.root.gui.m_string(400515))
s_win.setHiddenInput(False)
s_win.doModal()
if s_win.isConfirmed():
q = s_win.getText()
else:
self.notify(self.m_string(400525), '')
return
else:
q = pickle.loads(binascii.unhexlify(q))
history = get_search_history(_FILE_USER_SEARCH_HISTORY)
try:
del history[history.index(q)]
except ValueError:
pass
history = [q] + history
put_search_history(history, _FILE_USER_SEARCH_HISTORY)
query_hex = binascii.hexlify(pickle.dumps(q, -1))
kwargs = {
'page': page,
'q': q
}
u = User(self.root.u.id, self.root.conn)
search_res = u.user_search(**kwargs)
if page < search_res['pages']:
2018-05-24 20:40:56 +03:00
params = {'do': _DO_USER_SEARCH, 'q': query_hex, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
self.m__create_user_list_(search_res)
if page < search_res['pages']:
2018-05-24 20:40:56 +03:00
params = {'do': _DO_USER_SEARCH, 'q': query_hex, 'page': page + 1}
self.root.add_folder(self.root.gui.m_string(400602), params)
xbmcplugin.endOfDirectory(_addon_id)
def m_logout(self):
dialog = xbmcgui.Dialog()
ret = dialog.yesno(self.m_string(400526), self.m_string(400527), nolabel=self.m_string(400529),
yeslabel=self.m_string(400528))
if ret:
_addon.setSetting(_SETTINGS_ID_TOKEN, '')
xbmc.executebuiltin("XBMC.Container.Update(path,replace)")
xbmc.executebuiltin("XBMC.ActivateWindow(Home)")
else:
return
class KodiVk:
conn = None
def __init__(self):
self.gui = KodiVkGUI(self)
self.conn = self.__connect_()
if not self.conn: raise Exception()
u_info = self.conn.users.get()[0]
self.u = User(u_info['id'], self.conn)
self.u.set_info()
p = {'do': _DO_HOME}
if sys.argv[2]:
p.update(dict(urllib.parse.parse_qsl(sys.argv[2][1:])))
p['oid'] = int(p.get('oid', self.u.info['id']))
self.params = p
if 'content_type' not in list(self.params.keys()):
cw_id = xbmcgui.getCurrentWindowId()
if cw_id in (10006, 10024, 10025, 10028):
2017-01-31 09:26:11 +03:00
self.params['content_type'] = _CTYPE_VIDEO
# elif id in (10005, 10500, 10501, 10502):
# self.params['content_type'] = _CTYPE_AUDIO
elif id in (10002,):
2017-01-31 09:26:11 +03:00
self.params['content_type'] = _CTYPE_IMAGE
self.c_type = self.params.get('content_type', None)
def url(self, params={}, **kwparams):
if self.c_type:
kwparams['content_type'] = self.c_type
params.update(kwparams)
return _addon_url + "?" + urlencode(params)
def add_folder(self, name, params):
url = self.url(**params)
item = xbmcgui.ListItem(name)
xbmcplugin.addDirectoryItem(_addon_id, url, item, isFolder=True)
def __connect_(self):
token = _addon.getSetting(_SETTINGS_ID_TOKEN)
conn = Connection(_APP_ID, access_token=token)
try:
tmp__ = conn.users.get()[0]
except vk.exceptions.VkAPIError as e:
if e.code == 5:
2018-05-24 20:40:56 +03:00
token = None
else:
raise
if token in [None, '']:
token = None
count = _LOGIN_RETRY
while token in [None, ''] and count > 0:
count -= 1
try:
login, password = self.gui.m_login_form()
except:
self.gui.notify(self.gui.m_string(400525), '')
try:
token = auth(login, password, _APP_ID, _APP_SEC, _SCOPE,"0")
if token == '-1':
code = self.m_ask_code()
token = auth(login, password, _APP_ID, _APP_SEC, _SCOPE, code)
if token not in (None, ''):
_addon.setSetting(_SETTINGS_ID_TOKEN, token)
conn = Connection(_APP_ID, login, password, scope=_SCOPE)
else:
raise vk.api.VkAuthError
except vk.api.VkAuthError:
continue
if token in [None, '']:
return
return conn
def m_ask_code(self):
code_keyboard = xbmc.Keyboard()
code_keyboard.setHeading(self.gui.m_string(400700))
code_keyboard.setHiddenInput(False)
code_keyboard.doModal()
if code_keyboard.isConfirmed():
return code_keyboard.getText()
else:
raise Exception("2FA Code input was cancelled")
def parse_vk_player_html(self, v_url):
p = re.compile('"url(\d+)":"([^"]+)"')
headers = {'User-Agent': 'Kodi-vk/%s (linux gnu)' % (_VERSION,)}
req = urllib.request.Request(v_url, None, headers)
http_res = urllib.request.urlopen(req)
if http_res.code != 200:
return None
html = http_res.read()
re_res = p.findall(html)
if len(re_res) < 1:
return None
res = {}
for tup in re_res:
res[int(tup[0])] = tup[1].replace('\\', '')
return res
# взято с https://github.com/VkKodi/vkkodi/blob/master/xbmc-vk.svoka.com/vk_auth.py
def auth(email, password, client_id, secret,scope,code):
if code == "0":
try:
url = urlopen("https://oauth.vk.com/token?" + urlencode({
"grant_type": "password",
"client_id": client_id,
"client_secret": secret,
"username": email,
"password": password,
"scope": scope,
"2fa_supported": "1"
}))
out = json.load(url)
except IOError as e:
xbmc.log(e.message)
xbmc.log("===VK 2FA Code requested===")
return "-1"
else:
url = urlopen("https://oauth.vk.com/token?" + urlencode({
"grant_type": "password",
"client_id": client_id,
"client_secret": secret,
"username": email,
"password": password,
"scope": scope,
"2fa_supported": "1",
"code": code
}))
out = json.load(url)
if "access_token" not in out:
xbmc.log(f'kodi-vk auth: {out}')
return out["access_token"]
if __name__ == '__main__':
try:
kvk = KodiVk()
except Exception as e:
import traceback
xbmc.log(traceback.format_exc())
sys.exit()
_DO = {
_DO_HOME: kvk.gui.m_home,
_DO_MAIN_PHOTO: kvk.gui.photos.m_main_photo,
_DO_PHOTO: kvk.gui.photos.m_photo,
_DO_PHOTO_ALBUMS: kvk.gui.photos.m_photo_albums,
_DO_MAIN_VIDEO: kvk.gui.videos.m_main_video,
_DO_VIDEO: kvk.gui.videos.m_video,
_DO_VIDEO_ALBUMS: kvk.gui.videos.m_video_albums,
_DO_PLAY_VIDEO: kvk.gui.videos.m_play_video,
_DO_MAIN_VIDEO_SEARCH: kvk.gui.videos.m_main_video_search,
_DO_VIDEO_SEARCH: kvk.gui.videos.m_video_search,
_DO_GROUPS: kvk.gui.m_groups,
_DO_MAIN_GROUP_SEARCH: kvk.gui.m_main_group_search,
_DO_GROUP_SEARCH: kvk.gui.m_group_search,
_DO_FRIENDS: kvk.gui.m_friends,
_DO_MAIN_USER_SEARCH: kvk.gui.m_main_user_search,
_DO_USER_SEARCH: kvk.gui.m_user_search,
_DO_MEMBERS: kvk.gui.m_members,
_DO_MAIN_FAVE: kvk.gui.faves.m_main_fave,
_DO_FAVE_VIDEO: kvk.gui.faves.m_video,
_DO_FAVE_PHOTO: kvk.gui.faves.m_photo,
_DO_FAVE_USERS: kvk.gui.faves.m_users,
_DO_FAVE_GROUPS: kvk.gui.faves.m_groups,
_DO_LOGOUT: kvk.gui.m_logout
}
2018-05-24 20:40:56 +03:00
_do_method = kvk.params['do']
if _do_method in list(_DO.keys()):
_DO[_do_method]()