{"action":"created","comment":{"url":"https://api.github.com/repos/xbmc/repo-plugins/pulls/comments/197615283","pull_request_review_id":131398080,"id":197615283,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5NzYxNTI4Mw==","diff_hunk":"@@ -0,0 +1,1153 @@\n+# -*- coding: utf-8 -*-\n+#\n+# Advanced MAME Launcher MAME filter engine.\n+#\n+\n+# Copyright (c) 2016-2018 Wintermute0110 <wintermute0110@gmail.com>\n+#\n+# This program is free software; you can redistribute it and/or modify\n+# it under the terms of the GNU General Public License as published by\n+# the Free Software Foundation; version 2 of the License.\n+#\n+# This program is distributed in the hope that it will be useful,\n+# but WITHOUT ANY WARRANTY; without even the implied warranty of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+# GNU General Public License for more details.\n+\n+# --- Python standard library ---\n+# Division operator: https://www.python.org/dev/peps/pep-0238/\n+from __future__ import unicode_literals\n+from __future__ import division\n+\n+import xml.etree.ElementTree as ET\n+\n+# --- Modules/packages in this plugin ---\n+from constants import *\n+from utils import *\n+from utils_kodi import *\n+from mame import *\n+\n+# -------------------------------------------------------------------------------------------------\n+# Parse filter XML definition\n+# -------------------------------------------------------------------------------------------------\n+def strip_str_list(t_list):\n+    for i, s_t in enumerate(t_list): t_list[i] = s_t.strip()\n+\n+    return t_list\n+\n+def _get_comma_separated_list(text_t):\n+    if not text_t:\n+        return []\n+    else:\n+        return strip_str_list(text_t.split(','))\n+\n+#\n+# Parse a string 'XXXXXX with YYYYYY'\n+#\n+def _get_change_tuple(text_t):\n+    if not text_t:\n+        return ''\n+    tuple_list = re.findall(r'(\\w+) with (\\w+)', text_t)\n+    if tuple_list:\n+        return tuple_list\n+    else:\n+        log_error('_get_change_tuple() text_t = \"{0}\"'.format(text_t))\n+        m = '(Exception) Cannot parse <Change> \"{0}\"'.format(text_t)\n+        log_error(m)\n+        raise Addon_Error(m)\n+\n+#\n+# Returns a list of dictionaries, each dictionary has the filter definition.\n+#\n+def filter_parse_XML(fname_str):\n+    __debug_xml_parser = False\n+\n+    # If XML has errors (invalid characters, etc.) this will rais exception 'err'\n+    XML_FN = FileName(fname_str)\n+    if not XML_FN.exists():\n+        kodi_dialog_OK('Custom filter XML file not found.')\n+        return\n+    log_debug('filter_parse_XML() Reading XML OP \"{0}\"'.format(XML_FN.getOriginalPath()))\n+    log_debug('filter_parse_XML() Reading XML  P \"{0}\"'.format(XML_FN.getPath()))\n+    try:\n+        xml_tree = ET.parse(XML_FN.getPath())\n+    except IOError as ex:\n+        log_error('(Exception) {0}'.format(ex))\n+        log_error('(Exception) Syntax error in the XML file definition')\n+        raise Addon_Error('(Exception) ET.parse(XML_FN.getPath()) failed.')\n+    xml_root = xml_tree.getroot()\n+    define_dic = {}\n+    filters_list = []\n+    for root_element in xml_root:\n+        if __debug_xml_parser: log_debug('Root child {0}'.format(root_element.tag))\n+\n+        if root_element.tag == 'DEFINE':\n+            name_str = root_element.attrib['name']\n+            define_str = root_element.text if root_element.text else ''\n+            log_debug('DEFINE \"{0}\" := \"{1}\"'.format(name_str, define_str))\n+            define_dic[name_str] = define_str\n+        elif root_element.tag == 'MAMEFilter':\n+            this_filter_dic = {\n+                'name'         : '',\n+                'plot'         : '',\n+                'options'      : [], # List of strings\n+                'driver'       : '',\n+                'manufacturer' : '',\n+                'genre'        : '',\n+                'controls'     : '',\n+                'devices'      : '',\n+                'year'         : '',\n+                'include'      : [], # List of strings\n+                'exclude'      : [], # List of strings\n+                'change'       : [], # List of tuples (change_orig, change_dest)\n+            }\n+            for filter_element in root_element:\n+                text_t = filter_element.text if filter_element.text else ''\n+                if filter_element.tag == 'Name':\n+                    this_filter_dic['name'] = text_t\n+                elif filter_element.tag == 'Plot':\n+                    this_filter_dic['plot'] = text_t\n+                elif filter_element.tag == 'Options':\n+                    t_list = _get_comma_separated_list(text_t)\n+                    if t_list:\n+                        this_filter_dic['options'].extend(t_list)\n+                elif filter_element.tag == 'Driver':\n+                    this_filter_dic['driver'] = text_t\n+                elif filter_element.tag == 'Manufacturer':\n+                    this_filter_dic['manufacturer'] = text_t\n+                elif filter_element.tag == 'Genre':\n+                    this_filter_dic['genre'] = text_t\n+                elif filter_element.tag == 'Controls':\n+                    this_filter_dic['controls'] = text_t\n+                elif filter_element.tag == 'Devices':\n+                    this_filter_dic['devices'] = text_t\n+                elif filter_element.tag == 'Year':\n+                    this_filter_dic['year'] = text_t\n+                elif filter_element.tag == 'Include':\n+                    t_list = _get_comma_separated_list(text_t)\n+                    if t_list:\n+                        this_filter_dic['include'].extend(t_list)\n+                elif filter_element.tag == 'Exclude':\n+                    t_list = _get_comma_separated_list(text_t)\n+                    if t_list:\n+                        this_filter_dic['exclude'].extend(t_list)\n+                elif filter_element.tag == 'Change':\n+                    tuple_t = _get_change_tuple(text_t)\n+                    if tuple_t: this_filter_dic['change'].append(tuple_t)\n+                else:\n+                    m = '(Exception) Unrecognised tag <{0}>'.format(filter_element.tag)\n+                    log_debug(m)\n+                    raise Addon_Error(m)\n+            log_debug('Adding filter \"{0}\"'.format(this_filter_dic['name']))\n+            filters_list.append(this_filter_dic)\n+\n+    # >> Resolve DEFINE tags (substitute by the defined value)\n+    for f_definition in filters_list:\n+        for initial_str, final_str in define_dic.iteritems():\n+            f_definition['driver']       = f_definition['driver'].replace(initial_str, final_str)\n+            f_definition['manufacturer'] = f_definition['manufacturer'].replace(initial_str, final_str)\n+            f_definition['genre']        = f_definition['genre'].replace(initial_str, final_str)\n+            f_definition['controls']     = f_definition['controls'].replace(initial_str, final_str)\n+            f_definition['devices']      = f_definition['devices'].replace(initial_str, final_str)\n+            # f_definition['include']      = f_definition['include'].replace(initial_str, final_str)\n+            # f_definition['exclude']      = f_definition['exclude'].replace(initial_str, final_str)\n+            # f_definition['change']       = f_definition['change'].replace(initial_str, final_str)\n+    return filters_list\n+\n+#\n+# Returns a dictionary of dictionaries.\n+#\n+def filter_get_filter_DB(machine_main_dic, machine_render_dic,\n+                         assets_dic, main_pclone_dic, machine_archives_dic, pDialog):\n+    pDialog.create('Advanced MAME Launcher', 'Building filter database ...')\n+    total_items = len(main_pclone_dic)\n+    item_count = 0\n+    main_filter_dic = {}\n+    for m_name in main_pclone_dic:\n+        pDialog.update(int((item_count*100) / total_items))\n+        if 'att_coins' in machine_main_dic[m_name]['input']:\n+            coins = machine_main_dic[m_name]['input']['att_coins']\n+        else:\n+            coins = 0\n+        if m_name in machine_archives_dic:\n+            hasROMs = True if machine_archives_dic[m_name]['ROMs'] else False\n+        else:\n+            hasROMs = False\n+        if m_name in machine_archives_dic:\n+            hasCHDs = True if machine_archives_dic[m_name]['CHDs'] else False\n+        else:\n+            hasCHDs = False\n+        if m_name in machine_archives_dic:\n+            hasSamples = True if machine_archives_dic[m_name]['Samples'] else False\n+        else:\n+            hasSamples = False\n+\n+        # >> Fix this to match \"Controls (Compact)\" filter\n+        raw_control_list = machine_main_dic[m_name]['control_type']\n+        pretty_control_type_list = mame_improve_control_type_list(raw_control_list)\n+        control_list = mame_compress_item_list_compact(pretty_control_type_list)\n+        if not control_list: control_list = [ '[ No controls ]' ]\n+\n+        # >> Fix this to match \"Device (Compact)\" filter\n+        raw_device_list = [ device['att_type'] for device in machine_main_dic[m_name]['devices'] ]\n+        pretty_device_list = mame_improve_device_list(raw_device_list)\n+        device_list = mame_compress_item_list_compact(pretty_device_list)\n+        if not device_list: device_list = [ '[ No devices ]' ]\n+\n+        # --- Build filtering dictionary ---\n+        main_filter_dic[m_name] = {\n+            # --- Default filters ---\n+            'isDevice' : machine_render_dic[m_name]['isDevice'],\n+            # --- <Option> filters ---\n+            'coins' : coins,\n+            'hasROMs' : hasROMs,\n+            'hasCHDs' : hasCHDs,\n+            'hasSamples' : hasSamples,\n+            'isMature' : machine_render_dic[m_name]['isMature'],\n+            'isBIOS' : machine_render_dic[m_name]['isBIOS'],\n+            'isMechanical' : machine_main_dic[m_name]['isMechanical'],\n+            'isImperfect' : True if machine_render_dic[m_name]['driver_status'] == 'imperfect' else False,\n+            'isNonWorking' : True if machine_render_dic[m_name]['driver_status'] == 'preliminary' else False,\n+            # --- Other filters ---\n+            'driver' : machine_main_dic[m_name]['sourcefile'],\n+            'manufacturer' : machine_render_dic[m_name]['manufacturer'],\n+            'genre' : machine_render_dic[m_name]['genre'],\n+            'control_list' : control_list,\n+            'device_list' : device_list,\n+            'year' : machine_render_dic[m_name]['year'],\n+        }\n+        item_count += 1\n+    pDialog.update(100)\n+    pDialog.close()\n+\n+    return main_filter_dic\n+\n+# -------------------------------------------------------------------------------------------------\n+# String Parser (SP) engine. Grammar token objects.\n+# Parser inspired by http://effbot.org/zone/simple-top-down-parsing.htm\n+#\n+# SP operators: and, or, not, has, lacks, literal.\n+# -------------------------------------------------------------------------------------------------\n+debug_SP_parser = False\n+debug_SP_parse_exec = False\n+\n+class SP_literal_token:\n+    def __init__(self, value):\n+        self.value = value\n+        self.id = \"STRING\"\n+    def nud(self):\n+        return self\n+    def exec_token(self):\n+        if debug_SP_parser: log_debug('Executing LITERAL token value \"{0}\"'.format(self.value))\n+        ret = self.value\n+        if debug_SP_parser: log_debug('LITERAL token returns {0} \"{1}\"'.format(type(ret), unicode(ret)))\n+        return ret\n+    def __repr__(self):\n+        return '<LITERAL \"{0}\">'.format(self.value)\n+\n+class SP_operator_has_token:\n+    lbp = 50\n+    def __init__(self):\n+        self.id = \"OP HAS\"\n+    def nud(self):\n+        self.first = SP_expression(50)\n+        return self\n+    def exec_token(self):\n+        if debug_SP_parser: log_debug('Executing HAS token')\n+        ret = True if SP_parser_search_string.find(self.first.exec_token()) >= 0 else False\n+        if debug_SP_parser: log_debug('HAS token returns {0} \"{1}\"'.format(type(ret), unicode(ret)))\n+        return ret\n+    def __repr__(self):\n+        return \"<OP has>\"\n+\n+class SP_operator_lacks_token:\n+    lbp = 50\n+    def __init__(self):\n+        self.id = \"OP LACKS\"\n+    def nud(self):\n+        self.first = SP_expression(50)\n+        return self\n+    def exec_token(self):\n+        if debug_SP_parser: log_debug('Executing LACKS token')\n+        ret = False if SP_parser_search_string.find(self.first.exec_token()) >= 0 else True\n+        if debug_SP_parser: log_debug('LACKS token returns {0} \"{1}\"'.format(type(ret), unicode(ret)))\n+        return ret\n+    def __repr__(self):\n+        return \"<OP lacks>\"\n+\n+class SP_operator_not_token:\n+    lbp = 50\n+    def __init__(self):\n+        self.id = \"OP NOT\"\n+    def nud(self):\n+        self.first = SP_expression(50)\n+        return self\n+    def exec_token(self):\n+        if debug_SP_parser: log_debug('Executing NOT token')\n+        ret = not self.first.exec_token()\n+        if debug_SP_parser: log_debug('NOT token returns {0} \"{1}\"'.format(type(ret), unicode(ret)))\n+        return ret\n+    def __repr__(self):\n+        return \"<OP not>\"\n+\n+class SP_operator_and_token:\n+    lbp = 10\n+    def __init__(self):\n+        self.id = \"OP AND\"\n+    def led(self, left):\n+        if debug_SP_parser: log_debug('Executing AND token')\n+        self.first = left\n+        self.second = SP_expression(10)\n+        return self\n+    def exec_token(self):\n+        if debug_SP_parser: log_debug('Executing AND token')\n+        ret = self.first.exec_token() and self.second.exec_token()\n+        if debug_SP_parser: log_debug('AND token returns {0} \"{1}\"'.format(type(ret), unicode(ret)))\n+        return ret\n+    def __repr__(self):\n+        return \"<OP and>\"\n+\n+class SP_operator_or_token:\n+    lbp = 10\n+    def __init__(self):\n+        self.id = \"OP OR\"\n+    def led(self, left):\n+        self.first = left\n+        self.second = SP_expression(10)\n+        return self\n+    def exec_token(self):\n+        if debug_SP_parser: log_debug('Executing OR token')\n+        ret = self.first.exec_token() or self.second.exec_token()\n+        if debug_SP_parser: log_debug('OR token returns {0} \"{1}\"'.format(type(ret), unicode(ret)))\n+        return ret\n+    def __repr__(self):\n+        return \"<OP or>\"\n+\n+class SP_end_token:\n+    lbp = 0\n+    def __init__(self):\n+        self.id = \"END TOKEN\"\n+    def __repr__(self):\n+        return \"<END token>\"\n+\n+# -------------------------------------------------------------------------------------------------\n+# Tokenizer\n+# See http://jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/\n+# -------------------------------------------------------------------------------------------------\n+SP_token_pat = re.compile(\"\\s*(?:(and|or|not|has|lacks)|(\\\"[ \\.\\w_\\-\\&\\/]+\\\")|([\\.\\w_\\-\\&]+))\")\n+\n+def SP_tokenize(program):\n+    # \\s* -> Matches any number of blanks [ \\t\\n\\r\\f\\v].\n+    # (?:...) -> A non-capturing version of regular parentheses.\n+    # \\w -> Matches [a-zA-Z0-9_]\n+    for operator, q_string, string in SP_token_pat.findall(program):\n+        if string:\n+            yield SP_literal_token(string)\n+        elif q_string:\n+            if q_string[0] == '\"': q_string = q_string[1:]\n+            if q_string[-1] == '\"': q_string = q_string[:-1]\n+            yield SP_literal_token(q_string)\n+        elif operator == \"and\":\n+            yield SP_operator_and_token()\n+        elif operator == \"or\":\n+            yield SP_operator_or_token()\n+        elif operator == \"not\":\n+            yield SP_operator_not_token()\n+        elif operator == \"has\":\n+            yield SP_operator_has_token()\n+        elif operator == \"lacks\":\n+            yield SP_operator_lacks_token()\n+        else:\n+            raise SyntaxError(\"Unknown operator: '{0}'\".format(operator))\n+    yield SP_end_token()\n+\n+# -------------------------------------------------------------------------------------------------\n+# Manufacturer Parser (SP) inspired by http://effbot.org/zone/simple-top-down-parsing.htm\n+# -------------------------------------------------------------------------------------------------\n+def SP_expression(rbp = 0):\n+    global SP_token\n+\n+    t = SP_token\n+    SP_token = SP_next()\n+    left = t.nud()\n+    while rbp < SP_token.lbp:\n+        t = SP_token\n+        SP_token = SP_next()\n+        left = t.led(left)\n+    return left\n+\n+def SP_parse_exec(program, search_string):\n+    global SP_token, SP_next, SP_parser_search_string\n+\n+    if debug_SP_parse_exec:\n+        log_debug('SP_parse_exec() Initialising program execution')\n+        log_debug('SP_parse_exec() Search string \"{0}\"'.format(search_string))\n+        log_debug('SP_parse_exec() Program       \"{0}\"'.format(program))\n+    SP_parser_search_string = search_string\n+    SP_next = SP_tokenize(program).next\n+    SP_token = SP_next()\n+\n+    # --- Old function parse_exec() ---\n+    rbp = 0\n+    t = SP_token\n+    SP_token = SP_next()\n+    left = t.nud()\n+    while rbp < SP_token.lbp:\n+        t = SP_token\n+        SP_token = SP_next()\n+        left = t.led(left)\n+    if debug_SP_parse_exec:\n+        log_debug('SP_parse_exec() Init exec program in token {0}'.format(left))\n+\n+    return left.exec_token()\n+\n+# -------------------------------------------------------------------------------------------------\n+# List of String Parser (LSP) engine. Grammar token objects.\n+# Parser inspired by http://effbot.org/zone/simple-top-down-parsing.htm\n+#\n+# LSP operators: and, or, not, '(', ')', literal.\n+# -------------------------------------------------------------------------------------------------\n+debug_LSP_parser = False\n+debug_LSP_parse_exec = False\n+\n+class LSP_literal_token:\n+    def __init__(self, value):\n+        self.value = value\n+        self.id = \"STRING\"\n+    def nud(self):\n+        return self\n+    def exec_token(self):\n+        if debug_LSP_parser: log_debug('Executing LITERAL token value \"{0}\"'.format(self.value))\n+        ret = self.value\n+        if debug_LSP_parser: log_debug('LITERAL token returns {0} \"{1}\"'.format(type(ret), unicode(ret)))\n+        return ret\n+    def __repr__(self):\n+        return '<LITERAL \"{0}\">'.format(self.value)\n+\n+def LSP_advance(id = None):\n+    global LSP_token\n+\n+    if id and LSP_token.id != id:","path":"plugin.program.AML/resources/filters.py","position":430,"original_position":430,"commit_id":"8d74b8671cc47c2c35004bf47c333b1ce5cee70c","original_commit_id":"8d74b8671cc47c2c35004bf47c333b1ce5cee70c","user":{"login":"codacy-bot","id":19940114,"node_id":"MDQ6VXNlcjE5OTQwMTE0","avatar_url":"https://avatars1.githubusercontent.com/u/19940114?v=4","gravatar_id":"","url":"https://api.github.com/users/codacy-bot","html_url":"https://github.com/codacy-bot","followers_url":"https://api.github.com/users/codacy-bot/followers","following_url":"https://api.github.com/users/codacy-bot/following{/other_user}","gists_url":"https://api.github.com/users/codacy-bot/gists{/gist_id}","starred_url":"https://api.github.com/users/codacy-bot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codacy-bot/subscriptions","organizations_url":"https://api.github.com/users/codacy-bot/orgs","repos_url":"https://api.github.com/users/codacy-bot/repos","events_url":"https://api.github.com/users/codacy-bot/events{/privacy}","received_events_url":"https://api.github.com/users/codacy-bot/received_events","type":"User","site_admin":false},"body":"![Codacy](https://app.codacy.com/assets/images/favicon.png) Issue found: [Using variable 'LSP_token' before assignment](https://app.codacy.com/app/Kodi/repo-plugins/pullRequest?prid=1818299)","created_at":"2018-06-23T15:28:06Z","updated_at":"2018-06-23T15:28:07Z","html_url":"https://github.com/xbmc/repo-plugins/pull/1910#discussion_r197615283","pull_request_url":"https://api.github.com/repos/xbmc/repo-plugins/pulls/1910","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/xbmc/repo-plugins/pulls/comments/197615283"},"html":{"href":"https://github.com/xbmc/repo-plugins/pull/1910#discussion_r197615283"},"pull_request":{"href":"https://api.github.com/repos/xbmc/repo-plugins/pulls/1910"}}},"pull_request":{"url":"https://api.github.com/repos/xbmc/repo-plugins/pulls/1910","id":196898195,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk2ODk4MTk1","html_url":"https://github.com/xbmc/repo-plugins/pull/1910","diff_url":"https://github.com/xbmc/repo-plugins/pull/1910.diff","patch_url":"https://github.com/xbmc/repo-plugins/pull/1910.patch","issue_url":"https://api.github.com/repos/xbmc/repo-plugins/issues/1910","number":1910,"state":"open","locked":false,"title":"[plugin.program.AML] 0.9.8","user":{"login":"Wintermute0110","id":7764978,"node_id":"MDQ6VXNlcjc3NjQ5Nzg=","avatar_url":"https://avatars3.githubusercontent.com/u/7764978?v=4","gravatar_id":"","url":"https://api.github.com/users/Wintermute0110","html_url":"https://github.com/Wintermute0110","followers_url":"https://api.github.com/users/Wintermute0110/followers","following_url":"https://api.github.com/users/Wintermute0110/following{/other_user}","gists_url":"https://api.github.com/users/Wintermute0110/gists{/gist_id}","starred_url":"https://api.github.com/users/Wintermute0110/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Wintermute0110/subscriptions","organizations_url":"https://api.github.com/users/Wintermute0110/orgs","repos_url":"https://api.github.com/users/Wintermute0110/repos","events_url":"https://api.github.com/users/Wintermute0110/events{/privacy}","received_events_url":"https://api.github.com/users/Wintermute0110/received_events","type":"User","site_admin":false},"body":"### Description\r\n\r\nAdvanced MAME Launcher is a MAME front-end for Kodi. It has been developed over the last 18 months and I think is stable enough to be added to the Kodi official repository. More information about AML can be found in Github and in the Kodi Forum.\r\n\r\nCode has been reviewed and updated to meet Kodi repo standards in this [PR](https://github.com/xbmc/repo-plugins/pull/1886).\r\n\r\n### Checklist:\r\n- [x] My code follows the [add-on rules](http://kodi.wiki/view/Add-on_rules) and [piracy stance](http://kodi.wiki/view/Official:Forum_rules#Piracy_Policy) of this project. \r\n- [x] I have read the [CONTRIBUTING](https://github.com/xbmc/repo-plugins/blob/master/CONTRIBUTING.md) document\r\n- [x] Each add-on submission should be a single commit with using the following style: [plugin.video.foo] v1.0.0\r\n","created_at":"2018-06-23T11:54:32Z","updated_at":"2018-06-23T15:28:07Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d5577bc6bccbcfd9012be50701e7a7a76e08762a","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/xbmc/repo-plugins/pulls/1910/commits","review_comments_url":"https://api.github.com/repos/xbmc/repo-plugins/pulls/1910/comments","review_comment_url":"https://api.github.com/repos/xbmc/repo-plugins/pulls/comments{/number}","comments_url":"https://api.github.com/repos/xbmc/repo-plugins/issues/1910/comments","statuses_url":"https://api.github.com/repos/xbmc/repo-plugins/statuses/8d74b8671cc47c2c35004bf47c333b1ce5cee70c","head":{"label":"Wintermute0110:plugin.program.AML-0.9.8","ref":"plugin.program.AML-0.9.8","sha":"8d74b8671cc47c2c35004bf47c333b1ce5cee70c","user":{"login":"Wintermute0110","id":7764978,"node_id":"MDQ6VXNlcjc3NjQ5Nzg=","avatar_url":"https://avatars3.githubusercontent.com/u/7764978?v=4","gravatar_id":"","url":"https://api.github.com/users/Wintermute0110","html_url":"https://github.com/Wintermute0110","followers_url":"https://api.github.com/users/Wintermute0110/followers","following_url":"https://api.github.com/users/Wintermute0110/following{/other_user}","gists_url":"https://api.github.com/users/Wintermute0110/gists{/gist_id}","starred_url":"https://api.github.com/users/Wintermute0110/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Wintermute0110/subscriptions","organizations_url":"https://api.github.com/users/Wintermute0110/orgs","repos_url":"https://api.github.com/users/Wintermute0110/repos","events_url":"https://api.github.com/users/Wintermute0110/events{/privacy}","received_events_url":"https://api.github.com/users/Wintermute0110/received_events","type":"User","site_admin":false},"repo":{"id":134825619,"node_id":"MDEwOlJlcG9zaXRvcnkxMzQ4MjU2MTk=","name":"repo-plugins","full_name":"Wintermute0110/repo-plugins","owner":{"login":"Wintermute0110","id":7764978,"node_id":"MDQ6VXNlcjc3NjQ5Nzg=","avatar_url":"https://avatars3.githubusercontent.com/u/7764978?v=4","gravatar_id":"","url":"https://api.github.com/users/Wintermute0110","html_url":"https://github.com/Wintermute0110","followers_url":"https://api.github.com/users/Wintermute0110/followers","following_url":"https://api.github.com/users/Wintermute0110/following{/other_user}","gists_url":"https://api.github.com/users/Wintermute0110/gists{/gist_id}","starred_url":"https://api.github.com/users/Wintermute0110/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Wintermute0110/subscriptions","organizations_url":"https://api.github.com/users/Wintermute0110/orgs","repos_url":"https://api.github.com/users/Wintermute0110/repos","events_url":"https://api.github.com/users/Wintermute0110/events{/privacy}","received_events_url":"https://api.github.com/users/Wintermute0110/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Wintermute0110/repo-plugins","description":"Official source repository for Kodi plugin add-ons","fork":true,"url":"https://api.github.com/repos/Wintermute0110/repo-plugins","forks_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/forks","keys_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/teams","hooks_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/hooks","issue_events_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/issues/events{/number}","events_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/events","assignees_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/assignees{/user}","branches_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/branches{/branch}","tags_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/tags","blobs_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/git/refs{/sha}","trees_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/statuses/{sha}","languages_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/languages","stargazers_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/stargazers","contributors_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/contributors","subscribers_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/subscribers","subscription_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/subscription","commits_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/commits{/sha}","git_commits_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/git/commits{/sha}","comments_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/comments{/number}","issue_comment_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/issues/comments{/number}","contents_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/contents/{+path}","compare_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/merges","archive_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/downloads","issues_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/issues{/number}","pulls_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/pulls{/number}","milestones_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/milestones{/number}","notifications_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/labels{/name}","releases_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/releases{/id}","deployments_url":"https://api.github.com/repos/Wintermute0110/repo-plugins/deployments","created_at":"2018-05-25T08:13:45Z","updated_at":"2018-05-25T08:13:48Z","pushed_at":"2018-06-23T11:50:12Z","git_url":"git://github.com/Wintermute0110/repo-plugins.git","ssh_url":"git@github.com:Wintermute0110/repo-plugins.git","clone_url":"https://github.com/Wintermute0110/repo-plugins.git","svn_url":"https://github.com/Wintermute0110/repo-plugins","homepage":"","size":616563,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"xbmc:krypton","ref":"krypton","sha":"b35d4027b13ba85237899cdd2a9180824a583f56","user":{"login":"xbmc","id":199122,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE5OTEyMg==","avatar_url":"https://avatars2.githubusercontent.com/u/199122?v=4","gravatar_id":"","url":"https://api.github.com/users/xbmc","html_url":"https://github.com/xbmc","followers_url":"https://api.github.com/users/xbmc/followers","following_url":"https://api.github.com/users/xbmc/following{/other_user}","gists_url":"https://api.github.com/users/xbmc/gists{/gist_id}","starred_url":"https://api.github.com/users/xbmc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xbmc/subscriptions","organizations_url":"https://api.github.com/users/xbmc/orgs","repos_url":"https://api.github.com/users/xbmc/repos","events_url":"https://api.github.com/users/xbmc/events{/privacy}","received_events_url":"https://api.github.com/users/xbmc/received_events","type":"Organization","site_admin":false},"repo":{"id":25118538,"node_id":"MDEwOlJlcG9zaXRvcnkyNTExODUzOA==","name":"repo-plugins","full_name":"xbmc/repo-plugins","owner":{"login":"xbmc","id":199122,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE5OTEyMg==","avatar_url":"https://avatars2.githubusercontent.com/u/199122?v=4","gravatar_id":"","url":"https://api.github.com/users/xbmc","html_url":"https://github.com/xbmc","followers_url":"https://api.github.com/users/xbmc/followers","following_url":"https://api.github.com/users/xbmc/following{/other_user}","gists_url":"https://api.github.com/users/xbmc/gists{/gist_id}","starred_url":"https://api.github.com/users/xbmc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xbmc/subscriptions","organizations_url":"https://api.github.com/users/xbmc/orgs","repos_url":"https://api.github.com/users/xbmc/repos","events_url":"https://api.github.com/users/xbmc/events{/privacy}","received_events_url":"https://api.github.com/users/xbmc/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/xbmc/repo-plugins","description":"Official source repository for Kodi plugin add-ons","fork":false,"url":"https://api.github.com/repos/xbmc/repo-plugins","forks_url":"https://api.github.com/repos/xbmc/repo-plugins/forks","keys_url":"https://api.github.com/repos/xbmc/repo-plugins/keys{/key_id}","collaborators_url":"https://api.github.com/repos/xbmc/repo-plugins/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/xbmc/repo-plugins/teams","hooks_url":"https://api.github.com/repos/xbmc/repo-plugins/hooks","issue_events_url":"https://api.github.com/repos/xbmc/repo-plugins/issues/events{/number}","events_url":"https://api.github.com/repos/xbmc/repo-plugins/events","assignees_url":"https://api.github.com/repos/xbmc/repo-plugins/assignees{/user}","branches_url":"https://api.github.com/repos/xbmc/repo-plugins/branches{/branch}","tags_url":"https://api.github.com/repos/xbmc/repo-plugins/tags","blobs_url":"https://api.github.com/repos/xbmc/repo-plugins/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/xbmc/repo-plugins/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/xbmc/repo-plugins/git/refs{/sha}","trees_url":"https://api.github.com/repos/xbmc/repo-plugins/git/trees{/sha}","statuses_url":"https://api.github.com/repos/xbmc/repo-plugins/statuses/{sha}","languages_url":"https://api.github.com/repos/xbmc/repo-plugins/languages","stargazers_url":"https://api.github.com/repos/xbmc/repo-plugins/stargazers","contributors_url":"https://api.github.com/repos/xbmc/repo-plugins/contributors","subscribers_url":"https://api.github.com/repos/xbmc/repo-plugins/subscribers","subscription_url":"https://api.github.com/repos/xbmc/repo-plugins/subscription","commits_url":"https://api.github.com/repos/xbmc/repo-plugins/commits{/sha}","git_commits_url":"https://api.github.com/repos/xbmc/repo-plugins/git/commits{/sha}","comments_url":"https://api.github.com/repos/xbmc/repo-plugins/comments{/number}","issue_comment_url":"https://api.github.com/repos/xbmc/repo-plugins/issues/comments{/number}","contents_url":"https://api.github.com/repos/xbmc/repo-plugins/contents/{+path}","compare_url":"https://api.github.com/repos/xbmc/repo-plugins/compare/{base}...{head}","merges_url":"https://api.github.com/repos/xbmc/repo-plugins/merges","archive_url":"https://api.github.com/repos/xbmc/repo-plugins/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/xbmc/repo-plugins/downloads","issues_url":"https://api.github.com/repos/xbmc/repo-plugins/issues{/number}","pulls_url":"https://api.github.com/repos/xbmc/repo-plugins/pulls{/number}","milestones_url":"https://api.github.com/repos/xbmc/repo-plugins/milestones{/number}","notifications_url":"https://api.github.com/repos/xbmc/repo-plugins/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/xbmc/repo-plugins/labels{/name}","releases_url":"https://api.github.com/repos/xbmc/repo-plugins/releases{/id}","deployments_url":"https://api.github.com/repos/xbmc/repo-plugins/deployments","created_at":"2014-10-12T12:17:54Z","updated_at":"2018-06-17T01:24:02Z","pushed_at":"2018-06-23T15:15:55Z","git_url":"git://github.com/xbmc/repo-plugins.git","ssh_url":"git@github.com:xbmc/repo-plugins.git","clone_url":"https://github.com/xbmc/repo-plugins.git","svn_url":"https://github.com/xbmc/repo-plugins","homepage":"","size":625795,"stargazers_count":53,"watchers_count":53,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":250,"mirror_url":null,"archived":false,"open_issues_count":8,"license":null,"forks":250,"open_issues":8,"watchers":53,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/xbmc/repo-plugins/pulls/1910"},"html":{"href":"https://github.com/xbmc/repo-plugins/pull/1910"},"issue":{"href":"https://api.github.com/repos/xbmc/repo-plugins/issues/1910"},"comments":{"href":"https://api.github.com/repos/xbmc/repo-plugins/issues/1910/comments"},"review_comments":{"href":"https://api.github.com/repos/xbmc/repo-plugins/pulls/1910/comments"},"review_comment":{"href":"https://api.github.com/repos/xbmc/repo-plugins/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/xbmc/repo-plugins/pulls/1910/commits"},"statuses":{"href":"https://api.github.com/repos/xbmc/repo-plugins/statuses/8d74b8671cc47c2c35004bf47c333b1ce5cee70c"}},"author_association":"NONE"}}
{"actor":{"display_login":"codacy-bot"}}