Add context menu to player
authorChocobozzz <me@florianbigard.com>
Wed, 30 May 2018 15:10:00 +0000 (17:10 +0200)
committerChocobozzz <me@florianbigard.com>
Wed, 30 May 2018 15:10:00 +0000 (17:10 +0200)
14 files changed:
.sass-lint.yml
client/package.json
client/src/app/videos/+video-watch/modal/video-share.component.ts
client/src/app/videos/+video-watch/video-watch.component.ts
client/src/assets/player/peertube-link-button.ts
client/src/assets/player/peertube-player.ts
client/src/assets/player/peertube-videojs-plugin.ts
client/src/assets/player/utils.ts
client/src/assets/player/video-renderer.ts
client/src/sass/video-js-custom.scss
client/src/standalone/videos/embed.ts
client/yarn.lock
package.json
yarn.lock

index 55a487138c3010a8919c094702b11743a4d78496..50b9e4f93bfa264056dd918b10f9bfb3d9078933 100644 (file)
@@ -22,4 +22,4 @@ rules:
   space-before-colon: 1
   hex-length: 1
   hex-notation: 0
-  indentation: 1
+  indentation: 2
index 0d5acf9979d66843ee5421e8a5f91e99d723a047..61f94758aa383c27352f3eefb5391bc71ad0139e 100644 (file)
@@ -23,7 +23,7 @@
   },
   "license": "GPLv3",
   "resolutions": {
-    "videojs-dock/video.js": "^7",
+    "video.js": "^7",
     "webtorrent/create-torrent/junk": "^1",
     "simple-get": "^2.8.1"
   },
@@ -99,6 +99,8 @@
     "typescript": "2.7",
     "uglifyjs-webpack-plugin": "^1.1.2",
     "video.js": "^7.0.3",
+    "videojs-contextmenu": "^2.0.0",
+    "videojs-contextmenu-ui": "^4.0.0",
     "videojs-dock": "^2.0.2",
     "videojs-hotkeys": "^0.2.21",
     "webpack": "^4.5.0",
index 678cccfb5dfcc0557909850b04a60be677070a6e..33998c5d804d7f91232da019d065732055bec237 100644 (file)
@@ -4,6 +4,7 @@ import { NotificationsService } from 'angular2-notifications'
 
 import { ModalDirective } from 'ngx-bootstrap/modal'
 import { VideoDetails } from '../../../shared/video/video-details.model'
