# coding=utf-8 import xbmc import xbmcgui try: import simplejson as json except: import json from define import * from dt import ru_strftime from datetime import datetime import time from urllib2 import HTTPError from framework import gui from etvnet.api import eTV __xbmc_full_version__ = xbmc.getInfoLabel("System.BuildVersion") __xbmc_main_relise_version__ = __xbmc_full_version__[:2] class Thinker(object): config = gui.Settings() def __init__(self, files): if __xbmc_main_relise_version__ == '12': self.possible_files = [ {"bitrate": 250, "format": "wmv"}, {"bitrate": 400, "format": "mp4"}, {"bitrate": 600, "format": "wmv"}, {"bitrate": 800, "format": "mp4"}, {"bitrate": 1200, "format": "wmv"}, {"bitrate": 1200, "format": "mp4"}, ] else: self.possible_files = [ {"bitrate": 400, "format": "mp4"}, {"bitrate": 250, "format": "wmv"}, {"bitrate": 800, "format": "mp4"}, {"bitrate": 600, "format": "wmv"}, {"bitrate": 1200, "format": "mp4"}, {"bitrate": 1200, "format": "wmv"}, ] q = self.config.GetValue('quality') if not q: self.quality = 2 else: self.quality = int(q) self.files = files def get_shift(self): # shift can be 0, 2 or 4\ return (self.quality * 2) - 2 def choose_file(self): shift = self.get_shift() # loop to go through all the item in self.possible_files for spin in range(len(self.possible_files)): # here we choose needed index index = (shift + spin) % (len(self.possible_files)) # here we get item to match with files list: needed_file = self.possible_files[index] # if we found needed lets bracke loop if needed_file in self.files: break # but we dont need to go in start of possible_files list if we started from high quality # instead we need to go backward. So in that case we replace midium and low quality. elif needed_file not in self.files and index == len(self.possible_files) - 1 and self.quality is 3: self.chage_order_in_files_list() return needed_file def chage_order_in_files_list(self): self.possible_files.insert(0, self.possible_files.pop(2)) self.possible_files.insert(1, self.possible_files.pop(3)) def decide(self): fl = self.choose_file() protocol = None if fl['format'] == 'mp4' and __xbmc_main_relise_version__ == '12': protocol = 'hls' elif int(__xbmc_main_relise_version__) >= 13: protocol = 'hls' return fl['format'], fl['bitrate'], protocol class VoteWindow(gui.XMLWindow): xml = 'vote.xml' def onInit(self, params=None): self.media_id = self.params['media_id'] self.details_window = self.params['details_window'] self.curent_mark = None @gui.onclick(9031) def set_mark_1(self): self.set_mark(1) @gui.onclick(9032) def set_mark_2(self): self.set_mark(2) @gui.onclick(9033) def set_mark_3(self): self.set_mark(3) @gui.onclick(9034) def set_mark_4(self): self.set_mark(4) @gui.onclick(9035) def set_mark_5(self): self.set_mark(5) def set_mark(self, mark): resp = self.details_window.etv.setMark(self.media_id, mark * 2) self.details_window.data['mark'] = resp['data'] self.close() class MediaDetails(gui.XMLWindow): xml = 'details.xml' def onInit(self, params=None): self.is_loaded = self.define_loaded() self.shut_up_player() self.image = 'image' self.genre = 'Genre, Rubric, Category' if not self.is_loaded: self.data = self.params['data'] self.etv = eTV(access_token=self.config.GetValue('access_token')) self.show_breadcrumbs(self.params['breadcrumbs']) self.show(onexit=self.is_loaded) def define_loaded(self): if hasattr(self, 'is_loaded'): return True return False def shut_up_player(self): player = xbmc.Player(xbmc.PLAYER_CORE_DVDPLAYER) if player.isPlaying(): player.stop() def isInBookmarks(self): try: resp = self.etv.getBookmarkById(self.data['id']) except HTTPError: return False if resp == 404: return False return True def show_breadcrumbs(self, breadcrumbs): self.getControl(9090).setLabel(breadcrumbs) @gui.in_thread def show_bookmark_button(self): if self.isInBookmarks(): self.manager.show(9119) self.manager.hide(9118) else: self.manager.show(9118) self.manager.hide(9119) def show(self, onexit=None): self.show_bookmark_button() self.show_image() self.show_description() self.show_name() self.show_stars() self.show_info_panel() def show_stars(self): stars_image_path = 'stars/%d_big.png' % self.data['mark']['total'] self.getControl(9116).setImage(stars_image_path) def show_image(self): self.getControl(9114).setImage(self.data['thumb'].encode('utf-8')) def show_name(self): self.getControl(9111).setLabel(self.data['name'].encode('utf-8')) def show_description(self): xbmc.executebuiltin('Skin.SetString(9112,"' + self.data['description'].encode('utf-8') + '")') def show_rating(self): label = "Рейтинг: " + str(self.data['rating']) self.getControl(9131).setLabel(label) def show_duration(self): label = str(self.data['duration']) + ' мин.' self.getControl(9132).setLabel(label) def show_on_air(self): dt = datetime(*time.strptime(self.data['on_air'], '%Y-%m-%d %H:%M:%S')[:6]) label = ru_strftime(format=u"%d %b %Y %H:%M", date=dt) self.getControl(9133).setLabel(label) def show_channel(self): label = self.data['channel']['name'].encode('utf-8') self.getControl(9134).setLabel(label) def show_info_panel(self): self.show_channel() self.show_on_air() self.show_duration() self.show_rating() def isH264(self): files = self.data['files'] if isinstance(files, dict): return for item in files: if item['format'] in 'mp4': return True return False def isContainer(self): if self.data['type'] in 'Container': return True return False @gui.onclick(9115) def playItem(self, preview=False): self.Play_RTMP_or_WMV(preview=preview) @gui.onclick(9117) def playFreeItem(self, preview=True): self.Play_RTMP_or_WMV(preview=preview) @gui.onclick(9120) def playOtherServer(self, preview=True): self.Play_RTMP_or_WMV(other_server=1) @gui.with_progress def Play_RTMP_or_WMV(self, preview=False, other_server=None): id = self.data['id'] is_h264 = self.isH264() format = ('wmv', 'mp4')[is_h264 is True] bitrate = ('600', '800')[is_h264 is True] thinker = Thinker(self.data['files']) if self.params['main_window'].quality: thinker.quality = self.params['main_window'].quality format, bitrate, protocol = thinker.decide() path = self.etv.get_xbmc_url(media_id=int(id), format=format, bitrate=bitrate, preview=preview, other_server=other_server, protocol=protocol).encode('utf-8') # make playlist item to show metadata in player listitem = xbmcgui.ListItem(self.data['name'], '', self.data['thumb'], self.data['thumb']) # play item self.playUrlInXBMC(path, listitem) @gui.onclick(9128) def close_window(self): self.close() def playUrlInXBMC(self, url, listitem): xbmc.Player(xbmc.PLAYER_CORE_AUTO).play(url, listitem) @gui.onclick(9118) def addToBookmarks(self): r = self.etv.addToBookmarks(self.data['id']) if r == {"status": "Created"}: self.notify(ADDED_TO_BOOKMARKS_MESSAGE) self.manager.show(9119) self.manager.hide(9118) @gui.onclick(9119) def removeFromBookmarks(self): r = self.etv.removeFromBookmarks(self.data['id']) if r == {"status": "Deleted"}: self.notify(REMOVED_TO_BOOKMARKS_MESSAGE) self.manager.show(9118) self.manager.hide(9119) @gui.onclick(9121) def showVote(self): wn = VoteWindow(params={'media_id': self.data['id'], 'details_window': self}) wn.doModal() del wn def set_status(self, text): self.getControl(9199).setLabel(text) @gui.onfocus(9115) def set_play_focus(self): self.set_status('Начать воспроизведение') @gui.onfocus(9117) def set_free_play_focus(self): self.set_status('Бесплатный отрывок') @gui.onfocus(9118) def set_add_to_bookmarks_focus(self): self.set_status('Добавить в избранное') @gui.onfocus(9119) def set_remove_from_bookmarks_focus(self): self.set_status('Удалить из избранного') @gui.onfocus(9120) def set_other_server_focus(self): self.set_status('Смотреть с другого сервера') @gui.onfocus(9121) def set_vote_focus(self): self.set_status('Поставить оценку') @gui.onfocus(9113) def set_cntinious_paly_focus(self): self.set_status('Проиграть все серии начиная с этой') class ContainerDetails(MediaDetails): xml = 'container.xml' DUBBLE_EXIT_TIME = 25 play_container = False def onInit(self, *a, **k): super(ContainerDetails, self).onInit(*a, **k) if not self.is_loaded: self.parent_stack = [] self.parent_objects = [] self.back_button = False self.per_page = 13 self.setup_series() def show(self, onexit=False): if onexit and self.play_container: runned = self.play_next_item() if not runned: self.play_container = False self.show() else: if self.isContainer(): self.manager.hide(FREE_PLAY_BUTTON, 9113) self.manager.hide(PLAY_BUTTON) self.manager.hide(OTHER_PLAY_BUTTON) else: self.manager.show(FREE_PLAY_BUTTON, 9113) self.manager.show(PLAY_BUTTON) self.manager.show(OTHER_PLAY_BUTTON) super(ContainerDetails, self).show() # if next item found and runned returns True otherwise returns False # return false when you want to stop play container continiusly def play_next_item(self): next_data = self.get_next_item(self.data) last_time_exited_second_ago = datetime.now() - self.last_exit_time if last_time_exited_second_ago.seconds <= self.DUBBLE_EXIT_TIME: return False else: self.last_exit_time = datetime.now() if next_data is not None: self.data = next_data self.playItem(play_container=True) return bool(next_data) def get_next_item(self, curent): for list_item in self.side_bar_objects: if int(list_item['series_num']) == int(curent['series_num']) + 1: return list_item def playItem(self, *args, **kwargs): self.play_container = kwargs.get('play_container', False) if self.play_container: del kwargs['play_container'] super(ContainerDetails, self).playItem(*args, **kwargs) def setup_pagination(self, pagination): if pagination: if pagination['has_next']: self.manager.show(9156) else: self.manager.hide(9156) if pagination['has_previous']: self.manager.show(9155) else: self.manager.hide(9155) if pagination['page'] and pagination['pages']: page_pages = '%d / %d' % (pagination['page'], pagination['pages']) self.getControl(9157).setLabel(page_pages) def get_page_num(self): serie = self.data['series_num'] return int(float(serie) / self.per_page) + 1 def jump_to_details(self): params = {} params['data'] = json.dumps(self.data) params['breadcrumbs'] = str(self.params['breadcrumbs']) __cwd__ = self.config.getAddonInfo('path') wn = MediaDetails('details.xml', __cwd__, "DefaultSkin", params=params) wn.doModal() del wn @gui.in_thread @gui.with_progress def getChildrenForBoxee(self, parent, back_button=False, next=False, prev=False): if next: resp = self.etv.getNextPage() elif prev: resp = self.etv.getPreviousPage() else: page, direction = None, None if not self.hasChildren(): page = 1 # self.get_page_num() self.etv._current_page = page direction = 'asc' resp = self.etv.getChildren(parent, per_page=self.per_page, page=page, dir=direction) if resp == 400: self.jump_to_details() if getattr(resp, 'data', None): self.setup_pagination(resp.data['pagination']) else: return itemL = [] if back_button: self.back_button = True list_item = xbmcgui.ListItem() list_item.setProperty('id', str(0)) list_item.setProperty('back', 'back') itemL.append(list_item) # stote list side bar items data in case if self.side_bar_objects = resp.data['children'] for item in resp.data['children']: # TODO: uncomment line below when children_count field will be in the API # if item['children_count']: list_item = xbmcgui.ListItem() list_item.setProperty('id', str(item['id'])) if item['watch_status'] == 2: image_watch_status = 'clean/smotreli_small.png' elif item['watch_status'] == 1: image_watch_status = 'clean/nachinali_prosmotr_small.png' else: image_watch_status = '' list_item.setProperty('watch_status', image_watch_status) name = item['short_name'].encode('utf-8') if item['tag'].lower() == u"новости": dt = datetime(*time.strptime(item['on_air'], '%Y-%m-%d %H:%M:%S')[:6]) date_str = ru_strftime(format=u"%d %b %Y %H:%M", date=dt) name = item['short_name'].encode('utf-8') + ' от ' + date_str list_item.setLabel(name) list_item.setProperty('data', json.dumps(item)) itemL.append(list_item) self.getControl(9058).reset() self.getControl(9058).addItems(itemL) def hasParent(self): return self.data[u'parent'] != u'' def hasChildren(self): return self.data[u'type'] == u'Container' @gui.onclick(9058) def LoadSerieOrConteiner(self): control = self.getControl(SERIES_MENU) item = control.getSelectedItem() # back button presed: go back if int(item.getProperty('id')) == 0: self.go_back() else: self.parent_objects.append(self.data) self.data = json.loads(item.getProperty('data')) # after self.data changed the method hasChildren returns different value # depend on self.data, this method can return different value sins last two line of code if not self.hasChildren(): self.parent_objects.pop() if self.hasChildren(): self.parent_stack.append(self.data[u'parent']) self.getChildrenForBoxee(self.data[u'id'], back_button=True) self.show() def go_back(self): self.etv._current_page = 1 self.etv._last_url_requested = None self.etv._has_next_page = True parent_id = self.parent_stack.pop() has_back = bool(len(self.parent_stack)) self.back_button = has_back self.getChildrenForBoxee(parent_id, back_button=has_back) self.data = self.parent_objects.pop() self.show() def isAnounce(self): return bool(self.data[u'children_count'] == 0 and self.data[u'type'] == u'Container') def setup_series(self): if self.isAnounce(): itemL = [] list_item = xbmcgui.ListItem() list_item.setLabel(u'Скоро на eTVnet!'.encode('utf-8')) list_item.setProperty('id', str(0)) itemL.append(list_item) self.getControl(9058).reset() self.getControl(9058).addItems(itemL) return if self.data[u'type'] == u'MediaObject' and not self.isAnounce(): self.getChildrenForBoxee(self.data[u'parent']) elif self.data[u'type'] == u'Container' and not self.isAnounce(): self.getChildrenForBoxee(self.data[u'id']) @gui.onclick(9155) def getPrevPage(self): self.getChildrenForBoxee(0, prev=True, back_button=self.back_button) @gui.onclick(9156) @gui.with_progress def getNextPage(self): self.getChildrenForBoxee(0, next=True, back_button=self.back_button) @gui.onclick(9113) def play_container_continious(self): from datetime import datetime self.last_exit_time = datetime.now() self.playItem(play_container=True)