{"action":"created","comment":{"url":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/comments/353573474","pull_request_review_id":326632131,"id":353573474,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDM1MzU3MzQ3NA==","diff_hunk":"@@ -104,6 +107,139 @@ def is_asleep(self):\n         return not self._is_not_asleep.is_set()\n \n \n+class ProcessingQueue(Queue.Queue, object):\n+    \"\"\"\n+    Queue of queues that processes a queue completely before moving on to the\n+    next queue. There's one queue per Section(). You need to initialize each\n+    section with add_section(section) first.\n+    Put tuples (count, item) into this queue, with count being the respective\n+    position of the item in the queue, starting with 0 (zero).\n+    (None, None) is the sentinel for a single queue being exhausted, added by\n+    put_sentinel()\n+    \"\"\"\n+    def _init(self, maxsize):\n+        self.queue = deque()\n+        self._sections = deque()\n+        self._queues = deque()\n+        self._current_section = None\n+        self._current_queue = None\n+        self._counter = 0\n+\n+    def _qsize(self):\n+        return self._current_queue._qsize() if self._current_queue else 0\n+\n+    def total_size(self):\n+        \"\"\"\n+        Return the approximate total size of all queues (not reliable!)\n+        \"\"\"\n+        self.mutex.acquire()\n+        n = sum(q._qsize() for q in self._queues) if self._queues else 0\n+        self.mutex.release()\n+        return n\n+\n+    def put(self, item, block=True, timeout=None):\n+        \"\"\"Put an item into the queue.\n+\n+        If optional args 'block' is true and 'timeout' is None (the default),\n+        block if necessary until a free slot is available. If 'timeout' is\n+        a non-negative number, it blocks at most 'timeout' seconds and raises\n+        the Full exception if no free slot was available within that time.\n+        Otherwise ('block' is false), put an item on the queue if a free slot\n+        is immediately available, else raise the Full exception ('timeout'\n+        is ignored in that case).\n+        \"\"\"\n+        self.not_full.acquire()\n+        try:\n+            if self.maxsize > 0:\n+                if not block:\n+                    if self._qsize() == self.maxsize:\n+                        raise Queue.Full\n+                elif timeout is None:\n+                    while self._qsize() == self.maxsize:\n+                        self.not_full.wait()\n+                elif timeout < 0:\n+                    raise ValueError(\"'timeout' must be a non-negative number\")\n+                else:\n+                    endtime = _time() + timeout\n+                    while self._qsize() == self.maxsize:\n+                        remaining = endtime - _time()\n+                        if remaining <= 0.0:\n+                            raise Queue.Full\n+                        self.not_full.wait(remaining)\n+            if self._put(item) == 0:\n+                # Only notify one waiting thread if this item is put into the\n+                # current queue\n+                self.not_empty.notify()\n+            self.unfinished_tasks += 1\n+        finally:\n+            self.not_full.release()\n+\n+    def _put(self, item):\n+        \"\"\"\n+        Returns the index of the section in whose subqueue we need to put the\n+        item into\n+        \"\"\"\n+        for i, section in enumerate(self._sections):\n+            if item[1]['section'] == section:\n+                self._queues[i]._put(item)\n+                break\n+        else:\n+            raise RuntimeError('Could not find section for item %s' % item[1])\n+        return i\n+\n+    def put_sentinel(self, section):\n+        \"\"\"\n+        Adds a new empty section as a sentinel. Call with an empty Section()\n+        object.\n+        Once the get()-method returns None, you've received the sentinel and\n+        you've thus exhausted the queue\n+        \"\"\"\n+        self.not_empty.acquire()\n+        try:\n+            section.number_of_items = 1\n+            self._add_section(section)\n+            # Add the actual sentinel to the queue we just added\n+            self._queues[-1]._put((None, None))\n+            self.unfinished_tasks += 1\n+            if len(self._queues) == 1:\n+                # queue was already exhausted!\n+                self.not_empty.notify()\n+        finally:\n+            self.not_empty.release()\n+\n+    def add_section(self, section):\n+        self.mutex.acquire()\n+        try:\n+            self._add_section(section)\n+        finally:\n+            self.mutex.release()\n+\n+    def _add_section(self, section):\n+        self._sections.append(section)\n+        self._queues.append(\n+            OrderedQueue(self.mutex) if section.plex_type == v.PLEX_TYPE_ALBUM\n+            else Queue.Queue())\n+        if self._current_section is None:\n+            self._switch_queues()\n+\n+    def _init_next_section(self):\n+        self._sections.popleft()\n+        self._queues.popleft()\n+        self._counter = 0\n+        self._switch_queues()\n+\n+    def _switch_queues(self):\n+        self._current_section = self._sections[0] if self._sections else None\n+        self._current_queue = self._queues[0] if self._queues else None\n+\n+    def _get(self):\n+        item = self._current_queue._get()  # Will block for OrderedQueue!","path":"resources/lib/backgroundthread.py","position":147,"original_position":147,"commit_id":"a7a4ddcb6d1525caf1e8d603d41b3a68c0efe054","original_commit_id":"a7a4ddcb6d1525caf1e8d603d41b3a68c0efe054","user":{"login":"croneter","id":4637940,"node_id":"MDQ6VXNlcjQ2Mzc5NDA=","avatar_url":"https://avatars3.githubusercontent.com/u/4637940?v=4","gravatar_id":"","url":"https://api.github.com/users/croneter","html_url":"https://github.com/croneter","followers_url":"https://api.github.com/users/croneter/followers","following_url":"https://api.github.com/users/croneter/following{/other_user}","gists_url":"https://api.github.com/users/croneter/gists{/gist_id}","starred_url":"https://api.github.com/users/croneter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/croneter/subscriptions","organizations_url":"https://api.github.com/users/croneter/orgs","repos_url":"https://api.github.com/users/croneter/repos","events_url":"https://api.github.com/users/croneter/events{/privacy}","received_events_url":"https://api.github.com/users/croneter/received_events","type":"User","site_admin":false},"body":"![Codacy](https://app.codacy.com/assets/images/favicon.png) Issue found: [Access to a protected member _get of a client class](https://app.codacy.com/app/croneter/PlexKodiConnect/pullRequest?prid=4612184)","created_at":"2019-12-04T06:51:59Z","updated_at":"2019-12-04T06:51:59Z","html_url":"https://github.com/croneter/PlexKodiConnect/pull/1075#discussion_r353573474","pull_request_url":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/1075","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/comments/353573474"},"html":{"href":"https://github.com/croneter/PlexKodiConnect/pull/1075#discussion_r353573474"},"pull_request":{"href":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/1075"}}},"pull_request":{"url":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/1075","id":348722711,"node_id":"MDExOlB1bGxSZXF1ZXN0MzQ4NzIyNzEx","html_url":"https://github.com/croneter/PlexKodiConnect/pull/1075","diff_url":"https://github.com/croneter/PlexKodiConnect/pull/1075.diff","patch_url":"https://github.com/croneter/PlexKodiConnect/pull/1075.patch","issue_url":"https://api.github.com/repos/croneter/PlexKodiConnect/issues/1075","number":1075,"state":"open","locked":false,"title":"Rewire library sync to speed it up and fix sync getting stuck in rare cases","user":{"login":"croneter","id":4637940,"node_id":"MDQ6VXNlcjQ2Mzc5NDA=","avatar_url":"https://avatars3.githubusercontent.com/u/4637940?v=4","gravatar_id":"","url":"https://api.github.com/users/croneter","html_url":"https://github.com/croneter","followers_url":"https://api.github.com/users/croneter/followers","following_url":"https://api.github.com/users/croneter/following{/other_user}","gists_url":"https://api.github.com/users/croneter/gists{/gist_id}","starred_url":"https://api.github.com/users/croneter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/croneter/subscriptions","organizations_url":"https://api.github.com/users/croneter/orgs","repos_url":"https://api.github.com/users/croneter/repos","events_url":"https://api.github.com/users/croneter/events{/privacy}","received_events_url":"https://api.github.com/users/croneter/received_events","type":"User","site_admin":false},"body":"Supersedes https://github.com/croneter/PlexKodiConnect/pull/1067","created_at":"2019-12-04T06:48:31Z","updated_at":"2019-12-04T06:51:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7414a89f4d8a269616b96483a7b589f7311f296b","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/1075/commits","review_comments_url":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/1075/comments","review_comment_url":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/comments{/number}","comments_url":"https://api.github.com/repos/croneter/PlexKodiConnect/issues/1075/comments","statuses_url":"https://api.github.com/repos/croneter/PlexKodiConnect/statuses/a7a4ddcb6d1525caf1e8d603d41b3a68c0efe054","head":{"label":"croneter:improve-sync","ref":"improve-sync","sha":"a7a4ddcb6d1525caf1e8d603d41b3a68c0efe054","user":{"login":"croneter","id":4637940,"node_id":"MDQ6VXNlcjQ2Mzc5NDA=","avatar_url":"https://avatars3.githubusercontent.com/u/4637940?v=4","gravatar_id":"","url":"https://api.github.com/users/croneter","html_url":"https://github.com/croneter","followers_url":"https://api.github.com/users/croneter/followers","following_url":"https://api.github.com/users/croneter/following{/other_user}","gists_url":"https://api.github.com/users/croneter/gists{/gist_id}","starred_url":"https://api.github.com/users/croneter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/croneter/subscriptions","organizations_url":"https://api.github.com/users/croneter/orgs","repos_url":"https://api.github.com/users/croneter/repos","events_url":"https://api.github.com/users/croneter/events{/privacy}","received_events_url":"https://api.github.com/users/croneter/received_events","type":"User","site_admin":false},"repo":{"id":48641539,"node_id":"MDEwOlJlcG9zaXRvcnk0ODY0MTUzOQ==","name":"PlexKodiConnect","full_name":"croneter/PlexKodiConnect","private":false,"owner":{"login":"croneter","id":4637940,"node_id":"MDQ6VXNlcjQ2Mzc5NDA=","avatar_url":"https://avatars3.githubusercontent.com/u/4637940?v=4","gravatar_id":"","url":"https://api.github.com/users/croneter","html_url":"https://github.com/croneter","followers_url":"https://api.github.com/users/croneter/followers","following_url":"https://api.github.com/users/croneter/following{/other_user}","gists_url":"https://api.github.com/users/croneter/gists{/gist_id}","starred_url":"https://api.github.com/users/croneter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/croneter/subscriptions","organizations_url":"https://api.github.com/users/croneter/orgs","repos_url":"https://api.github.com/users/croneter/repos","events_url":"https://api.github.com/users/croneter/events{/privacy}","received_events_url":"https://api.github.com/users/croneter/received_events","type":"User","site_admin":false},"html_url":"https://github.com/croneter/PlexKodiConnect","description":"Plex integration in Kodi done right","fork":true,"url":"https://api.github.com/repos/croneter/PlexKodiConnect","forks_url":"https://api.github.com/repos/croneter/PlexKodiConnect/forks","keys_url":"https://api.github.com/repos/croneter/PlexKodiConnect/keys{/key_id}","collaborators_url":"https://api.github.com/repos/croneter/PlexKodiConnect/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/croneter/PlexKodiConnect/teams","hooks_url":"https://api.github.com/repos/croneter/PlexKodiConnect/hooks","issue_events_url":"https://api.github.com/repos/croneter/PlexKodiConnect/issues/events{/number}","events_url":"https://api.github.com/repos/croneter/PlexKodiConnect/events","assignees_url":"https://api.github.com/repos/croneter/PlexKodiConnect/assignees{/user}","branches_url":"https://api.github.com/repos/croneter/PlexKodiConnect/branches{/branch}","tags_url":"https://api.github.com/repos/croneter/PlexKodiConnect/tags","blobs_url":"https://api.github.com/repos/croneter/PlexKodiConnect/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/croneter/PlexKodiConnect/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/croneter/PlexKodiConnect/git/refs{/sha}","trees_url":"https://api.github.com/repos/croneter/PlexKodiConnect/git/trees{/sha}","statuses_url":"https://api.github.com/repos/croneter/PlexKodiConnect/statuses/{sha}","languages_url":"https://api.github.com/repos/croneter/PlexKodiConnect/languages","stargazers_url":"https://api.github.com/repos/croneter/PlexKodiConnect/stargazers","contributors_url":"https://api.github.com/repos/croneter/PlexKodiConnect/contributors","subscribers_url":"https://api.github.com/repos/croneter/PlexKodiConnect/subscribers","subscription_url":"https://api.github.com/repos/croneter/PlexKodiConnect/subscription","commits_url":"https://api.github.com/repos/croneter/PlexKodiConnect/commits{/sha}","git_commits_url":"https://api.github.com/repos/croneter/PlexKodiConnect/git/commits{/sha}","comments_url":"https://api.github.com/repos/croneter/PlexKodiConnect/comments{/number}","issue_comment_url":"https://api.github.com/repos/croneter/PlexKodiConnect/issues/comments{/number}","contents_url":"https://api.github.com/repos/croneter/PlexKodiConnect/contents/{+path}","compare_url":"https://api.github.com/repos/croneter/PlexKodiConnect/compare/{base}...{head}","merges_url":"https://api.github.com/repos/croneter/PlexKodiConnect/merges","archive_url":"https://api.github.com/repos/croneter/PlexKodiConnect/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/croneter/PlexKodiConnect/downloads","issues_url":"https://api.github.com/repos/croneter/PlexKodiConnect/issues{/number}","pulls_url":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls{/number}","milestones_url":"https://api.github.com/repos/croneter/PlexKodiConnect/milestones{/number}","notifications_url":"https://api.github.com/repos/croneter/PlexKodiConnect/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/croneter/PlexKodiConnect/labels{/name}","releases_url":"https://api.github.com/repos/croneter/PlexKodiConnect/releases{/id}","deployments_url":"https://api.github.com/repos/croneter/PlexKodiConnect/deployments","created_at":"2015-12-27T10:43:05Z","updated_at":"2019-11-30T20:56:19Z","pushed_at":"2019-12-04T06:51:49Z","git_url":"git://github.com/croneter/PlexKodiConnect.git","ssh_url":"git@github.com:croneter/PlexKodiConnect.git","clone_url":"https://github.com/croneter/PlexKodiConnect.git","svn_url":"https://github.com/croneter/PlexKodiConnect","homepage":"","size":14240,"stargazers_count":575,"watchers_count":575,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":58,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":25,"license":{"key":"gpl-2.0","name":"GNU General Public License v2.0","spdx_id":"GPL-2.0","url":"https://api.github.com/licenses/gpl-2.0","node_id":"MDc6TGljZW5zZTg="},"forks":58,"open_issues":25,"watchers":575,"default_branch":"master"}},"base":{"label":"croneter:beta-version","ref":"beta-version","sha":"f4ea051c81d8c844601210bd276baf3e931c3e4a","user":{"login":"croneter","id":4637940,"node_id":"MDQ6VXNlcjQ2Mzc5NDA=","avatar_url":"https://avatars3.githubusercontent.com/u/4637940?v=4","gravatar_id":"","url":"https://api.github.com/users/croneter","html_url":"https://github.com/croneter","followers_url":"https://api.github.com/users/croneter/followers","following_url":"https://api.github.com/users/croneter/following{/other_user}","gists_url":"https://api.github.com/users/croneter/gists{/gist_id}","starred_url":"https://api.github.com/users/croneter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/croneter/subscriptions","organizations_url":"https://api.github.com/users/croneter/orgs","repos_url":"https://api.github.com/users/croneter/repos","events_url":"https://api.github.com/users/croneter/events{/privacy}","received_events_url":"https://api.github.com/users/croneter/received_events","type":"User","site_admin":false},"repo":{"id":48641539,"node_id":"MDEwOlJlcG9zaXRvcnk0ODY0MTUzOQ==","name":"PlexKodiConnect","full_name":"croneter/PlexKodiConnect","private":false,"owner":{"login":"croneter","id":4637940,"node_id":"MDQ6VXNlcjQ2Mzc5NDA=","avatar_url":"https://avatars3.githubusercontent.com/u/4637940?v=4","gravatar_id":"","url":"https://api.github.com/users/croneter","html_url":"https://github.com/croneter","followers_url":"https://api.github.com/users/croneter/followers","following_url":"https://api.github.com/users/croneter/following{/other_user}","gists_url":"https://api.github.com/users/croneter/gists{/gist_id}","starred_url":"https://api.github.com/users/croneter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/croneter/subscriptions","organizations_url":"https://api.github.com/users/croneter/orgs","repos_url":"https://api.github.com/users/croneter/repos","events_url":"https://api.github.com/users/croneter/events{/privacy}","received_events_url":"https://api.github.com/users/croneter/received_events","type":"User","site_admin":false},"html_url":"https://github.com/croneter/PlexKodiConnect","description":"Plex integration in Kodi done right","fork":true,"url":"https://api.github.com/repos/croneter/PlexKodiConnect","forks_url":"https://api.github.com/repos/croneter/PlexKodiConnect/forks","keys_url":"https://api.github.com/repos/croneter/PlexKodiConnect/keys{/key_id}","collaborators_url":"https://api.github.com/repos/croneter/PlexKodiConnect/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/croneter/PlexKodiConnect/teams","hooks_url":"https://api.github.com/repos/croneter/PlexKodiConnect/hooks","issue_events_url":"https://api.github.com/repos/croneter/PlexKodiConnect/issues/events{/number}","events_url":"https://api.github.com/repos/croneter/PlexKodiConnect/events","assignees_url":"https://api.github.com/repos/croneter/PlexKodiConnect/assignees{/user}","branches_url":"https://api.github.com/repos/croneter/PlexKodiConnect/branches{/branch}","tags_url":"https://api.github.com/repos/croneter/PlexKodiConnect/tags","blobs_url":"https://api.github.com/repos/croneter/PlexKodiConnect/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/croneter/PlexKodiConnect/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/croneter/PlexKodiConnect/git/refs{/sha}","trees_url":"https://api.github.com/repos/croneter/PlexKodiConnect/git/trees{/sha}","statuses_url":"https://api.github.com/repos/croneter/PlexKodiConnect/statuses/{sha}","languages_url":"https://api.github.com/repos/croneter/PlexKodiConnect/languages","stargazers_url":"https://api.github.com/repos/croneter/PlexKodiConnect/stargazers","contributors_url":"https://api.github.com/repos/croneter/PlexKodiConnect/contributors","subscribers_url":"https://api.github.com/repos/croneter/PlexKodiConnect/subscribers","subscription_url":"https://api.github.com/repos/croneter/PlexKodiConnect/subscription","commits_url":"https://api.github.com/repos/croneter/PlexKodiConnect/commits{/sha}","git_commits_url":"https://api.github.com/repos/croneter/PlexKodiConnect/git/commits{/sha}","comments_url":"https://api.github.com/repos/croneter/PlexKodiConnect/comments{/number}","issue_comment_url":"https://api.github.com/repos/croneter/PlexKodiConnect/issues/comments{/number}","contents_url":"https://api.github.com/repos/croneter/PlexKodiConnect/contents/{+path}","compare_url":"https://api.github.com/repos/croneter/PlexKodiConnect/compare/{base}...{head}","merges_url":"https://api.github.com/repos/croneter/PlexKodiConnect/merges","archive_url":"https://api.github.com/repos/croneter/PlexKodiConnect/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/croneter/PlexKodiConnect/downloads","issues_url":"https://api.github.com/repos/croneter/PlexKodiConnect/issues{/number}","pulls_url":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls{/number}","milestones_url":"https://api.github.com/repos/croneter/PlexKodiConnect/milestones{/number}","notifications_url":"https://api.github.com/repos/croneter/PlexKodiConnect/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/croneter/PlexKodiConnect/labels{/name}","releases_url":"https://api.github.com/repos/croneter/PlexKodiConnect/releases{/id}","deployments_url":"https://api.github.com/repos/croneter/PlexKodiConnect/deployments","created_at":"2015-12-27T10:43:05Z","updated_at":"2019-11-30T20:56:19Z","pushed_at":"2019-12-04T06:51:49Z","git_url":"git://github.com/croneter/PlexKodiConnect.git","ssh_url":"git@github.com:croneter/PlexKodiConnect.git","clone_url":"https://github.com/croneter/PlexKodiConnect.git","svn_url":"https://github.com/croneter/PlexKodiConnect","homepage":"","size":14240,"stargazers_count":575,"watchers_count":575,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":58,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":25,"license":{"key":"gpl-2.0","name":"GNU General Public License v2.0","spdx_id":"GPL-2.0","url":"https://api.github.com/licenses/gpl-2.0","node_id":"MDc6TGljZW5zZTg="},"forks":58,"open_issues":25,"watchers":575,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/1075"},"html":{"href":"https://github.com/croneter/PlexKodiConnect/pull/1075"},"issue":{"href":"https://api.github.com/repos/croneter/PlexKodiConnect/issues/1075"},"comments":{"href":"https://api.github.com/repos/croneter/PlexKodiConnect/issues/1075/comments"},"review_comments":{"href":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/1075/comments"},"review_comment":{"href":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/croneter/PlexKodiConnect/pulls/1075/commits"},"statuses":{"href":"https://api.github.com/repos/croneter/PlexKodiConnect/statuses/a7a4ddcb6d1525caf1e8d603d41b3a68c0efe054"}},"author_association":"OWNER"}}
{"actor":{"display_login":"croneter"}}