{"action":"created","comment":{"url":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/comments/104296268","pull_request_review_id":25131579,"id":104296268,"diff_hunk":"@@ -13,309 +13,338 @@\n  */\n \n /**\n- * Microphone plugin definition factory\n+ * Visualise microphone input in a wavesurfer instance.\n  *\n- * @param  {MicrophonePluginParams} params parameters use to initialise the plugin\n- * @return {PluginDefinition} an object representing the plugin\n+ * @implements {PluginClass}\n+ * @extends {Observer}\n+ * @example\n+ * // es6\n+ * import MicrophonePlugin from 'wavesurfer.js/dist/plugin/wavesurfer.microphone.js';\n+ *\n+ * // commonjs\n+ * var MicrophonePlugin = require('wavesurfer.js/dist/plugin/wavesurfer.microphone.js');\n+ *\n+ * // if you are using <script> tags\n+ * var MicrophonePlugin = window.WaveSurfer.microphone;\n+ *\n+ * // ... initialising wavesurfer with the plugin\n+ * var wavesurfer = WaveSurfer.create({\n+ *   // wavesurfer options ...\n+ *   plugins: [\n+ *     MicrophonePlugin.create({\n+ *       // plugin options ...\n+ *     })\n+ *   ]\n+ * });\n  */\n-export default function(params = {}) {\n-    return {\n-        name: 'microphone',\n-        deferInit: params && params.deferInit ? params.deferInit : false,\n-        extends: 'observer',\n-        instance: Observer => class MicrophonePlugin extends Observer {\n-            constructor(wavesurfer) {\n-                super();\n-                this.params = params;\n-                this.wavesurfer = wavesurfer;\n-\n-                this.active = false;\n-                this.paused = false;\n-                this.reloadBufferFunction = e => this.reloadBuffer(e);\n-\n-                // cross-browser getUserMedia\n-                const promisifiedOldGUM = (constraints, successCallback, errorCallback) => {\n-                    // get ahold of getUserMedia, if present\n-                    const getUserMedia = (navigator.getUserMedia ||\n-                        navigator.webkitGetUserMedia ||\n-                        navigator.mozGetUserMedia ||\n-                        navigator.msGetUserMedia\n-                    );\n-                    // Some browsers just don't implement it - return a rejected\n-                    // promise with an error to keep a consistent interface\n-                    if (!getUserMedia) {\n-                        return Promise.reject(\n-                            new Error('getUserMedia is not implemented in this browser')\n-                        );\n-                    }\n-                    // otherwise, wrap the call to the old navigator.getUserMedia with\n-                    // a Promise\n-                    return new Promise((successCallback, errorCallback) => {\n-                        getUserMedia.call(navigator, constraints, successCallback, errorCallback);\n-                    });\n-                };\n-                // Older browsers might not implement mediaDevices at all, so we set an\n-                // empty object first\n-                if (navigator.mediaDevices === undefined) {\n-                    navigator.mediaDevices = {};\n-                }\n-                // Some browsers partially implement mediaDevices. We can't just assign\n-                // an object with getUserMedia as it would overwrite existing\n-                // properties. Here, we will just add the getUserMedia property if it's\n-                // missing.\n-                if (navigator.mediaDevices.getUserMedia === undefined) {\n-                    navigator.mediaDevices.getUserMedia = promisifiedOldGUM;\n-                }\n-                this.constraints = this.params.constraints || {\n-                    video: false,\n-                    audio: true\n-                };\n-                this.bufferSize = this.params.bufferSize || 4096;\n-                this.numberOfInputChannels = this.params.numberOfInputChannels || 1;\n-                this.numberOfOutputChannels = this.params.numberOfOutputChannels || 1;\n-\n-                this._onBackendCreated = () => {\n-                    // wavesurfer's AudioContext where we'll route the mic signal to\n-                    this.micContext = this.wavesurfer.backend.getAudioContext();\n-                };\n+export default class MicrophonePlugin {\n+    /**\n+     * Microphone plugin definition factory\n+     *\n+     * This function must be used to create a plugin definition which can be\n+     * used by wavesurfer to correctly instantiate the plugin.\n+     *\n+     * @param  {MicrophonePluginParams} params parameters use to initialise the plugin\n+     * @return {PluginDefinition} an object representing the plugin\n+     */\n+    static create(params) {\n+        return {\n+            name: 'microphone',\n+            deferInit: params && params.deferInit ? params.deferInit : false,\n+            params: params,\n+            instance: MicrophonePlugin\n+        };\n+    }\n+\n+    constructor(params, ws) {\n+        this.params = params;\n+        this.wavesurfer = ws;\n+\n+        this.active = false;\n+        this.paused = false;\n+        this.reloadBufferFunction = e => this.reloadBuffer(e);\n+\n+        // cross-browser getUserMedia\n+        const promisifiedOldGUM = (constraints, successCallback, errorCallback) => {\n+            // get ahold of getUserMedia, if present\n+            const getUserMedia = (navigator.getUserMedia ||\n+                navigator.webkitGetUserMedia ||\n+                navigator.mozGetUserMedia ||\n+                navigator.msGetUserMedia\n+            );\n+            // Some browsers just don't implement it - return a rejected\n+            // promise with an error to keep a consistent interface\n+            if (!getUserMedia) {\n+                return Promise.reject(\n+                    new Error('getUserMedia is not implemented in this browser')\n+                );\n             }\n-\n-            init() {\n-                this.wavesurfer.on('backend-created', this._onBackendCreated);\n-                if (this.wavesurfer.backend) {\n-                    this._onBackendCreated();\n-                }\n-            }\n-\n-            /**\n-             * Destroy the microphone plugin.\n-             */\n-            destroy() {\n-                // make sure the buffer is not redrawn during\n-                // cleanup and demolition of this plugin.\n-                this.paused = true;\n-\n-                this.wavesurfer.un('backend-created', this._onBackendCreated);\n-                this.stop();\n-            }\n-\n-            /**\n-            * Allow user to select audio input device, eg. microphone, and\n-            * start the visualization.\n-            */\n-            start() {\n-                navigator.mediaDevices.getUserMedia(this.constraints)\n-                    .then((data) => this.gotStream(data))\n-                    .catch((data) => this.deviceError(data));\n-            }\n-\n-            /**\n-            * Pause/resume visualization.\n-            */\n-            togglePlay() {\n-                if (!this.active) {\n-                    // start it first\n-                    this.start();\n-                } else {\n-                    // toggle paused\n-                    this.paused = !this.paused;\n-\n-                    if (this.paused) {\n-                        this.pause();\n-                    } else {\n-                        this.play();\n-                    }\n-                }\n-            }\n-\n-            /**\n-            * Play visualization.\n-            */\n-            play() {\n-                this.paused = false;\n-\n-                this.connect();\n-            }\n-\n-            /**\n-            * Pause visualization.\n-            */\n-            pause() {\n-                this.paused = true;\n-\n-                // disconnect sources so they can be used elsewhere\n-                // (eg. during audio playback)\n-                this.disconnect();\n-            }\n-\n-            /**\n-            * Stop the device stream and remove any remaining waveform drawing from\n-            * the wavesurfer canvas.\n-            */\n-            stop() {\n-                if (this.active) {\n-                    // stop visualization and device\n-                    this.stopDevice();\n-\n-                    // empty last frame\n-                    this.wavesurfer.empty();\n-                }\n-            }\n-\n-            /**\n-            * Stop the device and the visualization.\n-            */\n-            stopDevice() {\n-                this.active = false;\n-\n-                // stop visualization\n-                this.disconnect();\n-\n-                // stop stream from device\n-                if (this.stream) {\n-                    const result = this.detectBrowser();\n-                    // MediaStream.stop is deprecated since:\n-                    // - Firefox 44 (https://www.fxsitecompat.com/en-US/docs/2015/mediastream-stop-has-been-deprecated/)\n-                    // - Chrome 45 (https://developers.google.com/web/updates/2015/07/mediastream-deprecations)\n-                    if ((result.browser === 'chrome' && result.version >= 45) ||\n-                    (result.browser === 'firefox' && result.version >= 44) ||\n-                    (result.browser === 'edge')) {\n-                        if (this.stream.getTracks) { // note that this should not be a call\n-                            this.stream.getTracks().forEach(stream => stream.stop());\n-                            return;\n-                        }\n-                    }\n-\n-                    this.stream.stop();\n-                }\n-            }\n-\n-            /**\n-            * Connect the media sources that feed the visualization.\n-            */\n-            connect() {\n-                if (this.stream !== undefined) {\n-                    // Create an AudioNode from the stream.\n-                    this.mediaStreamSource = this.micContext.createMediaStreamSource(this.stream);\n-\n-                    this.levelChecker = this.micContext.createScriptProcessor(\n-                        this.bufferSize,\n-                        this.numberOfInputChannels,\n-                        this.numberOfOutputChannels\n-                    );\n-                    this.mediaStreamSource.connect(this.levelChecker);\n-\n-                    this.levelChecker.connect(this.micContext.destination);\n-                    this.levelChecker.onaudioprocess = this.reloadBufferFunction;\n-                }\n-            }\n-\n-            /**\n-            * Disconnect the media sources that feed the visualization.\n-            */\n-            disconnect() {\n-                if (this.mediaStreamSource !== undefined) {\n-                    this.mediaStreamSource.disconnect();\n-                }\n-\n-                if (this.levelChecker !== undefined) {\n-                    this.levelChecker.disconnect();\n-                    this.levelChecker.onaudioprocess = undefined;\n-                }\n-            }\n-\n-            /**\n-            * Redraw the waveform.\n-            */\n-            reloadBuffer(event) {\n-                if (!this.paused) {\n-                    this.wavesurfer.empty();\n-                    this.wavesurfer.loadDecodedBuffer(event.inputBuffer);\n-                }\n-            }\n-\n-            /**\n-            * Audio input device is ready.\n-            *\n-            * @param {LocalMediaStream} stream: the microphone's media stream.\n-            */\n-            gotStream(stream) {\n-                this.stream = stream;\n-                this.active = true;\n-\n-                // start visualization\n+            // otherwise, wrap the call to the old navigator.getUserMedia with\n+            // a Promise\n+            return new Promise((successCallback, errorCallback) => {\n+                getUserMedia.call(navigator, constraints, successCallback, errorCallback);\n+            });\n+        };\n+        // Older browsers might not implement mediaDevices at all, so we set an\n+        // empty object first\n+        if (navigator.mediaDevices === undefined) {\n+            navigator.mediaDevices = {};\n+        }\n+        // Some browsers partially implement mediaDevices. We can't just assign\n+        // an object with getUserMedia as it would overwrite existing\n+        // properties. Here, we will just add the getUserMedia property if it's\n+        // missing.\n+        if (navigator.mediaDevices.getUserMedia === undefined) {\n+            navigator.mediaDevices.getUserMedia = promisifiedOldGUM;\n+        }\n+        this.constraints = this.params.constraints || {\n+            video: false,\n+            audio: true\n+        };\n+        this.bufferSize = this.params.bufferSize || 4096;\n+        this.numberOfInputChannels = this.params.numberOfInputChannels || 1;\n+        this.numberOfOutputChannels = this.params.numberOfOutputChannels || 1;\n+\n+        this._onBackendCreated = () => {\n+            // wavesurfer's AudioContext where we'll route the mic signal to\n+            this.micContext = this.wavesurfer.backend.getAudioContext();\n+        };\n+    }\n+\n+    init() {\n+        this.wavesurfer.on('backend-created', this._onBackendCreated);\n+        if (this.wavesurfer.backend) {\n+            this._onBackendCreated();\n+        }\n+    }\n+\n+    /**\n+     * Destroy the microphone plugin.\n+     */\n+    destroy() {\n+        // make sure the buffer is not redrawn during\n+        // cleanup and demolition of this plugin.\n+        this.paused = true;\n+\n+        this.wavesurfer.un('backend-created', this._onBackendCreated);\n+        this.stop();\n+    }\n+\n+    /**\n+    * Allow user to select audio input device, eg. microphone, and\n+    * start the visualization.\n+    */\n+    start() {\n+        navigator.mediaDevices.getUserMedia(this.constraints)","path":"src/plugin/microphone.js","position":354,"original_position":354,"commit_id":"fc007bbaf70ccb4cda53fe3d1e9de0ac5d9bc130","original_commit_id":"fc007bbaf70ccb4cda53fe3d1e9de0ac5d9bc130","user":{"login":"thijstriemstra","id":305679,"avatar_url":"https://avatars0.githubusercontent.com/u/305679?v=3","gravatar_id":"","url":"https://api.github.com/users/thijstriemstra","html_url":"https://github.com/thijstriemstra","followers_url":"https://api.github.com/users/thijstriemstra/followers","following_url":"https://api.github.com/users/thijstriemstra/following{/other_user}","gists_url":"https://api.github.com/users/thijstriemstra/gists{/gist_id}","starred_url":"https://api.github.com/users/thijstriemstra/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thijstriemstra/subscriptions","organizations_url":"https://api.github.com/users/thijstriemstra/orgs","repos_url":"https://api.github.com/users/thijstriemstra/repos","events_url":"https://api.github.com/users/thijstriemstra/events{/privacy}","received_events_url":"https://api.github.com/users/thijstriemstra/received_events","type":"User","site_admin":false},"body":"this doesn't work in all browsers. Why remove the previous logic?","created_at":"2017-03-04T20:20:54Z","updated_at":"2017-03-04T20:20:54Z","html_url":"https://github.com/katspaugh/wavesurfer.js/pull/1025#discussion_r104296268","pull_request_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/1025","_links":{"self":{"href":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/comments/104296268"},"html":{"href":"https://github.com/katspaugh/wavesurfer.js/pull/1025#discussion_r104296268"},"pull_request":{"href":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/1025"}}},"pull_request":{"url":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/1025","id":109111612,"html_url":"https://github.com/katspaugh/wavesurfer.js/pull/1025","diff_url":"https://github.com/katspaugh/wavesurfer.js/pull/1025.diff","patch_url":"https://github.com/katspaugh/wavesurfer.js/pull/1025.patch","issue_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/issues/1025","number":1025,"state":"open","locked":false,"title":"Next: Updated plugin definition format and class exports","user":{"login":"mspae","id":1044829,"avatar_url":"https://avatars3.githubusercontent.com/u/1044829?v=3","gravatar_id":"","url":"https://api.github.com/users/mspae","html_url":"https://github.com/mspae","followers_url":"https://api.github.com/users/mspae/followers","following_url":"https://api.github.com/users/mspae/following{/other_user}","gists_url":"https://api.github.com/users/mspae/gists{/gist_id}","starred_url":"https://api.github.com/users/mspae/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mspae/subscriptions","organizations_url":"https://api.github.com/users/mspae/orgs","repos_url":"https://api.github.com/users/mspae/repos","events_url":"https://api.github.com/users/mspae/events{/privacy}","received_events_url":"https://api.github.com/users/mspae/received_events","type":"User","site_admin":false},"body":"### Short description of changes:\r\n* For the reasons described here: https://github.com/katspaugh/wavesurfer.js/pull/1015#issuecomment-283609182 the plugin definition format was updated.\r\n  * There is no `extends` property anymore in the plugin definition format\r\n    * All plugin classes are turned into observers when they are passed through `addPlugin`. (The plugin classes have the `@inherits {Observer}` jsdoc tag so the documentation generator gets things right.)\r\n    * Minimap instantiates a drawer using `this.drawer = wavesurfer.Drawer(el, params);` and doesn't directly inherit from drawer.\r\n  * Plugin class constructor functions are called with `wavesurfer` and `params` parameters by the core lib\r\n* Plugin classes are exported from plugin files and have a static `create` function, which is the factory function for the plugin definition object (which includes the plugin class as the `instance` property).\r\n* Other minor changes:\r\n  * Fixed wrong source map config and disabled hot module reloading\r\n  * Fixed an issue related to https://github.com/katspaugh/wavesurfer.js/issues/736 (minimap does not render on initial load with backend `MediaElement`) by checking which backend is used and using the correct event to hook into. (`ready` or `waveform-ready`)\r\n  * Updated jsdoc comments and added a correct `PluginClass` interface class (is removed in minified build by build system)\r\n  * Updated upgrade guide\r\n  * Updated example html and js\r\n\r\n### Breaking in the external API:\r\n* The plugin definition factory function is now the static `create` method of the plugin class, which is the default export of the plugin files. This means code needs to be adjusted (see Code example)\r\n\r\n### Breaking changes in the internal API:\r\n* The above changes have been applied within the code base, so there should be no internal breakage.\r\n\r\n### Todos/Notes:\r\n* Esdoc now parses the plugin classes (the ones that are exported, not the single `Region` class), this has caused the documentation coverage to decrease to `57.96% (171/295)`\r\n\r\n### Code example\r\n\r\n```javascript\r\n// EITHER - accessing modules with <script> tags\r\nvar WaveSurfer = window.WaveSurfer;\r\nvar TimelinePlugin = window.WaveSurfer.timeline;\r\nvar MinimapPlugin = window.WaveSurfer.minimap;\r\n\r\n// OR - importing as es6 module\r\nimport WaveSurfer from 'wavesurfer.js';\r\nimport TimelinePlugin from 'wavesurfer.js/dist/plugin/wavesurfer.timeline.min.js';\r\nimport MinimapPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.minimap.min.js';\r\n\r\n// OR - importing as require.js/commonjs modules\r\nvar WaveSurfer = require('wavesurfer.js');\r\nvar TimelinePlugin = require('wavesurfer.js/dist/plugin/wavesurfer.timeline.min.js');\r\nvar MinimapPlugin = require('wavesurfer.js/dist/plugin/wavesurfer.minimap.min.js');\r\n\r\n// ... initialising waveform with plugins\r\nvar wavesurfer = WaveSurfer.create({\r\n    container: '#waveform',\r\n    waveColor: 'violet',\r\n    plugins: [\r\n        TimelinePlugin.create({\r\n            container: '#wave-timeline'\r\n        }),\r\n        MinimapPlugin.create()\r\n    ]\r\n});\r\n```\r\n","created_at":"2017-03-04T15:42:49Z","updated_at":"2017-03-04T20:20:54Z","closed_at":null,"merged_at":null,"merge_commit_sha":"755974185882a4b809ad37b21c5fca71646b6782","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/1025/commits","review_comments_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/1025/comments","review_comment_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/comments{/number}","comments_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/issues/1025/comments","statuses_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/statuses/fc007bbaf70ccb4cda53fe3d1e9de0ac5d9bc130","head":{"label":"mspae:next-plugin-def","ref":"next-plugin-def","sha":"fc007bbaf70ccb4cda53fe3d1e9de0ac5d9bc130","user":{"login":"mspae","id":1044829,"avatar_url":"https://avatars3.githubusercontent.com/u/1044829?v=3","gravatar_id":"","url":"https://api.github.com/users/mspae","html_url":"https://github.com/mspae","followers_url":"https://api.github.com/users/mspae/followers","following_url":"https://api.github.com/users/mspae/following{/other_user}","gists_url":"https://api.github.com/users/mspae/gists{/gist_id}","starred_url":"https://api.github.com/users/mspae/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mspae/subscriptions","organizations_url":"https://api.github.com/users/mspae/orgs","repos_url":"https://api.github.com/users/mspae/repos","events_url":"https://api.github.com/users/mspae/events{/privacy}","received_events_url":"https://api.github.com/users/mspae/received_events","type":"User","site_admin":false},"repo":{"id":49826542,"name":"wavesurfer.js","full_name":"mspae/wavesurfer.js","owner":{"login":"mspae","id":1044829,"avatar_url":"https://avatars3.githubusercontent.com/u/1044829?v=3","gravatar_id":"","url":"https://api.github.com/users/mspae","html_url":"https://github.com/mspae","followers_url":"https://api.github.com/users/mspae/followers","following_url":"https://api.github.com/users/mspae/following{/other_user}","gists_url":"https://api.github.com/users/mspae/gists{/gist_id}","starred_url":"https://api.github.com/users/mspae/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mspae/subscriptions","organizations_url":"https://api.github.com/users/mspae/orgs","repos_url":"https://api.github.com/users/mspae/repos","events_url":"https://api.github.com/users/mspae/events{/privacy}","received_events_url":"https://api.github.com/users/mspae/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mspae/wavesurfer.js","description":"Navigable waveform built on Web Audio and Canvas","fork":true,"url":"https://api.github.com/repos/mspae/wavesurfer.js","forks_url":"https://api.github.com/repos/mspae/wavesurfer.js/forks","keys_url":"https://api.github.com/repos/mspae/wavesurfer.js/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mspae/wavesurfer.js/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mspae/wavesurfer.js/teams","hooks_url":"https://api.github.com/repos/mspae/wavesurfer.js/hooks","issue_events_url":"https://api.github.com/repos/mspae/wavesurfer.js/issues/events{/number}","events_url":"https://api.github.com/repos/mspae/wavesurfer.js/events","assignees_url":"https://api.github.com/repos/mspae/wavesurfer.js/assignees{/user}","branches_url":"https://api.github.com/repos/mspae/wavesurfer.js/branches{/branch}","tags_url":"https://api.github.com/repos/mspae/wavesurfer.js/tags","blobs_url":"https://api.github.com/repos/mspae/wavesurfer.js/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mspae/wavesurfer.js/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mspae/wavesurfer.js/git/refs{/sha}","trees_url":"https://api.github.com/repos/mspae/wavesurfer.js/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mspae/wavesurfer.js/statuses/{sha}","languages_url":"https://api.github.com/repos/mspae/wavesurfer.js/languages","stargazers_url":"https://api.github.com/repos/mspae/wavesurfer.js/stargazers","contributors_url":"https://api.github.com/repos/mspae/wavesurfer.js/contributors","subscribers_url":"https://api.github.com/repos/mspae/wavesurfer.js/subscribers","subscription_url":"https://api.github.com/repos/mspae/wavesurfer.js/subscription","commits_url":"https://api.github.com/repos/mspae/wavesurfer.js/commits{/sha}","git_commits_url":"https://api.github.com/repos/mspae/wavesurfer.js/git/commits{/sha}","comments_url":"https://api.github.com/repos/mspae/wavesurfer.js/comments{/number}","issue_comment_url":"https://api.github.com/repos/mspae/wavesurfer.js/issues/comments{/number}","contents_url":"https://api.github.com/repos/mspae/wavesurfer.js/contents/{+path}","compare_url":"https://api.github.com/repos/mspae/wavesurfer.js/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mspae/wavesurfer.js/merges","archive_url":"https://api.github.com/repos/mspae/wavesurfer.js/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mspae/wavesurfer.js/downloads","issues_url":"https://api.github.com/repos/mspae/wavesurfer.js/issues{/number}","pulls_url":"https://api.github.com/repos/mspae/wavesurfer.js/pulls{/number}","milestones_url":"https://api.github.com/repos/mspae/wavesurfer.js/milestones{/number}","notifications_url":"https://api.github.com/repos/mspae/wavesurfer.js/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mspae/wavesurfer.js/labels{/name}","releases_url":"https://api.github.com/repos/mspae/wavesurfer.js/releases{/id}","deployments_url":"https://api.github.com/repos/mspae/wavesurfer.js/deployments","created_at":"2016-01-17T16:58:22Z","updated_at":"2016-01-17T16:58:23Z","pushed_at":"2017-03-04T16:30:57Z","git_url":"git://github.com/mspae/wavesurfer.js.git","ssh_url":"git@github.com:mspae/wavesurfer.js.git","clone_url":"https://github.com/mspae/wavesurfer.js.git","svn_url":"https://github.com/mspae/wavesurfer.js","homepage":"http://wavesurfer-js.org","size":52676,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"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":"katspaugh:next","ref":"next","sha":"717247186779371c9d2634c84bc483eddaa28b3f","user":{"login":"katspaugh","id":381895,"avatar_url":"https://avatars2.githubusercontent.com/u/381895?v=3","gravatar_id":"","url":"https://api.github.com/users/katspaugh","html_url":"https://github.com/katspaugh","followers_url":"https://api.github.com/users/katspaugh/followers","following_url":"https://api.github.com/users/katspaugh/following{/other_user}","gists_url":"https://api.github.com/users/katspaugh/gists{/gist_id}","starred_url":"https://api.github.com/users/katspaugh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/katspaugh/subscriptions","organizations_url":"https://api.github.com/users/katspaugh/orgs","repos_url":"https://api.github.com/users/katspaugh/repos","events_url":"https://api.github.com/users/katspaugh/events{/privacy}","received_events_url":"https://api.github.com/users/katspaugh/received_events","type":"User","site_admin":false},"repo":{"id":3618686,"name":"wavesurfer.js","full_name":"katspaugh/wavesurfer.js","owner":{"login":"katspaugh","id":381895,"avatar_url":"https://avatars2.githubusercontent.com/u/381895?v=3","gravatar_id":"","url":"https://api.github.com/users/katspaugh","html_url":"https://github.com/katspaugh","followers_url":"https://api.github.com/users/katspaugh/followers","following_url":"https://api.github.com/users/katspaugh/following{/other_user}","gists_url":"https://api.github.com/users/katspaugh/gists{/gist_id}","starred_url":"https://api.github.com/users/katspaugh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/katspaugh/subscriptions","organizations_url":"https://api.github.com/users/katspaugh/orgs","repos_url":"https://api.github.com/users/katspaugh/repos","events_url":"https://api.github.com/users/katspaugh/events{/privacy}","received_events_url":"https://api.github.com/users/katspaugh/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/katspaugh/wavesurfer.js","description":"Navigable waveform built on Web Audio and Canvas","fork":false,"url":"https://api.github.com/repos/katspaugh/wavesurfer.js","forks_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/forks","keys_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/keys{/key_id}","collaborators_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/teams","hooks_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/hooks","issue_events_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/issues/events{/number}","events_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/events","assignees_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/assignees{/user}","branches_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/branches{/branch}","tags_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/tags","blobs_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/git/refs{/sha}","trees_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/git/trees{/sha}","statuses_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/statuses/{sha}","languages_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/languages","stargazers_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/stargazers","contributors_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/contributors","subscribers_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/subscribers","subscription_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/subscription","commits_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/commits{/sha}","git_commits_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/git/commits{/sha}","comments_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/comments{/number}","issue_comment_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/issues/comments{/number}","contents_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/contents/{+path}","compare_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/compare/{base}...{head}","merges_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/merges","archive_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/downloads","issues_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/issues{/number}","pulls_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls{/number}","milestones_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/milestones{/number}","notifications_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/labels{/name}","releases_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/releases{/id}","deployments_url":"https://api.github.com/repos/katspaugh/wavesurfer.js/deployments","created_at":"2012-03-04T14:38:02Z","updated_at":"2017-03-04T16:48:57Z","pushed_at":"2017-03-04T20:18:08Z","git_url":"git://github.com/katspaugh/wavesurfer.js.git","ssh_url":"git@github.com:katspaugh/wavesurfer.js.git","clone_url":"https://github.com/katspaugh/wavesurfer.js.git","svn_url":"https://github.com/katspaugh/wavesurfer.js","homepage":"https://wavesurfer-js.org","size":47480,"stargazers_count":2124,"watchers_count":2124,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":555,"mirror_url":null,"open_issues_count":89,"forks":555,"open_issues":89,"watchers":2124,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/1025"},"html":{"href":"https://github.com/katspaugh/wavesurfer.js/pull/1025"},"issue":{"href":"https://api.github.com/repos/katspaugh/wavesurfer.js/issues/1025"},"comments":{"href":"https://api.github.com/repos/katspaugh/wavesurfer.js/issues/1025/comments"},"review_comments":{"href":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/1025/comments"},"review_comment":{"href":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/katspaugh/wavesurfer.js/pulls/1025/commits"},"statuses":{"href":"https://api.github.com/repos/katspaugh/wavesurfer.js/statuses/fc007bbaf70ccb4cda53fe3d1e9de0ac5d9bc130"}}}}
{"actor":{"display_login":"thijstriemstra"}}