def search_history(): """ Show search history. """ listing = views.list_search_history(plugin) __log__('search_history; listing', listing) return plugin.finish(listing, view_mode=50)
def search_category(path=''): """ Perform search in an ex.ua category or via Google.com. """ listing = [] keyboard = xbmc.Keyboard('', u'Поисковый запрос') keyboard.doModal() search_text = keyboard.getText() if search_text and keyboard.isConfirmed(): if path: search_path = '/search?s={0}&original_id={1}'.format(urllib.quote_plus(search_text), SEARCH_CATEGORIES[path]) else: if plugin.addon.getSetting('use_google') == 'false': search_path = '/search?s={0}'.format(urllib.quote_plus(search_text)) else: search_path = 'http://www.google.com.ua/search?q=site%3Aex.ua+{0}'.format(urllib.quote_plus(search_text)) __log__('search_category; search_path', search_path) if plugin.addon.getSetting('cache_pages') == 'true': videos = get_videos(search_path, page=0, pages=plugin.addon.getSetting('itemcount')) else: videos = exua_parser.get_videos(search_path, page=0, pages=plugin.addon.getSetting('itemcount')) listing = views.list_videos(plugin, videos, search_path) if listing and plugin.addon.getSetting('savesearch') == 'true': storage['search_history'].insert(0, {'text': search_text, 'query': search_path}) if len(storage['search_history']) > int(plugin.addon.getSetting('historylength')): storage['search_history'].pop(-1) elif not listing: xbmcgui.Dialog().ok(u'Ничего не найдено!', u'Уточните поисковый запрос и повторите попытку.') __log__('search_category; listing', listing) return listing
def search_history(): """ Show search history. """ listing = views.list_search_history(plugin) __log__('search_history; listing', listing) return listing
def display_path(path): """ Display path depending on its contents: video item, video list or categories. """ __log__('display_path; path', path) if plugin.addon.getSetting('cache_pages') == 'true': page_type, contents = check_page(path) else: page_type, contents = exua_parser.check_page(path) view_mode = None if page_type == 'video_page': listing = views.list_video_details(plugin, contents) if plugin.addon.getSetting('use_skin_info') == 'true': # Switch view based on a current skin. current_skin = xbmc.getSkinDir() if current_skin in ('skin.confluence', 'skin.confluence-plood', 'skin.confluence-plood-gotham'): view_mode = 503 elif current_skin in ('skin.aeon.nox', 'skin.aeon.nox.gotham', 'skin.aeon.shednox.helix'): view_mode = 52 elif current_skin == 'skin.aeon.nox.5': view_mode = 55 elif page_type == 'video_list': listing = views.list_videos(plugin, contents, path=path) elif page_type == 'categories': listing = views.list_categories(plugin, contents) else: listing = [] __log__('display_path; listing', listing) return plugin.finish(listing, view_mode=view_mode)
def list_categories(plugin, categories): """ Create a list of video categories form ex.ua """ listing = [] for category in categories: item = {'label': u'{0} [{1}]'.format(category['name'], category['items#']), 'path': plugin.url_for('video_articles', mode='list', path=category['path'], page_No='0'), 'thumbnail': os.path.join(icons, 'video.png')} listing.append(item) if addon.getSetting('use_google') == 'false': search_label = u'[Поиск…]' search_icon = os.path.join(icons, 'search.png') else: search_label = u'[Поиск Google…]' search_icon = os.path.join(icons, 'google.png') listing.append({'label': search_label, 'path': plugin.url_for('global_search'), 'thumbnail': search_icon}) if plugin.addon.getSetting('savesearch') == 'true': listing.append({'label': u'[История поиска]', 'path': plugin.url_for('search_history'), 'thumbnail': os.path.join(icons, 'search.png')}) if plugin.addon.getSetting('authorization') == 'true': if loader.is_logged_in(): label = u'[Мои запомненные]' thumbnail = os.path.join(icons, 'bookmarks.png') else: label = u'[Войти на ex.ua]' thumbnail = os.path.join(icons, 'key.png') listing.append({'label': label, 'path': plugin.url_for('bookmarks'), 'thumbnail': thumbnail}) __log__('categories; listing', listing) return listing
def google_search(url): """ Search ex.ua videos on Google.com :param url: :return: """ __log__('exua_parser.google_search; url', url) videos = [] opener = Opener(host='www.google.com.ua', language='uk-ua') try: session = opener.open(url) except urllib2.URLError: page = '' else: page = session.read().decode('utf-8') session.close() soup = BeautifulSoup(page) results = soup.find_all('a', {'href': re.compile('^' + SITE)}) for result in results: videos.append({'thumb': google_icon, 'path': result['href'].replace(SITE, ''), 'title': result.get_text()}) prev = next_ = '' prev_tag = soup.find('span', text=u'Назад') if prev_tag is not None: prev = '<' next_tag = soup.find('span', text=u'Уперед') if next_tag is not None: next_ = '>' return {'videos': videos, 'prev': prev, 'next': next_}
def get_page(self, url, data=None): """ Load a web-page with a given url. """ self.cookie_jar.load() __log__('WebLoader.get_page; cookies', self.get_cookies()) web_page = self.opener.get_page(url, data) self.cookie_jar.save() return web_page
def get_page(self, url, data=None): try: session = self.opener.open(url, data) except (urllib2.URLError, socket.timeout) as ex: __log__('webloader.Opener.get_page. Connection error', ex) web_page = '' else: web_page = session.read().decode('utf-8', 'replace') session.close() return web_page
def get_direct_link(self, url): """Get direct link to a video file""" try: sesion = self.opener.open(url) except (urllib2.URLError, socket.timeout) as ex: __log__('webloader.WebLoader.get_girect_link. Connection error', ex) resolved_url = '' else: resolved_url = sesion.geturl() sesion.close() return resolved_url
def get_categories(): """ Get the list of video categories. Return the list of caterory properies: name url items# (items count) """ web_page = loader.get_page('http://www.ex.ua/ru/video?per=24') __log__('exua_parser.get_categories; web_page', web_page) return parse_categories(web_page)
def search_history(): """ Show search history. """ listing = [] for item in storage.get('search_history'): listing.append({'label': item['text'], 'path': plugin.url_for('video_articles', path=item['query'], page_No='0'), 'thumbnail': os.path.join(icons, 'search.png')}) __log__('search_history; listing', listing) return plugin.finish(listing, view_mode=50)
def check_captcha(self): """ Check if there is a captcha on a loging page. Returns a dictionary with 'captcha_id' and 'captcha_file' keys. """ web_page = self.get_page(LOGIN_URL) captcha = {'captcha_id': '', 'captcha_file': ''} captcha_group = re.search('<img src=\'/captcha\?captcha_id=(.+?)\'', web_page, re.UNICODE) if captcha_group is not None: captcha_id = captcha_group.group(1) captcha = {'captcha_id': captcha_id, 'captcha_file': 'http://www.ex.ua/captcha?captcha_id=' + captcha_id} __log__('WebLoader.check_captcha; captcha', captcha) return captcha
def parse_videos(web_page): """ Parse a list of videos. Return the dictionary: videos: the list of videos, each item is a dict of the following properties: thumb path title prev: numbers of previous pages, if any. next: numbers of next pages, if any. """ soup = BeautifulSoup(web_page) videos = [] content_table = soup.find('table', cellspacing='8') if content_table is not None: content_cells = content_table.find_all('td') for content_cell in content_cells: try: link_tag = content_cell.find('a') path = link_tag['href'] image_tag = content_cell.find('img') if image_tag is not None: thumb = image_tag['src'][:-3] + IMG_QUALITY title = image_tag['alt'] else: thumb = '' title = link_tag.text except TypeError: continue else: videos.append({'thumb': thumb, 'path': path, 'title': title}) nav_table = soup.find('table', cellpadding='5') if nav_table is not None: prev_tag = nav_table.find('img', alt=re.compile(u'предыдущую', re.UNICODE)) if prev_tag is not None: prev_page = prev_tag.find_previous('a', text=re.compile(u'\.\.')).text else: prev_page = '' next_tag = nav_table.find('img', alt=re.compile(u'следующую', re.UNICODE)) if next_tag is not None: next_page = next_tag.find_next('a', text=re.compile(u'\.\.')).text else: next_page = '' else: prev_page = next_page = '' else: prev_page = next_page = [] result = {'videos': videos, 'prev': prev_page, 'next': next_page} __log__('exua_parser.parse_videos; result', result) return result
def parse_categories(web_page): """ Parse categories page. Return the list of caterory properies: name url items# (items count) """ parse = re.findall('<b>(.*?)</b></a><p><a href=\'(.*?)\' class=info>(.*?)</a>', web_page, re.UNICODE) categories = [] for item in parse: categories.append({'name': item[0], 'path': item[1], 'items#': item[2]}) __log__('exua_parser.get_categories; categories', categories) return categories
def video_articles(path, page_No='0'): """ Show video articles. """ __log__('video_articles; path', path) page = int(page_No) pages = plugin.addon.getSetting('itemcount') if plugin.addon.getSetting('cache_pages') == 'true': videos = get_videos(path, page, pages) else: videos = exua_parser.get_videos(path, page=page, pages=pages) listing = views.list_videos(plugin, videos, path, page) __log__('video_articles; listing', listing) return plugin.finish(listing, view_mode=50)
def get_page(self, url, data=None): """ Load a web-page with a given url. """ self.cookie_jar.load() __log__('WebLoader.get_page; cookies', self.get_cookies()) try: session = self.opener.open(url, data) except urllib2.URLError: web_page = '' else: self.cookie_jar.save() web_page = session.read().decode('utf-8') session.close() return web_page
def check_captcha(self): """ Check if there is a captcha on a loging page. Returns a dictionary with 'captcha_id' and 'captcha_file' keys. """ web_page = self.get_page(LOGIN_URL) captcha = {'captcha_id': '', 'captcha_file': ''} captcha_group = re.search('<img src=\'/captcha\?captcha_id=(.+?)\'', web_page, re.UNICODE) if captcha_group is not None: captcha_id = captcha_group.group(1) captcha_file = os.path.join(_cookie_dir, 'captcha.png') os.remove(captcha_file) urllib.urlretrieve('http://www.ex.ua/captcha?captcha_id=' + captcha_id, captcha_file) captcha = {'captcha_id': captcha_id, 'captcha_file': captcha_file} __log__('WebLoader.check_captcha; captcha', captcha) return captcha
def get_video_details(path): """ Get video details. Return a dictionary with the following properties: title thumb videos [the list of dicts with pairs of 'filename': 'path'] flvs [the list of LQ .flv videos, if any] year genre director duration plot """ web_page = loader.get_page(SITE + path) __log__('exua_parser.get_video_details; web_page', web_page) return parse_video_details(web_page)
def video_articles(path, page_No='0'): """ Show video articles. """ __log__('video_articles; path', path) page = int(page_No) pages = get_items_per_page() if plugin.addon.getSetting('cache_pages') == 'true': videos = get_videos(path, page, pages) else: videos = exua_parser.get_videos(path, page=page, pages=pages) listing = list_videos(videos, path, page) # if page_No != '0': # listing.insert(0, {'label': u'<< Главная', # 'path': plugin.url_for('categories'), # 'thumbnail': os.path.join(icons, 'home.png')}) __log__('video_articles; listing', listing) return plugin.finish(listing, view_mode=50)
def bookmarks(): """ Login to display ex.ua bookmarks :return: None """ successful_login = False listing = [] if not loader.is_logged_in(): username = plugin.addon.getSetting('username') password = webloader.decode(plugin.addon.getSetting('password')) captcha = loader.check_captcha() login_dialog = login_window.LoginWindow(username, password, captcha['captcha_file']) if not login_dialog.login_cancelled: successful_login = loader.login(login_dialog.username, login_dialog.password, captcha_text=login_dialog.captcha_text, captcha_id=captcha['captcha_id']) if successful_login: plugin.addon.setSetting('username', login_dialog.username) if plugin.addon.getSetting('save_pass') == 'true': plugin.addon.setSetting('password', webloader.encode(login_dialog.password)) else: plugin.addon.setSetting('password', '') else: xbmcgui.Dialog().ok(u'Ошибка входа!', u'Проверьте логин и пароль, а затем повторите попытку.') del login_dialog __log__('bookmarks; is_logged_in', loader.is_logged_in()) __log__('bookmarks; successful_login', successful_login) if loader.is_logged_in() or successful_login: listing += views.list_videos(plugin, exua_parser.get_videos('/buffer', loader)) __log__('bookmarks; listing', listing) return listing
def play_video(path, mirrors='', flv=''): """ Play video. """ if mirrors and flv: if plugin.addon.getSetting('choose_mirrors') == '1': if mirrors != 'none': mirrors_list = urlparse.parse_qsl(mirrors) menu_items = [u'Зеркало {0}'.format(item[0]) for item in mirrors_list] urls = [item[1] for item in mirrors_list] else: urls = [] menu_items = [] urls.insert(0, path) menu_items.insert(0, u'Оригинальное видео') if flv != 'none': urls.append(flv) menu_items.append(u'Облегченное видео (FLV)') index = xbmcgui.Dialog().select(u'Выберите видео', menu_items) if index >= 0: path = urls[index] else: return None elif plugin.addon.getSetting('choose_mirrors') == '2': path = flv if plugin.addon.getSetting('authorization') == 'true' and loader.is_logged_in(): cookies = '|Cookie=' + urllib.urlencode(loader.get_cookies()) else: cookies = '' if path[0] == '/': path = 'http://www.ex.ua' + path if plugin.addon.getSetting('direct_link') == 'true': path = loader.get_direct_link(path) if not path: xbmc.executebuiltin(u'Notification(Ошибка!,Ссылка недоступна)'.encode('utf-8')) return None __log__('play_video; path', path) __log__('play_video; cookies', cookies) plugin.set_resolved_url(path + cookies)
def google_search(url): """ Search ex.ua videos on Google.com :param url: str :return: dict """ __log__('exua_parser.google_search; url', url) videos = [] opener = Opener(host='www.google.com.ua', language='uk-ua') soup = BeautifulSoup(opener.get_page(url)) results = soup.find_all('a', {'href': re.compile('^' + SITE)}) for result in results: videos.append({'thumb': google_icon, 'path': result['href'].replace(SITE, ''), 'title': result.get_text()}) prev = next_ = '' prev_tag = soup.find('span', text=u'Назад') if prev_tag is not None: prev = '<' next_tag = soup.find('span', text=u'Уперед') if next_tag is not None: next_ = '>' return {'videos': videos, 'prev': prev, 'next': next_}
def get_videos(path, page_loader=loader, page=0, pages='25'): """ Get the list of videos from categories. Return the dictionary: videos: the list of videos, each item is a dict of the following properties: thumb path title prev: numbers of previous pages, if any. next: numbers of next pages, if any. """ if 'www.google.com.ua' in path: start = '' if page > 0: start = '&start={0}'.format(10 * page) url = path + start results = google_search(url) else: if page > 0: if '?r=' in path or '?s=' in path: p = '&p=' else: p = '?p=' pageNo = p + str(page) else: pageNo = '' if path != '/buffer': page_count = '&per={0}'.format(pages) else: page_count = '' url = SITE + path + pageNo + page_count web_page = page_loader.get_page(url) __log__('exua_parser.get_videos; web_page', web_page) results = parse_videos(web_page) __log__('exua_parser.get_videos; url', url) return results
def check_page(path): """ Check page type by common patterns. Return page type and its parsed contents depending on the type. """ page_type = 'unknown' contents = None __log__('exua_parser.check_page; path', path) web_page = loader.get_page(SITE + path) __log__('exua_parser.check_page; page', web_page) if re.search(u'Файлы:', web_page, re.UNICODE) is not None: page_type = 'video_page' contents = parse_video_details(web_page) elif re.search(u'Видео на других языках', web_page, re.UNICODE) is not None: page_type = 'categories' contents = parse_categories(web_page) elif re.search('<table width=100%.+?cellspacing=8', web_page, re.UNICODE) is not None: page_type = 'video_list' contents = parse_videos(web_page) __log__('exua_parser.check_page; page_type', page_type) __log__('exua_parser.check_page; contents', contents) return page_type, contents
def parse_video_details(web_page): """ Parse video details page. Return a dictionary with the following properties: title thumb videos [the list of dicts with pairs of 'filename': 'url'] flvs [the list of LQ .flv videos, if any] year genre director duration plot """ details = {'videos': []} soup = BeautifulSoup(web_page) if u'Артисты @ EX.UA' in soup.find('title').text: details['title'] = soup.find('meta', {'name': 'title'})['content'] details['plot'] = soup.find('div', id="content_page").get_text(' ', strip=True) details['thumb'] = soup.find('link', rel='image_src')['href'][:-3] + IMG_QUALITY video_path = re.search('playlist: \[ \"(.*?)\" \]', soup.find('script', {'type': 'text/javascript'}, text=re.compile('playlist')).text).group(1) details['videos'].append({'filename': 'Video', 'path': video_path, 'mirrors': []}) details['year'] = details['genre'] = details['director'] = details['duration'] = details['cast'] = '' details['flvs'] = [] details['rating'] = '' else: details['title'] = soup.find('h1').text thumb_tag = soup.find('link', rel='image_src') if thumb_tag is not None: details['thumb'] = thumb_tag['href'][:-3] + IMG_QUALITY else: details['thumb'] = '' video_tags = soup.find_all('a', title=re.compile('(.*\.(?:{0})(?!.))'.format(MEDIA_EXTENSIONS))) for video_tag in video_tags: mirror_tags = video_tag.find_next('td', {'class': 'small'}).find_all('a', {'rel': 'nofollow', 'title': True}) mirrors = [] if mirror_tags: for mirror_tag in mirror_tags: mirrors.append((mirror_tag.text, mirror_tag['href'])) details['videos'].append({'filename': video_tag.text, 'path': video_tag['href'], 'mirrors': mirrors}) flvs = re.compile('player_list = \'(.*)\';') var_player_list = soup.find('script', text=flvs) if var_player_list is not None: details['flvs'] = [] for flv_item in ast.literal_eval('[' + re.search(flvs, var_player_list.text).group(1) + ']'): details['flvs'].append(flv_item['url']) else: details['flvs'] = '' for detail in VIDEO_DETAILS.keys(): search_detail = soup.find(text=re.compile(VIDEO_DETAILS[detail][0], re.UNICODE)) if search_detail is not None: detail_text = re.search(VIDEO_DETAILS[detail][1], search_detail, re.UNICODE) if detail_text is not None: text = detail_text.group(1) if detail_text is None or len(text) <= 3: while True: next_ = search_detail.find_next(text=True) try: text_group = re.search(VIDEO_DETAILS[detail][2], next_, re.UNICODE) except TypeError: text = '' break if text_group is not None: text = text_group.group(0) else: text = '' if len(text) > 2: break else: search_detail = next_ else: text = '' details[detail] = text.replace(': ', '') if not details['plot']: prev_tag = soup.find('span', {'class': 'modify_time'}) if prev_tag is not None: text = '' while True: next_tag = prev_tag.find_next() if next_tag.name == 'span': break else: try: text += next_tag.get_text('\n', strip=True) prev_tag = next_tag except AttributeError: break details['plot'] = text.replace(u'смотреть онлайн', '') __log__('exua_parser.get_videos; parse_video_details', details) return details