{"action":"created","comment":{"url":"https://api.github.com/repos/quodlibet/mutagen/pulls/comments/134199846","pull_request_review_id":57462505,"id":134199846,"diff_hunk":"@@ -0,0 +1,369 @@\n+# -*- coding: utf-8 -*-\n+# Copyright (C) 2017  Borewit\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; either version 2 of the License, or\n+# (at your option) any later version.\n+\n+\"\"\"Microsoft WAVE/RIFF audio file/stream information and tags.\"\"\"\n+\n+import sys\n+import struct\n+from struct import pack\n+\n+from ._compat import endswith, reraise\n+\n+from mutagen import StreamInfo, FileType\n+\n+from mutagen.id3 import ID3\n+from mutagen._riff import RiffFile, RiffChunkHeader\n+from mutagen.id3._util import ID3NoHeaderError, error as ID3Error\n+from mutagen._util import resize_bytes, delete_bytes, MutagenError, loadfile, \\\n+    convert_error\n+\n+__all__ = [\"WAVE\", \"Open\", \"delete\"]\n+\n+\n+class error(MutagenError):\n+    pass\n+\n+\n+class InvalidChunk(error):\n+    pass\n+\n+\n+def is_valid_chunk_id(id):\n+    # looks like this is failing if python is not started with -bb in TravisCI:\n+    # assert isinstance(id, text_type)\n+\n+    return ((len(id) <= 4) and (min(id) >= u' ') and\n+            (max(id) <= u'~'))\n+\n+\n+def assert_valid_chunk_id(id):\n+    if not is_valid_chunk_id(id):\n+        raise KeyError(\"RIFF/WAVE-chunk-Id must be four ASCII characters.\")\n+\n+\n+class WaveChunk(object):\n+    \"\"\"Representation of a common WaveChunk\"\"\"\n+\n+    #  Chunk headers are 8 bytes long (4 for ID and 4 for the size)\n+    HEADER_SIZE = 8\n+\n+    def __init__(self, fileobj, parent_chunk=None):\n+        self.__fileobj = fileobj\n+        self.parent_chunk = parent_chunk\n+        self.offset = fileobj.tell()\n+\n+        header = fileobj.read(self.HEADER_SIZE)\n+        if len(header) < self.HEADER_SIZE:\n+            raise InvalidChunk()\n+\n+        self.id, self.data_size = struct.unpack('<4sI', header)\n+\n+        try:\n+            self.id = self.id.decode('ascii')\n+        except UnicodeDecodeError:\n+            raise InvalidChunk()\n+\n+        if not is_valid_chunk_id(self.id):\n+            raise InvalidChunk()\n+\n+        self.size = self.HEADER_SIZE + self.data_size\n+        self.data_offset = fileobj.tell()\n+\n+    def read(self):\n+        \"\"\"Read the chunks data\"\"\"\n+\n+        self.__fileobj.seek(self.data_offset)\n+        return self.__fileobj.read(self.data_size)\n+\n+    def write(self, data):\n+        \"\"\"Write the chunk data\"\"\"\n+\n+        if len(data) > self.data_size:\n+            raise ValueError\n+\n+        self.__fileobj.seek(self.data_offset)\n+        self.__fileobj.write(data)\n+\n+    def delete(self):\n+        \"\"\"Removes the chunk from the file\"\"\"\n+\n+        delete_bytes(self.__fileobj, self.size, self.offset)\n+        if self.parent_chunk is not None:\n+            self.parent_chunk._update_size(\n+                self.parent_chunk.data_size - self.size)\n+\n+    def _update_size(self, data_size):\n+        \"\"\"Update the size of the chunk\"\"\"\n+\n+        self.__fileobj.seek(self.offset + 4)\n+        self.__fileobj.write(pack('>I', data_size))\n+        if self.parent_chunk is not None:\n+            size_diff = self.data_size - data_size\n+            self.parent_chunk._update_size(\n+                self.parent_chunk.data_size - size_diff)\n+        self.data_size = data_size\n+        self.size = data_size + self.HEADER_SIZE\n+\n+    def resize(self, new_data_size):\n+        \"\"\"Resize the file and update the chunk sizes\"\"\"\n+\n+        resize_bytes(\n+            self.__fileobj, self.data_size, new_data_size, self.data_offset)\n+        self._update_size(new_data_size)\n+\n+\n+class WaveFile(RiffFile):\n+    \"\"\"Representation of a RIFF/WAVE file\"\"\"\n+\n+    def __init__(self, fileobj):\n+        RiffFile.__init__(self, fileobj)\n+\n+        if self.fileType != u'WAVE':\n+            raise KeyError(\"Expected RIFF/WAVE.\")\n+\n+        self.__wavChunks = {}\n+\n+        # RIFF Files always start with the RIFF chunk which contains a 4 byte\n+        # ID before the start of other chunks\n+        fileobj.seek(0)\n+        self.__wavChunks[u'RIFF'] = RiffChunkHeader(fileobj)\n+\n+        # Skip past the 4 byte chunk id ('RIFF')\n+        fileobj.seek(RiffChunkHeader.HEADER_SIZE + 4)\n+\n+        # Where the next chunk can be located. We need to keep track of this\n+        # since the size indicated in the RIFF header may not match up with the\n+        # offset determined from the size of the last chunk in the file\n+        self.__next_offset = fileobj.tell()\n+\n+        # Load all of the chunks\n+        while True:\n+            try:\n+                chunk = WaveChunk(fileobj, self[u'RIFF'])\n+            except InvalidChunk:\n+                break\n+            # Normalize ID3v2-tag-chunk to lowercase\n+            if chunk.id == u'ID3 ':\n+                chunk.id = u'id3 '\n+            self.__wavChunks[chunk.id] = chunk\n+\n+            # Calculate the location of the next chunk,\n+            # considering the pad byte\n+            self.__next_offset = chunk.offset + chunk.size\n+            self.__next_offset += self.__next_offset % 2\n+            fileobj.seek(self.__next_offset)\n+\n+    def __contains__(self, id_):\n+        \"\"\"Check if the RIFF/WAVE file contains a specific chunk\"\"\"\n+\n+        assert_valid_chunk_id(id_)\n+\n+        return id_ in self.__wavChunks\n+\n+    def __getitem__(self, id_):\n+        \"\"\"Get a chunk from the RIFF/WAVE file\"\"\"\n+\n+        assert_valid_chunk_id(id_)\n+\n+        try:\n+            return self.__wavChunks[id_]\n+        except KeyError:\n+            raise KeyError(\n+                \"%r has no %r chunk\" % (self._fileobj, id_))\n+\n+    def __delitem__(self, id_):\n+        \"\"\"Remove a chunk from the RIFF/WAVE file\"\"\"\n+\n+        assert_valid_chunk_id(id_)\n+\n+        self.__wavChunks.pop(id_).delete()\n+\n+    def insert_chunk(self, id_):\n+        \"\"\"Insert a new chunk at the end of the RIFF/WAVE file\"\"\"\n+\n+        assert_valid_chunk_id(id_)\n+\n+        self._fileobj.seek(self.__next_offset)\n+        self._fileobj.write(pack('<4si', id_.ljust(4).encode('ascii'), 0))\n+        self._fileobj.seek(self.__next_offset)\n+        chunk = RiffChunkHeader(self._fileobj)\n+        self[u'RIFF']._update_size(self[u'RIFF'].data_size + chunk.size)\n+\n+        self.__wavChunks[id_] = chunk\n+        self.__next_offset = chunk.offset + chunk.size\n+\n+\n+class WaveStreamInfo(StreamInfo):\n+    \"\"\"WaveStreamInfo()\n+\n+    Microsoft WAVE file information.\n+\n+    Information is parsed from the 'fmt ' & 'data'chunk of the RIFF/WAVE file\n+\n+    Attributes:\n+        length (`float`): audio length, in seconds\n+        bitrate (`int`): audio bitrate, in bits per second\n+        channels (`int`): The number of audio channels\n+        sample_rate (`int`): audio sample rate, in Hz\n+        sample_size (`int`): The audio sample size\n+    \"\"\"\n+\n+    length = 0\n+    bitrate = 0\n+    channels = 0\n+    sample_rate = 0\n+\n+    @convert_error(IOError, error)\n+    def __init__(self, fileobj):\n+        \"\"\"Raises error\"\"\"\n+\n+        waveFile = WaveFile(fileobj)\n+        try:\n+            waveFormatChunk = waveFile[u'fmt ']\n+        except KeyError as e:\n+            raise error(str(e))\n+\n+        data = waveFormatChunk.read()\n+\n+        #  RIFF: http://soundfile.sapp.org/doc/WaveFormat/\n+        #  Python struct.unpack:\n+        #    https://docs.python.org/2/library/struct.html#byte-order-size-and-alignment\n+        info = struct.unpack('<hhLLhh', data[:16])\n+        self.audioFormat, self.channels, self.sample_rate, byte_rate, \\\n+            block_align, self.sample_size = info\n+        self.bitrate = self.channels * block_align * self.sample_rate\n+\n+        try:\n+            waveDataChunk = waveFile[u'data']","path":"mutagen/wave.py","position":242,"original_position":242,"commit_id":"65dd01ecbe76c1108ebe0fc18994eda1eb7b60c8","original_commit_id":"65dd01ecbe76c1108ebe0fc18994eda1eb7b60c8","user":{"login":"lazka","id":991986,"avatar_url":"https://avatars2.githubusercontent.com/u/991986?v=4","gravatar_id":"","url":"https://api.github.com/users/lazka","html_url":"https://github.com/lazka","followers_url":"https://api.github.com/users/lazka/followers","following_url":"https://api.github.com/users/lazka/following{/other_user}","gists_url":"https://api.github.com/users/lazka/gists{/gist_id}","starred_url":"https://api.github.com/users/lazka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lazka/subscriptions","organizations_url":"https://api.github.com/users/lazka/orgs","repos_url":"https://api.github.com/users/lazka/repos","events_url":"https://api.github.com/users/lazka/events{/privacy}","received_events_url":"https://api.github.com/users/lazka/received_events","type":"User","site_admin":false},"body":"ah, right, I missed that","created_at":"2017-08-21T10:39:59Z","updated_at":"2017-08-21T10:39:59Z","html_url":"https://github.com/quodlibet/mutagen/pull/321#discussion_r134199846","pull_request_url":"https://api.github.com/repos/quodlibet/mutagen/pulls/321","_links":{"self":{"href":"https://api.github.com/repos/quodlibet/mutagen/pulls/comments/134199846"},"html":{"href":"https://github.com/quodlibet/mutagen/pull/321#discussion_r134199846"},"pull_request":{"href":"https://api.github.com/repos/quodlibet/mutagen/pulls/321"}}},"pull_request":{"url":"https://api.github.com/repos/quodlibet/mutagen/pulls/321","id":136320252,"html_url":"https://github.com/quodlibet/mutagen/pull/321","diff_url":"https://github.com/quodlibet/mutagen/pull/321.diff","patch_url":"https://github.com/quodlibet/mutagen/pull/321.patch","issue_url":"https://api.github.com/repos/quodlibet/mutagen/issues/321","number":321,"state":"open","locked":false,"title":"RIFF/WAVE support, using ID3v2 ","user":{"login":"Borewit","id":23255260,"avatar_url":"https://avatars0.githubusercontent.com/u/23255260?v=4","gravatar_id":"","url":"https://api.github.com/users/Borewit","html_url":"https://github.com/Borewit","followers_url":"https://api.github.com/users/Borewit/followers","following_url":"https://api.github.com/users/Borewit/following{/other_user}","gists_url":"https://api.github.com/users/Borewit/gists{/gist_id}","starred_url":"https://api.github.com/users/Borewit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Borewit/subscriptions","organizations_url":"https://api.github.com/users/Borewit/orgs","repos_url":"https://api.github.com/users/Borewit/repos","events_url":"https://api.github.com/users/Borewit/events{/privacy}","received_events_url":"https://api.github.com/users/Borewit/received_events","type":"User","site_admin":false},"body":"Initial implementation of RIFF/WAVE format.\r\n\r\nCurrently using ID3v2 tag chunk to store metadata.\r\n\r\nStoring metadata in the RIFF/INFO tag is still something which needs to be done.\r\n\r\nRelated issues: \r\n* #207: Support RIFF INFO chunk metadata (AVI, WAV, XMA, xWMA, RMI, DLS) \r\n* [PICARD-1128: Support Microsoft WAVE format (RIFF/WAVE) tagging](https://tickets.metabrainz.org/browse/PICARD-1128?jql=text%20~%20%22RIFF%22)\r\n* Borewit/music-metadata#19\r\n\r\n","created_at":"2017-08-17T18:14:35Z","updated_at":"2017-08-21T10:39:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5b8909d85869eb1ab8dbc49e69d381ff1afe2423","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/quodlibet/mutagen/pulls/321/commits","review_comments_url":"https://api.github.com/repos/quodlibet/mutagen/pulls/321/comments","review_comment_url":"https://api.github.com/repos/quodlibet/mutagen/pulls/comments{/number}","comments_url":"https://api.github.com/repos/quodlibet/mutagen/issues/321/comments","statuses_url":"https://api.github.com/repos/quodlibet/mutagen/statuses/65dd01ecbe76c1108ebe0fc18994eda1eb7b60c8","head":{"label":"Borewit:feature/riff-wave","ref":"feature/riff-wave","sha":"65dd01ecbe76c1108ebe0fc18994eda1eb7b60c8","user":{"login":"Borewit","id":23255260,"avatar_url":"https://avatars0.githubusercontent.com/u/23255260?v=4","gravatar_id":"","url":"https://api.github.com/users/Borewit","html_url":"https://github.com/Borewit","followers_url":"https://api.github.com/users/Borewit/followers","following_url":"https://api.github.com/users/Borewit/following{/other_user}","gists_url":"https://api.github.com/users/Borewit/gists{/gist_id}","starred_url":"https://api.github.com/users/Borewit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Borewit/subscriptions","organizations_url":"https://api.github.com/users/Borewit/orgs","repos_url":"https://api.github.com/users/Borewit/repos","events_url":"https://api.github.com/users/Borewit/events{/privacy}","received_events_url":"https://api.github.com/users/Borewit/received_events","type":"User","site_admin":false},"repo":{"id":100121084,"name":"mutagen","full_name":"Borewit/mutagen","owner":{"login":"Borewit","id":23255260,"avatar_url":"https://avatars0.githubusercontent.com/u/23255260?v=4","gravatar_id":"","url":"https://api.github.com/users/Borewit","html_url":"https://github.com/Borewit","followers_url":"https://api.github.com/users/Borewit/followers","following_url":"https://api.github.com/users/Borewit/following{/other_user}","gists_url":"https://api.github.com/users/Borewit/gists{/gist_id}","starred_url":"https://api.github.com/users/Borewit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Borewit/subscriptions","organizations_url":"https://api.github.com/users/Borewit/orgs","repos_url":"https://api.github.com/users/Borewit/repos","events_url":"https://api.github.com/users/Borewit/events{/privacy}","received_events_url":"https://api.github.com/users/Borewit/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Borewit/mutagen","description":"Python 2/3 module for handling audio metadata","fork":true,"url":"https://api.github.com/repos/Borewit/mutagen","forks_url":"https://api.github.com/repos/Borewit/mutagen/forks","keys_url":"https://api.github.com/repos/Borewit/mutagen/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Borewit/mutagen/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Borewit/mutagen/teams","hooks_url":"https://api.github.com/repos/Borewit/mutagen/hooks","issue_events_url":"https://api.github.com/repos/Borewit/mutagen/issues/events{/number}","events_url":"https://api.github.com/repos/Borewit/mutagen/events","assignees_url":"https://api.github.com/repos/Borewit/mutagen/assignees{/user}","branches_url":"https://api.github.com/repos/Borewit/mutagen/branches{/branch}","tags_url":"https://api.github.com/repos/Borewit/mutagen/tags","blobs_url":"https://api.github.com/repos/Borewit/mutagen/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Borewit/mutagen/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Borewit/mutagen/git/refs{/sha}","trees_url":"https://api.github.com/repos/Borewit/mutagen/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Borewit/mutagen/statuses/{sha}","languages_url":"https://api.github.com/repos/Borewit/mutagen/languages","stargazers_url":"https://api.github.com/repos/Borewit/mutagen/stargazers","contributors_url":"https://api.github.com/repos/Borewit/mutagen/contributors","subscribers_url":"https://api.github.com/repos/Borewit/mutagen/subscribers","subscription_url":"https://api.github.com/repos/Borewit/mutagen/subscription","commits_url":"https://api.github.com/repos/Borewit/mutagen/commits{/sha}","git_commits_url":"https://api.github.com/repos/Borewit/mutagen/git/commits{/sha}","comments_url":"https://api.github.com/repos/Borewit/mutagen/comments{/number}","issue_comment_url":"https://api.github.com/repos/Borewit/mutagen/issues/comments{/number}","contents_url":"https://api.github.com/repos/Borewit/mutagen/contents/{+path}","compare_url":"https://api.github.com/repos/Borewit/mutagen/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Borewit/mutagen/merges","archive_url":"https://api.github.com/repos/Borewit/mutagen/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Borewit/mutagen/downloads","issues_url":"https://api.github.com/repos/Borewit/mutagen/issues{/number}","pulls_url":"https://api.github.com/repos/Borewit/mutagen/pulls{/number}","milestones_url":"https://api.github.com/repos/Borewit/mutagen/milestones{/number}","notifications_url":"https://api.github.com/repos/Borewit/mutagen/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Borewit/mutagen/labels{/name}","releases_url":"https://api.github.com/repos/Borewit/mutagen/releases{/id}","deployments_url":"https://api.github.com/repos/Borewit/mutagen/deployments","created_at":"2017-08-12T15:31:42Z","updated_at":"2017-08-12T15:31:44Z","pushed_at":"2017-08-17T17:59:41Z","git_url":"git://github.com/Borewit/mutagen.git","ssh_url":"git@github.com:Borewit/mutagen.git","clone_url":"https://github.com/Borewit/mutagen.git","svn_url":"https://github.com/Borewit/mutagen","homepage":"https://mutagen.readthedocs.io","size":6657,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"quodlibet:master","ref":"master","sha":"8fe2946fb048b22253013c5833eef42823308278","user":{"login":"quodlibet","id":11544695,"avatar_url":"https://avatars3.githubusercontent.com/u/11544695?v=4","gravatar_id":"","url":"https://api.github.com/users/quodlibet","html_url":"https://github.com/quodlibet","followers_url":"https://api.github.com/users/quodlibet/followers","following_url":"https://api.github.com/users/quodlibet/following{/other_user}","gists_url":"https://api.github.com/users/quodlibet/gists{/gist_id}","starred_url":"https://api.github.com/users/quodlibet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quodlibet/subscriptions","organizations_url":"https://api.github.com/users/quodlibet/orgs","repos_url":"https://api.github.com/users/quodlibet/repos","events_url":"https://api.github.com/users/quodlibet/events{/privacy}","received_events_url":"https://api.github.com/users/quodlibet/received_events","type":"Organization","site_admin":false},"repo":{"id":55713112,"name":"mutagen","full_name":"quodlibet/mutagen","owner":{"login":"quodlibet","id":11544695,"avatar_url":"https://avatars3.githubusercontent.com/u/11544695?v=4","gravatar_id":"","url":"https://api.github.com/users/quodlibet","html_url":"https://github.com/quodlibet","followers_url":"https://api.github.com/users/quodlibet/followers","following_url":"https://api.github.com/users/quodlibet/following{/other_user}","gists_url":"https://api.github.com/users/quodlibet/gists{/gist_id}","starred_url":"https://api.github.com/users/quodlibet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quodlibet/subscriptions","organizations_url":"https://api.github.com/users/quodlibet/orgs","repos_url":"https://api.github.com/users/quodlibet/repos","events_url":"https://api.github.com/users/quodlibet/events{/privacy}","received_events_url":"https://api.github.com/users/quodlibet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/quodlibet/mutagen","description":"Python 2/3 module for handling audio metadata","fork":false,"url":"https://api.github.com/repos/quodlibet/mutagen","forks_url":"https://api.github.com/repos/quodlibet/mutagen/forks","keys_url":"https://api.github.com/repos/quodlibet/mutagen/keys{/key_id}","collaborators_url":"https://api.github.com/repos/quodlibet/mutagen/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/quodlibet/mutagen/teams","hooks_url":"https://api.github.com/repos/quodlibet/mutagen/hooks","issue_events_url":"https://api.github.com/repos/quodlibet/mutagen/issues/events{/number}","events_url":"https://api.github.com/repos/quodlibet/mutagen/events","assignees_url":"https://api.github.com/repos/quodlibet/mutagen/assignees{/user}","branches_url":"https://api.github.com/repos/quodlibet/mutagen/branches{/branch}","tags_url":"https://api.github.com/repos/quodlibet/mutagen/tags","blobs_url":"https://api.github.com/repos/quodlibet/mutagen/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/quodlibet/mutagen/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/quodlibet/mutagen/git/refs{/sha}","trees_url":"https://api.github.com/repos/quodlibet/mutagen/git/trees{/sha}","statuses_url":"https://api.github.com/repos/quodlibet/mutagen/statuses/{sha}","languages_url":"https://api.github.com/repos/quodlibet/mutagen/languages","stargazers_url":"https://api.github.com/repos/quodlibet/mutagen/stargazers","contributors_url":"https://api.github.com/repos/quodlibet/mutagen/contributors","subscribers_url":"https://api.github.com/repos/quodlibet/mutagen/subscribers","subscription_url":"https://api.github.com/repos/quodlibet/mutagen/subscription","commits_url":"https://api.github.com/repos/quodlibet/mutagen/commits{/sha}","git_commits_url":"https://api.github.com/repos/quodlibet/mutagen/git/commits{/sha}","comments_url":"https://api.github.com/repos/quodlibet/mutagen/comments{/number}","issue_comment_url":"https://api.github.com/repos/quodlibet/mutagen/issues/comments{/number}","contents_url":"https://api.github.com/repos/quodlibet/mutagen/contents/{+path}","compare_url":"https://api.github.com/repos/quodlibet/mutagen/compare/{base}...{head}","merges_url":"https://api.github.com/repos/quodlibet/mutagen/merges","archive_url":"https://api.github.com/repos/quodlibet/mutagen/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/quodlibet/mutagen/downloads","issues_url":"https://api.github.com/repos/quodlibet/mutagen/issues{/number}","pulls_url":"https://api.github.com/repos/quodlibet/mutagen/pulls{/number}","milestones_url":"https://api.github.com/repos/quodlibet/mutagen/milestones{/number}","notifications_url":"https://api.github.com/repos/quodlibet/mutagen/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/quodlibet/mutagen/labels{/name}","releases_url":"https://api.github.com/repos/quodlibet/mutagen/releases{/id}","deployments_url":"https://api.github.com/repos/quodlibet/mutagen/deployments","created_at":"2016-04-07T17:10:15Z","updated_at":"2017-08-18T14:38:06Z","pushed_at":"2017-08-17T18:14:35Z","git_url":"git://github.com/quodlibet/mutagen.git","ssh_url":"git@github.com:quodlibet/mutagen.git","clone_url":"https://github.com/quodlibet/mutagen.git","svn_url":"https://github.com/quodlibet/mutagen","homepage":"https://mutagen.readthedocs.io","size":6601,"stargazers_count":183,"watchers_count":183,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":21,"mirror_url":null,"open_issues_count":24,"forks":21,"open_issues":24,"watchers":183,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/quodlibet/mutagen/pulls/321"},"html":{"href":"https://github.com/quodlibet/mutagen/pull/321"},"issue":{"href":"https://api.github.com/repos/quodlibet/mutagen/issues/321"},"comments":{"href":"https://api.github.com/repos/quodlibet/mutagen/issues/321/comments"},"review_comments":{"href":"https://api.github.com/repos/quodlibet/mutagen/pulls/321/comments"},"review_comment":{"href":"https://api.github.com/repos/quodlibet/mutagen/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/quodlibet/mutagen/pulls/321/commits"},"statuses":{"href":"https://api.github.com/repos/quodlibet/mutagen/statuses/65dd01ecbe76c1108ebe0fc18994eda1eb7b60c8"}}}}
{"actor":{"display_login":"lazka"}}