Example #1
0
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')
Example #2
0
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
Example #3
0
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
Example #4
0
    core.logger.info('Launching game %s' % internal_game_id)
    game_controller.launch_game(internal_game_id)

    del core
    del game_controller

if __name__ == '__main__':
    core = RequiredFeature('core').request()
    update_storage = plugin.get_storage('update', TTL=24*60)
    if not update_storage.get('checked'):
        updater = RequiredFeature('update-service').request()
        updater.check_for_update()
        del updater
    core.check_script_permissions()

    if plugin.get_setting('host', str):
        game_refresh_required = False

        try:
            from resources.lib.model.game import Game
            if plugin.get_storage('game_version')['version'] != Game.version:
                game_refresh_required = True
        except KeyError:
            game_refresh_required = True

        if game_refresh_required:
            game_controller = RequiredFeature('game-controller').request()
            game_controller.get_games()
            del game_controller

        plugin.run()
Example #5
0
    game_controller.launch_game(internal_game_id)

    del core
    del game_controller


if __name__ == '__main__':
    core = RequiredFeature('core').request()
    update_storage = plugin.get_storage('update', TTL=240 * 60)
    if not update_storage.get('checked'):
        updater = RequiredFeature('update-service').request()
        updater.check_for_update()
        del updater
    core.check_script_permissions()

    if plugin.get_setting('host', str):
        game_refresh_required = False

        try:
            from resources.lib.model.game import Game
            if plugin.get_storage('game_version')['version'] != Game.version:
                game_refresh_required = True
        except KeyError:
            game_refresh_required = True

        if game_refresh_required:
            game_controller = RequiredFeature('game-controller').request()
            game_controller.get_games()
            del game_controller

        if os.path.isfile("/storage/moonlight/zerotier.conf"):
Example #6
0
class TgdbScraper(AbstractScraper):
    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/')

    def name(self):
        return 'TGDB'

    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.fanart_cache, self.api_cache]

    def is_enabled(self):
        return self.plugin.get_setting('enable_tgdb', bool)

    def _gather_information(self, game):
        game_cover_path = self._set_up_path(os.path.join(self.cover_cache, game))
        game_fanart_path = self._set_up_path(os.path.join(self.fanart_cache, game))

        xml_response_file = self._get_xml_data(game)

        try:
            xml_root = ElementTree(file=xml_response_file).getroot()
        except:
            xbmcgui.Dialog().notification(
                self.core.string('name'),
                self.core.string('scraper_failed') % (game, self.name())
            )

            if xml_response_file is not None and os.path.isfile(xml_response_file):
                os.remove(xml_response_file)

            return ApiResponse()

        dict_response = self._parse_xml_to_dict(xml_root)

        if dict_response:
            posters = dict_response['posters']
            dict_response['posters'] = []
            for poster in posters:
                dict_response['posters'].append(self._dump_image(game_cover_path, poster))

            local_arts = {}
            for art in dict_response.get('fanarts'):
                art.set_thumb(self._dump_image(game_fanart_path, art.get_thumb()))
                local_arts[os.path.basename(art.get_thumb())] = art
            dict_response['fanarts'] = local_arts

            return ApiResponse.from_dict(**dict_response)

    def _get_xml_data(self, game):
        file_path = os.path.join(self.api_cache, game, game+'_tgdb.xml')

        if not os.path.isfile(file_path):
            curl = subprocess.Popen(['curl', '-XGET', self.api_url % game], stdout=subprocess.PIPE)
            with open(file_path, 'w') as response_file:
                response_file.write(curl.stdout.read())

        return file_path

    @staticmethod
    def _parse_xml_to_dict(root):
        """

        :rtype: dict
        :type root: Element
        """
        data = {'year': 'N/A', 'plot': 'N/A', 'posters': [], 'genre': [], 'fanarts': []}
        similar_id = []
        base_img_url = root.find('baseImgUrl').text

        for game in root.findall('Game'):
            if game.find('Platform').text == 'PC':
                if game.find('ReleaseDate') is not None:
                    data['year'] = os.path.basename(game.find('ReleaseDate').text)
                if game.find('Overview') is not None:
                    data['plot'] = game.find('Overview').text
                for img in game.find('Images'):
                    if img.get('side') == 'front':
                        data['posters'].append(os.path.join(base_img_url, img.text))
                    if img.tag == 'fanart':
                        image = Fanart()
                        image.set_original(os.path.join(base_img_url, img.find('original').text))
                        image.set_thumb(os.path.join(base_img_url, img.find('thumb').text))
                        data['fanarts'].append(image)
                        del image
                if game.find('Genres') is not None:
                    for genre in game.find('Genres'):
                        data['genre'].append(str(genre.text))
                if game.find('Similar') is not None:
                    for similar in game.find('Similar'):
                        if similar.tag == 'Game':
                            similar_id.append(similar.find('id').text)
                break

        for game in root.findall('Game'):
            if game.find('id').text in similar_id:
                for img in game.find('Images'):
                    if img.tag == 'fanart':
                        image = Fanart()
                        image.set_original(os.path.join(base_img_url, img.find('original').text))
                        image.set_thumb(os.path.join(base_img_url, img.find('thumb').text))
                        data['fanarts'].append(image)
                        del image

        return data
Example #7
0
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
Example #8
0
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