{"action":"created","comment":{"url":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/comments/56332196","id":56332196,"diff_hunk":"@@ -0,0 +1,519 @@\n+import Stream from './stream';\n+import PlaylistLoader from './playlist-loader';\n+import SegmentLoader from './segment-loader';\n+import Ranges from './ranges';\n+import videojs from 'video.js';\n+\n+// 5 minute blacklist\n+const BLACKLIST_DURATION = 5 * 60 * 1000;\n+\n+// A fudge factor to apply to advertised playlist bitrates to account for\n+// temporary flucations in client bandwidth\n+const BANDWIDTH_VARIANCE = 1.2;\n+\n+let Hls;\n+\n+/**\n+ * Returns the CSS value for the specified property on an element\n+ * using `getComputedStyle`. Firefox has a long-standing issue where\n+ * getComputedStyle() may return null when running in an iframe with\n+ * `display: none`.\n+ * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397\n+ */\n+const safeGetComputedStyle = function(el, property) {\n+  let result;\n+\n+  if (!el) {\n+    return '';\n+  }\n+\n+  result = getComputedStyle(el);\n+  if (!result) {\n+    return '';\n+  }\n+\n+  return result[property];\n+};\n+\n+/**\n+ * Chooses the appropriate media playlist based on the current\n+ * bandwidth estimate and the player size.\n+ * @return the highest bitrate playlist less than the currently detected\n+ * bandwidth, accounting for some amount of bandwidth variance\n+ */\n+const selectPlaylist = function() {\n+  let effectiveBitrate;\n+  let sortedPlaylists = this.playlists.master.playlists.slice();\n+  let bandwidthPlaylists = [];\n+  let now = +new Date();\n+  let i;\n+  let variant;\n+  let bandwidthBestVariant;\n+  let resolutionPlusOne;\n+  let resolutionPlusOneAttribute;\n+  let resolutionBestVariant;\n+  let width;\n+  let height;\n+\n+  sortedPlaylists.sort(Hls.comparePlaylistBandwidth);\n+\n+  // filter out any playlists that have been excluded due to\n+  // incompatible configurations or playback errors\n+  sortedPlaylists = sortedPlaylists.filter((localVariant) => {\n+    if (typeof localVariant.excludeUntil !== 'undefined') {\n+      return now >= localVariant.excludeUntil;\n+    }\n+    return true;\n+  });\n+\n+  // filter out any variant that has greater effective bitrate\n+  // than the current estimated bandwidth\n+  i = sortedPlaylists.length;\n+  while (i--) {\n+    variant = sortedPlaylists[i];\n+\n+    // ignore playlists without bandwidth information\n+    if (!variant.attributes || !variant.attributes.BANDWIDTH) {\n+      continue;\n+    }\n+\n+    effectiveBitrate = variant.attributes.BANDWIDTH * BANDWIDTH_VARIANCE;\n+\n+    if (effectiveBitrate < this.bandwidth) {\n+      bandwidthPlaylists.push(variant);\n+\n+      // since the playlists are sorted in ascending order by\n+      // bandwidth, the first viable variant is the best\n+      if (!bandwidthBestVariant) {\n+        bandwidthBestVariant = variant;\n+      }\n+    }\n+  }\n+\n+  i = bandwidthPlaylists.length;\n+\n+  // sort variants by resolution\n+  bandwidthPlaylists.sort(Hls.comparePlaylistResolution);\n+\n+  // forget our old variant from above,\n+  // or we might choose that in high-bandwidth scenarios\n+  // (this could be the lowest bitrate rendition as  we go through all of them above)\n+  variant = null;\n+\n+  width = parseInt(safeGetComputedStyle(this.tech_.el(), 'width'), 10);\n+  height = parseInt(safeGetComputedStyle(this.tech_.el(), 'height'), 10);\n+\n+  // iterate through the bandwidth-filtered playlists and find\n+  // best rendition by player dimension\n+  while (i--) {\n+    variant = bandwidthPlaylists[i];\n+\n+    // ignore playlists without resolution information\n+    if (!variant.attributes ||\n+        !variant.attributes.RESOLUTION ||\n+        !variant.attributes.RESOLUTION.width ||\n+        !variant.attributes.RESOLUTION.height) {\n+      continue;\n+    }\n+\n+    // since the playlists are sorted, the first variant that has\n+    // dimensions less than or equal to the player size is the best\n+\n+    let variantResolution = variant.attributes.RESOLUTION;\n+\n+    if (variantResolution.width === width &&\n+        variantResolution.height === height) {\n+      // if we have the exact resolution as the player use it\n+      resolutionPlusOne = null;\n+      resolutionBestVariant = variant;\n+      break;\n+    } else if (variantResolution.width < width &&\n+               variantResolution.height < height) {\n+      // if both dimensions are less than the player use the\n+      // previous (next-largest) variant\n+      break;\n+    } else if (!resolutionPlusOne ||\n+               (variantResolution.width < resolutionPlusOneAttribute.width &&\n+                variantResolution.height < resolutionPlusOneAttribute.height)) {\n+      // If we still haven't found a good match keep a\n+      // reference to the previous variant for the next loop\n+      // iteration\n+\n+      // By only saving variants if they are smaller than the\n+      // previously saved variant, we ensure that we also pick\n+      // the highest bandwidth variant that is just-larger-than\n+      // the video player\n+      resolutionPlusOne = variant;\n+      resolutionPlusOneAttribute = resolutionPlusOne.attributes.RESOLUTION;\n+    }\n+  }\n+\n+  // fallback chain of variants\n+  return resolutionPlusOne ||\n+    resolutionBestVariant ||\n+    bandwidthBestVariant ||\n+    sortedPlaylists[0];\n+};\n+\n+export default class MasterPlaylistController extends Stream {\n+  constructor({url, withCredentials, currentTimeFunc, mediaSourceMode, hlsHandler,\n+    externHls}) {\n+    super();\n+\n+    Hls = externHls;","path":"src/master-playlist-controller.js","position":163,"original_position":163,"commit_id":"6a6cc06b4dd34454cdcf16093a5975f27c1784a2","original_commit_id":"6a6cc06b4dd34454cdcf16093a5975f27c1784a2","user":{"login":"gesinger","id":356726,"avatar_url":"https://avatars.githubusercontent.com/u/356726?v=3","gravatar_id":"","url":"https://api.github.com/users/gesinger","html_url":"https://github.com/gesinger","followers_url":"https://api.github.com/users/gesinger/followers","following_url":"https://api.github.com/users/gesinger/following{/other_user}","gists_url":"https://api.github.com/users/gesinger/gists{/gist_id}","starred_url":"https://api.github.com/users/gesinger/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gesinger/subscriptions","organizations_url":"https://api.github.com/users/gesinger/orgs","repos_url":"https://api.github.com/users/gesinger/repos","events_url":"https://api.github.com/users/gesinger/events{/privacy}","received_events_url":"https://api.github.com/users/gesinger/received_events","type":"User","site_admin":false},"body":"Good call.","created_at":"2016-03-16T13:30:16Z","updated_at":"2016-03-16T13:30:16Z","html_url":"https://github.com/videojs/videojs-contrib-hls/pull/599#discussion_r56332196","pull_request_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/599","_links":{"self":{"href":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/comments/56332196"},"html":{"href":"https://github.com/videojs/videojs-contrib-hls/pull/599#discussion_r56332196"},"pull_request":{"href":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/599"}}},"pull_request":{"url":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/599","id":62830683,"html_url":"https://github.com/videojs/videojs-contrib-hls/pull/599","diff_url":"https://github.com/videojs/videojs-contrib-hls/pull/599.diff","patch_url":"https://github.com/videojs/videojs-contrib-hls/pull/599.patch","issue_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/issues/599","number":599,"state":"open","locked":false,"title":"[WIP] Master Playlist Controller + Support for Alternate Audio Track Loading","user":{"login":"gesinger","id":356726,"avatar_url":"https://avatars.githubusercontent.com/u/356726?v=3","gravatar_id":"","url":"https://api.github.com/users/gesinger","html_url":"https://github.com/gesinger","followers_url":"https://api.github.com/users/gesinger/followers","following_url":"https://api.github.com/users/gesinger/following{/other_user}","gists_url":"https://api.github.com/users/gesinger/gists{/gist_id}","starred_url":"https://api.github.com/users/gesinger/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gesinger/subscriptions","organizations_url":"https://api.github.com/users/gesinger/orgs","repos_url":"https://api.github.com/users/gesinger/repos","events_url":"https://api.github.com/users/gesinger/events{/privacy}","received_events_url":"https://api.github.com/users/gesinger/received_events","type":"User","site_admin":false},"body":"The first commit is the Master Playlist Controller (original PR: https://github.com/videojs/videojs-contrib-hls/pull/591 ).\r\n\r\nThe third commit includes changes to support alternate audio track loading.\r\n\r\nCODE MOVES:\r\n- A lot of moves were done from videojs-contrib-hls to master-playlist-controller to better confine the logic of the main plugin file (dealing with videojs interfaces), and the HLS specific logic.\r\n- Some old unused code was removed (including sourceBuffer handling and creation within videojs-contrib-hls, as that is now the responsibility of each segment loader's source updater).\r\n\r\nTODOs (included in code):\r\n- loadAlternateAudioPlaylist is unused, and should be used when we start listening to change events on AudioTracksList\r\n- within loadAlternateAudioPlaylists, on error events, there are TODOs to re-enable the main's audio\r\n- Some methods within videojs-contrib-hls are unused within the project, and should either be removed or used where appropriate (TODOs are labeled above excludeIncompatibleVariants, playlistUriToUrl, and setBandwidth).\r\n\r\nNOTES:\r\n- We're not listening to audio segment loader progress events. This is because we do not need to switch renditions, and don't gain much by keeping an eye on the bandwidth (instead we rely on the bandwidth estimates from the combined video/audio stream).\r\n- We're not pausing the alternate audio segment loading on media changes, as we might as well continue loading the same audio track.\r\n- We're only tracking expired time for the main stream.\r\n\r\nThere are currently no tests, and old tests were not moved/fixed. These need to be added.","created_at":"2016-03-14T22:56:31Z","updated_at":"2016-03-16T13:30:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/599/commits","review_comments_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/599/comments","review_comment_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/comments{/number}","comments_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/issues/599/comments","statuses_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/statuses/6a6cc06b4dd34454cdcf16093a5975f27c1784a2","head":{"label":"gesinger:my-rebase-master-playlist-controller-amended-dual-sl-pl","ref":"my-rebase-master-playlist-controller-amended-dual-sl-pl","sha":"6a6cc06b4dd34454cdcf16093a5975f27c1784a2","user":{"login":"gesinger","id":356726,"avatar_url":"https://avatars.githubusercontent.com/u/356726?v=3","gravatar_id":"","url":"https://api.github.com/users/gesinger","html_url":"https://github.com/gesinger","followers_url":"https://api.github.com/users/gesinger/followers","following_url":"https://api.github.com/users/gesinger/following{/other_user}","gists_url":"https://api.github.com/users/gesinger/gists{/gist_id}","starred_url":"https://api.github.com/users/gesinger/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gesinger/subscriptions","organizations_url":"https://api.github.com/users/gesinger/orgs","repos_url":"https://api.github.com/users/gesinger/repos","events_url":"https://api.github.com/users/gesinger/events{/privacy}","received_events_url":"https://api.github.com/users/gesinger/received_events","type":"User","site_admin":false},"repo":{"id":49451278,"name":"videojs-contrib-hls","full_name":"gesinger/videojs-contrib-hls","owner":{"login":"gesinger","id":356726,"avatar_url":"https://avatars.githubusercontent.com/u/356726?v=3","gravatar_id":"","url":"https://api.github.com/users/gesinger","html_url":"https://github.com/gesinger","followers_url":"https://api.github.com/users/gesinger/followers","following_url":"https://api.github.com/users/gesinger/following{/other_user}","gists_url":"https://api.github.com/users/gesinger/gists{/gist_id}","starred_url":"https://api.github.com/users/gesinger/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gesinger/subscriptions","organizations_url":"https://api.github.com/users/gesinger/orgs","repos_url":"https://api.github.com/users/gesinger/repos","events_url":"https://api.github.com/users/gesinger/events{/privacy}","received_events_url":"https://api.github.com/users/gesinger/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/gesinger/videojs-contrib-hls","description":"HLS library for video.js","fork":true,"url":"https://api.github.com/repos/gesinger/videojs-contrib-hls","forks_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/forks","keys_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/teams","hooks_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/hooks","issue_events_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/issues/events{/number}","events_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/events","assignees_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/assignees{/user}","branches_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/branches{/branch}","tags_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/tags","blobs_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/git/refs{/sha}","trees_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/statuses/{sha}","languages_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/languages","stargazers_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/stargazers","contributors_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/contributors","subscribers_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/subscribers","subscription_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/subscription","commits_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/commits{/sha}","git_commits_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/git/commits{/sha}","comments_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/comments{/number}","issue_comment_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/issues/comments{/number}","contents_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/contents/{+path}","compare_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/merges","archive_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/downloads","issues_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/issues{/number}","pulls_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/pulls{/number}","milestones_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/milestones{/number}","notifications_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/labels{/name}","releases_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/releases{/id}","deployments_url":"https://api.github.com/repos/gesinger/videojs-contrib-hls/deployments","created_at":"2016-01-11T20:07:30Z","updated_at":"2016-01-11T20:07:32Z","pushed_at":"2016-03-14T22:43:34Z","git_url":"git://github.com/gesinger/videojs-contrib-hls.git","ssh_url":"git@github.com:gesinger/videojs-contrib-hls.git","clone_url":"https://github.com/gesinger/videojs-contrib-hls.git","svn_url":"https://github.com/gesinger/videojs-contrib-hls","homepage":"http://videojs.github.io/videojs-contrib-hls/","size":14595,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"videojs:my-rebase","ref":"my-rebase","sha":"07ff699d242294acb8cc45d231138148d82524ba","user":{"login":"videojs","id":3287189,"avatar_url":"https://avatars.githubusercontent.com/u/3287189?v=3","gravatar_id":"","url":"https://api.github.com/users/videojs","html_url":"https://github.com/videojs","followers_url":"https://api.github.com/users/videojs/followers","following_url":"https://api.github.com/users/videojs/following{/other_user}","gists_url":"https://api.github.com/users/videojs/gists{/gist_id}","starred_url":"https://api.github.com/users/videojs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/videojs/subscriptions","organizations_url":"https://api.github.com/users/videojs/orgs","repos_url":"https://api.github.com/users/videojs/repos","events_url":"https://api.github.com/users/videojs/events{/privacy}","received_events_url":"https://api.github.com/users/videojs/received_events","type":"Organization","site_admin":false},"repo":{"id":14029328,"name":"videojs-contrib-hls","full_name":"videojs/videojs-contrib-hls","owner":{"login":"videojs","id":3287189,"avatar_url":"https://avatars.githubusercontent.com/u/3287189?v=3","gravatar_id":"","url":"https://api.github.com/users/videojs","html_url":"https://github.com/videojs","followers_url":"https://api.github.com/users/videojs/followers","following_url":"https://api.github.com/users/videojs/following{/other_user}","gists_url":"https://api.github.com/users/videojs/gists{/gist_id}","starred_url":"https://api.github.com/users/videojs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/videojs/subscriptions","organizations_url":"https://api.github.com/users/videojs/orgs","repos_url":"https://api.github.com/users/videojs/repos","events_url":"https://api.github.com/users/videojs/events{/privacy}","received_events_url":"https://api.github.com/users/videojs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/videojs/videojs-contrib-hls","description":"HLS library for video.js","fork":false,"url":"https://api.github.com/repos/videojs/videojs-contrib-hls","forks_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/forks","keys_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/keys{/key_id}","collaborators_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/teams","hooks_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/hooks","issue_events_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/issues/events{/number}","events_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/events","assignees_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/assignees{/user}","branches_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/branches{/branch}","tags_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/tags","blobs_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/git/refs{/sha}","trees_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/git/trees{/sha}","statuses_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/statuses/{sha}","languages_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/languages","stargazers_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/stargazers","contributors_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/contributors","subscribers_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/subscribers","subscription_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/subscription","commits_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/commits{/sha}","git_commits_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/git/commits{/sha}","comments_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/comments{/number}","issue_comment_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/issues/comments{/number}","contents_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/contents/{+path}","compare_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/compare/{base}...{head}","merges_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/merges","archive_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/downloads","issues_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/issues{/number}","pulls_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls{/number}","milestones_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/milestones{/number}","notifications_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/labels{/name}","releases_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/releases{/id}","deployments_url":"https://api.github.com/repos/videojs/videojs-contrib-hls/deployments","created_at":"2013-10-31T21:55:21Z","updated_at":"2016-03-16T13:08:28Z","pushed_at":"2016-03-15T20:56:18Z","git_url":"git://github.com/videojs/videojs-contrib-hls.git","ssh_url":"git@github.com:videojs/videojs-contrib-hls.git","clone_url":"https://github.com/videojs/videojs-contrib-hls.git","svn_url":"https://github.com/videojs/videojs-contrib-hls","homepage":"http://videojs.github.io/videojs-contrib-hls/","size":23580,"stargazers_count":513,"watchers_count":513,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":262,"mirror_url":null,"open_issues_count":105,"forks":262,"open_issues":105,"watchers":513,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/599"},"html":{"href":"https://github.com/videojs/videojs-contrib-hls/pull/599"},"issue":{"href":"https://api.github.com/repos/videojs/videojs-contrib-hls/issues/599"},"comments":{"href":"https://api.github.com/repos/videojs/videojs-contrib-hls/issues/599/comments"},"review_comments":{"href":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/599/comments"},"review_comment":{"href":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/videojs/videojs-contrib-hls/pulls/599/commits"},"statuses":{"href":"https://api.github.com/repos/videojs/videojs-contrib-hls/statuses/6a6cc06b4dd34454cdcf16093a5975f27c1784a2"}}}}