def launch_game(game_id): core = RequiredFeature('core').request() game_controller = RequiredFeature('game-controller').request() core.logger.info('Launching game %s' % game_id) game_controller.launch_game(game_id) del core del game_controller
def __init__(self, title=''): print 'Init Called' super(SelectInput, self).__init__(title) self.plugin = RequiredFeature('plugin').request() self.core = RequiredFeature('core').request() self.device_wrapper = RequiredFeature('device-wrapper').request() self.available_devices = self.device_wrapper.devices self.md5 = hashlib.md5() self.input_storage = self.plugin.get_storage('input_storage') for key, device in self.input_storage.iteritems(): print 'Devices during INIT: %s' % device.name background = None if self.core.get_active_skin() == 'skin.osmc': media_path = '/usr/share/kodi/addons/skin.osmc/media' if os.path.exists(media_path): background = os.path.join(media_path, 'dialogs/DialogBackground_old.png') if background is not None: self.background.setImage(background) self.removeControl(self.title_background) self.removeControl(self.window_close_button) self.removeControl(self.title_bar) self.controls = {} self.add_ctrl_btn = None self.setGeometry(1280, 720, 12, 6, padding=60) self.place_add_ctrl_btn() self.setFocus(self.add_ctrl_btn) self.connect(pyxbmct.ACTION_NAV_BACK, self.close_and_save) self.init_existing_controls() # initalise controls / mappings read from .storage
class SimplePairingManager(AbstractPairingManager): def __init__(self, crypto_provider): self.crypto_provider = crypto_provider self.config_helper = RequiredFeature('config-helper').request() self.logger = RequiredFeature('logger').request() def pair(self, nvhttp, server_info, dialog): self.logger.info('[MoonlightHelper] - Attempting to pair host: ' + self.config_helper.host_ip) pairing_proc = subprocess.Popen( ['stdbuf', '-oL', self.config_helper.get_binary(), 'pair', self.config_helper.host_ip], stdout=subprocess.PIPE) lines_iterator = iter(pairing_proc.stdout.readline, b"") pairing_thread = threading.Thread(target=self.loop_lines, args=(self.logger, lines_iterator, dialog)) pairing_thread.start() while True: xbmc.sleep(1000) if not pairing_thread.isAlive(): break new_server_info = nvhttp.get_server_info() if self.get_pair_state(nvhttp, new_server_info) == self.STATE_PAIRED: return self.STATE_PAIRED else: return self.STATE_FAILED def loop_lines(self, logger, iterator, dialog): pin_regex = r'^Please enter the following PIN on the target PC: (\d{4})' for line in iterator: match = re.match(pin_regex, line) if match: self.update_dialog(match.group(1), dialog) logger.info(line)
class TestScraperChain(unittest.TestCase): bootstrapper.bootstrap() def setUp(self): self.chain = RequiredFeature('scraper-chain').request() def testReturnType(self): game_name = 'Half-Life 2' game = self.chain.query_game_information(game_name) self.assertEqual(isinstance(game, Game), True) def testImageDump(self): game_name = 'Half-Life 2' game = self.chain.query_game_information(game_name) for img_id in game.fanarts: art = game.fanarts.get(img_id) self.assertEqual(os.path.isfile(art.get_thumb()), True) if art != game.get_selected_fanart(): self.assertEqual(os.path.isfile(art.get_original()), False) else: self.assertEqual(os.path.isfile(art.get_original()), True) for img_path in game.posters: self.assertEqual(os.path.isfile(img_path), True) self.assertEqual(os.path.isfile(game.get_selected_fanart().get_original()), True) def tearDown(self): self.chain.reset_cache()
def create_mapping(self, control): print 'Starting mapping' map_name = xbmcgui.Dialog().input(self.core.string('enter_filename')) progress_dialog = xbmcgui.DialogProgress() progress_dialog.create(self.core.string('name'), self.core.string('starting_mapping')) map_file = '%s/%s.map' % (os.path.expanduser('~'), map_name) moonlight_helper = RequiredFeature('moonlight-helper').request() success = moonlight_helper.create_ctrl_map_new(progress_dialog, map_file, control.device) if success: confirmed = xbmcgui.Dialog().yesno( self.core.string('name'), self.core.string('mapping_success'), self.core.string('set_mapping_active')) self.core.logger.info('Dialog Yes No Value: %s' % confirmed) if confirmed: control.set_mapping_file(map_file) for key, device in self.input_storage.iteritems(): print 'Iterating devices, current IS device: %s' % device.name if device.name == control.device.name: device.mapping = map_file print 'Found device and saved mapping' break else: xbmcgui.Dialog().ok(self.core.string('name'), self.core.string('mapping_failure'))
def show_games(): import xbmcgui if os.path.isfile( "/storage/.kodi/userdata/addon_data/script.luna/.storage/luna.conf" ): os.remove( "/storage/.kodi/userdata/addon_data/script.luna/.storage/luna.conf" ) if (check_host(plugin.get_setting('host', str)) == True): if os.path.isfile("/storage/.cache/moonlight/client.p12"): game_controller = RequiredFeature('game-controller').request() #plugin.set_content('movies') return plugin.finish(game_controller.get_games_as_list(), sort_methods=['label']) else: xbmcgui.Dialog().ok( 'Pair key not found!', 'Please pair with the host before proceeding...') open_settings() else: xbmcgui.Dialog().ok( 'Communication Error', 'The host is either not powered on or is asleep on the job. \nOtherwise, please troubleshoot a network issue.' )
def __init__(self): self.core = RequiredFeature('core').request() self.plugin = RequiredFeature('plugin').request() self.base_path = '/usr/share/kodi/addons/skin.osmc/16x9/' self.shortcut_path = '/usr/share/kodi/addons/skin.osmc/shortcuts/' self.widget = 'Includes_Widgets.xml' self.var = 'Variables.xml' self.home = 'Home.xml' self.override = 'overrides.xml' self.widget_backup = 'Includes_Widgets.backup' self.var_backup = 'Variables.backup' self.home_backup = 'Home.backup' self.override_backup = 'overrides.backup' self.id = None self.supported = self.core.get_active_skin() == 'skin.osmc' \ and os.path.isfile(os.path.join(self.base_path, self.widget)) \ and os.path.isfile(os.path.join(self.base_path, self.var)) \ and os.path.isfile(os.path.join(self.base_path, self.home)) \ and os.path.isfile(os.path.join(self.shortcut_path, self.override)) self.rollback_supported = os.path.isfile(os.path.join(self.base_path, self.widget_backup)) \ and os.path.isfile(os.path.join(self.base_path, self.var_backup)) \ and os.path.isfile(os.path.join(self.base_path, self.home_backup)) \ and os.path.isfile(os.path.join(self.shortcut_path, self.override_backup))
def __init__(self): AbstractScraper.__init__(self) self.plugin = RequiredFeature('plugin').request() self.core = RequiredFeature('core').request() self.api_url = 'http://thegamesdb.net/api/GetGame.php?name=%s' self.cover_cache = self._set_up_path(os.path.join(self.base_path, 'art/poster/')) self.fanart_cache = self._set_up_path(os.path.join(self.base_path, 'art/fanart/')) self.api_cache = os.path.join(self.base_path, 'api_cache/')
class TestUpdateService(unittest.TestCase): bootstrapper.bootstrap() def setUp(self): self.update_service = RequiredFeature('update-service').request() def testVersionCheck(self): self.update_service.check_for_update()
def __init__(self): AbstractScraper.__init__(self) self.plugin = RequiredFeature('plugin').request() self.api_url = 'http://www.omdbapi.com/?t=%s&plot=short&r=json&type=game' self.cover_cache = self._set_up_path( os.path.join(self.base_path, 'art/poster/')) self.api_cache = self._set_up_path( os.path.join(self.base_path, 'api_cache/'))
def __init__(self): AbstractScraper.__init__(self) self.plugin = RequiredFeature('plugin').request() self.api_url = 'https://www.igdb.com/api/v1/games/%s' self.api_img_url = 'https://res.cloudinary.com/igdb/image/upload/t_%s/%s.jpg' self.cover_cache = self._set_up_path( os.path.join(self.base_path, 'art/poster/')) self.api_cache = self._set_up_path( os.path.join(self.base_path, 'api_cache/'))
class ConfigController(Component): plugin = RequiredFeature('plugin') core = RequiredFeature('core') moonlight_helper = RequiredFeature('moonlight-helper') logger = RequiredFeature('logger') def __init__(self): pass def create_controller_mapping(self): self.logger.info('Starting mapping') controllers = ['XBOX', 'PS3', 'Wii'] ctrl_type = xbmcgui.Dialog().select( self.core.string('choose_ctrl_type'), controllers) map_name = xbmcgui.Dialog().input(self.core.string('enter_filename')) progress_dialog = xbmcgui.DialogProgress() progress_dialog.create(self.core.string('name'), self.core.string('starting_mapping')) self.core.logger.info('Trying to call subprocess') map_file = '%s/%s-%s.map' % (os.path.expanduser('~'), controllers[ctrl_type], map_name) success = self.moonlight_helper.create_ctrl_map( progress_dialog, map_file) if success: confirmed = xbmcgui.Dialog().yesno( self.core.string('name'), self.core.string('mapping_success'), self.core.string('set_mapping_active')) self.core.logger.info('Dialog Yes No Value: %s' % confirmed) if confirmed: self.plugin.set_setting('input_map', map_file) else: xbmcgui.Dialog().ok(self.core.string('name'), self.core.string('mapping_failure')) def pair_host(self): pair_dialog = xbmcgui.DialogProgress() pair_dialog.create(self.core.string('name'), 'Starting Pairing') success = self.moonlight_helper.pair_host(pair_dialog) if success: xbmcgui.Dialog().ok(self.core.string('name'), 'Successfully paired') else: confirmed = xbmcgui.Dialog().yesno( self.core.string('name'), 'Pairing failed - do you want to try again?') if confirmed: self.pair_host()
def start_running_game(): if plugin.get_setting('last_run', str): lastrun = plugin.get_setting('last_run', str) core = RequiredFeature('core').request() game_controller = RequiredFeature('game-controller').request() core.logger.info('Resuming game %s' % lastrun) game_controller.launch_game(lastrun) del core del game_controller
def build_etree(self, xml_string): try: etree = ET.fromstring(self.re_encode_string(xml_string)) except ET.ParseError as e: logger = RequiredFeature('logger').request() logger.error("Building ETree from XML failed: %s. Offending string follows ..." % e.message) logger.error(xml_string) raise ValueError("Building ETree Failed") return etree
class CoreMonitor(Component): logger = RequiredFeature('logger') config_helper = RequiredFeature('config-helper') def __init__(self): pass def onSettingsChanged(self): self.logger.info('Settings change called') self.config_helper.configure()
def launch_game_from_widget(xml_id): core = RequiredFeature('core').request() game_id = int(xml_id) internal_game_id = plugin.get_storage('sorted_game_storage').get(game_id) game_controller = RequiredFeature('game-controller').request() core.logger.info('Launching game %s' % internal_game_id) game_controller.launch_game(internal_game_id) del core del game_controller
def show_game_info(game_id): core = RequiredFeature('core').request() game = core.get_storage().get(game_id) cache_fanart = game.get_selected_fanart() cache_poster = game.get_selected_poster() window = GameInfo(game, game.name) window.doModal() del window if cache_fanart != game.get_selected_fanart( ) or cache_poster != game.get_selected_poster(): xbmc.executebuiltin('Container.Refresh') del core del game
def show_game_info(game_id): from resources.lib.views.gameinfo import GameInfo core = RequiredFeature('core').request() game = core.get_storage().get(game_id) cache_fanart = game.get_selected_fanart() cache_poster = game.get_selected_poster() window = GameInfo(game, game.name) window.doModal() del window if cache_fanart != game.get_selected_fanart() or cache_poster != game.get_selected_poster(): import xbmc xbmc.executebuiltin('Container.Refresh') del core del game
def testGetWrapperFeature(self): pairing_manager = RequiredFeature('pairing-manager').request() self.assertIsInstance(pairing_manager, PairingManagerWrapper) self.assertEqual(hasattr(pairing_manager, '_pairing_manager'), True) self.assertIsNone(pairing_manager._pairing_manager) crypto_provider = RequiredFeature('crypto-provider').request() self.assertIsInstance(crypto_provider, CryptoProviderWrapper) self.assertEqual(hasattr(crypto_provider, '_crypto_provider'), True) self.assertIsNone(crypto_provider._crypto_provider) asserted_path = os.path.join(os.path.expanduser('~'), '.cache/moonlight/') self.assertEqual(asserted_path, crypto_provider.get_key_dir()) self.assertIsNotNone(crypto_provider._crypto_provider) self.assertIsInstance(crypto_provider._crypto_provider, SimpleCryptoProvider) self.assertRaises(NotImplementedError, crypto_provider.get_client_private_key)
def __init__(self): AbstractScraper.__init__(self) self.plugin = RequiredFeature('plugin').request() self.api_url = 'https://www.igdb.com/api/v1/games/%s' self.api_img_url = 'https://res.cloudinary.com/igdb/image/upload/t_%s/%s.jpg' self.cover_cache = self._set_up_path(os.path.join(self.base_path, 'art/poster/')) self.api_cache = self._set_up_path(os.path.join(self.base_path, 'api_cache/'))
class SimplePairingManager(AbstractPairingManager): def __init__(self, crypto_provider): self.crypto_provider = crypto_provider self.config_helper = RequiredFeature('config-helper').request() self.logger = RequiredFeature('logger').request() def pair(self, nvhttp, server_info, dialog): self.logger.info('[MoonlightHelper] - Attempting to pair host: ' + self.config_helper.host_ip) pairing_proc = subprocess.Popen( ["moonlight", "pair"], cwd="/storage/moonlight", env={'LD_LIBRARY_PATH': '/storage/moonlight'}, shell=False, stdout=subprocess.PIPE, preexec_fn=os.setsid) lines_iterator = iter(pairing_proc.stdout.readline, b"") pairing_thread = threading.Thread(target=self.loop_lines, args=(self.logger, lines_iterator, dialog)) pairing_thread.start() while True: xbmc.sleep(1000) sys.stdout.flush() if not pairing_thread.isAlive(): break new_server_info = nvhttp.get_server_info() if self.get_pair_state(nvhttp, new_server_info) == self.STATE_PAIRED: return self.STATE_PAIRED else: return self.STATE_FAILED main = "pkill -x moonlight" print(os.system(main)) def loop_lines(self, logger, iterator, dialog): pin_regex = r'^Please enter the following PIN on the target PC: (\d{4})' for line in iterator: match = re.match(pin_regex, line) if match: self.update_dialog(match.group(1), dialog) logger.info(line)
def reset_cache(): core = RequiredFeature('core').request() confirmed = xbmcgui.Dialog().yesno(core.string('name'), core.string('reset_cache_warning')) if confirmed: scraper_chain = RequiredFeature('scraper-chain').request() scraper_chain.reset_cache() del scraper_chain del core
def __init__(self, title=''): print 'Init Called' super(SelectInput, self).__init__(title) self.plugin = RequiredFeature('plugin').request() self.core = RequiredFeature('core').request() self.device_wrapper = RequiredFeature('device-wrapper').request() self.available_devices = self.device_wrapper.devices self.md5 = hashlib.md5() self.input_storage = self.plugin.get_storage('input_storage') for key, device in self.input_storage.iteritems(): print 'Devices during INIT: %s' % device.name background = None if self.core.get_active_skin() == 'skin.osmc': media_path = '/usr/share/kodi/addons/skin.osmc/media' if os.path.exists(media_path): background = os.path.join(media_path, 'dialogs/DialogBackground_old.png') if background is not None: self.background.setImage(background) self.removeControl(self.title_background) self.removeControl(self.window_close_button) self.removeControl(self.title_bar) self.controls = {} self.add_ctrl_btn = None self.setGeometry(1280, 720, 12, 6, padding=60) self.place_add_ctrl_btn() self.setFocus(self.add_ctrl_btn) self.connect(pyxbmct.ACTION_NAV_BACK, self.close_and_save) self.init_existing_controls( ) # initalise controls / mappings read from .storage
def reset_cache(): import xbmcgui if plugin.get_setting('last_run', str): plugin.set_setting('last_run', '') core = RequiredFeature('core').request() confirmed = xbmcgui.Dialog().yesno(core.string('name'), core.string('reset_cache_warning')) if confirmed: scraper_chain = RequiredFeature('scraper-chain').request() scraper_chain.reset_cache() del scraper_chain del core
def pair(self, dialog): message = '' nvhttp = RequiredFeature('nvhttp').request() server_info = nvhttp.get_server_info() if nvhttp.get_pair_state(server_info) == AbstractPairingManager.STATE_PAIRED: message = 'Already paired.' pair_state = AbstractPairingManager.STATE_PAIRED else: if nvhttp.get_current_game(server_info) != 0: message = 'Host is currently in-game, please exit the game before pairing.' pair_state = AbstractPairingManager.STATE_FAILED else: pair_state = nvhttp.pair(server_info, dialog) if pair_state == AbstractPairingManager.STATE_PIN_WRONG: message = 'PIN wrong.' if pair_state == AbstractPairingManager.STATE_FAILED: message = 'Pairing failed.' if pair_state == AbstractPairingManager.STATE_PAIRED: message = 'Pairing successful.' return message, pair_state
def create_mapping(self, control): print 'Starting mapping' map_name = xbmcgui.Dialog().input(self.core.string('enter_filename')) progress_dialog = xbmcgui.DialogProgress() progress_dialog.create( self.core.string('name'), self.core.string('starting_mapping') ) map_file = '%s/%s.map' % (os.path.expanduser('~'), map_name) moonlight_helper = RequiredFeature('moonlight-helper').request() success = moonlight_helper.create_ctrl_map_new(progress_dialog, map_file, control.device) if success: confirmed = xbmcgui.Dialog().yesno( self.core.string('name'), self.core.string('mapping_success'), self.core.string('set_mapping_active') ) self.core.logger.info('Dialog Yes No Value: %s' % confirmed) if confirmed: control.set_mapping_file(map_file) for key, device in self.input_storage.iteritems(): print 'Iterating devices, current IS device: %s' % device.name if device.name == control.device.name: device.mapping = map_file print 'Found device and saved mapping' break else: xbmcgui.Dialog().ok( self.core.string('name'), self.core.string('mapping_failure') )
class Logger(Component): plugin = RequiredFeature('plugin') def __init__(self): pass def info(self, text): self.plugin.log.info(text) def debug(self, text): self.plugin.log.debug(text) def error(self, text): self.plugin.log.error(text)
def build_etree(self, xml_string): try: etree = ET.fromstring(self.re_encode_string(xml_string)) except ET.ParseError as e: logger = RequiredFeature('logger').request() logger.error( "Building ETree from XML failed: %s. Offending string follows ..." % e.message) logger.error(xml_string) raise ValueError("Building ETree Failed") return etree
def reset_cache(): import xbmcgui core = RequiredFeature('core').request() confirmed = xbmcgui.Dialog().yesno( core.string('name'), core.string('reset_cache_warning') ) if confirmed: scraper_chain = RequiredFeature('scraper-chain').request() scraper_chain.reset_cache() del scraper_chain del core
class PairingManagerWrapper(AbstractPairingManager): def __init__(self): # implementation will be lazy loaded when needed self._pairing_manager = None def pair(self, nvhttp, server_info, pin): if self._pairing_manager is None: self._load_pairing_manager() return self._pairing_manager.pair(nvhttp, server_info, pin) def _load_pairing_manager(self): try: module = importlib.import_module( 'resources.lib.nvhttp.pairingmanager.advancedpairingmanager') class_name = 'AdvancedPairingManager' except ImportError, e: print 'Could not load advanced pairing manager. Reason: %r' % e module = importlib.import_module( 'resources.lib.nvhttp.pairingmanager.simplepairingmanager') class_name = 'SimplePairingManager' class_ = getattr(module, class_name) self._pairing_manager = class_( RequiredFeature('crypto-provider').request())
class IgdbScraper(AbstractScraper): def __init__(self): AbstractScraper.__init__(self) self.plugin = RequiredFeature('plugin').request() self.api_url = 'https://www.igdb.com/api/v1/games/%s' self.api_img_url = 'https://res.cloudinary.com/igdb/image/upload/t_%s/%s.jpg' self.cover_cache = self._set_up_path(os.path.join(self.base_path, 'art/poster/')) self.api_cache = self._set_up_path(os.path.join(self.base_path, 'api_cache/')) def name(self): return 'IGDB' def get_game_information(self, game_name): if self.plugin.get_setting('api_key_file', str) == "": return ApiResponse() request_name = game_name.replace(" ", "+").replace(":", "") response = self._gather_information(request_name) response.name = game_name return response def return_paths(self): return [self.cover_cache, self.api_cache] def is_enabled(self): return self.plugin.get_setting('enable_igdb', bool) def _gather_information(self, game): game_cover_path = self._set_up_path(os.path.join(self.cover_cache, game)) game_cache_path = self._set_up_path(os.path.join(self.api_cache, game)) file_path = os.path.join(game_cache_path, game+'.json') try: cp = ConfigParser.ConfigParser() cp.read(self.plugin.get_setting('api_key_file', str)) igdb_api_key = cp.get('API', 'igdb') except: xbmcgui.Dialog().notification( self.core().string('name'), self.core().string('scraper_failed') % (game, self.name()) ) return ApiResponse() url_opener = urllib2.build_opener() url_opener.addheaders = [ ('Accept', 'application/json'), ('Authorization', 'Token token=%s' % igdb_api_key) ] if not os.path.isfile(file_path): query_string = 'search?q=%s' % game response = url_opener.open(self.api_url % query_string) if response.getcode() in [200, 304]: search_results = json.load(url_opener.open(self.api_url % query_string)) print search_results if len(search_results) > 0: best_match_id = search_results['games'][0]['id'] else: return None else: raise IOError("Server failed with status code %s" % response.getcode()) else: best_match_id = None try: json_data = json.load(open(self._get_json_data(url_opener, game_cache_path, game, best_match_id))) except IOError: return None json_data = json_data['game'] api_response = ApiResponse() api_response.year = date_parser.parse(json_data['release_date']).year api_response.plot = json_data['summary'].encode('utf-8') for genre in json_data['genres']: api_response.genre.append(genre['name'].encode('utf-8')) if json_data['cover'] is not None: img_id = json_data['cover']['id'] cover_path = self._dump_image(game_cover_path, self.api_img_url % ('cover_big', img_id)) if cover_path is not None: api_response.posters.append(cover_path) return api_response def _get_json_data(self, url_opener, path, game, best_match_id): file_path = os.path.join(path, game+'_igdb.json') if not os.path.exists(file_path) and best_match_id is not None: response = url_opener.open(self.api_url % best_match_id) if response.getcode() in [200, 304]: json_response = json.load(response) with open(file_path, 'w') as response_file: json.dump(json_response, response_file) else: raise IOError("Server failed with status code %s" % response.get()) return file_path
class GameInfo(pyxbmct.AddonDialogWindow): plugin = RequiredFeature('plugin') core = RequiredFeature('core') def __init__(self, game, title=''): super(GameInfo, self).__init__(title) self.game = game background = None if self.core.get_active_skin() == 'skin.osmc': media_path = '/usr/share/kodi/addons/skin.osmc/media' if os.path.exists(media_path): background = os.path.join(media_path, 'dialogs/DialogBackground_old.png') if background is not None: self.background.setImage(background) self.removeControl(self.title_background) self.removeControl(self.window_close_button) self.removeControl(self.title_bar) # init controls self.image = None self.genre = None self.year = None self.plot = None self.button_play = None self.button_cover_art = None self.button_fanart = None self.setGeometry(1280, 720, 12, 6, padding=60) self.set_info_controls(game) self.set_active_controls(game) self.set_navigation() self.connect(pyxbmct.ACTION_NAV_BACK, self.close) def set_info_controls(self, game): title_label = pyxbmct.Label(game.name, alignment=pyxbmct.ALIGN_LEFT, font='XLarge', textColor=COLOR_HEADING) self.placeControl(title_label, 0, 0, 2, 3) image_path = game.get_selected_poster() if image_path is None: image_path = '' self.image = pyxbmct.Image(image_path) self.placeControl(self.image, 2, 0, 6, 1) genre_label = pyxbmct.Label('Genre', alignment=pyxbmct.ALIGN_LEFT, font='Med', textColor=COLOR_DETAILS) self.placeControl(genre_label, 2, 2) self.genre = pyxbmct.FadeLabel(_alignment=pyxbmct.ALIGN_LEFT, font='Med') self.placeControl(self.genre, 2, 3, columnspan=3) self.genre.addLabel(game.get_genre_as_string()) year_label = pyxbmct.Label('Year', alignment=pyxbmct.ALIGN_LEFT, font='Med', textColor=COLOR_DETAILS) self.placeControl(year_label, 3, 2) self.year = pyxbmct.Label(game.year, alignment=pyxbmct.ALIGN_LEFT, font='Med') self.placeControl(self.year, 3, 3) self.plot = pyxbmct.TextBox() self.placeControl(self.plot, 4, 2, 6, 3) self.plot.setText(game.plot) self.plot.autoScroll(delay=5000, time=2000, repeat=10000) def set_active_controls(self, game): self.button_play = pyxbmct.Button('Play', focusTexture='', noFocusTexture='', focusedColor=COLOR_FO, textColor=COLOR_NF, font='Med', alignment=pyxbmct.ALIGN_LEFT) self.placeControl(self.button_play, 11, 0) self.connect(self.button_play, self.launch_game) self.button_cover_art = pyxbmct.Button('Choose Cover Art', focusTexture='', noFocusTexture='', focusedColor=COLOR_FO, textColor=COLOR_NF, font='Med', alignment=pyxbmct.ALIGN_LEFT) self.placeControl(self.button_cover_art, 11, 1, columnspan=2) self.connect(self.button_cover_art, self.select_cover_art) self.button_fanart = pyxbmct.Button('Choose Fanart', focusTexture='', noFocusTexture='', focusedColor=COLOR_FO, textColor=COLOR_NF, font='Med', alignment=pyxbmct.ALIGN_LEFT) self.placeControl(self.button_fanart, 11, 3, columnspan=2) self.connect(self.button_fanart, self.select_fanart) def set_navigation(self): self.button_play.controlRight(self.button_cover_art) self.button_play.controlLeft(self.button_fanart) self.button_cover_art.controlRight(self.button_fanart) self.button_cover_art.controlLeft(self.button_play) self.button_fanart.controlRight(self.button_play) self.button_fanart.controlLeft(self.button_cover_art) self.setFocus(self.button_play) def launch_game(self): xbmc.executebuiltin('XBMC.RunPlugin(%s)' % self.plugin.url_for( endpoint='launch_game', game_id=self.game.name)) def select_fanart(self): browser = xbmcgui.Dialog().browse( 2, 'Select Fanart', 'files', '.jpg|.png', False, False, self.game.get_selected_fanart().get_thumb()) if browser: self.game.set_selected_fanart(browser) self.core.get_storage().sync() def select_cover_art(self): browser = xbmcgui.Dialog().browse(2, 'Select Cover Art', 'files', '.jpg|.png', False, False, self.game.get_poster(0, '')) if browser: self.game.selected_poster = browser self.core.get_storage().sync() self.image = pyxbmct.Image(browser) self.placeControl(self.image, 2, 0, 6, 1) def setAnimation(self, control): control.setAnimations([( 'WindowOpen', 'effect=fade start=0 end=100 time=500', ), ( 'WindowClose', 'effect=fade start=100 end=0 time=500', )])
def re_encode_string(self, xml_string): logger = RequiredFeature('logger').request() regex = re.compile('UTF-\d{1,2}') specified_encoding = regex.search(xml_string) logger.info("Trying to decode as: %s" % 'ASCII') try: xml_string = xml_string.decode(encoding='ascii') except UnicodeDecodeError as e: logger.info("Decoding as %s failed, trying as %s" % ('ASCII', 'UTF-8')) try: xml_string = xml_string.decode(encoding='UTF-8') except UnicodeDecodeError as e: logger.info("Decoding as %s failed, trying as %s" % ('UTF-8', 'UTF-16')) try: xml_string = xml_string.decode(encoding='UTF-16') except UnicodeDecodeError as e: logger.error( "Decoding as UTF-16 failed, this was the last attempt. Offending string follows ..." ) logger.error(xml_string) raise ValueError("String Decode Failed") if specified_encoding is not None: try: logger.info("Trying to encode as specified in XML: %s" % specified_encoding.group(0)) xml_string = xml_string.encode( encoding=specified_encoding.group(0)) except UnicodeEncodeError as e: new_encode_setting = 'UTF-16' if specified_encoding.group( 0) == 'UTF-8' else 'UTF-8' logger.info("Encoding as %s failed, trying as %s" % (specified_encoding.group(0), new_encode_setting)) try: xml_string = xml_string.encode(encoding=new_encode_setting) except UnicodeEncodeError as e: logger.error( "Encoding as %s failed, this was the last attempt. Offending string follows ..." % new_encode_setting) logger.error(xml_string) raise ValueError("String Encode Failed") return xml_string else: logger.info("RegExp couldn't find a match in the XML string ...") try: logger.info("Trying to encode as: UTF-8") xml_string = xml_string.encode(encoding='UTF-8') except UnicodeEncodeError as e: logger.info("Encoding as UTF-8 failed, trying as UTF-16") try: xml_string = xml_string.encode(encoding='UTF-16') except UnicodeEncodeError as e: logger.error( "Encoding as UTF-16 failed, this was the last attempt. Offending string follows ..." ) logger.error(xml_string) raise ValueError("String Encode Failed") return xml_string
def __init__(self, crypto_provider): self.crypto_provider = crypto_provider self.config_helper = RequiredFeature('config-helper').request() self.logger = RequiredFeature('logger').request()
def do_update(self): updater = RequiredFeature('update-service').request() updater.do_update(self)
class SkinPatcher: def __init__(self): self.core = RequiredFeature('core').request() self.plugin = RequiredFeature('plugin').request() self.base_path = '/usr/share/kodi/addons/skin.osmc/16x9/' self.shortcut_path = '/usr/share/kodi/addons/skin.osmc/shortcuts/' self.widget = 'Includes_Widgets.xml' self.var = 'Variables.xml' self.home = 'Home.xml' self.override = 'overrides.xml' self.widget_backup = 'Includes_Widgets.backup' self.var_backup = 'Variables.backup' self.home_backup = 'Home.backup' self.override_backup = 'overrides.backup' self.id = None self.supported = self.core.get_active_skin() == 'skin.osmc' \ and os.path.isfile(os.path.join(self.base_path, self.widget)) \ and os.path.isfile(os.path.join(self.base_path, self.var)) \ and os.path.isfile(os.path.join(self.base_path, self.home)) \ and os.path.isfile(os.path.join(self.shortcut_path, self.override)) self.rollback_supported = os.path.isfile(os.path.join(self.base_path, self.widget_backup)) \ and os.path.isfile(os.path.join(self.base_path, self.var_backup)) \ and os.path.isfile(os.path.join(self.base_path, self.home_backup)) \ and os.path.isfile(os.path.join(self.shortcut_path, self.override_backup)) def backup(self): shutil.copy(os.path.join(self.base_path, self.widget), os.path.join(self.base_path, self.widget_backup)) shutil.copy(os.path.join(self.base_path, self.var), os.path.join(self.base_path, self.var_backup)) shutil.copy(os.path.join(self.base_path, self.home), os.path.join(self.base_path, self.home_backup)) shutil.copy(os.path.join(self.shortcut_path, self.override), os.path.join(self.shortcut_path, self.override_backup)) def patch(self): if self.supported: self.backup() self.patch_widget() self.patch_home() self.patch_var() self.patch_override() self.plugin.set_setting('luna_widget_patched', 'true') else: print 'Not Supported' def patch_widget(self): xml_root = ElementTree.ElementTree(file=os.path.join(self.base_path, self.widget)).getroot() include = ElementTree.SubElement(xml_root, 'include', name="Luna") content = ElementTree.SubElement(include, 'content') for i in range(0, 20): item = ElementTree.SubElement(content, 'item') ElementTree.SubElement(item, 'icon').text = "$INFO[Window.Property(Luna.%s.icon)]" % i ElementTree.SubElement(item, 'thumb').text = "$INFO[Window.Property(Luna.%s.thumb)]" % i ElementTree.SubElement(item, 'label').text = "$INFO[Window.Property(Luna.%s.name)]" % i ElementTree.SubElement(item, 'property', name="fanart").text = "$INFO[Window.Property(Luna.%s.fanart)]" % i ElementTree.SubElement(item, 'onclick')\ .text = "RunPlugin(plugin://script.luna/games/launch-from-widget/%s)" % i ElementTree.SubElement(item, 'visible').text = "!IsEmpty(Window.Property(Luna.%s.name))" % i indent(include) tree = ElementTree.ElementTree(xml_root) tree.write(os.path.join(self.base_path, self.widget)) def patch_home(self): xml_root = ElementTree.ElementTree(file=os.path.join(self.base_path, self.home)).getroot() print self.plugin.get_setting('luna_force_fanart') controls = xml_root.find('controls') control_group = None for control in controls: print control.get('type') if control.get('type') == 'image': print "Found Image Control" if self.plugin.get_setting('luna_force_fanart', bool): control.find('visible').text = "True" print 'Visible Text is %s' % control.find('visible').text if control.get('type') == 'group': control_group = control break inner_control_group = None for control in control_group: if control.get('type') == 'group': inner_control_group = control_group break widget_control = None for control in inner_control_group: if control.get('type') == 'group': widget_control = control break inner_widget_control = None for control in widget_control: if control.get('id') is not None: inner_widget_control = control break current_max_id = "" myosmc_control = None for control in inner_widget_control: if control.get('id') is not None: current_max_id = control.get('id') myosmc_control = control current_max_id = int(current_max_id) + 1 self.id = current_max_id luna_control = copy.deepcopy(myosmc_control) luna_control.set('id', str(current_max_id)) luna_control.find('include').text = "Luna" luna_control.find('visible').text = "StringCompare(Container(9000).ListItem.Property(Widget),Luna)" luna_item_layout = luna_control.find('itemlayout') luna_item_layout.set('width', "270") luna_focus_layout = luna_control.find('focusedlayout') luna_focus_layout.set('width', "270") for control in luna_item_layout: if control.get('type') == 'image': control.find('width').text = "250" if control.find('texture') is not None and control.find('texture').text == 'common/black.png': control.find('texture').text = "" for control in luna_focus_layout: if control.get('type') == 'image': control.find('width').text = "250" if control.find('texture') is not None and control.find('texture').text == 'common/black.png': control.find('texture').text = "" inner_widget_control.append(luna_control) tree = ElementTree.ElementTree(xml_root) tree.write(os.path.join(self.base_path, self.home)) def patch_var(self): xml_root = ElementTree.ElementTree(file=os.path.join(self.base_path, self.var)).getroot() label_group = None heading_group = None fanart_group = None for var in xml_root.findall('variable'): if var.get('name') == 'WidgetLabel': label_group = var if var.get('name') == 'WidgetHeading': heading_group = var if var.get('name') == 'WidgetFanart': fanart_group = var if label_group is not None and heading_group is not None and fanart_group is not None: break ElementTree.SubElement(label_group, "value", condition="StringCompare(Container(9000).ListItem.Property(Widget),Luna)")\ .text = "$INFO[Container(%s).ListItem.Label]" % self.id ElementTree.SubElement(heading_group, "value", condition="StringCompare(Container(9000).ListItem.Property(Widget),Luna)")\ .text = "Games" ElementTree.SubElement(fanart_group, "value", condition="StringCompare(Container(9000).ListItem.Property(Widget),Luna)")\ .text = "$INFO[Container(%s).ListItem.Property(fanart)]" % self.id tree = ElementTree.ElementTree(xml_root) tree.write(os.path.join(self.base_path, self.var)) def patch_override(self): xml_root = ElementTree.ElementTree(file=os.path.join(self.shortcut_path, self.override)).getroot() ElementTree.SubElement(xml_root, "widget", label="Luna").text = "Luna" ElementTree.SubElement(xml_root, "widgetdefault", labelID="script.luna").text = "Luna" tree = ElementTree.ElementTree(xml_root) tree.write(os.path.join(self.shortcut_path, self.override)) def rollback(self): if self.rollback_supported: shutil.move(os.path.join(self.base_path, self.widget_backup), os.path.join(self.base_path, self.widget)) shutil.move(os.path.join(self.base_path, self.var_backup), os.path.join(self.base_path, self.var)) shutil.move(os.path.join(self.base_path, self.home_backup), os.path.join(self.base_path, self.home)) shutil.move(os.path.join(self.shortcut_path, self.override_backup), os.path.join(self.shortcut_path, self.override)) self.plugin.set_setting('luna_widget_patched', 'false')
class OmdbScraper(AbstractScraper): def __init__(self): AbstractScraper.__init__(self) self.plugin = RequiredFeature('plugin').request() self.api_url = 'http://www.omdbapi.com/?t=%s&plot=short&r=json&type=game' self.cover_cache = self._set_up_path(os.path.join(self.base_path, 'art/poster/')) self.api_cache = self._set_up_path(os.path.join(self.base_path, 'api_cache/')) def name(self): return 'OMDB' def get_game_information(self, game_name): request_name = game_name.replace(" ", "+").replace(":", "") response = self._gather_information(request_name) response.name = game_name return response def return_paths(self): return [self.cover_cache, self.api_cache] def is_enabled(self): return self.plugin.get_setting('enable_omdb', bool) def _gather_information(self, game): game_cover_path = self._set_up_path(os.path.join(self.cover_cache, game)) game_cache_path = self._set_up_path(os.path.join(self.api_cache, game)) json_file = self._get_json_data(game_cache_path, game) try: json_data = json.load(open(json_file)) except: xbmcgui.Dialog().notification( self.core().string('name'), self.core().string('scraper_failed') % (game, self.name()) ) if json_file is not None and os.path.isfile(json_file): os.remove(json_file) return ApiResponse() if json_data['Response'] != 'False': json_data['posters'] = [] cover_path = self._dump_image(game_cover_path, json_data['Poster']) if cover_path is not None: json_data['posters'].append(cover_path) del json_data['Poster'] response = dict((k.lower(), v) for k, v in json_data.iteritems()) if 'genre' in response: response['genre'] = response.get('genre').split(',') response['genre'] = [str(v).strip() for v in response.get('genre')] return ApiResponse.from_dict(**response) else: return ApiResponse() def _get_json_data(self, path, game): file_path = os.path.join(path, game+'_omdb.json') if not os.path.exists(file_path): json_response = json.load(urllib2.urlopen(self.api_url % game)) with open(file_path, 'w') as response_file: json.dump(json_response, response_file) return file_path
def create_mapping(): config_controller = RequiredFeature('config-controller').request() config_controller.create_controller_mapping() del config_controller
def check_update(): updater = RequiredFeature('update-service').request() update = updater.check_for_update(True) if update is not None: updater.initiate_update(update)
def re_encode_string(self, xml_string): logger = RequiredFeature('logger').request() regex = re.compile('UTF-\d{1,2}') specified_encoding = regex.search(xml_string) logger.info("Trying to decode as: %s" % 'ASCII') try: xml_string = xml_string.decode(encoding='ascii') except UnicodeDecodeError as e: logger.info("Decoding as %s failed, trying as %s" % ('ASCII', 'UTF-8')) try: xml_string = xml_string.decode(encoding='UTF-8') except UnicodeDecodeError as e: logger.info("Decoding as %s failed, trying as %s" % ('UTF-8', 'UTF-16')) try: xml_string = xml_string.decode(encoding='UTF-16') except UnicodeDecodeError as e: logger.error("Decoding as UTF-16 failed, this was the last attempt. Offending string follows ...") logger.error(xml_string) raise ValueError("String Decode Failed") if specified_encoding is not None: try: logger.info("Trying to encode as specified in XML: %s" % specified_encoding.group(0)) xml_string = xml_string.encode(encoding=specified_encoding.group(0)) except UnicodeEncodeError as e: new_encode_setting = 'UTF-16' if specified_encoding.group(0) == 'UTF-8' else 'UTF-8' logger.info("Encoding as %s failed, trying as %s" % (specified_encoding.group(0), new_encode_setting)) try: xml_string = xml_string.encode(encoding=new_encode_setting) except UnicodeEncodeError as e: logger.error( "Encoding as %s failed, this was the last attempt. Offending string follows ..." % new_encode_setting) logger.error(xml_string) raise ValueError("String Encode Failed") return xml_string else: logger.info("RegExp couldn't find a match in the XML string ...") try: logger.info("Trying to encode as: UTF-8") xml_string = xml_string.encode(encoding='UTF-8') except UnicodeEncodeError as e: logger.info("Encoding as UTF-8 failed, trying as UTF-16") try: xml_string = xml_string.encode(encoding='UTF-16') except UnicodeEncodeError as e: logger.error("Encoding as UTF-16 failed, this was the last attempt. Offending string follows ...") logger.error(xml_string) raise ValueError("String Encode Failed") return xml_string
def open_settings(): plugin.open_settings() core_monitor = RequiredFeature('core-monitor').request() core_monitor.onSettingsChanged() del core_monitor
def testConfigurationCorrectness(self): config = RequiredFeature('config-helper').request() config._configure(**self.fake_settings) config._dump_conf() self.assertEqual(self.bin_path, config.get_section_setting('General', 'binpath')) self.assertEqual('192.168.1.1', config.get_section_setting('General', 'address')) self.assertEqual('60', config.get_section_setting('General', 'fps')) self.assertEqual('-1', config.get_section_setting('General', 'bitrate')) self.assertEqual('1024', config.get_section_setting('General', 'packetsize')) self.assertEqual(os.path.join(self.addon_path, 'input.map'), config.get_section_setting('General', 'mapping')) self.assertEqual(os.path.join(self.addon_path, 'input.device'), config.get_section_setting('General', 'input')) self.assertEqual('False', config.get_section_setting('General', 'sops')) self.assertEqual('False', config.get_section_setting('General', 'localaudio')) self.assertEqual('False', config.get_section_setting('General', 'remote'))
def testConfigurationDump(self): config = RequiredFeature('config-helper').request() config._configure(**self.fake_settings) config._dump_conf() self.assertEqual(os.path.isfile(config.full_path), True)
def setUp(self): self.chain = RequiredFeature('scraper-chain').request()
def select_audio_device(): audio_controller = RequiredFeature('audio-controller').request() audio_controller.select_audio_device()
import xbmcaddon __addon__ = xbmcaddon.Addon() if __name__ == '__main__': if __addon__.getSetting("luna_widget_enable") == 'true': import resources.lib.config.bootstrap as bootstrapper from xbmcswift2 import xbmcgui from resources.lib.di.requiredfeature import RequiredFeature plugin = bootstrapper.bootstrap() WINDOW = xbmcgui.Window(10000) core = RequiredFeature('core').request() storage = core.get_storage() sorted_list = sorted(storage.raw_dict().keys()) sorted_storage = plugin.get_storage('sorted_game_storage') sorted_storage.clear() for i, game_name in enumerate(sorted_list): game = storage.get(game_name) WINDOW.setProperty('Luna.%s.name' % i, game.name) WINDOW.setProperty('Luna.%s.icon' % i, game.get_selected_poster()) WINDOW.setProperty('Luna.%s.thumb' % i, game.get_selected_poster()) WINDOW.setProperty('Luna.%s.fanart' % i, game.get_selected_fanart().get_original()) sorted_storage[i] = game_name sorted_storage.sync()
def pair_host(self, dialog): return RequiredFeature('connection-manager').request().pair(dialog)
def __init__(self): AbstractScraper.__init__(self) self.plugin = RequiredFeature('plugin').request() self.api_url = 'http://www.omdbapi.com/?t=%s&plot=short&r=json&type=game' self.cover_cache = self._set_up_path(os.path.join(self.base_path, 'art/poster/')) self.api_cache = self._set_up_path(os.path.join(self.base_path, 'api_cache/'))
def launch_game(self, game_id): import time import xbmcgui player = xbmc.Player() if player.isPlayingVideo(): player.stop() if self.plugin.get_setting('last_run', str): xbmc.audioSuspend() xbmc.executebuiltin("Dialog.Close(busydialog)") xbmc.executebuiltin("Dialog.Close(notification)") if os.path.isfile("/storage/moonlight/aml_decoder.stats"): os.remove("/storage/moonlight/aml_decoder.stats") self.config_helper.configure() if self.plugin.get_setting('last_run', str): sp = subprocess.Popen( ["moonlight", "stream", "-app", game_id, "-logging"], cwd="/storage/moonlight", env={'LD_LIBRARY_PATH': '/storage/moonlight'}, shell=False, preexec_fn=os.setsid) else: sp = subprocess.Popen( [ "moonlight", "stream", "-app", game_id, "-logging", "-delay", "10" ], cwd="/storage/moonlight", env={'LD_LIBRARY_PATH': '/storage/moonlight'}, shell=False, preexec_fn=os.setsid) subprocess.Popen([ '/storage/.kodi/addons/script.luna/resources/lib/launchscripts/osmc/moonlight-heartbeat.sh' ], shell=False) if not self.plugin.get_setting('last_run', str): xbmc.Player().play( '/storage/.kodi/addons/script.luna/resources/statics/loading.mp4' ) time.sleep(8) xbmc.audioSuspend() time.sleep(2.5) xbmc.Player().stop() self.plugin.set_setting('last_run', game_id) subprocess.Popen(['killall', '-STOP', 'kodi.bin'], shell=False) sp.wait() main = "pkill -x moonlight" heartbeat = "pkill -x moonlight-heart" print(os.system(main)) print(os.system(heartbeat)) xbmc.audioResume() if os.path.isfile("/storage/moonlight/aml_decoder.stats"): with open("/storage/moonlight/aml_decoder.stats") as stat_file: statistics = stat_file.read() if "StreamStatus = -1" in statistics: confirmed = xbmcgui.Dialog().yesno( 'Stream initialisation failed...', 'Try running ' + game_id + ' again?', nolabel='No', yeslabel='Yes') if confirmed: self.launch_game(game_id) else: xbmcgui.Dialog().ok('Stream statistics', statistics) game_controller = RequiredFeature('game-controller').request() game_controller.refresh_games() del game_controller xbmc.executebuiltin('Container.Refresh') xbmcgui.Dialog().notification( 'Information', game_id + ' is still running on host. Resume via Luna, ensuring to quit before the host is restarted!', xbmcgui.NOTIFICATION_INFO, False)
def list_games(self): return RequiredFeature('nvhttp').request().get_app_list()
def pair_host(): config_controller = RequiredFeature('config-controller').request() config_controller.pair_host() del config_controller