+import { buildVideoEmbed } from '../../../../assets/player/utils'
 
 @Component({
   selector: 'my-video-share',
@@ -28,10 +29,7 @@ export class VideoShareComponent {
   }
 
   getVideoIframeCode () {
-    return '<iframe width="560" height="315" ' +
-           'src="' + this.video.embedUrl + '" ' +
-           'frameborder="0" allowfullscreen>' +
-           '</iframe>'
+    return buildVideoEmbed(this.video.embedUrl)
   }
 
   getVideoUrl () {
index 35a7c04ccad1d910988696f55d597cba382e0446..c710516490d377b7cac6ab48fff67102611c8e26 100644 (file)
@@ -348,6 +348,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
       inactivityTimeout: 2500,
       videoFiles: this.video.files,
       playerElement: this.playerElement,
+      videoEmbedUrl: this.video.embedUrl,
       videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid),
       videoDuration: this.video.duration,
       enableHotkeys: true,
index 54d802732573d0fdde2a17f9ad99facd2b4472c4..a13815d611206388395186193a32654bdd72c55b 100644 (file)
@@ -1,15 +1,19 @@
 import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
+import { buildVideoLink } from './utils'
 
 const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button')
 class PeerTubeLinkButton extends Button {
 
+  constructor (player: videojs.Player, options) {
+    super(player, options)
+  }
+
   createEl () {
     return this.buildElement()
   }
 
   updateHref () {
-    const currentTime = Math.floor(this.player().currentTime())
-    this.el().setAttribute('href', this.buildHref(currentTime))
+    this.el().setAttribute('href', buildVideoLink(this.player().currentTime()))
   }
 
   handleClick () {
@@ -18,7 +22,7 @@ class PeerTubeLinkButton extends Button {
 
   private buildElement () {
     const el = videojsUntyped.dom.createEl('a', {
-      href: this.buildHref(),
+      href: buildVideoLink(),
       innerHTML: 'PeerTube',
       title: 'Go to the video page',
       className: 'vjs-peertube-link',
@@ -29,15 +33,5 @@ class PeerTubeLinkButton extends Button {
 
     return el
   }
-
-  private buildHref (time?: number) {
-    let href = window.location.href.replace('embed', 'watch')
-    if (time) {
-      if (window.location.search) href += '&start=' + time
-      else href += '?start=' + time
-    }
-
-    return href
-  }
 }
 Button.registerComponent('PeerTubeLinkButton', PeerTubeLinkButton)
index f419d58fc723528673788fc91bc96877d04367a2..9fe5af5692a425e7d73bbe984ed3b654d117faed 100644 (file)
@@ -2,12 +2,15 @@ import { VideoFile } from '../../../../shared/models/videos'
 
 import 'videojs-hotkeys'
 import 'videojs-dock'
+import 'videojs-contextmenu'
+import 'videojs-contextmenu-ui'
 import './peertube-link-button'
 import './resolution-menu-button'
 import './settings-menu-button'
 import './webtorrent-info-button'
 import './peertube-videojs-plugin'
 import { videojsUntyped } from './peertube-videojs-typings'
+import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils'
 
 // Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
 videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed'
@@ -16,6 +19,7 @@ function getVideojsOptions (options: {
   autoplay: boolean,
   playerElement: HTMLVideoElement,
   videoViewUrl: string,
+  videoEmbedUrl: string,
   videoDuration: number,
   videoFiles: VideoFile[],
   enableHotkeys: boolean,
@@ -38,6 +42,29 @@ function getVideojsOptions (options: {
         videoViewUrl: options.videoViewUrl,
         videoDuration: options.videoDuration,
         startTime: options.startTime
+      },
+      contextmenuUI: {
+        content: [
+          {
+            label: 'Copy the video URL',
+            listener: function () {
+              copyToClipboard(buildVideoLink())
+            }
+          },
+          {
+            label: 'Copy the video URL at the current time',
+            listener: function () {
+              const player = this
+              copyToClipboard(buildVideoLink(player.currentTime()))
+            }
+          },
+          {
+            label: 'Copy embed code',
+            listener: () => {
+              copyToClipboard(buildVideoEmbed(options.videoEmbedUrl))
+            }
+          }
+        ]
       }
     },
     controlBar: {
index d9ded7a7ed0979eb9084e0362849b61967f3cd04..65103f3ab732bc99586eb5ca6b3564285ce82417 100644 (file)
@@ -268,6 +268,10 @@ class PeerTubePlugin extends Plugin {
     this.trigger('autoResolutionUpdate')
   }
 
+  getCurrentVideoFile () {
+    return this.currentVideoFile
+  }
+
   private tryToPlay (done?: Function) {
     if (!done) done = function () { /* empty */ }
 
index 1df39d4e4a840ad4811062d8f594e917478a711d..487b3a1be055c9114d4a872dc4465c2126ab049b 100644 (file)
@@ -64,14 +64,48 @@ function isMobile () {
   return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
 }
 
+function buildVideoLink (time?: number) {
+  let href = window.location.href.replace('/embed/', '/watch/')
+  if (time) {
+    const timeInt = Math.floor(time)
+
+    if (window.location.search) href += '&start=' + timeInt
+    else href += '?start=' + timeInt
+  }
+
+  return href
+}
+
+function buildVideoEmbed (embedUrl: string) {
+  return '<iframe width="560" height="315" ' +
+    'src="' + embedUrl + '" ' +
+    'frameborder="0" allowfullscreen>' +
+    '</iframe>'
+}
+
+function copyToClipboard (text: string) {
+  const el = document.createElement('textarea')
+  el.value = text
+  el.setAttribute('readonly', '')
+  el.style.position = 'absolute'
+  el.style.left = '-9999px'
+  document.body.appendChild(el)
+  el.select()
+  document.execCommand('copy')
+  document.body.removeChild(el)
+}
+
 export {
   toTitleCase,
+  buildVideoLink,
   getStoredVolume,
   saveVolumeInStore,
   saveAverageBandwidth,
   getAverageBandwidth,
   saveMuteInStore,
+  buildVideoEmbed,
   getStoredMute,
+  copyToClipboard,
   isMobile,
   bytes
 }
index 4b54b661a4e24e8bfc00f1bae0d6285f00c4847a..4affb43cf1c951aa87cf23c3d246c971b83a9d7d 100644 (file)
@@ -50,7 +50,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca
 
       return fallbackToMediaSource()
     })
-    preparedElem.addEventListener('canplay', onLoadStart)
+    preparedElem.addEventListener('loadstart', onLoadStart)
     return videostream(file, preparedElem)
   }
 
@@ -66,7 +66,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca
 
       return callback(err)
     })
-    preparedElem.addEventListener('canplay', onLoadStart)
+    preparedElem.addEventListener('loadstart', onLoadStart)
 
     const wrapper = new MediaElementWrapper(preparedElem)
     const writable = wrapper.createWriteStream(codecs)
@@ -95,7 +95,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca
   }
 
   function onLoadStart () {
-    preparedElem.removeEventListener('canplay', onLoadStart)
+    preparedElem.removeEventListener('loadstart', onLoadStart)
     if (opts.autoplay) preparedElem.play()
 
     callback(null, renderer)
index 680958a9f8b0471785b3b2036d263bd094eab3ee..350e7cdd589814c5de5c87d7b31a43a5a48186bd 100644 (file)
@@ -21,6 +21,8 @@ $slider-bg-color: lighten($primary-background-color, 33%);
 $setting-transition-duration: 0.15s;
 $setting-transition-easing: ease-out;
 
+$context-menu-width: 350px;
+
 .video-js.vjs-peertube-skin {
   font-size: $font-size;
   color: $primary-foreground-color;
@@ -787,4 +789,32 @@ $setting-transition-easing: ease-out;
       }
     }
   }
+}
+
+/* Sass for videojs-contextmenu-ui */
+
+.video-js .vjs-contextmenu-ui-menu {
+  position: absolute;
+  background-color: rgba(0, 0, 0, 0.5);
+  padding: 5px 0;
+  width: $context-menu-width;
+
+  .vjs-menu-content {
+    opacity: $primary-foreground-opacity;
+    color: $primary-foreground-color;
+    font-size: $font-size !important;
+    font-weight: $font-semibold;
+  }
+
+  .vjs-menu-item {
+    cursor: pointer;
+    font-size: 1em;
+    padding: 8px 16px;
+    text-align: left;
+    text-transform: none;
+
+    &:hover {
+      background-color: rgba(255, 255, 255, 0.2);
+    }
+  }
 }
\ No newline at end of file
index ba906cc3215dd7e0fddd506d98a57456515c28e3..d603690cacdfd89dc0265e4050496b19af018033 100644 (file)
@@ -91,6 +91,7 @@ loadVideoInfo(videoId)
     const videojsOptions = getVideojsOptions({
       autoplay,
       inactivityTimeout: 1500,
+      videoEmbedUrl: window.location.origin + videoInfo.embedPath,
       videoViewUrl: getVideoUrl(videoId) + '/views',
       playerElement: videoElement,
       videoFiles: videoInfo.files,
index 7806611f2d14aca622daa846630fbe7640da3197..fe2e040d8d6e8bda129294e64d0c1f4ff203bcf5 100644 (file)
@@ -10006,6 +10006,21 @@ video.js@^5.19.2, "video.js@^6.8.0 || ^7.0.0", video.js@^7, video.js@^7.0.3:
     videojs-vtt.js "0.14.1"
     xhr "2.4.0"
 
+videojs-contextmenu-ui@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/videojs-contextmenu-ui/-/videojs-contextmenu-ui-4.0.0.tgz#e7ffceacac95c5d2bc7f80db6f75675404de542a"
+  dependencies:
+    global "^4.3.2"
+    video.js "^5.19.2"
+    videojs-contextmenu "^2.0.0"
+
+videojs-contextmenu@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/videojs-contextmenu/-/videojs-contextmenu-2.0.0.tgz#7213c8c420ecd2904d26f19c21085f7ebf496e9e"
+  dependencies:
+    global "^4.3.2"
+    video.js "^5.19.2"
+
 videojs-dock@^2.0.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/videojs-dock/-/videojs-dock-2.1.2.tgz#621c27c6f7dd131c541535300ac545377e515a0e"
index 4e890d771a325ee68d344c1ae6ee173afb41816b..608646e7d84422b5783b40e982e1e130d9ec272a 100644 (file)
@@ -65,7 +65,7 @@
   "lint-staged": {
     "*.{css,md}": "precise-commits",
     "*.scss": [
-      "sass-lint-auto-fix -c .sass-lint.yml --verbose",
+      "sass-lint -c .sass-lint.yml",
       "git add"
     ]
   },
     "chai-json-schema": "^1.5.0",
     "chai-xml": "^0.3.2",
     "husky": "^1.0.0-rc.4",
-    "libxmljs": "^0.18.9-pre0",
+    "libxmljs": "0.18.8",
     "lint-staged": "^7.1.0",
     "maildev": "^1.0.0-rc3",
     "mocha": "^5.0.0",
     "prettier": "1.13.2",
     "prompt": "^1.0.0",
     "sass-lint": "^1.12.1",
-    "sass-lint-auto-fix": "^0.10.0",
     "source-map-support": "^0.5.0",
     "spectacle-docs": "^1.0.2",
     "supertest": "^3.0.0",
index 90219a9cd49835ef26b272362384f30fd5537105..c1fed9c6001125866e582b9a614c2086809b5dd8 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
@@ -398,7 +398,7 @@ ajv-keywords@^1.0.0:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
 
-ajv@^4.7.0, ajv@^4.9.1:
+ajv@^4.7.0:
   version "4.11.8"
   resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
   dependencies:
@@ -2849,15 +2849,7 @@ fsevents@^1.1.2:
     nan "^2.9.2"
     node-pre-gyp "^0.10.0"
 
-fstream-ignore@^1.0.5:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
-  dependencies:
-    fstream "^1.0.0"
-    inherits "2"
-    minimatch "^3.0.0"
-
-fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+fstream@^1.0.0, fstream@^1.0.2:
   version "1.0.11"
   resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
   dependencies:
@@ -3308,10 +3300,6 @@ gzip-size@^3.0.0:
   optionalDependencies:
     uglify-js "^2.6"
 
-har-schema@^1.0.5:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
-
 har-schema@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
@@ -3325,13 +3313,6 @@ har-validator@~2.0.6:
     is-my-json-valid "^2.12.4"
     pinkie-promise "^2.0.0"
 
-har-validator@~4.2.1:
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
-  dependencies:
-    ajv "^4.9.1"
-    har-schema "^1.0.5"
-
 har-validator@~5.0.3:
   version "5.0.3"
   resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd"
@@ -3419,7 +3400,7 @@ hashish@~0.0.4:
   dependencies:
     traverse ">=0.2.4"
 
-hawk@3.1.3, hawk@~3.1.3:
+hawk@~3.1.3:
   version "3.1.3"
   resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
   dependencies:
@@ -4451,13 +4432,13 @@ levn@^0.3.0, levn@~0.3.0:
     prelude-ls "~1.1.2"
     type-check "~0.3.2"
 
-libxmljs@^0.18.9-pre0:
-  version "0.18.9-pre0"
-  resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.18.9-pre0.tgz#2e607aae228d856777bab1205d54e0dcefe825ba"
+libxmljs@0.18.8:
+  version "0.18.8"
+  resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.18.8.tgz#b0a07512a01290b6240600d6c2bc33a3c70976d6"
   dependencies:
-    bindings "~1.3.0"
+    bindings "^1.3.0"
     nan "~2.10.0"
-    node-pre-gyp "~0.6.37"
+    node-pre-gyp "^0.9.1"
 
 lint-staged@^7.1.0:
   version "7.1.2"
@@ -5013,7 +4994,7 @@ minimatch@0.3:
     lru-cache "2"
     sigmund "~1.0.0"
 
-"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2:
+"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
   dependencies:
@@ -5283,7 +5264,7 @@ node-gyp@^3.3.1:
     tar "^2.0.0"
     which "1"
 
-node-pre-gyp@0.9.1:
+node-pre-gyp@0.9.1, node-pre-gyp@^0.9.1:
   version "0.9.1"
   resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.9.1.tgz#f11c07516dd92f87199dbc7e1838eab7cd56c9e0"
   dependencies:
@@ -5313,22 +5294,6 @@ node-pre-gyp@^0.10.0:
     semver "^5.3.0"
     tar "^4"
 
-node-pre-gyp@~0.6.37:
-  version "0.6.39"
-  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649"
-  dependencies:
-    detect-libc "^1.0.2"
-    hawk "3.1.3"
-    mkdirp "^0.5.1"
-    nopt "^4.0.1"
-    npmlog "^4.0.2"
-    rc "^1.1.7"
-    request "2.81.0"
-    rimraf "^2.6.1"
-    semver "^5.3.0"
-    tar "^2.2.1"
-    tar-pack "^3.4.0"
-
 node-redis-scripty@0.0.5:
   version "0.0.5"
   resolved "https://registry.yarnpkg.com/node-redis-scripty/-/node-redis-scripty-0.0.5.tgz#4bf2d365ab6dab202cc08b7ac63f8f55aadc9625"
@@ -5866,10 +5831,6 @@ pem@^1.12.3:
     safe-buffer "^5.1.1"
     which "^1.2.4"
 
-performance-now@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
-
 performance-now@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
@@ -6289,10 +6250,6 @@ qs@~6.3.0:
   version "6.3.2"
   resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c"
 
-qs@~6.4.0:
-  version "6.4.0"
-  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
-
 random-access-file@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.0.1.tgz#dc22de79270e9a84cb36a2419b759725930dcaeb"
@@ -6604,33 +6561,6 @@ request@2, request@^2.81.0, request@^2.83.0:
     tunnel-agent "^0.6.0"
     uuid "^3.1.0"
 
-request@2.81.0:
-  version "2.81.0"
-  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
-  dependencies:
-    aws-sign2 "~0.6.0"
-    aws4 "^1.2.1"
-    caseless "~0.12.0"
-    combined-stream "~1.0.5"
-    extend "~3.0.0"
-    forever-agent "~0.6.1"
-    form-data "~2.1.1"
-    har-validator "~4.2.1"
-    hawk "~3.1.3"
-    http-signature "~1.1.0"
-    is-typedarray "~1.0.0"
-    isstream "~0.1.2"
-    json-stringify-safe "~5.0.1"
-    mime-types "~2.1.7"
-    oauth-sign "~0.8.1"
-    performance-now "^0.2.0"
-    qs "~6.4.0"
-    safe-buffer "^5.0.1"
-    stringstream "~0.0.4"
-    tough-cookie "~2.3.0"
-    tunnel-agent "^0.6.0"
-    uuid "^3.0.0"
-
 request@~2.79.0:
   version "2.79.0"
   resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
@@ -6734,7 +6664,7 @@ right-align@^0.1.1:
   dependencies:
     align-text "^0.1.1"
 
-rimraf@2, rimraf@2.x.x, rimraf@^2.2.1, rimraf@^2.2.8, rimraf@^2.4.2, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1:
+rimraf@2, rimraf@2.x.x, rimraf@^2.2.1, rimraf@^2.2.8, rimraf@^2.4.2, rimraf@^2.5.4, rimraf@^2.6.1:
   version "2.6.2"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
   dependencies:
@@ -6811,9 +6741,9 @@ sass-graph@^2.2.4:
     scss-tokenizer "^0.2.3"
     yargs "^7.0.0"
 
-sass-lint-auto-fix@^0.10.0:
-  version "0.10.0"
-  resolved "https://registry.yarnpkg.com/sass-lint-auto-fix/-/sass-lint-auto-fix-0.10.0.tgz#89fd3cfd29fae30ddb7bbefa488053553ef0f10e"
+sass-lint-auto-fix@^0.9.0:
+  version "0.9.2"
+  resolved "https://registry.yarnpkg.com/sass-lint-auto-fix/-/sass-lint-auto-fix-0.9.2.tgz#b8b6eb95644f7919dfea33d04c1fc19ae8f07a11"
   dependencies:
     chalk "^2.3.2"
     commander "^2.15.1"
@@ -7693,19 +7623,6 @@ tar-fs@^1.13.0:
     pump "^1.0.0"
     tar-stream "^1.1.2"
 
-tar-pack@^3.4.0:
-  version "3.4.1"
-  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f"
-  dependencies:
-    debug "^2.2.0"
-    fstream "^1.0.10"
-    fstream-ignore "^1.0.5"
-    once "^1.3.3"
-    readable-stream "^2.1.4"
-    rimraf "^2.5.1"
-    tar "^2.2.1"
-    uid-number "^0.0.6"
-
 tar-stream@^1.1.2:
   version "1.6.1"
   resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395"
@@ -7718,7 +7635,7 @@ tar-stream@^1.1.2:
     to-buffer "^1.1.0"
     xtend "^4.0.0"
 
-tar@^2.0.0, tar@^2.2.1:
+tar@^2.0.0:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
   dependencies:
@@ -8054,10 +7971,6 @@ uglify-to-browserify@~1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
 
-uid-number@^0.0.6:
-  version "0.0.6"
-  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
-
 uint64be@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/uint64be/-/uint64be-1.0.1.tgz#1f7154202f2a1b8af353871dda651bf34ce93e95"